PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/HTMLayout/include/htmlayout_dialog.hpp

#
C++ Header | 435 lines | 336 code | 66 blank | 33 comment | 49 complexity | 6d2052238ef67fd775c6f9bbf144e73f MD5 | raw file
Possible License(s): MIT
  1. /*
  2. * Terra Informatica Lightweight Embeddable HTMLayout control
  3. * http://terrainformatica.com/htmlayout
  4. *
  5. * HTML dialog.
  6. *
  7. * The code and information provided "as-is" without
  8. * warranty of any kind, either expressed or implied.
  9. *
  10. * (C) 2003-2009, Andrew Fedoniouk (andrew@terrainformatica.com)
  11. */
  12. /**\file
  13. * \brief Implementation of HTML based dialog
  14. **/
  15. #ifndef __htmlayout_dialog_hpp__
  16. #define __htmlayout_dialog_hpp__
  17. #include "htmlayout_dom.hpp"
  18. #include "htmlayout_behavior.hpp"
  19. #include "htmlayout_controls.hpp"
  20. #include "htmlayout_notifications.hpp"
  21. #include "htmlayout_queue.h"
  22. #include <shellapi.h>
  23. #include <assert.h>
  24. #pragma warning(disable:4786) //identifier was truncated...
  25. #pragma warning(disable:4996) //'strcpy' was declared deprecated
  26. #pragma warning(disable:4100) //unreferenced formal parameter
  27. #pragma once
  28. /**HTMLayout namespace.*/
  29. namespace htmlayout
  30. {
  31. class dialog: public event_handler,
  32. public notification_handler<dialog>
  33. {
  34. public:
  35. HWND hwnd;
  36. HWND parent;
  37. POINT position;
  38. INT alignment;
  39. UINT style;
  40. UINT style_ex;
  41. named_values* pvalues;
  42. LPCBYTE html;
  43. UINT html_length;
  44. json::string base_url;
  45. int return_id;
  46. dialog(HWND hWndParent, UINT styles = 0): pvalues(0),
  47. event_handler( HANDLE_BEHAVIOR_EVENT | HANDLE_INITIALIZATION),
  48. return_id(IDCANCEL)
  49. {
  50. parent = hWndParent;
  51. position.x = 0;
  52. position.y = 0;
  53. alignment = 1; // center of desktop
  54. style = WS_DLGFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | styles;
  55. style_ex = WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE;
  56. }
  57. // SHOW function family - show modal dalog and return one of
  58. // IDOK, IDCANCEL, etc. codes.
  59. // Dialog buttons shall be defined as <button name="OK">, <button name="CANCEL">, etc.
  60. // show HTML dialog from url
  61. unsigned int show( LPCWSTR url );
  62. // show HTML dialog from resource given by resource id
  63. unsigned int show( UINT html_res_id );
  64. // show HTML dialog from html in memory buffer
  65. unsigned int show( LPCBYTE html, UINT html_length );
  66. // INPUT function family - show modal dalog and return one of button codes,
  67. // values collection is used for initializing and returning values of inputs.
  68. // show HTML input dialog from url
  69. unsigned int input( LPCWSTR url, named_values& values )
  70. {
  71. pvalues = &values;
  72. return show(url);
  73. }
  74. // show HTML input dialog from resource given by resource id
  75. unsigned int input( UINT html_res_id, named_values& values )
  76. {
  77. pvalues = &values;
  78. return show(html_res_id);
  79. }
  80. // show HTML input dialog from html in memory buffer
  81. unsigned int input( LPCBYTE html, UINT html_length, named_values& values )
  82. {
  83. pvalues = &values;
  84. return show(html, html_length);
  85. }
  86. protected:
  87. virtual BOOL handle_event ( HELEMENT he, BEHAVIOR_EVENT_PARAMS& params );
  88. virtual BOOL handle_key ( HELEMENT he, KEY_PARAMS& params );
  89. virtual HWND create_window();
  90. static dialog* self(HWND hwndDlg)
  91. {
  92. #if defined(UNDER_CE)
  93. return static_cast<dialog*>( (void*)GetWindowLong(hwndDlg, DWL_USER) );
  94. #else
  95. return static_cast<dialog*>( (void*)GetWindowLongPtr(hwndDlg, DWLP_USER) );
  96. #endif
  97. }
  98. static INT_PTR CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
  99. static INT_PTR on_WM_INITDIALOG( HWND hwndDlg, WPARAM wParam, LPARAM lParam );
  100. static INT_PTR on_WM_DESTROY( HWND hwndDlg, WPARAM wParam, LPARAM lParam );
  101. static INT_PTR on_WM_USER( HWND hwndDlg, WPARAM wParam, LPARAM lParam );
  102. static INT_PTR on_WM_CLOSE( HWND hwndDlg, WPARAM wParam, LPARAM lParam );
  103. static void do_modal_loop(HWND hwnd);
  104. };
  105. // implementations
  106. // show HTML dialog from url
  107. inline unsigned int dialog::show( LPCWSTR url )
  108. {
  109. return show( (LPCBYTE) url, 0);
  110. }
  111. // show HTML dialog from resource given by resource id
  112. inline unsigned int dialog::show( UINT html_res_id )
  113. {
  114. PBYTE html;
  115. DWORD html_length;
  116. if(!load_html_resource(html_res_id, html, html_length ))
  117. {
  118. assert(false); // resource not found!
  119. return 0;
  120. }
  121. return show(html, html_length);
  122. }
  123. // show HTML dialog from html in memory buffer
  124. inline unsigned int dialog::show( LPCBYTE html, UINT html_length )
  125. {
  126. this->html = html;
  127. this->html_length = html_length;
  128. HWND hwnd = create_window();
  129. if(pvalues)
  130. {
  131. dom::element root = dom::element::root_element(hwnd);
  132. set_values(root,*pvalues);
  133. }
  134. ShowWindow(hwnd,SW_SHOW);
  135. do_modal_loop(hwnd);
  136. return return_id;
  137. }
  138. // handle button events.
  139. // here it does special treatment of "dialog buttons"
  140. inline BOOL dialog::handle_event (HELEMENT he, BEHAVIOR_EVENT_PARAMS& params )
  141. {
  142. dom::element src = params.heTarget;
  143. if( params.cmd == BUTTON_CLICK )
  144. {
  145. const wchar_t* bname = src.get_attribute("name");
  146. if(!bname)
  147. return FALSE;
  148. bool positive_answer = false;
  149. return_id = 0;
  150. if( aux::wcseqi(bname,L"OK") ) { return_id =IDOK ; positive_answer = true; }
  151. else if( aux::wcseqi(bname,L"CANCEL") ) return_id =IDCANCEL;
  152. else if( aux::wcseqi(bname,L"ABORT") ) return_id =IDABORT ;
  153. else if( aux::wcseqi(bname,L"RETRY") ) { return_id =IDRETRY ; positive_answer = true; }
  154. else if( aux::wcseqi(bname,L"IGNORE") ) return_id =IDIGNORE;
  155. else if( aux::wcseqi(bname,L"YES") ) { return_id =IDYES ; positive_answer = true; }
  156. else if( aux::wcseqi(bname,L"NO") ) return_id =IDNO ;
  157. else if( aux::wcseqi(bname,L"CLOSE") ) return_id =IDCLOSE ;
  158. else if( aux::wcseqi(bname,L"HELP") ) return_id =IDHELP ; // ?
  159. else
  160. return event_handler::handle_event (he, params) ;
  161. HWND hwndDlg = src.get_element_hwnd(true);
  162. if(positive_answer && pvalues)
  163. {
  164. dom::element root = src.root();
  165. pvalues->clear();
  166. get_values(root,*pvalues);
  167. }
  168. ::PostMessage(hwndDlg, WM_CLOSE, 0,0 );
  169. return TRUE;
  170. }
  171. #if !defined( _WIN32_WCE )
  172. else if (params.cmd == (HYPERLINK_CLICK | SINKING) )
  173. {
  174. HWND hwndLayout = src.get_element_hwnd(true);
  175. const wchar_t* url = src.get_attribute("href");
  176. if( url )
  177. {
  178. #if !defined(UNICODE)
  179. ::ShellExecuteA(hwndLayout,"open", aux::w2a(url), NULL,NULL,SW_SHOWNORMAL);
  180. #else
  181. ::ShellExecuteW(hwndLayout,L"open", url, NULL,NULL,SW_SHOWNORMAL);
  182. #endif
  183. return TRUE;
  184. }
  185. }
  186. #endif
  187. return FALSE;
  188. }
  189. inline BOOL dialog::handle_key (HELEMENT he, KEY_PARAMS& params )
  190. {
  191. if(params.cmd != KEY_DOWN)
  192. return FALSE;
  193. dom::element root = dom::element::root_element(hwnd);
  194. switch(params.key_code)
  195. {
  196. case VK_RETURN:
  197. {
  198. dom::element def = root.find_first("[role='default-button']");
  199. if( def.is_valid() )
  200. {
  201. METHOD_PARAMS params; params.methodID = DO_CLICK;
  202. return def.call_behavior_method(&params)? TRUE:FALSE;
  203. }
  204. } break;
  205. case VK_ESCAPE:
  206. {
  207. dom::element def = root.find_first("[role='cancel-button']");
  208. if( def.is_valid() )
  209. {
  210. METHOD_PARAMS params; params.methodID = DO_CLICK;
  211. return def.call_behavior_method(&params)? TRUE:FALSE;
  212. }
  213. } break;
  214. }
  215. return FALSE;
  216. }
  217. inline HWND dialog::create_window()
  218. {
  219. struct zDLGTEMPLATE: DLGTEMPLATE
  220. {
  221. WORD strings[3];
  222. };
  223. zDLGTEMPLATE dt;
  224. memset(&dt,0,sizeof(dt));
  225. dt.style = style;
  226. dt.dwExtendedStyle = style_ex;
  227. dt.cdit = 0;
  228. HINSTANCE hinstance =
  229. #if defined(UNDER_CE)
  230. (HINSTANCE)::GetModuleHandle(NULL);
  231. #else
  232. (HINSTANCE)GetWindowLongPtr(parent, GWLP_HINSTANCE);
  233. #endif
  234. hwnd = CreateDialogIndirectParam(
  235. hinstance, // handle to module
  236. &dt, // dialog box template
  237. parent, // handle to owner window
  238. &DialogProc, // dialog box procedure
  239. LPARAM(this) // initialization value
  240. );
  241. return hwnd;
  242. }
  243. inline void dialog::do_modal_loop(HWND hwnd)
  244. {
  245. #if defined(UNDER_CE)
  246. HWND frm = GetWindow(hwnd,GW_OWNER);
  247. #else
  248. HWND frm = GetAncestor(hwnd,GA_ROOTOWNER);
  249. #endif
  250. EnableWindow(frm,FALSE);
  251. MSG msg;
  252. while(::IsWindow(hwnd) && GetMessage(&msg,NULL,0,0))
  253. {
  254. queue::execute();
  255. TranslateMessage(&msg);
  256. DispatchMessage(&msg);
  257. }
  258. EnableWindow(frm,TRUE);
  259. SetForegroundWindow(frm);
  260. }
  261. inline INT_PTR CALLBACK dialog::DialogProc
  262. (
  263. HWND hwndDlg, // handle to dialog box
  264. UINT uMsg, // message
  265. WPARAM wParam, // first message parameter
  266. LPARAM lParam ) // second message parameter
  267. {
  268. BOOL handled = false;
  269. LRESULT lr = HTMLayoutProcND(hwndDlg,uMsg,wParam,lParam, &handled);
  270. if( handled )
  271. return lr;
  272. switch(uMsg)
  273. {
  274. case WM_INITDIALOG: return on_WM_INITDIALOG( hwndDlg, wParam, lParam );
  275. case WM_CLOSE: return on_WM_CLOSE( hwndDlg, wParam, lParam );
  276. case WM_DESTROY: return on_WM_DESTROY( hwndDlg, wParam, lParam );
  277. case WM_USER: return on_WM_USER( hwndDlg, wParam, lParam );
  278. }
  279. return FALSE;
  280. }
  281. inline INT_PTR dialog::on_WM_INITDIALOG( HWND hwndDlg, WPARAM wParam, LPARAM lParam )
  282. {
  283. dialog* ctl = static_cast<dialog*>((void*)lParam );
  284. #if defined(UNDER_CE)
  285. SetWindowLong(hwndDlg, DWL_USER, LONG(ctl));
  286. #else
  287. SetWindowLongPtr(hwndDlg, DWLP_USER, LONG_PTR(ctl));
  288. #endif
  289. ctl->setup_callback(hwndDlg);
  290. attach_event_handler(hwndDlg,ctl);
  291. if(!ctl->html)
  292. return FALSE;
  293. if(ctl->html_length == 0) // this is a file name
  294. HTMLayoutLoadFile(hwndDlg,(LPCWSTR)ctl->html);
  295. else
  296. HTMLayoutLoadHtmlEx(hwndDlg, ctl->html, ctl->html_length,ctl->base_url);
  297. dom::element root = dom::element::root_element(hwndDlg);
  298. if(!root.is_valid())
  299. return FALSE;
  300. // set dialog caption
  301. dom::element title = root.find_first("title");
  302. if( title.is_valid() )
  303. ::SetWindowText(hwndDlg,w2t(title.text().c_str()));
  304. SIZE sz;
  305. sz.cx = HTMLayoutGetMinWidth(hwndDlg);
  306. sz.cy = HTMLayoutGetMinHeight(hwndDlg,sz.cx);
  307. RECT rc; rc.left = ctl->position.x;
  308. rc.top = ctl->position.y;
  309. rc.right = rc.left + sz.cx;
  310. rc.bottom = rc.top + sz.cy;
  311. AdjustWindowRectEx(
  312. &rc,
  313. GetWindowLong(hwndDlg,GWL_STYLE),
  314. FALSE,
  315. GetWindowLong(hwndDlg,GWL_EXSTYLE));
  316. sz.cx = rc.right - rc.left;
  317. sz.cy = rc.bottom - rc.top;
  318. if( ctl->alignment == 1)
  319. {
  320. RECT prc;
  321. ::GetClientRect(::GetDesktopWindow(),&prc);
  322. rc.left = (prc.right - prc.left - sz.cx) / 2 + prc.left;
  323. rc.top = (prc.bottom - prc.top - sz.cy) / 2 + prc.top;
  324. rc.right = rc.left + sz.cx;
  325. rc.bottom = rc.top + sz.cy;
  326. }
  327. else if( ctl->alignment == 2 )
  328. {
  329. RECT prc;
  330. ::GetWindowRect(ctl->parent,&prc);
  331. rc.left = (prc.right - prc.left - sz.cx) / 2 + prc.left;
  332. rc.top = (prc.bottom - prc.top - sz.cy) / 2 + prc.top;
  333. rc.right = rc.left + sz.cx;
  334. rc.bottom = rc.top + sz.cy;
  335. }
  336. UINT MOVE_FLAGS = (SWP_NOZORDER);
  337. ::SetWindowPos(hwndDlg, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, MOVE_FLAGS);
  338. ::PostMessage(hwndDlg, WM_USER, 0,0);
  339. return 0;
  340. }
  341. inline INT_PTR dialog::on_WM_DESTROY( HWND hwndDlg, WPARAM wParam, LPARAM lParam )
  342. {
  343. dialog* ctl = self(hwndDlg);
  344. if( ctl)
  345. detach_event_handler(hwndDlg, ctl);
  346. return 0;
  347. }
  348. inline INT_PTR dialog::on_WM_USER( HWND hwndDlg, WPARAM wParam, LPARAM lParam )
  349. {
  350. dom::element root = dom::element::root_element(hwndDlg);
  351. if( !root.is_valid() )
  352. return 0;
  353. dom::element def = root.find_first("[role='default-button']");
  354. if( def.is_valid() )
  355. def.set_state(STATE_FOCUS);
  356. else
  357. ::SetFocus(hwndDlg);
  358. return 0;
  359. }
  360. inline INT_PTR dialog::on_WM_CLOSE( HWND hwndDlg, WPARAM wParam, LPARAM lParam )
  361. {
  362. HWND parent = ::GetParent(hwndDlg);
  363. ::EnableWindow(parent,TRUE);
  364. ::SetForegroundWindow(parent);
  365. ::DestroyWindow(hwndDlg);
  366. return 0;
  367. }
  368. }
  369. #endif