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 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 23 ProgressDlg::ProgressDlg(_In_ RunOnceExInstance &RunOnceExInst) : 24 m_hListBox(NULL), 25 m_hBoldFont(NULL), 26 m_PointedItem(0), 27 m_RunOnceExInst(RunOnceExInst) 28 { ; } 29 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 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 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 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 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