questionwnd.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #include "main.h"
  2. #include "./copyfiles.h"
  3. #include "./copyinternal.h"
  4. #include "./resource.h"
  5. #include "../nu/trace.h"
  6. #include <shlwapi.h>
  7. #include <strsafe.h>
  8. #define QUESTIONBOX_PROP TEXT("QUESTIONBOX")
  9. #define GetQuestionBox(__hdlg) ((QUESTIONBOX*)GetProp((__hdlg), QUESTIONBOX_PROP))
  10. #define GetResolvedString(__pszText, __pszBuffer, __chhBufferMax)\
  11. (IS_INTRESOURCE(__pszText) ? WASABI_API_LNGSTRINGW_BUF((UINT)(UINT_PTR)(__pszText), (__pszBuffer), (__chhBufferMax)) : (__pszText))
  12. static INT_PTR CALLBACK CopyQuestion_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  13. INT_PTR MLDisc_ShowQuestionBox(QUESTIONBOX *pQuestionBox)
  14. {
  15. if (!pQuestionBox) return IDCANCEL;
  16. return WASABI_API_DIALOGBOXPARAMW(IDD_FILECOPY_QUESTION, pQuestionBox->hParent, CopyQuestion_DialogProc, (LPARAM)pQuestionBox);
  17. }
  18. static BOOL FindPrefferedSizeEx(HDC hdc, LPCTSTR pszText, LPCTSTR pszNewLine, SIZE *pSize)
  19. {
  20. if (!pSize) return FALSE;
  21. pSize->cx = 0; pSize->cy = 0;
  22. if (!hdc || !pszText || !pszNewLine) return FALSE;
  23. LPCTSTR pszBlock = pszText;
  24. LPCTSTR pszCursor = pszBlock;
  25. INT cchSep = lstrlenW(pszNewLine);
  26. INT matched = 0;
  27. for(;;)
  28. {
  29. if (*pszCursor)
  30. {
  31. if (*pszCursor == pszNewLine[matched]) matched++;
  32. else matched = 0;
  33. pszCursor++;
  34. }
  35. if (matched == cchSep || TEXT('\0') == *pszCursor)
  36. {
  37. SIZE sz;
  38. INT l = (INT)(size_t)((pszCursor - pszBlock) - matched);
  39. if (l > 0)
  40. {
  41. if (!GetTextExtentPoint32(hdc, pszBlock, l, &sz)) return FALSE;
  42. }
  43. else
  44. {
  45. if (!GetTextExtentPoint32(hdc, TEXT("\n"), 1, &sz)) return FALSE;
  46. sz.cx = 0;
  47. }
  48. if (pSize->cx < sz.cx) pSize->cx= sz.cx;
  49. pSize->cy += sz.cy;
  50. if (TEXT('\0') == *pszCursor) break;
  51. else
  52. {
  53. matched = 0;
  54. pszBlock = pszCursor;
  55. }
  56. }
  57. }
  58. return TRUE;
  59. }
  60. static BOOL FindPrefferedSize(HWND hwnd, LPCTSTR pszText, LPCTSTR pszNewLine, SIZE *pSize)
  61. {
  62. HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_PARENTCLIP);
  63. if (!hdc) return FALSE;
  64. HFONT hf, hfo;
  65. hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
  66. if (NULL == hf) hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
  67. hfo = (NULL != hf) ? (HFONT)SelectObject(hdc, hf) : NULL;
  68. BOOL br = FindPrefferedSizeEx(hdc, pszText, pszNewLine, pSize);
  69. if (hfo) SelectObject(hdc, hfo);
  70. ReleaseDC(hwnd, hdc);
  71. return br;
  72. }
  73. static INT_PTR CopyQuestion_OnInitDialog(HWND hdlg, HWND hFocus, QUESTIONBOX *pqb)
  74. {
  75. if (!pqb) return FALSE;
  76. SetProp(hdlg, QUESTIONBOX_PROP, pqb);
  77. HWND hctrl;
  78. TCHAR szBuffer[2048] = {0};
  79. LONG messageLeft = 0;
  80. if (NULL != pqb->pszTitle) SetWindowText(hdlg, GetResolvedString(pqb->pszTitle, szBuffer, ARRAYSIZE(szBuffer)));
  81. if (NULL != pqb->pszBtnOkText) SetDlgItemText(hdlg, IDOK, GetResolvedString(pqb->pszBtnOkText, szBuffer, ARRAYSIZE(szBuffer)));
  82. if (NULL != pqb->pszBtnCancelText) SetDlgItemText(hdlg, IDCANCEL, GetResolvedString(pqb->pszBtnCancelText, szBuffer, ARRAYSIZE(szBuffer)));
  83. if (NULL != (hctrl = GetDlgItem(hdlg, IDC_BTN_EXTRA1)))
  84. {
  85. ShowWindow(hctrl, (QBF_SHOW_EXTRA_BUTTON & pqb->uFlags) ? SW_SHOWNA : SW_HIDE);
  86. if (NULL != pqb->pszBtnExtraText) SetWindowText(hctrl, GetResolvedString(pqb->pszBtnExtraText, szBuffer, ARRAYSIZE(szBuffer)));
  87. }
  88. if (NULL != (hctrl = GetDlgItem(hdlg, IDC_PIC_ICON)))
  89. {
  90. HICON hIcon = NULL;
  91. if (NULL != pqb->pszIcon)
  92. {
  93. hIcon = LoadIcon(WASABI_API_LNG_HINST, pqb->pszIcon);
  94. if (NULL == hIcon) hIcon = LoadIcon(WASABI_API_ORIG_HINST, pqb->pszIcon);
  95. if (NULL == hIcon) hIcon = LoadIcon(NULL, pqb->pszIcon);
  96. }
  97. SendMessage(hctrl, STM_SETICON, (WPARAM)hIcon, 0L);
  98. ShowWindow(hctrl, (hIcon) ? SW_SHOWNA : SW_HIDE);
  99. RECT rw;
  100. GetWindowRect(hctrl, &rw);
  101. MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2);
  102. messageLeft = (hIcon) ? (rw.right + 24) : rw.left;
  103. }
  104. INT shiftRight = 0, shiftBottom = 0;
  105. if (NULL != (hctrl = GetDlgItem(hdlg, IDC_LBL_MESSAGE)))
  106. {
  107. RECT rw;
  108. SIZE textSize = { 0, 0 };
  109. LPCTSTR pszText = (NULL != pqb->pszMessage) ? GetResolvedString(pqb->pszMessage, szBuffer, ARRAYSIZE(szBuffer)) : NULL;
  110. if (pszText)
  111. {
  112. FindPrefferedSize(hctrl, pszText, TEXT("\n"), &textSize);
  113. textSize.cx += 8; textSize.cy += 4;
  114. }
  115. SetWindowText(hctrl, pszText);
  116. GetWindowRect(hctrl, &rw);
  117. MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2);
  118. rw.left = messageLeft;
  119. shiftRight = (rw.left + textSize.cx) - rw.right;
  120. if (shiftRight < 0) shiftRight = 0;
  121. shiftBottom = textSize.cy - (rw.bottom - rw.top);
  122. if (shiftBottom < 0) shiftBottom = 0;
  123. SetWindowPos(hctrl, NULL, rw.left, rw.top, (rw.right - rw.left) + shiftRight, (rw.bottom - rw.top) + shiftBottom, SWP_NOACTIVATE | SWP_NOZORDER);
  124. }
  125. if (NULL != (hctrl = GetDlgItem(hdlg, IDC_CHECKBOX1)))
  126. {
  127. if (NULL != pqb->pszCheckboxText) SetWindowText(hctrl, GetResolvedString(pqb->pszCheckboxText, szBuffer, ARRAYSIZE(szBuffer)));
  128. SendMessage(hctrl, BM_SETCHECK, (pqb->checkboxChecked) ? BST_CHECKED : BST_UNCHECKED, 0L);
  129. RECT rw;
  130. GetWindowRect(hctrl, &rw);
  131. if (0 == (QBF_SHOW_CHECKBOX & pqb->uFlags))
  132. {
  133. shiftBottom -= (rw.bottom - rw.top);
  134. ShowWindow(hctrl, SW_HIDE);
  135. }
  136. else if (shiftRight || shiftBottom)
  137. {
  138. MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2);
  139. SetWindowPos(hctrl, NULL, rw.left, rw.top + shiftBottom,
  140. (rw.right - rw.bottom) + shiftRight, (rw.bottom - rw.top), SWP_NOACTIVATE | SWP_NOZORDER);
  141. ShowWindow(hctrl, SW_SHOWNA);
  142. }
  143. }
  144. if (shiftRight || shiftBottom)
  145. {
  146. RECT rw;
  147. INT idList[] = {IDC_BTN_EXTRA1, IDOK, IDCANCEL, };
  148. for (int i = 0; i < ARRAYSIZE(idList); i++)
  149. {
  150. if (NULL != (hctrl = GetDlgItem(hdlg, idList[i])))
  151. {
  152. GetWindowRect(hctrl, &rw);
  153. MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2);
  154. SetWindowPos(hctrl, NULL, rw.left + shiftRight, rw.top + shiftBottom, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
  155. }
  156. }
  157. }
  158. HWND hParent = GetParent(hdlg);
  159. if (hParent)
  160. {
  161. RECT rw, rc;
  162. GetClientRect(hParent, &rc);
  163. GetWindowRect(hdlg, &rw);
  164. rw.right += shiftRight;
  165. rw.bottom += shiftBottom;
  166. SetWindowPos(hdlg, NULL,
  167. rw.left + ((rc.right - rc.left) - (rw.right - rw.left))/2,
  168. rw.top + ((rc.bottom - rc.top) - (rw.bottom - rw.top))/2,
  169. rw.right - rw.left, rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER);
  170. }
  171. SendMessage(hdlg, DM_REPOSITION, 0, 0L);
  172. return FALSE;
  173. }
  174. static void CopyQuestion_OnDestroy(HWND hdlg)
  175. {
  176. QUESTIONBOX *pqb = GetQuestionBox(hdlg);
  177. if (pqb)
  178. {
  179. pqb->checkboxChecked = (BST_CHECKED == IsDlgButtonChecked(hdlg, IDC_CHECKBOX1));
  180. }
  181. RemoveProp(hdlg, QUESTIONBOX_PROP);
  182. }
  183. static void CopyQuestion_OnCommand(HWND hdlg, INT ctrlId, INT eventId, HWND hctrl)
  184. {
  185. switch(ctrlId)
  186. {
  187. case IDOK:
  188. case IDCANCEL:
  189. EndDialog(hdlg, ctrlId);
  190. break;
  191. case IDC_BTN_EXTRA1:
  192. if (BN_CLICKED == eventId) EndDialog(hdlg, ctrlId);
  193. break;
  194. }
  195. }
  196. #define IDT_POSTSHOW 1985
  197. #define DELAY_POSTSHOW 0
  198. static void CALLBACK CopyQuestion_OnPostShowElapsed(HWND hdlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  199. {
  200. QUESTIONBOX *pqb = GetQuestionBox(hdlg);
  201. KillTimer(hdlg, idEvent);
  202. if (!pqb) return;
  203. if (QBF_FLASH & pqb->uFlags)
  204. {
  205. FLASHWINFO flash = { sizeof(FLASHWINFO), };
  206. flash.hwnd = hdlg;
  207. flash.dwFlags = FLASHW_ALL;
  208. flash.uCount = 2;
  209. flash.dwTimeout = 300;
  210. FlashWindowEx(&flash);
  211. }
  212. if (QBF_BEEP & pqb->uFlags) MessageBeep(pqb->uBeepType);
  213. if ((QBF_SETFOREGROUND | QBF_TOPMOST) & pqb->uFlags)
  214. {
  215. SetForegroundWindow(hdlg);
  216. SetWindowPos(hdlg, (QBF_SETFOREGROUND & pqb->uFlags) ? HWND_TOP : HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
  217. }
  218. }
  219. static void CopyQuestion_OnShowWindow(HWND hdlg, BOOL bShow, UINT nStatus)
  220. {
  221. if (bShow)
  222. {
  223. SetTimer(hdlg, IDT_POSTSHOW, DELAY_POSTSHOW, CopyQuestion_OnPostShowElapsed);
  224. }
  225. }
  226. static INT_PTR CALLBACK CopyQuestion_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  227. {
  228. switch(uMsg)
  229. {
  230. case WM_INITDIALOG: return CopyQuestion_OnInitDialog(hdlg, (HWND)wParam, (QUESTIONBOX*)lParam);
  231. case WM_DESTROY: CopyQuestion_OnDestroy(hdlg); break;
  232. case WM_COMMAND: CopyQuestion_OnCommand(hdlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
  233. case WM_SHOWWINDOW: CopyQuestion_OnShowWindow(hdlg, (BOOL)wParam, (UINT)lParam); break;
  234. }
  235. return 0;
  236. }