https://git.reactos.org/?p=reactos.git;a=commitdiff;h=44b2a46d032fd50255f558...
commit 44b2a46d032fd50255f55895dc9f7c389778e212 Author: Katayama Hirofumi MZ katayama.hirofumi.mz@gmail.com AuthorDate: Wed Mar 15 07:29:25 2023 +0900 Commit: GitHub noreply@github.com CommitDate: Wed Mar 15 07:29:25 2023 +0900
[MSPAINT] Avoid flickering when resizing (#5144)
- Add CPaletteWindow::OnEraseBkgnd to avoid flickering. - Add getColorBoxRect and drawColorBox helper functions to draw a color box. - Add CPaletteWindow::DoHitTest helper function to do a hit test. - Improve CPaletteWindow::OnPaint by using a memory bitmap. - Improve readability of CMainWindow::alignChildrenToMainWindow. CORE-18867 --- base/applications/mspaint/palette.cpp | 175 +++++++++++++++++++++++----------- base/applications/mspaint/palette.h | 9 ++ base/applications/mspaint/resource.h | 1 + base/applications/mspaint/toolbox.cpp | 20 ++-- base/applications/mspaint/toolbox.h | 6 ++ base/applications/mspaint/winproc.cpp | 55 ++++++----- 6 files changed, 173 insertions(+), 93 deletions(-)
diff --git a/base/applications/mspaint/palette.cpp b/base/applications/mspaint/palette.cpp index 24fe9c96bf5..7795b97c28e 100644 --- a/base/applications/mspaint/palette.cpp +++ b/base/applications/mspaint/palette.cpp @@ -4,95 +4,162 @@ * FILE: base/applications/mspaint/palette.cpp * PURPOSE: Window procedure of the palette window * PROGRAMMERS: Benedikt Freisen + * Katayama Hirofumi MZ katayama.hirofumi.mz@gmail.com */
-/* INCLUDES *********************************************************/ - #include "precomp.h"
+/* The private metrics */ +#define CXY_SELECTEDBOX 15 /* width / height of a selected color box */ +#define X_MARGIN 4 /* horizontal margin */ +#define Y_MARGIN ((rcClient.bottom / 2) - CXY_COLORBOX) /* center position minus one color box */ +#define X_COLORBOX_OFFSET (X_MARGIN + CXY_BIGBOX + X_MARGIN) +#define COLOR_COUNT 28 +#define HALF_COLOR_COUNT (COLOR_COUNT / 2) + /* FUNCTIONS ********************************************************/
+static VOID drawColorBox(HDC hDC, LPCRECT prc, COLORREF rgbColor, UINT nBorder) +{ + RECT rc = *prc; + ::FillRect(hDC, &rc, (HBRUSH)(COLOR_3DFACE + 1)); + ::DrawEdge(hDC, &rc, nBorder, BF_RECT | BF_ADJUST); + + HBRUSH hbr = ::CreateSolidBrush(rgbColor); + ::FillRect(hDC, &rc, hbr); + ::DeleteObject(hbr); +} + +static VOID getColorBoxRect(LPRECT prc, const RECT& rcClient, INT iColor) +{ + INT dx = (iColor % HALF_COLOR_COUNT) * CXY_COLORBOX; /* delta x */ + INT dy = (iColor / HALF_COLOR_COUNT) * CXY_COLORBOX; /* delta y */ + prc->left = X_COLORBOX_OFFSET + dx; + prc->right = prc->left + CXY_COLORBOX; + prc->top = Y_MARGIN + dy; + prc->bottom = prc->top + CXY_COLORBOX; +} + +INT CPaletteWindow::DoHitTest(INT xPos, INT yPos) const +{ + RECT rcClient; + GetClientRect(&rcClient); + + /* delta x and y */ + INT dx = (xPos - X_COLORBOX_OFFSET), dy = (yPos - Y_MARGIN); + + /* horizontal and vertical indexes */ + INT ix = (dx / CXY_COLORBOX), iy = (dy / CXY_COLORBOX); + + /* Is it inside of a color box? */ + if (0 <= ix && ix < HALF_COLOR_COUNT && 0 <= iy && iy < 2) + return ix + (iy * HALF_COLOR_COUNT); /* return the color index */ + + return -1; /* Not found */ +} + +LRESULT CPaletteWindow::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + return TRUE; /* Avoid flickering */ +} + LRESULT CPaletteWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { - RECT rc = { 0, 0, 31, 32 }; - HPEN oldPen; - HBRUSH oldBrush; - int i, a, b; + RECT rc, rcClient; + GetClientRect(&rcClient);
PAINTSTRUCT ps; HDC hDC = BeginPaint(&ps);
- for(b = 2; b < 30; b++) - for(a = 2; a < 29; a++) - if ((a + b) % 2 == 1) - SetPixel(hDC, a, b, GetSysColor(COLOR_BTNHILIGHT)); - - DrawEdge(hDC, &rc, EDGE_RAISED, BF_TOPLEFT); - DrawEdge(hDC, &rc, BDR_SUNKENOUTER, BF_TOPLEFT | BF_BOTTOMRIGHT); - SetRect(&rc, 11, 12, 26, 27); - DrawEdge(hDC, &rc, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); - oldPen = (HPEN) SelectObject(hDC, CreatePen(PS_NULL, 0, 0)); - oldBrush = (HBRUSH) SelectObject(hDC, CreateSolidBrush(paletteModel.GetBgColor())); - Rectangle(hDC, rc.left, rc.top + 2, rc.right - 1, rc.bottom - 1); - DeleteObject(SelectObject(hDC, oldBrush)); - SetRect(&rc, 4, 5, 19, 20); - DrawEdge(hDC, &rc, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); - oldBrush = (HBRUSH) SelectObject(hDC, CreateSolidBrush(paletteModel.GetFgColor())); - Rectangle(hDC, rc.left + 2, rc.top + 2, rc.right - 1, rc.bottom - 1); - DeleteObject(SelectObject(hDC, oldBrush)); - DeleteObject(SelectObject(hDC, oldPen)); - - for(i = 0; i < 28; i++) + /* To avoid flickering, we use a memory bitmap. + The left and top values are zeros in client rectangle */ + HDC hMemDC = ::CreateCompatibleDC(hDC); + HBITMAP hbm = ::CreateCompatibleBitmap(hDC, rcClient.right, rcClient.bottom); + HGDIOBJ hbmOld = ::SelectObject(hMemDC, hbm); + + /* Fill the background (since WM_ERASEBKGND handling is disabled) */ + ::FillRect(hMemDC, &rcClient, (HBRUSH)(COLOR_3DFACE + 1)); + + /* Draw the big box that contains the black box and the white box */ + ::SetRect(&rc, X_MARGIN, Y_MARGIN, X_MARGIN + CXY_BIGBOX, Y_MARGIN + CXY_BIGBOX); + ::DrawEdge(hMemDC, &rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + COLORREF rgbLight = ::GetSysColor(COLOR_3DHIGHLIGHT); + for (INT y = rc.top; y < rc.bottom; ++y) + { + BOOL bLight = (y & 1); + for (INT x = rc.left; x < rc.right; ++x) + { + if (bLight) + ::SetPixelV(hMemDC, x, y, rgbLight); + bLight = !bLight; + } + } + + /* Draw the white box in the big box, at 5/8 position */ + rc.left = X_MARGIN + (CXY_BIGBOX * 5 / 8) - (CXY_SELECTEDBOX / 2); + rc.top = Y_MARGIN + (CXY_BIGBOX * 5 / 8) - (CXY_SELECTEDBOX / 2); + rc.right = rc.left + CXY_SELECTEDBOX; + rc.bottom = rc.top + CXY_SELECTEDBOX; + drawColorBox(hMemDC, &rc, paletteModel.GetBgColor(), BDR_RAISEDINNER); + + /* Draw the black box (overlapping the white box), at 3/8 position */ + rc.left = X_MARGIN + (CXY_BIGBOX * 3 / 8) - (CXY_SELECTEDBOX / 2); + rc.top = Y_MARGIN + (CXY_BIGBOX * 3 / 8) - (CXY_SELECTEDBOX / 2); + rc.right = rc.left + CXY_SELECTEDBOX; + rc.bottom = rc.top + CXY_SELECTEDBOX; + drawColorBox(hMemDC, &rc, paletteModel.GetFgColor(), BDR_RAISEDINNER); + + /* Draw the normal color boxes */ + for (INT i = 0; i < COLOR_COUNT; i++) { - SetRect(&rc, 31 + (i % 14) * 16, - 0 + (i / 14) * 16, 16 + 31 + (i % 14) * 16, 16 + 0 + (i / 14) * 16); - DrawEdge(hDC, &rc, EDGE_RAISED, BF_TOPLEFT); - DrawEdge(hDC, &rc, BDR_SUNKENOUTER, BF_RECT); - oldPen = (HPEN) SelectObject(hDC, CreatePen(PS_NULL, 0, 0)); - oldBrush = (HBRUSH) SelectObject(hDC, CreateSolidBrush(paletteModel.GetColor(i))); - Rectangle(hDC, rc.left + 2, rc.top + 2, rc.right - 1, rc.bottom - 1); - DeleteObject(SelectObject(hDC, oldBrush)); - DeleteObject(SelectObject(hDC, oldPen)); + getColorBoxRect(&rc, rcClient, i); + drawColorBox(hMemDC, &rc, paletteModel.GetColor(i), BDR_SUNKENOUTER); } + + /* Transfer bits (hDC <-- hMemDC) */ + ::BitBlt(hDC, 0, 0, rcClient.right, rcClient.bottom, hMemDC, 0, 0, SRCCOPY); + + ::SelectObject(hMemDC, hbmOld); + ::DeleteDC(hMemDC); EndPaint(&ps); return 0; }
LRESULT CPaletteWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { - if (GET_X_LPARAM(lParam) >= 31) - paletteModel.SetFgColor(paletteModel.GetColor((GET_X_LPARAM(lParam) - 31) / 16 + (GET_Y_LPARAM(lParam) / 16) * 14)); + INT iColor = DoHitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + if (iColor != -1) + paletteModel.SetFgColor(paletteModel.GetColor(iColor)); return 0; }
LRESULT CPaletteWindow::OnRButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { - if (GET_X_LPARAM(lParam) >= 31) - paletteModel.SetBgColor(paletteModel.GetColor((GET_X_LPARAM(lParam) - 31) / 16 + (GET_Y_LPARAM(lParam) / 16) * 14)); + INT iColor = DoHitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + if (iColor != -1) + paletteModel.SetBgColor(paletteModel.GetColor(iColor)); return 0; }
LRESULT CPaletteWindow::OnLButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { - if (GET_X_LPARAM(lParam) >= 31) - if (ChooseColor(&choosecolor)) - { - paletteModel.SetColor((GET_X_LPARAM(lParam) - 31) / 16 + (GET_Y_LPARAM(lParam) / 16) * 14, - choosecolor.rgbResult); - paletteModel.SetFgColor(choosecolor.rgbResult); - } + INT iColor = DoHitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + if (iColor != -1 && ChooseColor(&choosecolor)) + { + paletteModel.SetColor(iColor, choosecolor.rgbResult); + paletteModel.SetFgColor(choosecolor.rgbResult); + } return 0; }
LRESULT CPaletteWindow::OnRButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { - if (GET_X_LPARAM(lParam) >= 31) - if (ChooseColor(&choosecolor)) - { - paletteModel.SetColor((GET_X_LPARAM(lParam) - 31) / 16 + (GET_Y_LPARAM(lParam) / 16) * 14, - choosecolor.rgbResult); - paletteModel.SetBgColor(choosecolor.rgbResult); - } + INT iColor = DoHitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + if (iColor != -1 && ChooseColor(&choosecolor)) + { + paletteModel.SetColor(iColor, choosecolor.rgbResult); + paletteModel.SetBgColor(choosecolor.rgbResult); + } return 0; }
diff --git a/base/applications/mspaint/palette.h b/base/applications/mspaint/palette.h index ca84fc5e9d3..13a7b1663be 100644 --- a/base/applications/mspaint/palette.h +++ b/base/applications/mspaint/palette.h @@ -8,12 +8,17 @@
#pragma once
+#define CXY_COLORBOX 16 /* width / height of a normal color box */ +#define CXY_BIGBOX (CXY_COLORBOX * 2) /* width / height of the big box */ +#define CY_PALETTE (8 + CXY_BIGBOX + 8) + class CPaletteWindow : public CWindowImpl<CPaletteWindow> { public: DECLARE_WND_CLASS_EX(_T("Palette"), CS_DBLCLKS, COLOR_BTNFACE)
BEGIN_MSG_MAP(CPaletteWindow) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonDown) @@ -23,6 +28,7 @@ public: MESSAGE_HANDLER(WM_PALETTEMODELPALETTECHANGED, OnPaletteModelPaletteChanged) END_MSG_MAP()
+ LRESULT OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnRButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); @@ -30,4 +36,7 @@ public: LRESULT OnRButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnPaletteModelPaletteChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + +protected: + INT DoHitTest(INT xPos, INT yPos) const; }; diff --git a/base/applications/mspaint/resource.h b/base/applications/mspaint/resource.h index 3e563416309..fed82f9e1f0 100644 --- a/base/applications/mspaint/resource.h +++ b/base/applications/mspaint/resource.h @@ -119,6 +119,7 @@ #define ID_SHAPE 613 #define ID_ELLIPSE 614 #define ID_RRECT 615 +#define NUM_TOOLS (ID_RRECT - ID_FREESEL + 1)
#define ID_ACCELERATORS 800
diff --git a/base/applications/mspaint/toolbox.cpp b/base/applications/mspaint/toolbox.cpp index d11917b5cac..575ad62692c 100644 --- a/base/applications/mspaint/toolbox.cpp +++ b/base/applications/mspaint/toolbox.cpp @@ -18,15 +18,13 @@ LRESULT CToolBox::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandl HIMAGELIST hImageList; HBITMAP tempBm; int i; - TCHAR tooltips[16][30]; - - /* - * FIXME: Unintentionally there is a line above the tool bar (hidden by y-offset). - * To prevent cropping of the buttons height has been increased from 200 to 205 - */ - RECT toolbarPos = {1, -2, 1 + 50, -2 + 205}; - toolbar.Create(TOOLBARCLASSNAME, m_hWnd, toolbarPos, NULL, - WS_CHILD | WS_VISIBLE | CCS_NOPARENTALIGN | CCS_VERT | CCS_NORESIZE | TBSTYLE_TOOLTIPS); + TCHAR tooltips[NUM_TOOLS][30]; + + /* NOTE: The horizontal line above the toolbar is hidden by CCS_NODIVIDER style. */ + RECT toolbarPos = {0, 0, CX_TOOLBAR, CY_TOOLBAR}; + DWORD style = WS_CHILD | WS_VISIBLE | CCS_NOPARENTALIGN | CCS_VERT | CCS_NORESIZE | + TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER; + toolbar.Create(TOOLBARCLASSNAME, m_hWnd, toolbarPos, NULL, style); hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 16, 0); toolbar.SendMessage(TB_SETIMAGELIST, 0, (LPARAM) hImageList); tempBm = (HBITMAP) LoadImage(hProgInstance, MAKEINTRESOURCE(IDB_TOOLBARICONS), IMAGE_BITMAP, 256, 16, 0); @@ -34,7 +32,7 @@ LRESULT CToolBox::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandl DeleteObject(tempBm); toolbar.SendMessage(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
- for(i = 0; i < 16; i++) + for (i = 0; i < NUM_TOOLS; i++) { TBBUTTON tbbutton; int wrapnow = 0; @@ -54,7 +52,7 @@ LRESULT CToolBox::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandl
toolbar.SendMessage(TB_CHECKBUTTON, ID_PEN, MAKELPARAM(TRUE, 0)); toolbar.SendMessage(TB_SETMAXTEXTROWS, 0, 0); - toolbar.SendMessage(TB_SETBUTTONSIZE, 0, MAKELPARAM(25, 25)); + toolbar.SendMessage(TB_SETBUTTONSIZE, 0, MAKELPARAM(CXY_TB_BUTTON, CXY_TB_BUTTON));
return 0; } diff --git a/base/applications/mspaint/toolbox.h b/base/applications/mspaint/toolbox.h index f7cdfc91288..fc02299565b 100644 --- a/base/applications/mspaint/toolbox.h +++ b/base/applications/mspaint/toolbox.h @@ -9,6 +9,12 @@
#pragma once
+#define TOOLBAR_ROWS 8 +#define TOOLBAR_COLUMNS 2 +#define CXY_TB_BUTTON 25 +#define CX_TOOLBAR ((TOOLBAR_COLUMNS * CXY_TB_BUTTON) + 2) +#define CY_TOOLBAR ((TOOLBAR_ROWS * CXY_TB_BUTTON) + 2) + class CToolBox : public CWindowImpl<CToolBox> { public: diff --git a/base/applications/mspaint/winproc.cpp b/base/applications/mspaint/winproc.cpp index 3a064799c40..366e711ed06 100644 --- a/base/applications/mspaint/winproc.cpp +++ b/base/applications/mspaint/winproc.cpp @@ -47,45 +47,45 @@ zoomTo(int newZoom, int mouseX, int mouseY)
void CMainWindow::alignChildrenToMainWindow() { - int x, y, w, h; - RECT clientRect; + RECT clientRect, rc; GetClientRect(&clientRect); + RECT rcSpace = clientRect;
- if (::IsWindowVisible(toolBoxContainer)) + if (::IsWindowVisible(hStatusBar)) { - x = 56; - w = clientRect.right - 56; + ::GetWindowRect(hStatusBar, &rc); + rcSpace.bottom -= rc.bottom - rc.top; } - else + + HDWP hDWP = ::BeginDeferWindowPos(3); + + if (::IsWindowVisible(toolBoxContainer)) { - x = 0; - w = clientRect.right; + hDWP = ::DeferWindowPos(hDWP, toolBoxContainer, NULL, + rcSpace.left, rcSpace.top, + CX_TOOLBAR, rcSpace.bottom - rcSpace.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION); + rcSpace.left += CX_TOOLBAR; } + if (::IsWindowVisible(paletteWindow)) { - y = 49; - h = clientRect.bottom - 49; - } - else - { - y = 3; - h = clientRect.bottom - 3; + hDWP = ::DeferWindowPos(hDWP, paletteWindow, NULL, + rcSpace.left, rcSpace.top, + rcSpace.right - rcSpace.left, CY_PALETTE, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION); + rcSpace.top += CY_PALETTE; }
- INT statusBarHeight = 0; - if (::IsWindowVisible(hStatusBar)) + if (scrollboxWindow.IsWindow()) { - RECT Rect; - INT borders[3]; - ::SendMessage(hStatusBar, SB_GETRECT, 0, (LPARAM)&Rect); - ::SendMessage(hStatusBar, SB_GETBORDERS, 0, (LPARAM)&borders); - statusBarHeight = Rect.bottom - Rect.top + borders[1]; + hDWP = ::DeferWindowPos(hDWP, scrollboxWindow, NULL, + rcSpace.left, rcSpace.top, + rcSpace.right - rcSpace.left, rcSpace.bottom - rcSpace.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION); }
- if (scrollboxWindow.IsWindow()) - scrollboxWindow.MoveWindow(x, y, w, h - statusBarHeight, TRUE); - if (paletteWindow.IsWindow()) - paletteWindow.MoveWindow(x, 9, 255, 32, TRUE); + ::EndDeferWindowPos(hDWP); }
void CMainWindow::saveImage(BOOL overwrite) @@ -369,11 +369,10 @@ LRESULT CMainWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHand int test[] = { LOWORD(lParam) - 260, LOWORD(lParam) - 140, LOWORD(lParam) - 20 }; if (::IsWindow(hStatusBar)) { - ::SendMessage(hStatusBar, WM_SIZE, wParam, lParam); + ::SendMessage(hStatusBar, WM_SIZE, 0, 0); ::SendMessage(hStatusBar, SB_SETPARTS, 3, (LPARAM)&test); } alignChildrenToMainWindow(); - Invalidate(TRUE); return 0; }