xref: /reactos/dll/win32/iernonce/dialog.cpp (revision 4d0cc206)
1 /*
2  * PROJECT:     ReactOS system libraries
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Classes for displaying progress dialog.
5  * COPYRIGHT:   Copyright 2021 He Yang <1160386205@qq.com>
6  */
7 
8 #include "iernonce.h"
9 #include <process.h>
10 
11 #define ITEM_VPADDING     3
12 #define ITEM_LEFTPADDING 22
13 
CreateBoldFont(_In_ HFONT hOrigFont)14 HFONT CreateBoldFont(_In_ HFONT hOrigFont)
15 {
16     LOGFONTW fontAttributes = { 0 };
17     GetObjectW(hOrigFont, sizeof(fontAttributes), &fontAttributes);
18     fontAttributes.lfWeight = FW_BOLD;
19 
20     return CreateFontIndirectW(&fontAttributes);
21 }
22 
ProgressDlg(_In_ RunOnceExInstance & RunOnceExInst)23 ProgressDlg::ProgressDlg(_In_ RunOnceExInstance &RunOnceExInst) :
24     m_hListBox(NULL),
25     m_hBoldFont(NULL),
26     m_PointedItem(0),
27     m_RunOnceExInst(RunOnceExInst)
28 { ; }
29 
RunDialogBox()30 BOOL ProgressDlg::RunDialogBox()
31 {
32     // Show the dialog and run the items only when the list is not empty.
33     if (m_RunOnceExInst.m_SectionList.GetSize() != 0)
34     {
35         return (DoModal() == 1);
36     }
37     return TRUE;
38 }
39 
CalcTextRect(_In_ LPCWSTR lpText,_Inout_ PRECT pRect)40 void ProgressDlg::CalcTextRect(
41     _In_ LPCWSTR lpText,
42     _Inout_ PRECT pRect)
43 {
44     HDC hdc = ::GetDC(m_hListBox);
45     ::GetClientRect(m_hListBox, pRect);
46 
47     pRect->bottom = pRect->top;
48     pRect->left += ITEM_LEFTPADDING;
49 
50     HFONT OldFont = SelectFont(hdc, GetFont());
51     DrawTextW(hdc, lpText, -1, pRect, DT_CALCRECT | DT_WORDBREAK);
52     SelectFont(hdc, OldFont);
53     ::ReleaseDC(m_hListBox, hdc);
54 
55     pRect->bottom -= pRect->top;
56     pRect->bottom += ITEM_VPADDING * 2;
57     pRect->top = 0;
58     pRect->right -= pRect->left;
59     pRect->left = 0;
60 }
61 
ResizeListBoxAndDialog(_In_ int NewHeight)62 void ProgressDlg::ResizeListBoxAndDialog(_In_ int NewHeight)
63 {
64     RECT ListBoxRect;
65     RECT DlgRect;
66     ::GetWindowRect(m_hListBox, &ListBoxRect);
67     GetWindowRect(&DlgRect);
68 
69     int HeightDiff = NewHeight - (ListBoxRect.bottom - ListBoxRect.top);
70 
71     ::SetWindowPos(m_hListBox, NULL, 0, 0,
72                    ListBoxRect.right - ListBoxRect.left, NewHeight,
73                    SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
74 
75     SetWindowPos(HWND_TOP, 0, 0,
76                  DlgRect.right - DlgRect.left,
77                  DlgRect.bottom - DlgRect.top + HeightDiff,
78                  SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
79 }
80 
81 unsigned int __stdcall
RunOnceExExecThread(_In_ void * Param)82 RunOnceExExecThread(_In_ void *Param)
83 {
84     ProgressDlg *pProgressDlg = (ProgressDlg *)Param;
85 
86     pProgressDlg->m_RunOnceExInst.Exec(pProgressDlg->m_hWnd);
87     return 0;
88 }
89 
90 BOOL
ProcessWindowMessage(_In_ HWND hwnd,_In_ UINT message,_In_ WPARAM wParam,_In_ LPARAM lParam,_Out_ LRESULT & lResult,_In_ DWORD dwMsgMapID)91 ProgressDlg::ProcessWindowMessage(
92     _In_ HWND hwnd,
93     _In_ UINT message,
94     _In_ WPARAM wParam,
95     _In_ LPARAM lParam,
96     _Out_ LRESULT& lResult,
97     _In_ DWORD dwMsgMapID)
98 {
99     lResult = 0;
100     switch (message)
101     {
102         case WM_INITDIALOG:
103         {
104             if (!m_RunOnceExInst.m_Title.IsEmpty())
105             {
106                 SetWindowTextW(m_RunOnceExInst.m_Title);
107             }
108 
109             m_hListBox = GetDlgItem(IDC_LB_ITEMS);
110 
111             m_hBoldFont = CreateBoldFont(GetFont());
112 
113             m_hArrowBmp = LoadBitmapW(NULL, MAKEINTRESOURCE(OBM_MNARROW));
114             GetObjectW(m_hArrowBmp, sizeof(BITMAP), &m_ArrowBmp);
115 
116             // Add all sections with non-empty title into listbox
117             int TotalHeight = 0;
118             for (int i = 0; i < m_RunOnceExInst.m_SectionList.GetSize(); i++)
119             {
120                 RunOnceExSection &Section = m_RunOnceExInst.m_SectionList[i];
121 
122                 if (!Section.m_SectionTitle.IsEmpty())
123                 {
124                     INT Index = ListBox_AddString(m_hListBox, Section.m_SectionTitle);
125                     TotalHeight += ListBox_GetItemHeight(m_hListBox, Index);
126                     ListBox_SetItemData(m_hListBox, Index, i);
127                 }
128             }
129 
130             // Remove the sunken-edged border from the listbox.
131             ::SetWindowLongPtr(m_hListBox, GWL_EXSTYLE, ::GetWindowLongPtr(m_hListBox, GWL_EXSTYLE) & ~WS_EX_CLIENTEDGE);
132 
133             ResizeListBoxAndDialog(TotalHeight);
134 
135             // Launch a thread to execute tasks.
136             HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, RunOnceExExecThread, (void *)this, 0, NULL);
137             if (hThread == INVALID_HANDLE_VALUE)
138             {
139                 EndDialog(0);
140                 return TRUE;
141             }
142             CloseHandle(hThread);
143 
144             lResult = TRUE; // set keyboard focus to the dialog box control.
145             break;
146         }
147 
148         case WM_MEASUREITEM:
149         {
150             PMEASUREITEMSTRUCT pMeasureItem = (PMEASUREITEMSTRUCT)lParam;
151             RECT TextRect = { 0 };
152 
153             CStringW ItemText;
154             ListBox_GetText(m_hListBox, pMeasureItem->itemID,
155                             ItemText.GetBuffer(ListBox_GetTextLen(m_hListBox,
156                             pMeasureItem->itemID) + 1));
157 
158             CalcTextRect(ItemText, &TextRect);
159 
160             ItemText.ReleaseBuffer();
161 
162             pMeasureItem->itemHeight = TextRect.bottom - TextRect.top;
163             pMeasureItem->itemWidth  = TextRect.right - TextRect.left;
164 
165             break;
166         }
167 
168         case WM_DRAWITEM:
169         {
170             LPDRAWITEMSTRUCT pDrawItem = (PDRAWITEMSTRUCT)lParam;
171             CStringW ItemText;
172 
173             ListBox_GetText(m_hListBox, pDrawItem->itemID,
174                             ItemText.GetBuffer(ListBox_GetTextLen(m_hListBox,
175                             pDrawItem->itemID) + 1));
176 
177             SetBkMode(pDrawItem->hDC, TRANSPARENT);
178 
179             HFONT hOldFont = NULL;
180             if (m_PointedItem == (INT)pDrawItem->itemData)
181             {
182                 HDC hCompDC = CreateCompatibleDC(pDrawItem->hDC);
183 
184                 SelectBitmap(hCompDC, m_hArrowBmp);
185 
186                 int IconLeftPadding = (ITEM_LEFTPADDING - m_ArrowBmp.bmWidth) / 2;
187                 int IconTopPadding = (pDrawItem->rcItem.bottom - pDrawItem->rcItem.top - m_ArrowBmp.bmHeight) / 2;
188 
189                 BitBlt(pDrawItem->hDC, IconLeftPadding, pDrawItem->rcItem.top + IconTopPadding,
190                        m_ArrowBmp.bmWidth, m_ArrowBmp.bmHeight, hCompDC, 0, 0, SRCAND);
191 
192                 DeleteDC(hCompDC);
193 
194                 hOldFont = SelectFont(pDrawItem->hDC, m_hBoldFont);
195             }
196 
197             pDrawItem->rcItem.left += ITEM_LEFTPADDING;
198             pDrawItem->rcItem.top += ITEM_VPADDING;
199             DrawTextW(pDrawItem->hDC, ItemText, -1,
200                       &(pDrawItem->rcItem), DT_WORDBREAK);
201 
202             if (hOldFont)
203             {
204                 SelectFont(pDrawItem->hDC, hOldFont);
205             }
206             ItemText.ReleaseBuffer();
207 
208             break;
209         }
210 
211         case WM_SETINDEX:
212         {
213             if ((int)wParam == m_RunOnceExInst.m_SectionList.GetSize())
214             {
215                 // All sections are handled, lParam is bSuccess.
216                 EndDialog(lParam);
217             }
218             m_PointedItem = wParam;
219             InvalidateRect(NULL);
220             break;
221         }
222 
223         case WM_CTLCOLORLISTBOX:
224         {
225             lResult = (LRESULT)GetStockBrush(NULL_BRUSH);
226             break;
227         }
228 
229         case WM_DESTROY:
230         {
231             DeleteObject(m_hArrowBmp);
232             DeleteFont(m_hBoldFont);
233             break;
234         }
235     }
236     return TRUE;
237 }
238