PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Samples/Chap19/MDIDemo/MDIDemo.d

http://github.com/AndrejMitrovic/DWinProgramming
D | 563 lines | 393 code | 142 blank | 28 comment | 25 complexity | fe94034e1120cdb89285e486b8dd7d89 MD5 | raw file
  1. /+
  2. + Copyright (c) Charles Petzold, 1998.
  3. + Ported to the D Programming Language by Andrej Mitrovic, 2011.
  4. +/
  5. module MDIDemo;
  6. import core.memory;
  7. import core.runtime;
  8. import core.thread;
  9. import core.stdc.config;
  10. import std.algorithm : min, max;
  11. import std.conv;
  12. import std.math;
  13. import std.random;
  14. import std.range;
  15. import std.string;
  16. import std.utf;
  17. auto toUTF16z(S)(S s)
  18. {
  19. return toUTFz!(const(wchar)*)(s);
  20. }
  21. pragma(lib, "gdi32.lib");
  22. pragma(lib, "comdlg32.lib");
  23. import core.sys.windows.windef;
  24. import core.sys.windows.winuser;
  25. import core.sys.windows.wingdi;
  26. import core.sys.windows.winbase;
  27. import core.sys.windows.commdlg;
  28. import resource;
  29. string appName = "MDIDemo";
  30. string description = "MDI Demonstration";
  31. HINSTANCE hinst;
  32. extern (Windows)
  33. int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
  34. {
  35. int result;
  36. try
  37. {
  38. Runtime.initialize();
  39. result = myWinMain(hInstance, hPrevInstance, lpCmdLine, iCmdShow);
  40. Runtime.terminate();
  41. }
  42. catch (Throwable o)
  43. {
  44. MessageBox(null, o.toString().toUTF16z, "Error", MB_OK | MB_ICONEXCLAMATION);
  45. result = 0;
  46. }
  47. return result;
  48. }
  49. int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
  50. {
  51. HACCEL hAccel;
  52. HWND hwndFrame, hwndClient;
  53. MSG msg;
  54. WNDCLASS wndclass;
  55. hinst = hInstance;
  56. // Register the frame window class
  57. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  58. wndclass.lpfnWndProc = &FrameWndProc;
  59. wndclass.cbClsExtra = 0;
  60. wndclass.cbWndExtra = 0;
  61. wndclass.hInstance = hInstance;
  62. wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  63. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  64. wndclass.hbrBackground = cast(HBRUSH)(COLOR_APPWORKSPACE + 1);
  65. wndclass.lpszMenuName = NULL;
  66. wndclass.lpszClassName = szFrameClass.toUTF16z;
  67. if (!RegisterClass(&wndclass))
  68. {
  69. MessageBox(NULL, "This program requires Windows NT!",
  70. appName.toUTF16z, MB_ICONERROR);
  71. return 0;
  72. }
  73. // Register the Hello child window class
  74. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  75. wndclass.lpfnWndProc = &HelloWndProc;
  76. wndclass.cbClsExtra = 0;
  77. wndclass.cbWndExtra = HANDLE.sizeof;
  78. wndclass.hInstance = hInstance;
  79. wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  80. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  81. wndclass.hbrBackground = cast(HBRUSH)GetStockObject(WHITE_BRUSH);
  82. wndclass.lpszMenuName = NULL;
  83. wndclass.lpszClassName = szHelloClass.toUTF16z;
  84. RegisterClass(&wndclass);
  85. // Register the Rect child window class
  86. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  87. wndclass.lpfnWndProc = &RectWndProc;
  88. wndclass.cbClsExtra = 0;
  89. wndclass.cbWndExtra = HANDLE.sizeof;
  90. wndclass.hInstance = hInstance;
  91. wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  92. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  93. wndclass.hbrBackground = cast(HBRUSH)GetStockObject(WHITE_BRUSH);
  94. wndclass.lpszMenuName = NULL;
  95. wndclass.lpszClassName = szRectClass.toUTF16z;
  96. RegisterClass(&wndclass);
  97. // Obtain handles to three possible menus & submenus
  98. hMenuInit = LoadMenu(hInstance, "MdiMenuInit");
  99. hMenuHello = LoadMenu(hInstance, "MdiMenuHello");
  100. hMenuRect = LoadMenu(hInstance, "MdiMenuRect");
  101. hMenuInitWindow = GetSubMenu(hMenuInit, INIT_MENU_POS);
  102. hMenuHelloWindow = GetSubMenu(hMenuHello, HELLO_MENU_POS);
  103. hMenuRectWindow = GetSubMenu(hMenuRect, RECT_MENU_POS);
  104. // Load accelerator table
  105. hAccel = LoadAccelerators(hInstance, appName.toUTF16z);
  106. // Create the frame window
  107. hwndFrame = CreateWindow(szFrameClass.toUTF16z, "MDI Demonstration",
  108. WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  109. CW_USEDEFAULT, CW_USEDEFAULT,
  110. CW_USEDEFAULT, CW_USEDEFAULT,
  111. NULL, hMenuInit, hInstance, NULL);
  112. hwndClient = GetWindow(hwndFrame, GW_CHILD);
  113. ShowWindow(hwndFrame, iCmdShow);
  114. UpdateWindow(hwndFrame);
  115. // Enter the modified message loop
  116. while (GetMessage(&msg, NULL, 0, 0))
  117. {
  118. if (!TranslateMDISysAccel(hwndClient, &msg) &&
  119. !TranslateAccelerator(hwndFrame, hAccel, &msg))
  120. {
  121. TranslateMessage(&msg);
  122. DispatchMessage(&msg);
  123. }
  124. }
  125. // Clean up by deleting unattached menus
  126. DestroyMenu(hMenuHello);
  127. DestroyMenu(hMenuRect);
  128. return msg.wParam;
  129. }
  130. enum INIT_MENU_POS = 0;
  131. enum HELLO_MENU_POS = 2;
  132. enum RECT_MENU_POS = 1;
  133. enum IDM_FIRSTCHILD = 50000;
  134. // structure for storing data unique to each Hello child window
  135. struct HELLODATA
  136. {
  137. UINT iColor;
  138. COLORREF clrText;
  139. }
  140. alias HELLODATA* PHELLODATA;
  141. // structure for storing data unique to each Rect child window
  142. struct RECTDATA
  143. {
  144. short cxClient;
  145. short cyClient;
  146. }
  147. alias RECTDATA* PRECTDATA;
  148. string szFrameClass = "MdiFrame";
  149. string szHelloClass = "MdiHelloChild";
  150. string szRectClass = "MdiRectChild";
  151. HMENU hMenuInit, hMenuHello, hMenuRect;
  152. HMENU hMenuInitWindow, hMenuHelloWindow, hMenuRectWindow;
  153. extern (Windows)
  154. LRESULT FrameWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  155. nothrow
  156. {
  157. scope (failure) assert(0);
  158. static HWND hwndClient;
  159. CLIENTCREATESTRUCT clientcreate;
  160. HWND hwndChild;
  161. MDICREATESTRUCT mdicreate;
  162. switch (message)
  163. {
  164. case WM_CREATE: // Create the client window
  165. clientcreate.hWindowMenu = hMenuInitWindow;
  166. clientcreate.idFirstChild = IDM_FIRSTCHILD;
  167. hwndClient = CreateWindow("MDICLIENT", NULL,
  168. WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
  169. 0, 0, 0, 0, hwnd, cast(HMENU) 1, hinst,
  170. cast(PSTR)&clientcreate);
  171. return 0;
  172. case WM_COMMAND:
  173. switch (LOWORD(wParam))
  174. {
  175. case IDM_FILE_NEWHELLO: // Create a Hello child window
  176. mdicreate.szClass = szHelloClass.toUTF16z;
  177. mdicreate.szTitle = "Hello";
  178. mdicreate.hOwner = hinst;
  179. mdicreate.x = CW_USEDEFAULT;
  180. mdicreate.y = CW_USEDEFAULT;
  181. mdicreate.cx = CW_USEDEFAULT;
  182. mdicreate.cy = CW_USEDEFAULT;
  183. mdicreate.style = 0;
  184. mdicreate.lParam = 0;
  185. hwndChild = cast(HWND)SendMessage(hwndClient,
  186. WM_MDICREATE, 0,
  187. cast(LPARAM)cast(LPMDICREATESTRUCT)&mdicreate);
  188. return 0;
  189. case IDM_FILE_NEWRECT: // Create a Rect child window
  190. mdicreate.szClass = szRectClass.toUTF16z;
  191. mdicreate.szTitle = "Rectangles";
  192. mdicreate.hOwner = hinst;
  193. mdicreate.x = CW_USEDEFAULT;
  194. mdicreate.y = CW_USEDEFAULT;
  195. mdicreate.cx = CW_USEDEFAULT;
  196. mdicreate.cy = CW_USEDEFAULT;
  197. mdicreate.style = 0;
  198. mdicreate.lParam = 0;
  199. hwndChild = cast(HWND)SendMessage(hwndClient,
  200. WM_MDICREATE, 0,
  201. cast(LPARAM)cast(LPMDICREATESTRUCT)&mdicreate);
  202. return 0;
  203. case IDM_FILE_CLOSE: // Close the active window
  204. hwndChild = cast(HWND)SendMessage(hwndClient,
  205. WM_MDIGETACTIVE, 0, 0);
  206. if (SendMessage(hwndChild, WM_QUERYENDSESSION, 0, 0))
  207. SendMessage(hwndClient, WM_MDIDESTROY,
  208. cast(WPARAM)hwndChild, 0);
  209. return 0;
  210. case IDM_APP_EXIT: // Exit the program
  211. SendMessage(hwnd, WM_CLOSE, 0, 0);
  212. return 0;
  213. // messages for arranging windows
  214. case IDM_WINDOW_TILE:
  215. SendMessage(hwndClient, WM_MDITILE, 0, 0);
  216. return 0;
  217. case IDM_WINDOW_CASCADE:
  218. SendMessage(hwndClient, WM_MDICASCADE, 0, 0);
  219. return 0;
  220. case IDM_WINDOW_ARRANGE:
  221. SendMessage(hwndClient, WM_MDIICONARRANGE, 0, 0);
  222. return 0;
  223. case IDM_WINDOW_CLOSEALL: // Attempt to close all children
  224. EnumChildWindows(hwndClient, &CloseEnumProc, 0);
  225. return 0;
  226. default: // Pass to active child...
  227. hwndChild = cast(HWND)SendMessage(hwndClient,
  228. WM_MDIGETACTIVE, 0, 0);
  229. if (IsWindow(hwndChild))
  230. SendMessage(hwndChild, WM_COMMAND, wParam, lParam);
  231. break; // ...and then to DefFrameProc
  232. }
  233. break;
  234. case WM_QUERYENDSESSION:
  235. case WM_CLOSE: // Attempt to close all children
  236. SendMessage(hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0);
  237. if (NULL != GetWindow(hwndClient, GW_CHILD))
  238. return 0;
  239. break; // i.e., call DefFrameProc
  240. case WM_DESTROY:
  241. PostQuitMessage(0);
  242. return 0;
  243. default:
  244. }
  245. // Pass unprocessed messages to DefFrameProc (not DefWindowProc)
  246. return DefFrameProc(hwnd, hwndClient, message, wParam, lParam);
  247. }
  248. extern (Windows)
  249. BOOL CloseEnumProc(HWND hwnd, LPARAM lParam) nothrow
  250. {
  251. scope (failure) assert(0);
  252. if (GetWindow(hwnd, GW_OWNER)) // Check for icon title
  253. return TRUE;
  254. SendMessage(GetParent(hwnd), WM_MDIRESTORE, cast(WPARAM)hwnd, 0);
  255. if (!SendMessage(hwnd, WM_QUERYENDSESSION, 0, 0))
  256. return TRUE;
  257. SendMessage(GetParent(hwnd), WM_MDIDESTROY, cast(WPARAM)hwnd, 0);
  258. return TRUE;
  259. }
  260. extern (Windows)
  261. LRESULT HelloWndProc(HWND hwnd, UINT message,
  262. WPARAM wParam, LPARAM lParam) nothrow
  263. {
  264. scope (failure) assert(0);
  265. auto clrTextArray = [RGB(0, 0, 0), RGB(255, 0, 0),
  266. RGB(0, 255, 0), RGB( 0, 0, 255),
  267. RGB(255, 255, 255)];
  268. static HWND hwndClient, hwndFrame;
  269. HDC hdc;
  270. HMENU hMenu;
  271. PHELLODATA pHelloData;
  272. PAINTSTRUCT ps;
  273. RECT rect;
  274. switch (message)
  275. {
  276. case WM_CREATE:
  277. // Allocate memory for window private data
  278. pHelloData = cast(PHELLODATA)HeapAlloc(GetProcessHeap(),
  279. HEAP_ZERO_MEMORY, HELLODATA.sizeof);
  280. pHelloData.iColor = IDM_COLOR_BLACK;
  281. pHelloData.clrText = RGB(0, 0, 0);
  282. SetWindowLongPtr(hwnd, 0, cast(c_long)pHelloData);
  283. // Save some window handles
  284. hwndClient = GetParent(hwnd);
  285. hwndFrame = GetParent(hwndClient);
  286. return 0;
  287. case WM_COMMAND:
  288. switch (LOWORD(wParam))
  289. {
  290. case IDM_COLOR_BLACK:
  291. case IDM_COLOR_RED:
  292. case IDM_COLOR_GREEN:
  293. case IDM_COLOR_BLUE:
  294. case IDM_COLOR_WHITE:
  295. // Change the text color
  296. pHelloData = cast(PHELLODATA)GetWindowLongPtr(hwnd, 0);
  297. hMenu = GetMenu(hwndFrame);
  298. CheckMenuItem(hMenu, pHelloData.iColor, MF_UNCHECKED);
  299. pHelloData.iColor = wParam;
  300. CheckMenuItem(hMenu, pHelloData.iColor, MF_CHECKED);
  301. pHelloData.clrText = clrTextArray[wParam - IDM_COLOR_BLACK];
  302. InvalidateRect(hwnd, NULL, FALSE);
  303. break;
  304. default:
  305. }
  306. return 0;
  307. case WM_PAINT:
  308. // Paint the window
  309. hdc = BeginPaint(hwnd, &ps);
  310. pHelloData = cast(PHELLODATA)GetWindowLongPtr(hwnd, 0);
  311. SetTextColor(hdc, pHelloData.clrText);
  312. GetClientRect(hwnd, &rect);
  313. DrawText(hdc, "Hello, World!", -1, &rect,
  314. DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  315. EndPaint(hwnd, &ps);
  316. return 0;
  317. case WM_MDIACTIVATE:
  318. // Set the Hello menu if gaining focus
  319. if (lParam == cast(LPARAM)hwnd)
  320. SendMessage(hwndClient, WM_MDISETMENU,
  321. cast(WPARAM)hMenuHello, cast(LPARAM)hMenuHelloWindow);
  322. // Check or uncheck menu item
  323. pHelloData = cast(PHELLODATA)GetWindowLongPtr(hwnd, 0);
  324. CheckMenuItem(hMenuHello, pHelloData.iColor,
  325. (lParam == cast(LPARAM)hwnd) ? MF_CHECKED : MF_UNCHECKED);
  326. // Set the Init menu if losing focus
  327. if (lParam != cast(LPARAM)hwnd)
  328. SendMessage(hwndClient, WM_MDISETMENU, cast(WPARAM)hMenuInit,
  329. cast(LPARAM)hMenuInitWindow);
  330. DrawMenuBar(hwndFrame);
  331. return 0;
  332. case WM_QUERYENDSESSION:
  333. case WM_CLOSE:
  334. if (IDOK != MessageBox(hwnd, "OK to close window?",
  335. "Hello",
  336. MB_ICONQUESTION | MB_OKCANCEL))
  337. return 0;
  338. break; // i.e., call DefMDIChildProc
  339. case WM_DESTROY:
  340. pHelloData = cast(PHELLODATA)GetWindowLongPtr(hwnd, 0);
  341. HeapFree(GetProcessHeap(), 0, pHelloData);
  342. return 0;
  343. default:
  344. }
  345. // Pass unprocessed message to DefMDIChildProc
  346. return DefMDIChildProc(hwnd, message, wParam, lParam);
  347. }
  348. extern (Windows)
  349. LRESULT RectWndProc(HWND hwnd, UINT message,
  350. WPARAM wParam, LPARAM lParam) nothrow
  351. {
  352. scope (failure) assert(0);
  353. static HWND hwndClient, hwndFrame;
  354. HBRUSH hBrush;
  355. HDC hdc;
  356. PRECTDATA pRectData;
  357. PAINTSTRUCT ps;
  358. int xLeft, xRight, yTop, yBottom;
  359. short nRed, nGreen, nBlue;
  360. switch (message)
  361. {
  362. case WM_CREATE:
  363. // Allocate memory for window private data
  364. pRectData = cast(PRECTDATA)HeapAlloc(GetProcessHeap(),
  365. HEAP_ZERO_MEMORY, RECTDATA.sizeof);
  366. SetWindowLongPtr(hwnd, 0, cast(c_long)pRectData);
  367. // Start the timer going
  368. SetTimer(hwnd, 1, 250, NULL);
  369. // Save some window handles
  370. hwndClient = GetParent(hwnd);
  371. hwndFrame = GetParent(hwndClient);
  372. return 0;
  373. case WM_SIZE: // If not minimized, save the window size
  374. if (wParam != SIZE_MINIMIZED)
  375. {
  376. pRectData = cast(PRECTDATA)GetWindowLongPtr(hwnd, 0);
  377. pRectData.cxClient = LOWORD(lParam);
  378. pRectData.cyClient = HIWORD(lParam);
  379. }
  380. break; // WM_SIZE must be processed by DefMDIChildProc
  381. case WM_TIMER: // Display a random rectangle
  382. pRectData = cast(PRECTDATA)GetWindowLongPtr(hwnd, 0);
  383. xLeft = uniform(0, pRectData.cxClient);
  384. xRight = uniform(0, pRectData.cxClient);
  385. yTop = uniform(0, pRectData.cyClient);
  386. yBottom = uniform(0, pRectData.cyClient);
  387. nRed = cast(short)uniform(0, 255);
  388. nGreen = cast(short)uniform(0, 255);
  389. nBlue = cast(short)uniform(0, 255);
  390. hdc = GetDC(hwnd);
  391. hBrush = CreateSolidBrush(RGB(cast(ubyte)nRed, cast(ubyte)nGreen, cast(ubyte)nBlue));
  392. SelectObject(hdc, hBrush);
  393. Rectangle(hdc, min(xLeft, xRight), min(yTop, yBottom),
  394. max(xLeft, xRight), max(yTop, yBottom));
  395. ReleaseDC(hwnd, hdc);
  396. DeleteObject(hBrush);
  397. return 0;
  398. case WM_PAINT: // Clear the window
  399. InvalidateRect(hwnd, NULL, TRUE);
  400. hdc = BeginPaint(hwnd, &ps);
  401. EndPaint(hwnd, &ps);
  402. return 0;
  403. case WM_MDIACTIVATE: // Set the appropriate menu
  404. if (lParam == cast(LPARAM)hwnd)
  405. SendMessage(hwndClient, WM_MDISETMENU, cast(WPARAM)hMenuRect,
  406. cast(LPARAM)hMenuRectWindow);
  407. else
  408. SendMessage(hwndClient, WM_MDISETMENU, cast(WPARAM)hMenuInit,
  409. cast(LPARAM)hMenuInitWindow);
  410. DrawMenuBar(hwndFrame);
  411. return 0;
  412. case WM_DESTROY:
  413. pRectData = cast(PRECTDATA)GetWindowLongPtr(hwnd, 0);
  414. HeapFree(GetProcessHeap(), 0, pRectData);
  415. KillTimer(hwnd, 1);
  416. return 0;
  417. default:
  418. }
  419. // Pass unprocessed message to DefMDIChildProc
  420. return DefMDIChildProc(hwnd, message, wParam, lParam);
  421. }