helpwnd.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #include "main.h"
  2. #include "./resource.h"
  3. #include "../nu/trace.h"
  4. #include <strsafe.h>
  5. #define MLHELP_PROP TEXT("MLHELP")
  6. typedef struct __SIMPLEHELP
  7. {
  8. LPCWSTR pszTitle;
  9. LPCWSTR pszCaption;
  10. LPCWSTR pszText;
  11. HWND hOwner;
  12. UINT uFlags;
  13. } SIMPLEHELP;
  14. typedef struct __MLHELP
  15. {
  16. HWND hOwner;
  17. UINT uFlags;
  18. LONG width;
  19. LONG height;
  20. } MLHELP;
  21. #define GetHelp(__hwnd) ((MLHELP*)GetProp((__hwnd), MLHELP_PROP))
  22. #define CLIENT_MIN_WIDTH 280
  23. #define CLIENT_MIN_HEIGHT 200
  24. #define CLIENT_MAX_WIDTH 800
  25. #define CLIENT_MAX_HEIGHT 600
  26. #define BORDER_SPACE 10
  27. static INT_PTR CALLBACK SimpleHelp_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  28. HWND MLDisc_ShowHelp(HWND hOwner, LPCWSTR pszWindowTitle, LPCWSTR pszCaption, LPCWSTR pszText, UINT uFlags)
  29. {
  30. SIMPLEHELP help;
  31. help.pszTitle = pszWindowTitle;
  32. help.pszCaption = pszCaption;
  33. help.pszText = pszText;
  34. help.uFlags = uFlags;
  35. help.hOwner = hOwner;
  36. if (HF_DOMODAL & uFlags)
  37. {
  38. WASABI_API_DIALOGBOXPARAMW(IDD_SIMPLEHELP, hOwner, SimpleHelp_DialogProc, (LPARAM)&help);
  39. return NULL;
  40. }
  41. return WASABI_API_CREATEDIALOGPARAMW(IDD_SIMPLEHELP, hOwner, SimpleHelp_DialogProc, (LPARAM)&help);
  42. }
  43. static BOOL FindPrefferedSizeEx(HDC hdc, LPCTSTR pszText, LPCTSTR pszNewLine, SIZE *pSize)
  44. {
  45. if (!pSize) return FALSE;
  46. pSize->cx = 0; pSize->cy = 0;
  47. if (!hdc || !pszText || !pszNewLine) return FALSE;
  48. LPCTSTR pszBlock = pszText;
  49. LPCTSTR pszCursor = pszBlock;
  50. INT cchSep = lstrlenW(pszNewLine);
  51. INT matched = 0;
  52. for(;;)
  53. {
  54. if (*pszCursor)
  55. {
  56. if (*pszCursor == pszNewLine[matched]) matched++;
  57. else matched = 0;
  58. pszCursor++;
  59. }
  60. if (matched == cchSep || TEXT('\0') == *pszCursor)
  61. {
  62. SIZE sz;
  63. INT l = (INT)(size_t)((pszCursor - pszBlock) - matched);
  64. if (l > 0)
  65. {
  66. if (!GetTextExtentPoint32(hdc, pszBlock, l, &sz)) return FALSE;
  67. }
  68. else
  69. {
  70. if (!GetTextExtentPoint32(hdc, TEXT("\n"), 1, &sz)) return FALSE;
  71. sz.cx = 0;
  72. }
  73. if (pSize->cx < sz.cx) pSize->cx= sz.cx;
  74. pSize->cy += sz.cy;
  75. if (TEXT('\0') == *pszCursor) break;
  76. else
  77. {
  78. matched = 0;
  79. pszBlock = pszCursor;
  80. }
  81. }
  82. }
  83. return TRUE;
  84. }
  85. static BOOL FindPrefferedSize(HWND hwnd, LPCTSTR pszText, LPCTSTR pszNewLine, SIZE *pSize)
  86. {
  87. HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_PARENTCLIP);
  88. if (!hdc) return FALSE;
  89. HFONT hf, hfo;
  90. hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
  91. if (NULL == hf) hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
  92. hfo = (NULL != hf) ? (HFONT)SelectObject(hdc, hf) : NULL;
  93. BOOL br = FindPrefferedSizeEx(hdc, pszText, pszNewLine, pSize);
  94. if (hfo) SelectObject(hdc, hfo);
  95. ReleaseDC(hwnd, hdc);
  96. return br;
  97. }
  98. static INT_PTR SimpleHlp_OnInitDialog(HWND hdlg, HWND hFocus, LPARAM lParam)
  99. {
  100. SIMPLEHELP *pHelp = (SIMPLEHELP*)lParam;
  101. SIZE sizeCaption = { 0, 0 };
  102. SIZE sizeText = { 0, 0 };
  103. SIZE sizeClient = {0, 0};
  104. SIZE sizeButton = {0, 0};
  105. MLHELP *pmlh = (MLHELP*)calloc(1, sizeof(MLHELP));
  106. if (pmlh)
  107. {
  108. pmlh->hOwner = pHelp->hOwner;
  109. pmlh->uFlags = pHelp->uFlags;
  110. pmlh->height = 0;
  111. pmlh->width = 0;
  112. }
  113. SetProp(hdlg, MLHELP_PROP, (HANDLE)pmlh);
  114. HWND hctrl;
  115. if(pHelp)
  116. {
  117. WCHAR szBuffer[4096] = {0};
  118. if (pHelp->pszTitle)
  119. {
  120. if (IS_INTRESOURCE(pHelp->pszCaption))
  121. {
  122. WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pHelp->pszTitle, szBuffer, ARRAYSIZE(szBuffer));
  123. pHelp->pszTitle = szBuffer;
  124. }
  125. SetWindowText(hdlg, pHelp->pszTitle);
  126. }
  127. if (pHelp->pszCaption)
  128. {
  129. if (IS_INTRESOURCE(pHelp->pszCaption))
  130. {
  131. WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pHelp->pszCaption, szBuffer, ARRAYSIZE(szBuffer));
  132. pHelp->pszCaption = szBuffer;
  133. }
  134. if (NULL != (hctrl = GetDlgItem(hdlg, IDC_LBL_CAPTION)))
  135. {
  136. FindPrefferedSize(hctrl, pHelp->pszCaption, TEXT("\n"), &sizeCaption);
  137. SetWindowText(hctrl, pHelp->pszCaption);
  138. }
  139. }
  140. if (pHelp->pszText)
  141. {
  142. if (IS_INTRESOURCE(pHelp->pszText))
  143. {
  144. WCHAR form_szBuffer[4096] = {0}, *fszB = form_szBuffer, *szB = szBuffer;
  145. WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pHelp->pszText, form_szBuffer, ARRAYSIZE(form_szBuffer));
  146. while(fszB && *fszB){
  147. if(*fszB == L'\n' && *CharPrevW(form_szBuffer,fszB) != L'\r'){
  148. *szB = L'\r';
  149. szB = CharNextW(szB);
  150. }
  151. *szB = *fszB;
  152. szB = CharNextW(szB);
  153. fszB = CharNextW(fszB);
  154. }
  155. *szB = 0;
  156. pHelp->pszText = szBuffer;
  157. }
  158. if (NULL != (hctrl = GetDlgItem(hdlg, IDC_EDT_TEXT)))
  159. {
  160. FindPrefferedSize(hctrl, pHelp->pszText, TEXT("\r\n"), &sizeText);
  161. SetWindowText(hctrl, pHelp->pszText);
  162. }
  163. }
  164. if (0 == (HF_ALLOWRESIZE & pHelp->uFlags))
  165. {
  166. SetWindowLongPtrW(hdlg, GWL_EXSTYLE, GetWindowLongPtrW(hdlg, GWL_EXSTYLE) | WS_EX_DLGMODALFRAME);
  167. SetWindowLongPtrW(hdlg, GWL_STYLE, (GetWindowLongPtrW(hdlg, GWL_STYLE) & ~WS_THICKFRAME) | DS_MODALFRAME);
  168. }
  169. }
  170. if (sizeText.cx > 0) sizeText.cx += GetSystemMetrics(SM_CXVSCROLL);
  171. sizeClient.cx = ((sizeText.cx > sizeCaption.cx) ? sizeText.cx : sizeCaption.cx) + 8;
  172. if (sizeClient.cx < CLIENT_MIN_WIDTH) sizeClient.cx = CLIENT_MIN_WIDTH;
  173. if (sizeClient.cx > CLIENT_MAX_WIDTH) sizeClient.cx = CLIENT_MAX_WIDTH;
  174. sizeText.cx = sizeClient.cx;
  175. sizeCaption.cx = sizeClient.cx;
  176. sizeClient.cx += BORDER_SPACE * 2;
  177. if (sizeCaption.cy > 0) sizeCaption.cy += 16;
  178. if (sizeCaption.cy > CLIENT_MAX_HEIGHT/3) sizeCaption.cy = CLIENT_MAX_HEIGHT/3;
  179. if (sizeText.cy > 0) sizeText.cy += 16;
  180. if (sizeText.cy < (CLIENT_MIN_HEIGHT - sizeCaption.cy)) sizeText.cy = (CLIENT_MIN_HEIGHT - sizeCaption.cy);
  181. if (sizeText.cy > (CLIENT_MAX_HEIGHT - sizeCaption.cy)) sizeText.cy = (CLIENT_MAX_HEIGHT - sizeCaption.cy);
  182. if (NULL != (hctrl = GetDlgItem(hdlg, IDCANCEL)))
  183. {
  184. RECT rw;
  185. if (GetWindowRect(hctrl, &rw)) { sizeButton.cx = rw.right - rw.left; sizeButton.cy = rw.bottom - rw.top; }
  186. }
  187. LONG top = BORDER_SPACE;
  188. sizeClient.cy = BORDER_SPACE +sizeCaption.cy + sizeText.cy + 8 + sizeButton.cy + BORDER_SPACE;
  189. if (NULL != (hctrl = GetDlgItem(hdlg, IDC_LBL_CAPTION)))
  190. {
  191. if (0 == sizeCaption.cy) EnableWindow(hctrl, FALSE);
  192. SetWindowPos(hctrl, NULL, BORDER_SPACE, top, sizeCaption.cx, sizeCaption.cy, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
  193. top += sizeCaption.cy;
  194. }
  195. if (NULL != (hctrl = GetDlgItem(hdlg, IDC_EDT_TEXT)))
  196. {
  197. if (0 == sizeText.cy) EnableWindow(hctrl, FALSE);
  198. SetWindowPos(hctrl, NULL, BORDER_SPACE, top, sizeText.cx, sizeText.cy, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
  199. }
  200. if (NULL != (hctrl = GetDlgItem(hdlg, IDCANCEL)))
  201. {
  202. SetWindowPos(hctrl, NULL, sizeClient.cx - BORDER_SPACE - sizeButton.cx, sizeClient.cy - BORDER_SPACE - sizeButton.cy,
  203. sizeButton.cx, sizeButton.cy, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
  204. }
  205. RECT rw, rc;
  206. if (GetClientRect(hdlg, &rc) && GetWindowRect(hdlg, &rw))
  207. {
  208. sizeClient.cx += ((rw.right - rw.left) - (rc.right - rc.left));
  209. sizeClient.cy += ((rw.bottom - rw.top) - (rc.bottom - rc.top));
  210. }
  211. SetRect(&rw, 0, 0, 0, 0);
  212. if (pHelp->hOwner && GetWindowRect(pHelp->hOwner, &rw))
  213. {
  214. rw.left += ((rw.right - rw.left) - sizeClient.cx)/2;
  215. rw.top += ((rw.bottom - rw.top) - sizeClient.cy)/2;
  216. }
  217. UINT swpFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | ((HF_DOMODAL & pHelp->uFlags) ? SWP_NOZORDER : 0);
  218. pmlh->width = sizeClient.cx;
  219. pmlh->height = sizeClient.cy;
  220. SetWindowPos(hdlg, HWND_TOP, rw.left, rw.top, sizeClient.cx, sizeClient.cy, swpFlags);
  221. return FALSE;
  222. }
  223. static void SimpleHelp_OnDestroy(HWND hdlg)
  224. {
  225. MLHELP *pHelp = GetHelp(hdlg);
  226. RemoveProp(hdlg, MLHELP_PROP);
  227. if (pHelp && 0 == (HF_DOMODAL & pHelp->uFlags) && pHelp->hOwner && IsWindow(pHelp->hOwner))
  228. SendMessageW(pHelp->hOwner, WM_PARENTNOTIFY, MAKEWPARAM(WM_DESTROY, 0), (LPARAM)hdlg);
  229. if (pHelp) free(pHelp);
  230. }
  231. static void SimpleHlp_OnCommand(HWND hdlg, INT ctrlId, INT eventId, HWND hctrl)
  232. {
  233. MLHELP *pHelp = GetHelp(hdlg);
  234. switch(ctrlId)
  235. {
  236. case IDCANCEL:
  237. case IDOK:
  238. if (!pHelp || (HF_DOMODAL & pHelp->uFlags)) EndDialog(hdlg, ctrlId);
  239. else DestroyWindow(hdlg);
  240. break;
  241. }
  242. }
  243. /*static void SimpleHlp_OnWindowPosChanging(HWND hdlg, WINDOWPOS *pwp)
  244. {
  245. MLHELP *pHelp = GetHelp(hdlg);
  246. if (!pHelp) return;
  247. if (0 == (SWP_NOSIZE & pwp->flags))
  248. {
  249. if (pwp->cx < CLIENT_MIN_WIDTH) pwp->cx = CLIENT_MIN_WIDTH;
  250. if (pwp->cx > CLIENT_MAX_WIDTH) pwp->cx = CLIENT_MAX_WIDTH;
  251. if (pwp->cy < CLIENT_MIN_HEIGHT) pwp->cy = CLIENT_MIN_HEIGHT;
  252. if (pwp->cy > CLIENT_MAX_HEIGHT) pwp->cy = CLIENT_MAX_HEIGHT;
  253. }
  254. }
  255. static void SimpleHlp_OnWindowPosChanged(HWND hdlg, WINDOWPOS *pwp)
  256. {
  257. MLHELP *pHelp = GetHelp(hdlg);
  258. if (!pHelp) return;
  259. if (0 == (SWP_NOSIZE & pwp->flags))
  260. {
  261. RECT rw;
  262. GetWindowRect(hdlg, &rw);
  263. LONG dx = (rw.right - rw.left) - pHelp->width;
  264. LONG dy = (rw.bottom - rw.top) - pHelp->height;
  265. pHelp->width = rw.right - rw.left;
  266. pHelp->height = rw.bottom - rw.top;
  267. HDWP hdwp = BeginDeferWindowPos(3);
  268. HWND hctrl;
  269. if (hdwp && 0 != dx && NULL != (hctrl = GetDlgItem(hdlg, IDC_LBL_CAPTION)) && GetWindowRect(hctrl, &rw))
  270. {
  271. hdwp = DeferWindowPos(hdwp, hctrl, NULL, 0, 0,
  272. (rw.right - rw.left) + dx, (rw.bottom - rw.top), SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW);
  273. InvalidateRect(hctrl, NULL, TRUE);
  274. }
  275. if (hdwp && (0 != dx || 0 != dy) &&
  276. NULL != (hctrl = GetDlgItem(hdlg, IDC_EDT_TEXT)) && GetWindowRect(hctrl, &rw))
  277. {
  278. hdwp = DeferWindowPos(hdwp, hctrl, NULL, 0, 0,
  279. (rw.right - rw.left) + dx, (rw.bottom - rw.top) + dy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW);
  280. }
  281. if (hdwp && (0 != dx || 0 != dy) &&
  282. NULL != (hctrl = GetDlgItem(hdlg, IDCANCEL)) && GetWindowRect(hctrl, &rw))
  283. {
  284. MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2);
  285. hdwp = DeferWindowPos(hdwp, hctrl, NULL, rw.left + dx, rw.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW);
  286. }
  287. if (hdwp && EndDeferWindowPos(hdwp))
  288. {
  289. RedrawWindow(hdlg, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_INTERNALPAINT | RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_ERASENOW);
  290. }
  291. }
  292. }*/
  293. static INT_PTR CALLBACK SimpleHelp_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  294. {
  295. switch(uMsg)
  296. {
  297. case WM_INITDIALOG: return SimpleHlp_OnInitDialog(hdlg, (HWND)wParam, lParam);
  298. case WM_DESTROY: SimpleHelp_OnDestroy(hdlg); break;
  299. case WM_COMMAND: SimpleHlp_OnCommand(hdlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
  300. /*case WM_WINDOWPOSCHANGING: SimpleHlp_OnWindowPosChanging(hdlg, (WINDOWPOS*)lParam); return 0;
  301. case WM_WINDOWPOSCHANGED: SimpleHlp_OnWindowPosChanged(hdlg, (WINDOWPOS*)lParam); return 0;*/
  302. }
  303. return 0;
  304. }