Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6742 lines
168 KiB

  1. //
  2. // MWND.CPP
  3. // Main WB Window
  4. //
  5. // Copyright Microsoft 1998-
  6. //
  7. // PRECOMP
  8. #include "precomp.h"
  9. #include <dde.h>
  10. #include "version.h"
  11. #include "nmwbobj.h"
  12. static const TCHAR s_cszHtmlHelpFile[] = TEXT("nmwhiteb.chm");
  13. // Class name
  14. TCHAR szMainClassName[] = "T126WBMainWindowClass";
  15. extern TCHAR g_PassedFileName[];
  16. void ShiftFocus(HWND hwndTop, BOOL bForward);
  17. BOOL IsWindowActive(HWND hwnd);
  18. //
  19. // Scroll accelerators
  20. //
  21. typedef struct tagSCROLL
  22. {
  23. UINT uiMenuId;
  24. UINT uiMessage;
  25. UINT uiScrollCode;
  26. }
  27. SCROLL;
  28. static const SCROLL s_MenuToScroll[] =
  29. {
  30. { IDM_PAGEUP, WM_VSCROLL, SB_PAGEUP },
  31. { IDM_PAGEDOWN, WM_VSCROLL, SB_PAGEDOWN },
  32. { IDM_SHIFTPAGEUP, WM_HSCROLL, SB_PAGEUP },
  33. { IDM_SHIFTPAGEDOWN, WM_HSCROLL, SB_PAGEDOWN },
  34. { IDM_HOME, WM_HSCROLL, SB_TOP },
  35. { IDM_HOME, WM_VSCROLL, SB_TOP },
  36. { IDM_END, WM_HSCROLL, SB_BOTTOM },
  37. { IDM_END, WM_VSCROLL, SB_BOTTOM },
  38. { IDM_LINEUP, WM_VSCROLL, SB_LINEUP },
  39. { IDM_LINEDOWN, WM_VSCROLL, SB_LINEDOWN },
  40. { IDM_SHIFTLINEUP, WM_HSCROLL, SB_LINEUP },
  41. { IDM_SHIFTLINEDOWN, WM_HSCROLL, SB_LINEDOWN }
  42. };
  43. // tooltip data
  44. // check codes
  45. #define NA 0 // dont't check checked state
  46. #define TB 1 // check toolbar for checked state
  47. #define BT 2 // check tipped wnd (a button) for checked state
  48. typedef struct
  49. {
  50. UINT nID;
  51. UINT nCheck;
  52. UINT nUpTipID;
  53. UINT nDownTipID;
  54. }
  55. TIPIDS;
  56. TIPIDS g_tipIDsArray[] =
  57. {
  58. {IDM_SELECT, TB, IDS_HINT_SELECT, IDS_HINT_SELECT},
  59. {IDM_ERASER, TB, IDS_HINT_ERASER, IDS_HINT_ERASER},
  60. {IDM_TEXT, TB, IDS_HINT_TEXT, IDS_HINT_TEXT},
  61. {IDM_HIGHLIGHT, TB, IDS_HINT_HIGHLIGHT, IDS_HINT_HIGHLIGHT},
  62. {IDM_PEN, TB, IDS_HINT_PEN, IDS_HINT_PEN},
  63. {IDM_LINE, TB, IDS_HINT_LINE, IDS_HINT_LINE},
  64. {IDM_BOX, TB, IDS_HINT_BOX, IDS_HINT_BOX},
  65. {IDM_FILLED_BOX, TB, IDS_HINT_FBOX, IDS_HINT_FBOX},
  66. {IDM_ELLIPSE, TB, IDS_HINT_ELLIPSE, IDS_HINT_ELLIPSE},
  67. {IDM_FILLED_ELLIPSE, TB, IDS_HINT_FELLIPSE, IDS_HINT_FELLIPSE},
  68. {IDM_ZOOM, TB, IDS_HINT_ZOOM_UP, IDS_HINT_ZOOM_DOWN},
  69. {IDM_REMOTE, TB, IDS_HINT_REMOTE_UP, IDS_HINT_REMOTE_DOWN},
  70. {IDM_LOCK, TB, IDS_HINT_LOCK_UP, IDS_HINT_LOCK_DOWN},
  71. {IDM_SYNC, TB, IDS_HINT_SYNC_UP, IDS_HINT_SYNC_DOWN},
  72. {IDM_GRAB_AREA, TB, IDS_HINT_GRAB_AREA, IDS_HINT_GRAB_AREA},
  73. {IDM_GRAB_WINDOW, TB, IDS_HINT_GRAB_WINDOW, IDS_HINT_GRAB_WINDOW},
  74. {IDM_WIDTH_1, NA, IDS_HINT_WIDTH_1, IDS_HINT_WIDTH_1},
  75. {IDM_WIDTH_2, NA, IDS_HINT_WIDTH_2, IDS_HINT_WIDTH_2},
  76. {IDM_WIDTH_3, NA, IDS_HINT_WIDTH_3, IDS_HINT_WIDTH_3},
  77. {IDM_WIDTH_4, NA, IDS_HINT_WIDTH_4, IDS_HINT_WIDTH_4},
  78. {IDM_PAGE_FIRST, BT, IDS_HINT_PAGE_FIRST, IDS_HINT_PAGE_FIRST},
  79. {IDM_PAGE_PREV, BT, IDS_HINT_PAGE_PREVIOUS, IDS_HINT_PAGE_PREVIOUS},
  80. {IDM_PAGE_ANY, NA, IDS_HINT_PAGE_ANY, IDS_HINT_PAGE_ANY},
  81. {IDM_PAGE_NEXT, BT, IDS_HINT_PAGE_NEXT, IDS_HINT_PAGE_NEXT},
  82. {IDM_PAGE_LAST, BT, IDS_HINT_PAGE_LAST, IDS_HINT_PAGE_LAST},
  83. {IDM_PAGE_INSERT_AFTER, BT, IDS_HINT_PAGE_INSERT, IDS_HINT_PAGE_INSERT}
  84. };
  85. ////////////
  86. HRESULT WbMainWindow::WB_LoadFile(LPCTSTR szFile)
  87. {
  88. //
  89. // If a file name was passed
  90. //
  91. if (szFile && g_pMain)
  92. {
  93. int cchLength;
  94. BOOL fSkippedQuote;
  95. // Skip past first quote
  96. if (fSkippedQuote = (*szFile == '"'))
  97. szFile++;
  98. cchLength = lstrlen(szFile);
  99. //
  100. // NOTE:
  101. // There may be DBCS implications with this. Hence we check to see
  102. // if we skipped the first quote; we assume that if the file name
  103. // starts with a quote it must end with one also. But we need to check
  104. // it out.
  105. //
  106. // Strip last quote
  107. if (fSkippedQuote && (cchLength > 0) && (szFile[cchLength - 1] == '"'))
  108. {
  109. BYTE * pLastQuote = (BYTE *)&szFile[cchLength - 1];
  110. TRACE_MSG(("Skipping last quote in file name %s", szFile));
  111. *pLastQuote = '\0';
  112. }
  113. g_pMain->OnOpen(szFile);
  114. }
  115. return S_OK;
  116. }
  117. void WbMainWindow::BringToFront(void)
  118. {
  119. if (NULL != m_hwnd)
  120. {
  121. int nCmdShow = SW_SHOW;
  122. WINDOWPLACEMENT wp;
  123. ::ZeroMemory(&wp, sizeof(wp));
  124. wp.length = sizeof(wp);
  125. if (::GetWindowPlacement(m_hwnd, &wp))
  126. {
  127. if (SW_MINIMIZE == wp.showCmd || SW_SHOWMINIMIZED == wp.showCmd)
  128. {
  129. // The window is minimized - restore it:
  130. nCmdShow = SW_RESTORE;
  131. }
  132. }
  133. // show the window now
  134. ::ShowWindow(m_hwnd, nCmdShow);
  135. // bring it to the foreground
  136. ::SetForegroundWindow(m_hwnd);
  137. }
  138. }
  139. //
  140. //
  141. // Function: WbMainWindow constructor
  142. //
  143. // Purpose: Create the main Whiteboard window. An exception is thrown
  144. // if an error occurs during construction.
  145. //
  146. //
  147. WbMainWindow::WbMainWindow(void)
  148. {
  149. OSVERSIONINFO OsData;
  150. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::WbMainWindow");
  151. //
  152. // Initialize member vars first!
  153. //
  154. ZeroMemory(m_ToolArray, sizeof(m_ToolArray));
  155. m_hwnd = NULL;
  156. m_hwndToolTip = NULL;
  157. ZeroMemory(&m_tiLastHit, sizeof(m_tiLastHit));
  158. m_nLastHit = -1;
  159. m_bInitOk = FALSE;
  160. m_bDisplayingError = FALSE;
  161. m_hwndSB = NULL;
  162. m_bStatusBarOn = TRUE;
  163. m_bToolBarOn = TRUE;
  164. // Load the main accelerator table
  165. m_hAccelTable =
  166. ::LoadAccelerators(g_hInstance, MAKEINTRESOURCE(MAINACCELTABLE));
  167. m_hwndQuerySaveDlg = NULL;
  168. m_hwndWaitForEventDlg = NULL;
  169. m_hwndWaitForLockDlg = NULL;
  170. m_pCurrentTool = NULL;
  171. ZeroMemory(m_strFileName, sizeof(m_strFileName));
  172. m_pTitleFileName = NULL;
  173. // Load the alternative accelerator table for the pages edit
  174. // field and text editor
  175. m_hAccelPagesGroup =
  176. ::LoadAccelerators(g_hInstance, MAKEINTRESOURCE(PAGESGROUPACCELTABLE));
  177. m_hAccelTextEdit =
  178. ::LoadAccelerators(g_hInstance, MAKEINTRESOURCE(TEXTEDITACCELTABLE));
  179. // Show that we are not yet in a call
  180. m_uiSubState = SUBSTATE_IDLE;
  181. // We are not currently displaying a menu
  182. m_hContextMenuBar = NULL;
  183. m_hContextMenu = NULL;
  184. m_hGrobjContextMenuBar = NULL;
  185. m_hGrobjContextMenu = NULL;
  186. m_bInSaveDialog = FALSE;
  187. m_bSelectAllInProgress = FALSE;
  188. m_bUnlockStateSettled = TRUE;
  189. m_bQuerySysShutdown = FALSE;
  190. // figure out if we're on Win95
  191. m_bIsWin95 = FALSE;
  192. OsData.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  193. if( GetVersionEx( &OsData ) )
  194. {
  195. if( OsData.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
  196. m_bIsWin95 = TRUE;
  197. }
  198. m_cancelModeSent = FALSE;
  199. //
  200. // We only do this once for the lifetime of the DLL. There is no
  201. // way really to clean up registered window messages, and each register
  202. // bumps up a ref count. If we registered each time WB was started up
  203. // during one session of CONF, we'd overflow the refcount.
  204. //
  205. if (!g_uConfShutdown)
  206. {
  207. g_uConfShutdown = ::RegisterWindowMessage( NM_ENDSESSION_MSG_NAME );
  208. }
  209. m_pLocalRemotePointer = NULL;
  210. m_localRemotePointerPosition.x = -50;
  211. m_localRemotePointerPosition.y = -50;
  212. }
  213. //
  214. // Open()
  215. // Do Main window initialization (stuff that can fail). After this,
  216. // the run code will try to join the current domain and do message loop
  217. // stuff.
  218. //
  219. BOOL WbMainWindow::Open(int iCommand)
  220. {
  221. WNDCLASSEX wc;
  222. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::Open");
  223. //
  224. // CREATE OTHER GLOBALS
  225. //
  226. if (!InitToolArray())
  227. {
  228. ERROR_OUT(("Can't create tools; failing to start up"));
  229. return(FALSE);
  230. }
  231. //
  232. // Init comon controls
  233. //
  234. InitCommonControls();
  235. //
  236. // CREATE THE MAIN FRAME WINDOW
  237. //
  238. ASSERT(!m_hwnd);
  239. //
  240. // Get the class info for it, and change the name.
  241. //
  242. ZeroMemory(&wc, sizeof(wc));
  243. wc.cbSize = sizeof(wc);
  244. wc.style = CS_DBLCLKS; // CS_HREDRAW | CS_VREDRAW?
  245. wc.lpfnWndProc = WbMainWindowProc;
  246. wc.hInstance = g_hInstance;
  247. wc.hIcon = ::LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_APP));
  248. wc.hCursor = ::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
  249. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  250. wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_WB_WITHFILE);
  251. wc.lpszClassName = szMainClassName;
  252. if (!::RegisterClassEx(&wc))
  253. {
  254. ERROR_OUT(("Can't register private frame window class"));
  255. return(FALSE);
  256. }
  257. // Create the main drawing window.
  258. if (!::CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, szMainClassName,
  259. NULL, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  260. CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, g_hInstance, this))
  261. {
  262. // Could not create the main window
  263. ERROR_OUT(("Failed to create main window"));
  264. return(FALSE);
  265. }
  266. ASSERT(m_hwnd);
  267. //
  268. // Create the pop-up context menu
  269. //
  270. if (!CreateContextMenus())
  271. {
  272. ERROR_OUT(("Failed to create context menus"));
  273. return(FALSE);
  274. }
  275. //
  276. // Register the the main window for Drag/Drop messages.
  277. //
  278. DragAcceptFiles(m_hwnd, TRUE);
  279. //
  280. // CREATE THE CHILD WINDOWS
  281. //
  282. // Create the drawing pane
  283. // (the Create call throws an exception on error)
  284. RECT clientRect;
  285. RECT drawingAreaRect;
  286. ::GetClientRect(m_hwnd, &clientRect);
  287. drawingAreaRect.top=0;
  288. drawingAreaRect.bottom = DRAW_HEIGHT;
  289. drawingAreaRect.left = 0;
  290. drawingAreaRect.right = DRAW_WIDTH;
  291. // Every control in the main window has a border on it, so increase the
  292. // client size by 1 to force these borders to be drawn under the inside
  293. // black line in the window frame. This prevents a 2 pel wide border
  294. // being drawn
  295. ::InflateRect(&clientRect, 1, 1);
  296. SIZE sizeAG;
  297. m_AG.GetNaturalSize(&sizeAG);
  298. if (!m_drawingArea.Create(m_hwnd, &drawingAreaRect))
  299. {
  300. ERROR_OUT(("Failed to create drawing area"));
  301. return(FALSE);
  302. }
  303. //
  304. // Create the toolbar
  305. //
  306. if (!m_TB.Create(m_hwnd))
  307. {
  308. ERROR_OUT(("Failed to create tool window"));
  309. return(FALSE);
  310. }
  311. //
  312. // Create the attributes group
  313. // The attributes group is on the bottom, underneath the
  314. // drawing area, above the status bar.
  315. //
  316. RECT rectAG;
  317. rectAG.left = clientRect.left;
  318. rectAG.right = clientRect.right;
  319. rectAG.top = drawingAreaRect.bottom;
  320. rectAG.bottom = rectAG.top + sizeAG.cy;
  321. if (!m_AG.Create(m_hwnd, &rectAG))
  322. {
  323. ERROR_OUT(("Failed to create attributes group window"));
  324. return(FALSE);
  325. }
  326. //
  327. // Create the widths group.
  328. // The widths group is on the left side, underneath the tools group
  329. //
  330. SIZE sizeWG;
  331. RECT rectWG;
  332. // The widths group is on the left side, underneath the toolbar
  333. m_WG.GetNaturalSize(&sizeWG);
  334. rectWG.left = 0;
  335. rectWG.right = rectWG.left + sizeWG.cx;
  336. rectWG.bottom = rectAG.top;
  337. rectWG.top = rectWG.bottom - sizeWG.cy;
  338. if (!m_WG.Create(m_hwnd, &rectWG))
  339. {
  340. ERROR_OUT(("Failed to create widths group window"));
  341. return(FALSE);
  342. }
  343. //
  344. // Create the status bar
  345. //
  346. m_hwndSB = ::CreateWindowEx(0, STATUSCLASSNAME, NULL,
  347. WS_CHILD | WS_VISIBLE | CCS_NOPARENTALIGN | CCS_NOMOVEY |
  348. CCS_NORESIZE | SBARS_SIZEGRIP,
  349. clientRect.left, clientRect.bottom - STATUSBAR_HEIGHT,
  350. (clientRect.right - clientRect.left), STATUSBAR_HEIGHT,
  351. m_hwnd, 0, g_hInstance, NULL);
  352. if (!m_hwndSB)
  353. {
  354. ERROR_OUT(("Failed to create status bar window"));
  355. return(FALSE);
  356. }
  357. // Initialize the color, width and tool menus
  358. InitializeMenus();
  359. m_currentMenuTool = IDM_SELECT;
  360. m_pCurrentTool = m_ToolArray[TOOL_INDEX(IDM_SELECT)];
  361. OnSelectTool(m_currentMenuTool);
  362. m_hwndToolTip = ::CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
  363. WS_POPUP | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT,
  364. CW_USEDEFAULT, CW_USEDEFAULT, m_hwnd, NULL, g_hInstance, NULL);
  365. if (!m_hwndToolTip)
  366. {
  367. ERROR_OUT(("Unable to create tooltip window"));
  368. return(FALSE);
  369. }
  370. // Add a dead-area tooltip
  371. TOOLINFO ti;
  372. ZeroMemory(&ti, sizeof(ti));
  373. ti.cbSize = sizeof(TOOLINFO);
  374. ti.uFlags = TTF_IDISHWND;
  375. ti.hwnd = m_hwnd;
  376. ti.uId = (UINT_PTR)m_hwnd;
  377. ::SendMessage(m_hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
  378. // Ensure the page buttons are disabled while starting
  379. UpdatePageButtons();
  380. // If this is the first time we have created a clipboard object,
  381. // register the private Whiteboard formats.
  382. if (g_ClipboardFormats[CLIPBOARD_PRIVATE] == 0)
  383. {
  384. g_ClipboardFormats[CLIPBOARD_PRIVATE] =
  385. (int) ::RegisterClipboardFormat("NMWT126");
  386. }
  387. m_bInitOk = TRUE;
  388. BOOL bSuccess = TRUE; // indicates whether window opened successfully
  389. // Get the position of the window from options
  390. RECT rectWindow;
  391. OPT_GetWindowRectOption(&rectWindow);
  392. ::MoveWindow(m_hwnd, rectWindow.left, rectWindow.top,
  393. rectWindow.right - rectWindow.left,
  394. rectWindow.bottom - rectWindow.top, FALSE );
  395. //
  396. // Inititalize the fake GCC handle, it will be used when we are not in a conference and need
  397. // handles for workspaces/drawings/bitmaps etc...
  398. //
  399. g_localGCCHandle = 1;
  400. //
  401. // Create a standard workspace
  402. //
  403. if(g_pCurrentWorkspace)
  404. {
  405. m_drawingArea.Attach(g_pCurrentWorkspace);
  406. }
  407. else
  408. {
  409. if(g_numberOfWorkspaces < WB_MAX_WORKSPACES)
  410. {
  411. m_drawingArea.Detach();
  412. WorkspaceObj * pObj;
  413. DBG_SAVE_FILE_LINE
  414. pObj = new WorkspaceObj();
  415. pObj->AddToWorkspace();
  416. g_pConferenceWorkspace = pObj;
  417. }
  418. }
  419. CheckMenuItem(IDM_STATUS_BAR_TOGGLE);
  420. CheckMenuItem(IDM_TOOL_BAR_TOGGLE);
  421. //
  422. // Start synced
  423. //
  424. Sync();
  425. if(!OPT_GetBooleanOption(OPT_MAIN_STATUSBARVISIBLE, DFLT_MAIN_STATUSBARVISIBLE))
  426. {
  427. OnStatusBarToggle();
  428. }
  429. if(!OPT_GetBooleanOption(OPT_MAIN_TOOLBARVISIBLE, DFLT_MAIN_TOOLBARVISIBLE))
  430. {
  431. OnToolBarToggle();
  432. }
  433. ::ShowWindow(m_hwnd, iCommand);
  434. ::UpdateWindow(m_hwnd);
  435. // Update the window title with no file name
  436. UpdateWindowTitle();
  437. // Return value indicating success or failure
  438. return(bSuccess);
  439. }
  440. //
  441. //
  442. // Function : OnMenuSelect
  443. //
  444. // Purpose : Update the text in the help bar
  445. //
  446. //
  447. void WbMainWindow::OnMenuSelect(UINT uiItemID, UINT uiFlags, HMENU hSysMenu)
  448. {
  449. UINT firstMenuId;
  450. UINT statusId;
  451. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnMenuSelect");
  452. //
  453. // Work out the help ID for the menu item. We have to store this now
  454. // because when the user presses F1 from a menu item, we can't tell
  455. // which item it was.
  456. //
  457. if ((uiFlags & MF_POPUP) && (uiFlags & MF_SYSMENU))
  458. {
  459. //
  460. // System menu selected
  461. //
  462. statusId = IDS_MENU_SYSTEM;
  463. }
  464. else if (uiFlags & MF_POPUP)
  465. {
  466. // get popup menu handle and first item (bug NM4db:463)
  467. HMENU hPopup = ::GetSubMenu( hSysMenu, uiItemID );
  468. firstMenuId = ::GetMenuItemID( hPopup, 0 );
  469. // figure out which popup it is so we can display the right help text
  470. switch (firstMenuId)
  471. {
  472. case IDM_NEW:
  473. statusId = IDS_MENU_FILE;
  474. break;
  475. case IDM_DELETE:
  476. statusId = IDS_MENU_EDIT;
  477. break;
  478. case IDM_TOOL_BAR_TOGGLE:
  479. statusId = IDS_MENU_VIEW;
  480. break;
  481. case IDM_EDITCOLOR:
  482. case IDM_TOOLS_START:
  483. statusId = IDS_MENU_TOOLS;
  484. break;
  485. case IDM_HELP:
  486. statusId = IDS_MENU_HELP;
  487. break;
  488. case IDM_WIDTH_1: // (added for bug NM4db:463)
  489. statusId = IDS_MENU_WIDTH;
  490. break;
  491. default:
  492. statusId = IDS_DEFAULT;
  493. break;
  494. }
  495. }
  496. else
  497. {
  498. //
  499. // A normal menu item has been selected
  500. //
  501. statusId = uiItemID;
  502. }
  503. // Set the new help text
  504. TCHAR szStatus[256];
  505. if (::LoadString(g_hInstance, statusId, szStatus, 256))
  506. {
  507. ::SetWindowText(m_hwndSB, szStatus);
  508. }
  509. }
  510. //
  511. // WbMainWindowProc()
  512. // Frame window message handler
  513. //
  514. LRESULT WbMainWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  515. {
  516. LRESULT lResult = 0;
  517. WbMainWindow * pMain;
  518. pMain = (WbMainWindow *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  519. switch (message)
  520. {
  521. case WM_NCCREATE:
  522. pMain = (WbMainWindow *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  523. ASSERT(pMain);
  524. pMain->m_hwnd = hwnd;
  525. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pMain);
  526. goto DefWndProc;
  527. break;
  528. case WM_DESTROY:
  529. ShutDownHelp();
  530. break;
  531. case WM_NCDESTROY:
  532. pMain->m_hwnd = NULL;
  533. break;
  534. case WM_SIZE:
  535. pMain->OnSize((UINT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
  536. break;
  537. case WM_ACTIVATE:
  538. if (GET_WM_ACTIVATE_STATE(wParam, lParam) == WA_INACTIVE)
  539. {
  540. // Cancel the tooltip if it's around
  541. if (pMain->m_hwndToolTip)
  542. ::SendMessage(pMain->m_hwndToolTip, TTM_ACTIVATE, FALSE, 0);
  543. }
  544. goto DefWndProc;
  545. break;
  546. case WM_SETFOCUS:
  547. pMain->OnSetFocus();
  548. break;
  549. case WM_CANCELMODE:
  550. pMain->OnCancelMode();
  551. break;
  552. case WM_INITMENUPOPUP:
  553. pMain->OnInitMenuPopup((HMENU)wParam, LOWORD(lParam), HIWORD(lParam));
  554. break;
  555. case WM_MENUSELECT:
  556. pMain->OnMenuSelect(GET_WM_MENUSELECT_CMD(wParam, lParam),
  557. GET_WM_MENUSELECT_FLAGS(wParam, lParam),
  558. GET_WM_MENUSELECT_HMENU(wParam, lParam));
  559. break;
  560. case WM_MEASUREITEM:
  561. pMain->OnMeasureItem((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam);
  562. break;
  563. case WM_DRAWITEM:
  564. pMain->OnDrawItem((UINT)wParam, (LPDRAWITEMSTRUCT)lParam);
  565. break;
  566. case WM_QUERYNEWPALETTE:
  567. lResult = pMain->OnQueryNewPalette();
  568. break;
  569. case WM_PALETTECHANGED:
  570. pMain->OnPaletteChanged((HWND)wParam);
  571. break;
  572. case WM_HELP:
  573. pMain->OnCommand(IDM_HELP, 0, NULL);
  574. break;
  575. case WM_CLOSE:
  576. pMain->OnClose();
  577. break;
  578. case WM_QUERYENDSESSION:
  579. lResult = pMain->OnQueryEndSession();
  580. break;
  581. case WM_ENDSESSION:
  582. pMain->OnEndSession((UINT)wParam);
  583. break;
  584. case WM_SYSCOLORCHANGE:
  585. pMain->OnSysColorChange();
  586. break;
  587. case WM_USER_PRIVATE_PARENTNOTIFY:
  588. pMain->OnParentNotify(GET_WM_PARENTNOTIFY_MSG(wParam, lParam));
  589. break;
  590. case WM_GETMINMAXINFO:
  591. if (pMain)
  592. pMain->OnGetMinMaxInfo((LPMINMAXINFO)lParam);
  593. break;
  594. case WM_COMMAND:
  595. pMain->OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
  596. break;
  597. case WM_NOTIFY:
  598. pMain->OnNotify((UINT)wParam, (NMHDR *)lParam);
  599. break;
  600. case WM_DROPFILES:
  601. pMain->OnDropFiles((HDROP)wParam);
  602. break;
  603. case WM_USER_DISPLAY_ERROR:
  604. pMain->OnDisplayError(wParam, lParam);
  605. break;
  606. case WM_USER_UPDATE_ATTRIBUTES:
  607. pMain->m_AG.DisplayTool(pMain->m_pCurrentTool);
  608. break;
  609. case WM_USER_LOAD_FILE:
  610. pMain->WB_LoadFile(g_PassedFileName);
  611. // Fall through.
  612. case WM_USER_BRING_TO_FRONT_WINDOW:
  613. pMain->BringToFront();
  614. break;
  615. default:
  616. if (message == g_uConfShutdown)
  617. {
  618. lResult = pMain->OnConfShutdown(wParam, lParam);
  619. }
  620. else
  621. {
  622. DefWndProc:
  623. lResult = DefWindowProc(hwnd, message, wParam, lParam);
  624. }
  625. break;
  626. }
  627. return(lResult);
  628. }
  629. //
  630. // OnCommand()
  631. // Command dispatcher for the main window
  632. //
  633. void WbMainWindow::OnCommand(UINT cmd, UINT code, HWND hwndCtl)
  634. {
  635. switch (cmd)
  636. {
  637. //
  638. // FILE MENU
  639. //
  640. case IDM_NEW:
  641. OnNew();
  642. break;
  643. case IDM_OPEN:
  644. OnOpen();
  645. break;
  646. case IDM_SAVE:
  647. OnSave(FALSE);
  648. break;
  649. case IDM_SAVE_AS:
  650. OnSave(TRUE);
  651. break;
  652. case IDM_PRINT:
  653. OnPrint();
  654. break;
  655. case IDM_EXIT:
  656. ::PostMessage(m_hwnd, WM_CLOSE, 0, 0);
  657. break;
  658. //
  659. // EDIT MENU
  660. //
  661. case IDM_DELETE:
  662. OnDelete();
  663. break;
  664. case IDM_UNDELETE:
  665. OnUndelete();
  666. break;
  667. case IDM_CUT:
  668. OnCut();
  669. break;
  670. case IDM_COPY:
  671. OnCopy();
  672. break;
  673. case IDM_PASTE:
  674. OnPaste();
  675. break;
  676. case IDM_SELECTALL:
  677. OnSelectAll();
  678. break;
  679. case IDM_BRING_TO_TOP:
  680. m_drawingArea.BringToTopSelection(TRUE, 0);
  681. break;
  682. case IDM_SEND_TO_BACK:
  683. m_drawingArea.SendToBackSelection(TRUE, 0);
  684. break;
  685. case IDM_CLEAR_PAGE:
  686. OnClearPage();
  687. break;
  688. case IDM_DELETE_PAGE:
  689. OnDeletePage();
  690. break;
  691. case IDM_PAGE_INSERT_AFTER:
  692. OnInsertPageAfter();
  693. break;
  694. //
  695. // VIEW MENU
  696. //
  697. case IDM_TOOL_BAR_TOGGLE:
  698. OnToolBarToggle();
  699. break;
  700. case IDM_STATUS_BAR_TOGGLE:
  701. OnStatusBarToggle();
  702. break;
  703. case IDM_ZOOM:
  704. OnZoom();
  705. break;
  706. //
  707. // TOOLS MENU
  708. //
  709. case IDM_SELECT:
  710. case IDM_PEN:
  711. case IDM_HIGHLIGHT:
  712. case IDM_TEXT:
  713. case IDM_ERASER:
  714. case IDM_LINE:
  715. case IDM_BOX:
  716. case IDM_FILLED_BOX:
  717. case IDM_ELLIPSE:
  718. case IDM_FILLED_ELLIPSE:
  719. OnSelectTool(cmd);
  720. break;
  721. case IDM_REMOTE:
  722. OnRemotePointer();
  723. //
  724. // Are we turnig remote pointer on
  725. //
  726. if(m_pLocalRemotePointer)
  727. {
  728. //put us in select-tool mode
  729. OnSelectTool(IDM_SELECT);
  730. }
  731. break;
  732. case IDM_GRAB_AREA:
  733. OnGrabArea();
  734. break;
  735. case IDM_GRAB_WINDOW:
  736. OnGrabWindow();
  737. break;
  738. case IDM_SYNC:
  739. OnSync();
  740. break;
  741. case IDM_LOCK:
  742. OnLock();
  743. break;
  744. case IDM_COLOR:
  745. OnSelectColor();
  746. break;
  747. case IDM_EDITCOLOR:
  748. m_AG.OnEditColors();
  749. break;
  750. case IDM_FONT:
  751. OnChooseFont();
  752. break;
  753. case IDM_WIDTH_1:
  754. case IDM_WIDTH_2:
  755. case IDM_WIDTH_3:
  756. case IDM_WIDTH_4:
  757. OnSelectWidth(cmd);
  758. break;
  759. //
  760. // HELP MENU
  761. //
  762. case IDM_ABOUT:
  763. OnAbout();
  764. break;
  765. case IDM_HELP:
  766. ShowHelp();
  767. break;
  768. //
  769. // PAGE BAR
  770. //
  771. case IDM_PAGE_FIRST:
  772. OnFirstPage();
  773. break;
  774. case IDM_PAGE_PREV:
  775. OnPrevPage();
  776. break;
  777. case IDM_PAGE_GOTO:
  778. OnGotoPage();
  779. break;
  780. case IDM_PAGE_NEXT:
  781. OnNextPage();
  782. break;
  783. case IDM_PAGE_LAST:
  784. OnLastPage();
  785. break;
  786. //
  787. // SCROLLING
  788. //
  789. case IDM_PAGEUP:
  790. case IDM_PAGEDOWN:
  791. case IDM_SHIFTPAGEUP:
  792. case IDM_SHIFTPAGEDOWN:
  793. case IDM_HOME:
  794. case IDM_END:
  795. case IDM_LINEUP:
  796. case IDM_LINEDOWN:
  797. case IDM_SHIFTLINEUP:
  798. case IDM_SHIFTLINEDOWN:
  799. OnScrollAccelerator(cmd);
  800. break;
  801. case ID_NAV_TAB:
  802. ShiftFocus(m_hwnd, TRUE);
  803. break;
  804. case ID_NAV_SHIFT_TAB:
  805. ShiftFocus(m_hwnd, FALSE);
  806. break;
  807. }
  808. }
  809. //
  810. //
  811. // Function: OnInitMenuPopup
  812. //
  813. // Purpose: Process a WM_INITMENUPOPUP event
  814. //
  815. //
  816. void WbMainWindow::OnInitMenuPopup
  817. (
  818. HMENU hMenu,
  819. UINT uiIndex,
  820. BOOL bSystemMenu
  821. )
  822. {
  823. // Ignore the event if it relates to the system menu
  824. if (!bSystemMenu)
  825. {
  826. if (hMenu)
  827. {
  828. SetMenuStates(hMenu);
  829. m_hInitMenu = hMenu;
  830. }
  831. else
  832. {
  833. m_hInitMenu = NULL;
  834. }
  835. // Save the last menu we handled, so that we can alter its state
  836. // if necessary whilst it is still visible
  837. }
  838. }
  839. //
  840. //
  841. // Function: GetMenuWithItem
  842. //
  843. // Purpose: Return the menu which contains the specified item.
  844. //
  845. //
  846. HMENU WbMainWindow::GetMenuWithItem(HMENU hMenu, UINT uiID)
  847. {
  848. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GetMenuWithItem");
  849. ASSERT(hMenu != NULL);
  850. HMENU hMenuResult = NULL;
  851. // Get the number ofitems in the menu
  852. UINT uiNumItems = ::GetMenuItemCount(hMenu);
  853. UINT uiPos;
  854. UINT uiNextID;
  855. // Look for the item through the menu
  856. for (uiPos = 0; uiPos < uiNumItems; uiPos++)
  857. {
  858. // Get the ID of the item at this position
  859. uiNextID = ::GetMenuItemID(hMenu, uiPos);
  860. if (uiNextID == uiID)
  861. {
  862. // We have found the item
  863. hMenuResult = hMenu;
  864. break;
  865. }
  866. }
  867. // If we have not yet found the item
  868. if (hMenuResult == NULL)
  869. {
  870. // Look through each of the submenus of the current menu
  871. HMENU hSubMenu;
  872. for (uiPos = 0; uiPos < uiNumItems; uiPos++)
  873. {
  874. // Get the ID of the item at this position
  875. uiNextID = ::GetMenuItemID(hMenu, uiPos);
  876. // If the item is a submenu
  877. if (uiNextID == -1)
  878. {
  879. // Get the submenu
  880. hSubMenu = ::GetSubMenu(hMenu, (int) uiPos);
  881. // Search the submenu
  882. hMenuResult = GetMenuWithItem(hSubMenu, uiID);
  883. if (hMenuResult != NULL)
  884. {
  885. // We have found the menu with the requested item
  886. break;
  887. }
  888. }
  889. }
  890. }
  891. return hMenuResult;
  892. }
  893. //
  894. //
  895. // Function: WbMainWindow::InitializeMenus
  896. //
  897. // Purpose: Initialise the menus: set up owner-drawn menu items and
  898. // those read from options file.
  899. //
  900. //
  901. void WbMainWindow::InitializeMenus(void)
  902. {
  903. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::InitializeMenus");
  904. // Make the width menu ownerdraw
  905. HMENU hMenu = GetMenuWithItem(::GetMenu(m_hwnd), IDM_WIDTH_1);
  906. if (hMenu != NULL)
  907. {
  908. // Change each entry to be ownerdraw (loop until failure)
  909. int iIndex;
  910. UINT uiId;
  911. int iCount = ::GetMenuItemCount(hMenu);
  912. for (iIndex = 0; iIndex < iCount; iIndex++)
  913. {
  914. uiId = ::GetMenuItemID(hMenu, iIndex);
  915. ::ModifyMenu(hMenu, iIndex,
  916. MF_BYPOSITION
  917. | MF_ENABLED
  918. | MF_OWNERDRAW,
  919. uiId,
  920. NULL);
  921. }
  922. }
  923. }
  924. //
  925. //
  926. // Function: CheckMenuItem
  927. //
  928. // Purpose: Check an item on the application menus (main and context
  929. // menu.)
  930. //
  931. //
  932. void WbMainWindow::CheckMenuItem(UINT uiId)
  933. {
  934. CheckMenuItemRecursive(::GetMenu(m_hwnd), uiId, MF_BYCOMMAND | MF_CHECKED);
  935. CheckMenuItemRecursive(m_hContextMenu, uiId, MF_BYCOMMAND | MF_CHECKED);
  936. CheckMenuItemRecursive(m_hGrobjContextMenu, uiId, MF_BYCOMMAND | MF_CHECKED);
  937. }
  938. //
  939. //
  940. // Function: UncheckMenuItem
  941. //
  942. // Purpose: Uncheck an item on the application menus (main and context
  943. // menus.)
  944. //
  945. //
  946. void WbMainWindow::UncheckMenuItem(UINT uiId)
  947. {
  948. CheckMenuItemRecursive(::GetMenu(m_hwnd), uiId, MF_BYCOMMAND | MF_UNCHECKED);
  949. CheckMenuItemRecursive(m_hContextMenu, uiId, MF_BYCOMMAND | MF_UNCHECKED);
  950. CheckMenuItemRecursive(m_hGrobjContextMenu, uiId, MF_BYCOMMAND | MF_UNCHECKED);
  951. }
  952. //
  953. //
  954. // Function: CheckMenuItemRecursive
  955. //
  956. // Purpose: Check or uncheck an item on the any of the Whiteboard menus.
  957. // This function recursively searches through the menus until
  958. // it finds the specified item. The menu item Ids must be
  959. // unique for this function to work.
  960. //
  961. //
  962. BOOL WbMainWindow::CheckMenuItemRecursive(HMENU hMenu,
  963. UINT uiId,
  964. BOOL bCheck)
  965. {
  966. UINT uiNumItems = ::GetMenuItemCount(hMenu);
  967. // Attempt to check the menu item
  968. UINT uiCheck = MF_BYCOMMAND | (bCheck ? MF_CHECKED : MF_UNCHECKED);
  969. // A return code of -1 from CheckMenuItem implies that
  970. // the menu item was not found
  971. BOOL bChecked = ((::CheckMenuItem(hMenu, uiId, uiCheck) == -1) ? FALSE : TRUE);
  972. if (bChecked)
  973. {
  974. //
  975. // If this item is on the active menu, ensure it's redrawn now
  976. //
  977. if (hMenu == m_hInitMenu)
  978. {
  979. InvalidateActiveMenu();
  980. }
  981. }
  982. else
  983. {
  984. UINT uiPos;
  985. HMENU hSubMenu;
  986. // Recurse through the submenus of the specified menu
  987. for (uiPos = 0; uiPos < uiNumItems; uiPos++)
  988. {
  989. // Assume that the next item is a submenu
  990. // and try to get a pointer to it
  991. hSubMenu = ::GetSubMenu(hMenu, (int)uiPos);
  992. // NULL return implies the item is a not submenu
  993. if (hSubMenu != NULL)
  994. {
  995. // Item is a submenu, make recursive call to search it
  996. bChecked = CheckMenuItemRecursive(hSubMenu, uiId, bCheck);
  997. if (bChecked)
  998. {
  999. // We have found the item
  1000. break;
  1001. }
  1002. }
  1003. }
  1004. }
  1005. return bChecked;
  1006. }
  1007. //
  1008. //
  1009. // Function: InvalidateActiveMenu
  1010. //
  1011. // Purpose: If a menu is currently active, gray items according to
  1012. // the current state, and force it to redraw.
  1013. //
  1014. //
  1015. void WbMainWindow::InvalidateActiveMenu()
  1016. {
  1017. if (m_hInitMenu != NULL)
  1018. {
  1019. // A menu is displayed, so set the state appropriately and force a
  1020. // repaint to show the new state
  1021. SetMenuStates(m_hInitMenu);
  1022. ::RedrawWindow(::GetTopWindow(::GetDesktopWindow()),
  1023. NULL, NULL,
  1024. RDW_FRAME | RDW_INVALIDATE | RDW_ERASE |
  1025. RDW_ERASENOW | RDW_ALLCHILDREN);
  1026. }
  1027. }
  1028. //
  1029. //
  1030. // Function: SetMenuState
  1031. //
  1032. // Purpose: Sets menu contents to their correct enabled/disabled state
  1033. //
  1034. //
  1035. void WbMainWindow::SetMenuStates(HMENU hInitMenu)
  1036. {
  1037. BOOL bLocked;
  1038. BOOL bPageOrderLocked;
  1039. BOOL bPresentationMode;
  1040. UINT uiEnable;
  1041. UINT uiCountPages;
  1042. BOOL bIdle;
  1043. BOOL bSelected;
  1044. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::SetMenuStates");
  1045. //
  1046. // Check menu exists
  1047. //
  1048. if (hInitMenu == NULL)
  1049. {
  1050. WARNING_OUT(("Menu doesn't exist"));
  1051. return;
  1052. }
  1053. HMENU hMainMenu = ::GetMenu(m_hwnd);
  1054. // Get the window's main menu and check that the menu
  1055. // now being popped up is one on the top-level. (We do not
  1056. // seem to be able to associate the index number passed with
  1057. // sub-menus easily.)
  1058. if ((hInitMenu != m_hContextMenu) && (hInitMenu != m_hGrobjContextMenu))
  1059. {
  1060. BOOL bTopLevel = FALSE;
  1061. int nCount = ::GetMenuItemCount(hMainMenu);
  1062. for (int nNext = 0; nNext < nCount; nNext++)
  1063. {
  1064. HMENU hNextMenu = ::GetSubMenu(hMainMenu, nNext);
  1065. if (hNextMenu != NULL)
  1066. {
  1067. if (hNextMenu == hInitMenu)
  1068. {
  1069. bTopLevel = TRUE;
  1070. break;
  1071. }
  1072. }
  1073. }
  1074. // not a top level, so leave the function now
  1075. if (!bTopLevel)
  1076. {
  1077. TRACE_DEBUG(("Not top-level menu"));
  1078. return;
  1079. }
  1080. }
  1081. BOOL bImNotLocked = (g_pCurrentWorkspace ? (g_pCurrentWorkspace->GetUpdatesEnabled() ? TRUE : g_pNMWBOBJ->m_LockerID == g_MyMemberID) :FALSE);
  1082. BOOL bIsThereAnything = IsThereAnythingInAnyWorkspace();
  1083. BOOL bIsThereSomethig = bImNotLocked && (g_pCurrentWorkspace && g_pCurrentWorkspace->GetHead() != NULL) ? TRUE : FALSE;
  1084. BOOL bIsThereTrash = bImNotLocked && (g_pTrash->GetHead() != NULL) && (g_pCurrentWorkspace != NULL);
  1085. BOOL bIsSomethingSelected = bImNotLocked && g_pDraw->GraphicSelected() && g_pDraw->GetSelectedGraphic()->GraphicTool() != TOOLTYPE_REMOTEPOINTER && g_pCurrentWorkspace != NULL;
  1086. BOOL bIsSynced = g_pDraw->IsSynced();
  1087. BOOL bOnlyOnePage = (g_pListOfWorkspaces->GetHead() == g_pListOfWorkspaces->GetTail());
  1088. //
  1089. // Functions which are disabled when contents is locked
  1090. //
  1091. uiEnable = MF_BYCOMMAND | (bImNotLocked && bIsSynced ? MF_ENABLED : MF_GRAYED);
  1092. //
  1093. // File menu
  1094. //
  1095. ::EnableMenuItem(hInitMenu, IDM_NEW, uiEnable);
  1096. ::EnableMenuItem(hInitMenu, IDM_OPEN, uiEnable);
  1097. uiEnable = MF_BYCOMMAND | (bIsThereAnything ? MF_ENABLED : MF_GRAYED);
  1098. ::EnableMenuItem(hInitMenu, IDM_SAVE, uiEnable);
  1099. ::EnableMenuItem(hInitMenu, IDM_SAVE_AS, uiEnable);
  1100. ::EnableMenuItem(hInitMenu, IDM_PRINT, uiEnable);
  1101. //
  1102. // Tools menu
  1103. //
  1104. uiEnable = MF_BYCOMMAND | (bImNotLocked ? MF_ENABLED : MF_GRAYED);
  1105. ::EnableMenuItem(hInitMenu, IDM_SELECT, uiEnable);
  1106. ::EnableMenuItem(hInitMenu, IDM_ERASER, uiEnable);
  1107. ::EnableMenuItem(hInitMenu, IDM_PEN, uiEnable);
  1108. ::EnableMenuItem(hInitMenu, IDM_HIGHLIGHT, uiEnable);
  1109. ::EnableMenuItem(hInitMenu, IDM_GRAB_AREA, uiEnable);
  1110. ::EnableMenuItem(hInitMenu, IDM_GRAB_WINDOW, uiEnable);
  1111. ::EnableMenuItem(hInitMenu, IDM_LINE, uiEnable);
  1112. ::EnableMenuItem(hInitMenu, IDM_BOX, uiEnable);
  1113. ::EnableMenuItem(hInitMenu, IDM_FILLED_BOX, uiEnable);
  1114. ::EnableMenuItem(hInitMenu, IDM_ELLIPSE, uiEnable);
  1115. ::EnableMenuItem(hInitMenu, IDM_FILLED_ELLIPSE, uiEnable);
  1116. ::EnableMenuItem(hInitMenu, IDM_TEXT, m_drawingArea.Zoomed() ? MF_BYCOMMAND | MF_GRAYED : uiEnable);
  1117. ::EnableMenuItem(hInitMenu, IDM_ZOOM, uiEnable);
  1118. ::EnableMenuItem(hInitMenu, IDM_REMOTE, uiEnable);
  1119. ::EnableMenuItem(hInitMenu, IDM_FONT, MF_BYCOMMAND | bImNotLocked && m_pCurrentTool->HasFont() ? MF_ENABLED : MF_GRAYED);
  1120. ::EnableMenuItem(hInitMenu, IDM_EDITCOLOR, MF_BYCOMMAND | bImNotLocked && m_pCurrentTool->HasColor() ? MF_ENABLED : MF_GRAYED);
  1121. HMENU hToolsMenu = ::GetSubMenu(hMainMenu, MENUPOS_TOOLS);
  1122. uiEnable = (bImNotLocked && m_pCurrentTool->HasWidth()) ? MF_ENABLED : MF_GRAYED;
  1123. if (hToolsMenu == hInitMenu )
  1124. {
  1125. ::EnableMenuItem(hToolsMenu, TOOLSPOS_WIDTH, MF_BYPOSITION | uiEnable );
  1126. }
  1127. UINT i;
  1128. UINT uIdmCurWidth = 0;
  1129. if( uiEnable == MF_ENABLED )
  1130. uIdmCurWidth = m_pCurrentTool->GetWidthIndex() + IDM_WIDTH_1;
  1131. for( i=IDM_WIDTH_1; i<=IDM_WIDTH_4; i++ )
  1132. {
  1133. ::EnableMenuItem(hInitMenu, i, uiEnable );
  1134. if( uiEnable == MF_ENABLED )
  1135. {
  1136. if( uIdmCurWidth == i )
  1137. ::CheckMenuItem(hInitMenu, i, MF_CHECKED );
  1138. else
  1139. ::CheckMenuItem(hInitMenu, i, MF_UNCHECKED );
  1140. }
  1141. }
  1142. //
  1143. // Edit Menu
  1144. //
  1145. uiEnable = MF_BYCOMMAND | (bIsSomethingSelected? MF_ENABLED : MF_GRAYED);
  1146. ::EnableMenuItem(hInitMenu, IDM_DELETE, uiEnable );
  1147. ::EnableMenuItem(hInitMenu, IDM_CUT, uiEnable );
  1148. ::EnableMenuItem(hInitMenu, IDM_COPY, uiEnable);
  1149. ::EnableMenuItem(hInitMenu, IDM_BRING_TO_TOP, uiEnable);
  1150. ::EnableMenuItem(hInitMenu, IDM_SEND_TO_BACK, uiEnable);
  1151. uiEnable = MF_BYCOMMAND | (bIsThereSomethig ?MF_ENABLED : MF_GRAYED);
  1152. ::EnableMenuItem(hInitMenu, IDM_CLEAR_PAGE, uiEnable);
  1153. ::EnableMenuItem(hInitMenu, IDM_SELECTALL, uiEnable);
  1154. ::EnableMenuItem(hInitMenu, IDM_PASTE, MF_BYCOMMAND | CLP_AcceptableClipboardFormat() && bImNotLocked ? MF_ENABLED : MF_GRAYED);
  1155. ::EnableMenuItem(hInitMenu, IDM_UNDELETE, MF_BYCOMMAND | (bIsThereTrash? MF_ENABLED : MF_GRAYED) );
  1156. ::EnableMenuItem(hInitMenu, IDM_DELETE_PAGE, MF_BYCOMMAND | bIsSynced && bImNotLocked && !bOnlyOnePage ? MF_ENABLED : MF_GRAYED);
  1157. ::EnableMenuItem(hInitMenu, IDM_PAGE_INSERT_AFTER, MF_BYCOMMAND | bIsSynced && bImNotLocked && g_numberOfWorkspaces < WB_MAX_WORKSPACES ? MF_ENABLED : MF_GRAYED);
  1158. //
  1159. // View Menu
  1160. //
  1161. ::EnableMenuItem(hInitMenu, IDM_SYNC, MF_BYCOMMAND | (bImNotLocked && !m_drawingArea.IsLocked()? MF_ENABLED : MF_GRAYED));
  1162. ::EnableMenuItem(hInitMenu, IDM_LOCK, MF_BYCOMMAND |((bImNotLocked && bIsSynced) ? MF_ENABLED : MF_GRAYED));
  1163. //
  1164. // Enable toolbar
  1165. //
  1166. EnableToolbar(bImNotLocked);
  1167. //
  1168. // Enable page controls
  1169. //
  1170. m_AG.EnablePageCtrls(bImNotLocked);
  1171. }
  1172. //
  1173. //
  1174. // Function: WbMainWindow destructor
  1175. //
  1176. // Purpose: Tidy up main window on destruction.
  1177. //
  1178. //
  1179. WbMainWindow::~WbMainWindow()
  1180. {
  1181. //
  1182. // Destroy the tooltip window
  1183. //
  1184. if (m_hwndToolTip)
  1185. {
  1186. ::DestroyWindow(m_hwndToolTip);
  1187. m_hwndToolTip = NULL;
  1188. }
  1189. if (m_hGrobjContextMenuBar != NULL)
  1190. {
  1191. ::DestroyMenu(m_hGrobjContextMenuBar);
  1192. m_hGrobjContextMenuBar = NULL;
  1193. }
  1194. m_hGrobjContextMenu = NULL;
  1195. if (m_hContextMenuBar != NULL)
  1196. {
  1197. ::DestroyMenu(m_hContextMenuBar);
  1198. m_hContextMenuBar = NULL;
  1199. }
  1200. m_hContextMenu = NULL;
  1201. POSITION position = m_pageToPosition.GetHeadPosition();
  1202. PAGE_POSITION * pPoint;
  1203. while (position)
  1204. {
  1205. pPoint = (PAGE_POSITION*)m_pageToPosition.GetNext(position);
  1206. delete pPoint;
  1207. }
  1208. m_pageToPosition.EmptyList();
  1209. //
  1210. // Free the palette
  1211. //
  1212. if (g_hRainbowPaletteDisplay)
  1213. {
  1214. if (g_pDraw && g_pDraw->m_hDCCached)
  1215. {
  1216. // Select out the rainbow palette so we can delete it
  1217. ::SelectPalette(g_pDraw->m_hDCCached, (HPALETTE)::GetStockObject(DEFAULT_PALETTE), TRUE);
  1218. }
  1219. DeletePalette(g_hRainbowPaletteDisplay);
  1220. g_hRainbowPaletteDisplay = NULL;
  1221. }
  1222. g_bPalettesInitialized = FALSE;
  1223. g_bUsePalettes = FALSE;
  1224. if (g_pIcons)
  1225. {
  1226. delete g_pIcons;
  1227. g_pIcons = NULL;
  1228. }
  1229. if(m_pTitleFileName)
  1230. {
  1231. delete m_pTitleFileName;
  1232. m_pTitleFileName = NULL;
  1233. }
  1234. //
  1235. // Delete all the objectsb in global lists
  1236. //
  1237. DeleteAllWorkspaces(FALSE);
  1238. ASSERT(g_pListOfWorkspaces);
  1239. g_pListOfWorkspaces->EmptyList();
  1240. ASSERT(g_pListOfObjectsThatRequestedHandles);
  1241. g_pListOfObjectsThatRequestedHandles->EmptyList();
  1242. g_numberOfWorkspaces = 0;
  1243. //
  1244. // Delete objects in limbo, sitting in the undelete trash
  1245. //
  1246. ASSERT(g_pTrash);
  1247. T126Obj* pGraphic;
  1248. //
  1249. // Burn trash
  1250. //
  1251. pGraphic = (T126Obj *)g_pTrash->RemoveTail();
  1252. while (pGraphic != NULL)
  1253. {
  1254. delete pGraphic;
  1255. pGraphic = (T126Obj *) g_pTrash->RemoveTail();
  1256. }
  1257. DeleteAllRetryPDUS();
  1258. DestroyToolArray();
  1259. ::DestroyWindow(m_hwnd);
  1260. ::UnregisterClass(szMainClassName, g_hInstance);
  1261. }
  1262. //
  1263. // OnToolHitTest()
  1264. // This handles tooltips for child windows.
  1265. //
  1266. int WbMainWindow::OnToolHitTest(POINT pt, TOOLINFO* pTI) const
  1267. {
  1268. HWND hwnd;
  1269. int status;
  1270. int nHit = -1;
  1271. ASSERT(!IsBadWritePtr(pTI, sizeof(TOOLINFO)));
  1272. hwnd = ::ChildWindowFromPointEx(m_hwnd, pt, CWP_SKIPINVISIBLE);
  1273. if (hwnd == m_AG.m_hwnd)
  1274. {
  1275. ::MapWindowPoints(m_hwnd, m_AG.m_hwnd, &pt, 1);
  1276. hwnd = ::ChildWindowFromPointEx(m_AG.m_hwnd, pt, CWP_SKIPINVISIBLE);
  1277. if (hwnd != NULL)
  1278. {
  1279. nHit = ::GetDlgCtrlID(hwnd);
  1280. pTI->hwnd = m_hwnd;
  1281. pTI->uId = (UINT_PTR)hwnd;
  1282. pTI->uFlags |= TTF_IDISHWND;
  1283. pTI->lpszText = LPSTR_TEXTCALLBACK;
  1284. return(nHit);
  1285. }
  1286. }
  1287. else if (hwnd == m_WG.m_hwnd)
  1288. {
  1289. int iItem;
  1290. ::MapWindowPoints(m_hwnd, m_WG.m_hwnd, &pt, 1);
  1291. iItem = m_WG.ItemFromPoint(pt.x, pt.y);
  1292. pTI->hwnd = m_WG.m_hwnd;
  1293. pTI->uId = iItem;
  1294. // Since the area isn't a window, we must fill in the rect ourself
  1295. m_WG.GetItemRect(iItem, &pTI->rect);
  1296. pTI->lpszText = LPSTR_TEXTCALLBACK;
  1297. return(iItem);
  1298. }
  1299. else if (hwnd == m_TB.m_hwnd)
  1300. {
  1301. RECT rect;
  1302. TBBUTTON button;
  1303. int i;
  1304. for (i = 0; i < TOOLBAR_MAXBUTTON; i++)
  1305. {
  1306. if (::SendMessage(m_TB.m_hwnd, TB_GETITEMRECT, i, (LPARAM)&rect) &&
  1307. ::PtInRect(&rect, pt) &&
  1308. ::SendMessage(m_TB.m_hwnd, TB_GETBUTTON, i, (LPARAM)&button) &&
  1309. !(button.fsStyle & TBSTYLE_SEP))
  1310. {
  1311. nHit = button.idCommand;
  1312. pTI->hwnd = m_TB.m_hwnd;
  1313. pTI->uId = nHit;
  1314. pTI->rect = rect;
  1315. pTI->lpszText = LPSTR_TEXTCALLBACK;
  1316. // found matching rect, return the ID of the button
  1317. return(nHit);
  1318. }
  1319. }
  1320. }
  1321. return(-1);
  1322. }
  1323. //
  1324. // WinHelp() wrapper
  1325. //
  1326. LRESULT WbMainWindow::ShowHelp(void)
  1327. {
  1328. HWND hwndCapture;
  1329. // Get the main window out of any mode
  1330. ::SendMessage(m_hwnd, WM_CANCELMODE, 0, 0);
  1331. // Cancel any other tracking
  1332. if (hwndCapture = ::GetCapture())
  1333. ::SendMessage(hwndCapture, WM_CANCELMODE, 0, 0);
  1334. // finally, run the NetMeeting Help engine
  1335. ShowNmHelp(s_cszHtmlHelpFile);
  1336. return S_OK;
  1337. }
  1338. //
  1339. // TimedDlgProc()
  1340. // This puts up a visible or invisible dialog which only goes away when
  1341. // an event occurs or a certain amount of time has passed. We store the
  1342. // DialogBoxParam parameter, a TMDLG pointer, in our user data. That is
  1343. // from the stack of the DialogBoxParam() caller, so it is valid until that
  1344. // function returns, which won't be until a bit after the dialog has been
  1345. // destroyed.
  1346. //
  1347. INT_PTR CALLBACK TimedDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  1348. {
  1349. BOOL fHandled = FALSE;
  1350. TMDLG * ptm;
  1351. switch (uMessage)
  1352. {
  1353. case WM_INITDIALOG:
  1354. ptm = (TMDLG *)lParam;
  1355. ASSERT(!IsBadWritePtr(ptm, sizeof(TMDLG)));
  1356. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)ptm);
  1357. //
  1358. // Set the WbMainWindow hwnd
  1359. //
  1360. if (ptm->bLockNotEvent)
  1361. {
  1362. g_pMain->m_hwndWaitForLockDlg = hwnd;
  1363. }
  1364. else
  1365. {
  1366. g_pMain->m_hwndWaitForEventDlg = hwnd;
  1367. }
  1368. //
  1369. // Set max timer
  1370. //
  1371. ::SetTimer(hwnd, TIMERID_MAXDISPLAY, ptm->uiMaxDisplay, NULL);
  1372. //
  1373. // Change the cursor if invisible
  1374. //
  1375. if (!ptm->bVisible)
  1376. ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  1377. fHandled = TRUE;
  1378. break;
  1379. case WM_TIMER:
  1380. ASSERT(wParam == TIMERID_MAXDISPLAY);
  1381. // End the dialog--since we timed out, it acts like cancel
  1382. ::SendMessage(hwnd, WM_COMMAND, MAKELONG(IDCANCEL, BN_CLICKED), 0);
  1383. fHandled = TRUE;
  1384. break;
  1385. case WM_COMMAND:
  1386. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1387. {
  1388. case IDOK:
  1389. case IDCANCEL:
  1390. if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
  1391. {
  1392. ptm = (TMDLG *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1393. ASSERT(!IsBadWritePtr(ptm, sizeof(TMDLG)));
  1394. // Clear out the HWND variable
  1395. if (ptm->bLockNotEvent)
  1396. {
  1397. g_pMain->m_hwndWaitForLockDlg = NULL;
  1398. }
  1399. else
  1400. {
  1401. g_pMain->m_hwndWaitForEventDlg = NULL;
  1402. }
  1403. // Restore the cursor
  1404. if (!ptm->bVisible)
  1405. ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  1406. ::KillTimer(hwnd, TIMERID_MAXDISPLAY);
  1407. ::EndDialog(hwnd, GET_WM_COMMAND_ID(wParam, lParam));
  1408. }
  1409. break;
  1410. }
  1411. fHandled = TRUE;
  1412. break;
  1413. //
  1414. // Don't let these dialogs be killed by any other means than our
  1415. // getting an event or timing out.
  1416. //
  1417. case WM_CLOSE:
  1418. fHandled = TRUE;
  1419. break;
  1420. }
  1421. return(fHandled);
  1422. }
  1423. //
  1424. // FilterMessage()
  1425. //
  1426. // This does tooltip message filtering, then translates accelerators.
  1427. //
  1428. BOOL WbMainWindow::FilterMessage(MSG* pMsg)
  1429. {
  1430. BOOL bResult = FALSE;
  1431. if ((pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) ||
  1432. (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK) ||
  1433. (pMsg->message == WM_RBUTTONDOWN || pMsg->message == WM_RBUTTONDBLCLK) ||
  1434. (pMsg->message == WM_MBUTTONDOWN || pMsg->message == WM_MBUTTONDBLCLK) ||
  1435. (pMsg->message == WM_NCLBUTTONDOWN || pMsg->message == WM_NCLBUTTONDBLCLK) ||
  1436. (pMsg->message == WM_NCRBUTTONDOWN || pMsg->message == WM_NCRBUTTONDBLCLK) ||
  1437. (pMsg->message == WM_NCMBUTTONDOWN || pMsg->message == WM_NCMBUTTONDBLCLK))
  1438. {
  1439. // Cancel any tooltip up
  1440. ::SendMessage(m_hwndToolTip, TTM_ACTIVATE, FALSE, 0);
  1441. }
  1442. // handle tooltip messages (some messages cancel, some may cause it to popup)
  1443. if ((pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE ||
  1444. pMsg->message == WM_LBUTTONUP || pMsg->message == WM_RBUTTONUP ||
  1445. pMsg->message == WM_MBUTTONUP) &&
  1446. (GetKeyState(VK_LBUTTON) >= 0 && GetKeyState(VK_RBUTTON) >= 0 &&
  1447. GetKeyState(VK_MBUTTON) >= 0))
  1448. {
  1449. #if 0
  1450. //
  1451. // If this mouse move isn't for a descendant of the main window, skip
  1452. // it. For example, when the tooltip is shown, it gets a mousemove
  1453. // to itself, which if we didn't check for it, would cause us to
  1454. // immediately dismiss this!
  1455. //
  1456. HWND hwndTmp = pMsg->hwnd;
  1457. while (hwndTmp && (::GetWindowLong(hwndTmp, GWL_STYLE) & WS_CHILD))
  1458. {
  1459. hwndTmp = ::GetParent(hwndTmp);
  1460. }
  1461. if (hwndTmp != m_hwnd)
  1462. {
  1463. // This is not for us, it's for another top level window in
  1464. // our app.
  1465. goto DoneToolTipFiltering;
  1466. }
  1467. #endif
  1468. // determine which tool was hit
  1469. POINT pt;
  1470. pt = pMsg->pt;
  1471. ::ScreenToClient(m_hwnd, &pt);
  1472. TOOLINFO tiHit;
  1473. ZeroMemory(&tiHit, sizeof(tiHit));
  1474. tiHit.cbSize = sizeof(TOOLINFO);
  1475. int nHit = OnToolHitTest(pt, &tiHit);
  1476. if (m_nLastHit != nHit)
  1477. {
  1478. if (nHit != -1)
  1479. {
  1480. // add new tool and activate the tip
  1481. if (!::SendMessage(m_hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&tiHit))
  1482. {
  1483. ERROR_OUT(("TTM_ADDTOOL failed"));
  1484. }
  1485. if (::GetActiveWindow() == m_hwnd)
  1486. {
  1487. // allow the tooltip to popup when it should
  1488. ::SendMessage(m_hwndToolTip, TTM_ACTIVATE, TRUE, 0);
  1489. // bring the tooltip window above other popup windows
  1490. ::SetWindowPos(m_hwndToolTip, HWND_TOP, 0, 0, 0, 0,
  1491. SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
  1492. }
  1493. }
  1494. // relay mouse event before deleting old tool
  1495. ::SendMessage(m_hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)pMsg);
  1496. // now safe to delete the old tool
  1497. if (m_tiLastHit.cbSize != 0)
  1498. ::SendMessage(m_hwndToolTip, TTM_DELTOOL, 0, (LPARAM)&m_tiLastHit);
  1499. m_nLastHit = nHit;
  1500. m_tiLastHit = tiHit;
  1501. }
  1502. else
  1503. {
  1504. // relay mouse events through the tooltip
  1505. if (nHit != -1)
  1506. ::SendMessage(m_hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)pMsg);
  1507. }
  1508. }
  1509. #if 0
  1510. DoneToolTipFiltering:
  1511. #endif
  1512. // Assume we will use the main accelerator table
  1513. HACCEL hAccelTable = m_hAccelTable;
  1514. // If this window has focus, just continue
  1515. HWND hwndFocus = ::GetFocus();
  1516. if (hwndFocus && (hwndFocus != m_hwnd))
  1517. {
  1518. // Check whether an edit field in the pages group has the focus
  1519. if (m_AG.IsChildEditField(hwndFocus))
  1520. {
  1521. hAccelTable = m_hAccelPagesGroup;
  1522. }
  1523. // Check whether text editor has the focus and is active
  1524. else if ( (hwndFocus == m_drawingArea.m_hwnd)
  1525. && (m_drawingArea.TextEditActive()))
  1526. {
  1527. // Let editbox do its own acceleration.
  1528. hAccelTable = NULL;
  1529. }
  1530. }
  1531. return ( (hAccelTable != NULL)
  1532. && ::TranslateAccelerator(m_hwnd, hAccelTable, pMsg));
  1533. }
  1534. //
  1535. //
  1536. // Function: OnDisplayError
  1537. //
  1538. // Purpose: Display an error message
  1539. //
  1540. //
  1541. void WbMainWindow::OnDisplayError(WPARAM uiFEReturnCode, LPARAM uiDCGReturnCode)
  1542. {
  1543. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnDisplayError");
  1544. // Only continue if we are not currently displaying an error
  1545. if (!m_bDisplayingError)
  1546. {
  1547. // Show that we are currently displaying an error message
  1548. m_bDisplayingError = TRUE;
  1549. // Display the error
  1550. ::ErrorMessage((UINT)uiFEReturnCode, (UINT)uiDCGReturnCode);
  1551. // Show that we are no longer displaying an error
  1552. m_bDisplayingError = FALSE;
  1553. }
  1554. }
  1555. //
  1556. //
  1557. // Function: OnPaletteChanged
  1558. //
  1559. // Purpose: The palette has changed.
  1560. //
  1561. //
  1562. void WbMainWindow::OnPaletteChanged(HWND hwndPalette)
  1563. {
  1564. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnPaletteChanged");
  1565. if ((hwndPalette != m_hwnd) &&
  1566. (hwndPalette != m_drawingArea.m_hwnd))
  1567. {
  1568. // Tell the drawing area to realize its palette
  1569. m_drawingArea.RealizePalette( TRUE );
  1570. }
  1571. }
  1572. //
  1573. //
  1574. // Function: OnQueryNewPalette
  1575. //
  1576. // Purpose: We are getting focus and must realize our palette
  1577. //
  1578. //
  1579. LRESULT WbMainWindow::OnQueryNewPalette(void)
  1580. {
  1581. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnQueryNewPalette");
  1582. // Tell the drawing area to realize its palette
  1583. m_drawingArea.RealizePalette( FALSE );
  1584. return TRUE;
  1585. }
  1586. //
  1587. //
  1588. // Function: PopupContextMenu
  1589. //
  1590. // Purpose: Popup the context menu for the drawing area. This is called
  1591. // by the drawing area window on a right mouse click.
  1592. //
  1593. //
  1594. void WbMainWindow::PopupContextMenu(int x, int y)
  1595. {
  1596. POINT surfacePos;
  1597. RECT clientRect;
  1598. T126Obj * pGraphic;
  1599. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::PopupContextMenu");
  1600. surfacePos.x = x;
  1601. surfacePos.y = y;
  1602. m_drawingArea.ClientToSurface(&surfacePos);
  1603. if( (pGraphic = m_drawingArea.GetHitObject( surfacePos )) != NULL
  1604. && pGraphic->GraphicTool() != TOOLTYPE_REMOTEPOINTER )
  1605. {
  1606. if(!pGraphic->IsSelected() )
  1607. {
  1608. g_pDraw->SelectGraphic(pGraphic);
  1609. }
  1610. // selector tool is active, and one or more objects are selected
  1611. m_hInitMenu = m_hGrobjContextMenu;
  1612. }
  1613. else
  1614. {
  1615. // no current selection, show drawing menu
  1616. m_hInitMenu = m_hContextMenu;
  1617. }
  1618. // set up current menu state
  1619. SetMenuStates(m_hInitMenu);
  1620. // pop it up
  1621. ::GetClientRect(m_drawingArea.m_hwnd, &clientRect);
  1622. ::MapWindowPoints(m_drawingArea.m_hwnd, NULL, (LPPOINT)&clientRect.left, 2);
  1623. ::TrackPopupMenu(m_hInitMenu, TPM_RIGHTALIGN | TPM_RIGHTBUTTON,
  1624. x + clientRect.left,
  1625. y + clientRect.top,
  1626. 0,
  1627. m_hwnd,
  1628. NULL);
  1629. // reset m_hInitMenu to indicate the popup menu isn't being shown anymore
  1630. m_hInitMenu = NULL;
  1631. }
  1632. //
  1633. //
  1634. // Function: OnSize
  1635. //
  1636. // Purpose: The window has been resized.
  1637. //
  1638. //
  1639. void WbMainWindow::OnSize(UINT nType, int cx, int cy )
  1640. {
  1641. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnSize");
  1642. // Only process this message if the window is not minimized
  1643. if (nType != SIZE_MINIMIZED)
  1644. {
  1645. // The user's view has changed
  1646. PositionUpdated();
  1647. if (m_bStatusBarOn)
  1648. {
  1649. ::ShowWindow(m_hwndSB, SW_HIDE);
  1650. }
  1651. // Resize the subpanes of the window
  1652. ResizePanes();
  1653. // Show it again
  1654. if (m_bStatusBarOn)
  1655. {
  1656. ::ShowWindow(m_hwndSB, SW_SHOW);
  1657. }
  1658. // If the status has changed, set the option
  1659. if (m_uiWindowSize != nType)
  1660. {
  1661. m_uiWindowSize = nType;
  1662. // Write the new option values to file
  1663. OPT_SetBooleanOption(OPT_MAIN_MAXIMIZED,
  1664. (m_uiWindowSize == SIZE_MAXIMIZED));
  1665. OPT_SetBooleanOption(OPT_MAIN_MINIMIZED,
  1666. (m_uiWindowSize == SIZE_MINIMIZED));
  1667. }
  1668. }
  1669. }
  1670. //
  1671. //
  1672. // Function: SaveWindowPosition
  1673. //
  1674. // Purpose: Save the current window position to the options file.
  1675. //
  1676. //
  1677. void WbMainWindow::SaveWindowPosition(void)
  1678. {
  1679. RECT rectWindow;
  1680. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::SaveWindowPosition");
  1681. // Get the new window rectangle
  1682. ::GetWindowRect(m_hwnd, &rectWindow);
  1683. // Write the new option values to file
  1684. OPT_SetWindowRectOption(&rectWindow);
  1685. }
  1686. //
  1687. //
  1688. // Function: ResizePanes
  1689. //
  1690. // Purpose: Resize the subpanes of the main window.
  1691. //
  1692. //
  1693. void WbMainWindow::ResizePanes(void)
  1694. {
  1695. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::ResizePanes");
  1696. //
  1697. //
  1698. // The client area is organized as follows:
  1699. //
  1700. // -------------------------------------
  1701. // | | |
  1702. // | T | |
  1703. // | o | Drawing Area |
  1704. // | o | |
  1705. // | l | |
  1706. // | s | |
  1707. // |---| |
  1708. // | W | |
  1709. // | i | |
  1710. // | d | |
  1711. // | t | |
  1712. // | h | |
  1713. // | s | |
  1714. // |-----------------------------------|
  1715. // | Attributes (colors) | Pages |
  1716. // |-----------------------------------|
  1717. // | Status |
  1718. // -------------------------------------
  1719. //
  1720. //
  1721. RECT clientRect;
  1722. RECT rectStatusBar;
  1723. RECT rectToolBar;
  1724. RECT rectWG;
  1725. RECT rectAG;
  1726. RECT rectDraw;
  1727. SIZE size;
  1728. SIZE sizeAG;
  1729. // Get the client rectangle
  1730. ::GetClientRect(m_hwnd, &clientRect);
  1731. rectStatusBar = clientRect;
  1732. // Resize the help bar and progress meter
  1733. if (m_bStatusBarOn)
  1734. {
  1735. rectStatusBar.top = rectStatusBar.bottom - STATUSBAR_HEIGHT;
  1736. ::MoveWindow(m_hwndSB, rectStatusBar.left, rectStatusBar.top,
  1737. rectStatusBar.right - rectStatusBar.left,
  1738. rectStatusBar.bottom - rectStatusBar.top, TRUE);
  1739. }
  1740. else
  1741. {
  1742. // Status bar is off - set it's height to zero
  1743. rectStatusBar.top = rectStatusBar.bottom;
  1744. }
  1745. // Resize the tool and width windows
  1746. m_TB.GetNaturalSize(&size);
  1747. rectToolBar.left = 0;
  1748. rectToolBar.right = rectToolBar.left + size.cx;
  1749. rectToolBar.top = 0;
  1750. rectToolBar.bottom = rectToolBar.top + size.cy;
  1751. m_WG.GetNaturalSize(&size);
  1752. rectWG.left = rectToolBar.left;
  1753. rectWG.top = rectToolBar.bottom;
  1754. rectWG.bottom = rectWG.top + size.cy;
  1755. if (!m_bToolBarOn)
  1756. {
  1757. // Toolbar is either off or floating - set its width to zero
  1758. rectToolBar.right = rectToolBar.left;
  1759. }
  1760. rectWG.right = rectToolBar.right;
  1761. // Position attribute group
  1762. m_AG.GetNaturalSize(&sizeAG);
  1763. ::MoveWindow(m_AG.m_hwnd, rectToolBar.left, rectStatusBar.top - sizeAG.cy,
  1764. clientRect.right - rectToolBar.left, sizeAG.cy, TRUE);
  1765. // finish fiddling with tools and widths bars
  1766. if (m_bToolBarOn)
  1767. {
  1768. //
  1769. // We make the toolbar, which includes the width bar, extend all
  1770. // down the left side.
  1771. //
  1772. rectToolBar.bottom = rectStatusBar.top - sizeAG.cy;
  1773. rectWG.left += TOOLBAR_MARGINX;
  1774. rectWG.right -= 2*TOOLBAR_MARGINX;
  1775. ::MoveWindow(m_TB.m_hwnd, rectToolBar.left,
  1776. rectToolBar.top, rectToolBar.right - rectToolBar.left,
  1777. rectToolBar.bottom - rectToolBar.top, TRUE);
  1778. ::MoveWindow(m_WG.m_hwnd, rectWG.left, rectWG.top,
  1779. rectWG.right - rectWG.left, rectWG.bottom - rectWG.top, TRUE);
  1780. ::BringWindowToTop(m_WG.m_hwnd);
  1781. }
  1782. // Resize the drawing pane
  1783. rectDraw = clientRect;
  1784. rectDraw.bottom = rectStatusBar.top - sizeAG.cy;
  1785. rectDraw.left = rectToolBar.right;
  1786. ::MoveWindow(m_drawingArea.m_hwnd, rectDraw.left, rectDraw.top,
  1787. rectDraw.right - rectDraw.left, rectDraw.bottom - rectDraw.top, TRUE);
  1788. // Check to see if Width group is overlapping Attributes group. This can happen if
  1789. // the menu bar has wrapped because the window isn't wide enough (bug 424)
  1790. RECT crWidthWnd;
  1791. RECT crAttrWnd;
  1792. ::GetWindowRect(m_WG.m_hwnd, &crWidthWnd);
  1793. ::GetWindowRect(m_AG.m_hwnd, &crAttrWnd);
  1794. if (crAttrWnd.top < crWidthWnd.bottom)
  1795. {
  1796. // the menu bar has wrapped and our height placements are wrong. Adjust window
  1797. // by difference and try again
  1798. RECT crMainWnd;
  1799. ::GetWindowRect(m_hwnd, &crMainWnd);
  1800. crMainWnd.bottom += (crWidthWnd.bottom - crAttrWnd.top + ::GetSystemMetrics(SM_CYFIXEDFRAME));
  1801. ::MoveWindow(m_hwnd, crMainWnd.left, crMainWnd.top,
  1802. crMainWnd.right - crMainWnd.left, crMainWnd.bottom - crMainWnd.top,
  1803. FALSE);
  1804. // this is going to recurse but the adjustment will happen only once.....
  1805. }
  1806. }
  1807. //
  1808. //
  1809. // Function: WbMainWindow::OnGetMinMaxInfo
  1810. //
  1811. // Purpose: Set the minimum and maximum tracking sizes of the window
  1812. //
  1813. //
  1814. void WbMainWindow::OnGetMinMaxInfo(LPMINMAXINFO lpmmi)
  1815. {
  1816. if (m_TB.m_hwnd == NULL)
  1817. return; // not ready to do this yet
  1818. SIZE csFrame;
  1819. SIZE csSeparator;
  1820. SIZE csAG;
  1821. SIZE csToolBar;
  1822. SIZE csWidthBar;
  1823. SIZE csMaxSize;
  1824. SIZE csScrollBars;
  1825. csFrame.cx = ::GetSystemMetrics(SM_CXSIZEFRAME);
  1826. csFrame.cy = ::GetSystemMetrics(SM_CYSIZEFRAME);
  1827. csSeparator.cx = ::GetSystemMetrics(SM_CXEDGE);
  1828. csSeparator.cy = ::GetSystemMetrics(SM_CYEDGE);
  1829. csScrollBars.cx = ::GetSystemMetrics(SM_CXVSCROLL);
  1830. csScrollBars.cy = ::GetSystemMetrics(SM_CYHSCROLL);
  1831. m_AG.GetNaturalSize(&csAG);
  1832. m_TB.GetNaturalSize(&csToolBar);
  1833. m_WG.GetNaturalSize(&csWidthBar);
  1834. // Set the minimum width and height of the window
  1835. lpmmi->ptMinTrackSize.x =
  1836. csFrame.cx + csAG.cx + csFrame.cx;
  1837. lpmmi->ptMinTrackSize.y =
  1838. csFrame.cy +
  1839. GetSystemMetrics( SM_CYCAPTION ) +
  1840. GetSystemMetrics( SM_CYMENU ) +
  1841. csToolBar.cy +
  1842. csWidthBar.cy +
  1843. csSeparator.cy +
  1844. csAG.cy +
  1845. csSeparator.cy +
  1846. csFrame.cy +
  1847. STATUSBAR_HEIGHT;
  1848. //
  1849. // Retrieves the size of the work area on the primary display monitor. The work
  1850. // area is the portion of the screen not obscured by the system taskbar or by
  1851. // application desktop toolbars
  1852. //
  1853. RECT rcWorkArea;
  1854. ::SystemParametersInfo( SPI_GETWORKAREA, 0, (&rcWorkArea), NULL );
  1855. csMaxSize.cx = rcWorkArea.right - rcWorkArea.left;
  1856. csMaxSize.cy = rcWorkArea.bottom - rcWorkArea.top;
  1857. lpmmi->ptMaxPosition.x = 0;
  1858. lpmmi->ptMaxPosition.y = 0;
  1859. lpmmi->ptMaxSize.x = csMaxSize.cx;
  1860. lpmmi->ptMaxSize.y = csMaxSize.cy;
  1861. lpmmi->ptMaxTrackSize.x = csMaxSize.cx;
  1862. lpmmi->ptMaxTrackSize.y = csMaxSize.cy;
  1863. }
  1864. //
  1865. //
  1866. // Function: WbMainWindow::CreateContextMenus
  1867. //
  1868. // Purpose: Create the pop-up context menus: used within the application
  1869. // drawing area.
  1870. //
  1871. //
  1872. BOOL WbMainWindow::CreateContextMenus(void)
  1873. {
  1874. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::CreateContextMenus");
  1875. m_hContextMenuBar = ::LoadMenu(g_hInstance, MAKEINTRESOURCE(CONTEXTMENU));
  1876. if (!m_hContextMenuBar)
  1877. {
  1878. ERROR_OUT(("Failed to create context menu"));
  1879. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  1880. return FALSE;
  1881. }
  1882. m_hContextMenu = ::GetSubMenu(m_hContextMenuBar, 0);
  1883. m_hGrobjContextMenuBar = ::LoadMenu(g_hInstance, MAKEINTRESOURCE(GROBJMENU));
  1884. if (!m_hGrobjContextMenuBar)
  1885. {
  1886. ERROR_OUT(("Failed to create grobj context menu"));
  1887. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  1888. return FALSE;
  1889. }
  1890. m_hGrobjContextMenu = ::GetSubMenu(m_hGrobjContextMenuBar, 0);
  1891. // make parts of m_hGrobjContextMenu be owner draw
  1892. ::ModifyMenu(m_hGrobjContextMenu, IDM_WIDTH_1, MF_ENABLED | MF_OWNERDRAW,
  1893. IDM_WIDTH_1, NULL);
  1894. ::ModifyMenu(m_hGrobjContextMenu, IDM_WIDTH_2, MF_ENABLED | MF_OWNERDRAW,
  1895. IDM_WIDTH_2, NULL);
  1896. ::ModifyMenu(m_hGrobjContextMenu, IDM_WIDTH_3, MF_ENABLED | MF_OWNERDRAW,
  1897. IDM_WIDTH_3, NULL);
  1898. ::ModifyMenu(m_hGrobjContextMenu, IDM_WIDTH_4, MF_ENABLED | MF_OWNERDRAW,
  1899. IDM_WIDTH_4, NULL);
  1900. return TRUE;
  1901. }
  1902. //
  1903. //
  1904. // Function: WbMainWindow::OnMeasureItem
  1905. //
  1906. // Purpose: Return the size of an item in the widths menu
  1907. //
  1908. //
  1909. void WbMainWindow::OnMeasureItem
  1910. (
  1911. int nIDCtl,
  1912. LPMEASUREITEMSTRUCT measureStruct
  1913. )
  1914. {
  1915. // Check that this is for a color menu item
  1916. if ( (measureStruct->itemID >= IDM_WIDTHS_START)
  1917. && (measureStruct->itemID < IDM_WIDTHS_END))
  1918. {
  1919. measureStruct->itemWidth = ::GetSystemMetrics(SM_CXMENUCHECK) +
  1920. (2 * CHECKMARK_BORDER_X) + COLOR_MENU_WIDTH;
  1921. measureStruct->itemHeight = ::GetSystemMetrics(SM_CYMENUCHECK) +
  1922. (2 * CHECKMARK_BORDER_Y);
  1923. }
  1924. }
  1925. //
  1926. //
  1927. // Function: WbMainWindow::OnDrawItem
  1928. //
  1929. // Purpose: Draw an item in the color menu
  1930. //
  1931. //
  1932. void WbMainWindow::OnDrawItem
  1933. (
  1934. int nIDCtl,
  1935. LPDRAWITEMSTRUCT drawStruct
  1936. )
  1937. {
  1938. COLORREF crMenuBackground;
  1939. COLORREF crMenuText;
  1940. HPEN hOldPen;
  1941. HBRUSH hOldBrush;
  1942. COLORREF crOldBkgnd;
  1943. COLORREF crOldText;
  1944. int nOldBkMode;
  1945. HBITMAP hbmp = NULL;
  1946. BITMAP bitmap;
  1947. UINT uiCheckWidth;
  1948. UINT uiCheckHeight;
  1949. RECT rect;
  1950. RECT rectCheck;
  1951. RECT rectLine;
  1952. HDC hMemDC;
  1953. UINT uiWidthIndex;
  1954. UINT uiWidth;
  1955. HPEN hPenMenu;
  1956. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnDrawItem");
  1957. // Check that this is a width menu item
  1958. if( (drawStruct->itemID < IDM_WIDTHS_START) ||
  1959. (drawStruct->itemID >= IDM_WIDTHS_END) )
  1960. {
  1961. return;
  1962. }
  1963. // get menu item colors
  1964. if( (drawStruct->itemState & ODS_SELECTED) ||
  1965. ((drawStruct->itemState & (ODS_SELECTED |ODS_CHECKED)) ==
  1966. (ODS_SELECTED |ODS_CHECKED))
  1967. )
  1968. {
  1969. crMenuBackground = COLOR_HIGHLIGHT;
  1970. crMenuText = COLOR_HIGHLIGHTTEXT;
  1971. }
  1972. else if( drawStruct->itemState & ODS_GRAYED)
  1973. {
  1974. crMenuBackground = COLOR_MENU;
  1975. crMenuText = COLOR_GRAYTEXT;
  1976. }
  1977. else
  1978. {
  1979. crMenuBackground = COLOR_MENU;
  1980. crMenuText = COLOR_MENUTEXT;
  1981. }
  1982. hPenMenu = ::CreatePen(PS_SOLID, 0, ::GetSysColor(crMenuBackground));
  1983. if (!hPenMenu)
  1984. {
  1985. TRACE_MSG(("Failed to create penMenu"));
  1986. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  1987. goto bail_out;
  1988. }
  1989. rect = drawStruct->rcItem;
  1990. // Fill the whole box with current menu background color
  1991. hOldPen = SelectPen(drawStruct->hDC, hPenMenu);
  1992. hOldBrush = SelectBrush(drawStruct->hDC, GetSysColorBrush(crMenuBackground));
  1993. ::Rectangle(drawStruct->hDC, rect.left, rect.top, rect.right, rect.bottom);
  1994. SelectBrush(drawStruct->hDC, hOldBrush);
  1995. SelectPen(drawStruct->hDC, hOldPen);
  1996. if( (hbmp = (HBITMAP)LoadImage( NULL, MAKEINTRESOURCE( OBM_CHECK ), IMAGE_BITMAP,
  1997. 0,0, 0 ))
  1998. == NULL )
  1999. {
  2000. TRACE_MSG(("Failed to create check image"));
  2001. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  2002. goto bail_out;
  2003. }
  2004. // Get the width and height of the bitmap (allowing some border)
  2005. ::GetObject(hbmp, sizeof(BITMAP), &bitmap);
  2006. uiCheckWidth = bitmap.bmWidth + (2 * CHECKMARK_BORDER_X);
  2007. uiCheckHeight = bitmap.bmHeight;
  2008. // Draw in a checkmark (if needed)
  2009. if (drawStruct->itemState & ODS_CHECKED)
  2010. {
  2011. hMemDC = ::CreateCompatibleDC(drawStruct->hDC);
  2012. if (!hMemDC)
  2013. {
  2014. ERROR_OUT(("Failed to create memDC"));
  2015. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  2016. goto bail_out;
  2017. }
  2018. crOldBkgnd = ::SetBkColor(drawStruct->hDC, GetSysColor( crMenuBackground ) );
  2019. crOldText = ::SetTextColor(drawStruct->hDC, GetSysColor( crMenuText ) );
  2020. nOldBkMode = ::SetBkMode(drawStruct->hDC, OPAQUE );
  2021. HBITMAP hOld = SelectBitmap(hMemDC, hbmp);
  2022. if (hOld != NULL)
  2023. {
  2024. rectCheck = rect;
  2025. rectCheck.top += ((rectCheck.bottom - rectCheck.top)/2 - uiCheckHeight/2);
  2026. rectCheck.right = rectCheck.left + uiCheckWidth;
  2027. rectCheck.bottom = rectCheck.top + uiCheckHeight;
  2028. ::BitBlt(drawStruct->hDC, rectCheck.left,
  2029. rectCheck.top,
  2030. rectCheck.right - rectCheck.left,
  2031. rectCheck.bottom - rectCheck.top,
  2032. hMemDC,
  2033. 0,
  2034. 0,
  2035. SRCCOPY);
  2036. SelectBitmap(hMemDC, hOld);
  2037. }
  2038. ::SetBkMode(drawStruct->hDC, nOldBkMode);
  2039. ::SetTextColor(drawStruct->hDC, crOldText);
  2040. ::SetBkColor(drawStruct->hDC, crOldBkgnd);
  2041. ::DeleteDC(hMemDC);
  2042. }
  2043. DeleteBitmap(hbmp);
  2044. // Allow room for the checkmark to the left of the color
  2045. rect.left += uiCheckWidth;
  2046. uiWidthIndex = drawStruct->itemID - IDM_WIDTHS_START;
  2047. uiWidth = g_PenWidths[uiWidthIndex];
  2048. // If pens are very wide they can be larger than the allowed rectangle.
  2049. // So we reduce the clipping rectangle here. We save the DC so that we
  2050. // can restore it - getting the clip region back.
  2051. if (::SaveDC(drawStruct->hDC) == 0)
  2052. {
  2053. ERROR_OUT(("Failed to save DC"));
  2054. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  2055. goto bail_out;
  2056. }
  2057. if (::IntersectClipRect(drawStruct->hDC, rect.left, rect.top,
  2058. rect.right, rect.bottom) == ERROR)
  2059. {
  2060. ERROR_OUT(("Failed to set clip rect"));
  2061. ::RestoreDC(drawStruct->hDC, -1);
  2062. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  2063. goto bail_out;
  2064. }
  2065. hOldPen = SelectPen(drawStruct->hDC, hPenMenu);
  2066. hOldBrush = SelectBrush(drawStruct->hDC, GetSysColorBrush(crMenuText));
  2067. rectLine.left = rect.left;
  2068. rectLine.top = rect.top + ((rect.bottom - rect.top) / 2) - uiWidth/2;
  2069. rectLine.right= rect.right - ((rect.right - rect.left) / 6);
  2070. rectLine.bottom = rectLine.top + uiWidth + 2;
  2071. ::Rectangle(drawStruct->hDC, rectLine.left, rectLine.top,
  2072. rectLine.right, rectLine.bottom);
  2073. SelectBrush(drawStruct->hDC, hOldBrush);
  2074. SelectPen(drawStruct->hDC, hOldPen);
  2075. ::RestoreDC(drawStruct->hDC, -1);
  2076. bail_out:
  2077. if (hPenMenu != NULL)
  2078. {
  2079. ::DeletePen(hPenMenu);
  2080. }
  2081. }
  2082. //
  2083. //
  2084. // Function: OnSetFocus
  2085. //
  2086. // Purpose: The window is getting the focus
  2087. //
  2088. //
  2089. void WbMainWindow::OnSetFocus(void)
  2090. {
  2091. // We pass the focus on to the main drawing area
  2092. ::SetFocus(m_drawingArea.m_hwnd);
  2093. }
  2094. //
  2095. //
  2096. // Function: OnParentNotfiy
  2097. //
  2098. // Purpose: Process a message coming from a child window
  2099. //
  2100. //
  2101. void WbMainWindow::OnParentNotify(UINT uiMessage)
  2102. {
  2103. switch (uiMessage)
  2104. {
  2105. // Scroll message from the drawing area. These are sent when the user
  2106. // scrolls the area using the scroll bars. We queue an update of the
  2107. // current sync position.
  2108. case WM_HSCROLL:
  2109. case WM_VSCROLL:
  2110. // The user's view has changed
  2111. PositionUpdated();
  2112. break;
  2113. }
  2114. }
  2115. //
  2116. //
  2117. // Function: QuerySaveRequired
  2118. //
  2119. // Purpose: Check whether the drawing pane contents are to be saved
  2120. // before a destructive function is performed.
  2121. //
  2122. //
  2123. int WbMainWindow::QuerySaveRequired(BOOL bCancelBtn)
  2124. {
  2125. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::QuerySaveRequired");
  2126. // If we are not maximized
  2127. if (!::IsZoomed(m_hwnd) && !::IsIconic(m_hwnd))
  2128. {
  2129. // Save the new position of the window
  2130. SaveWindowPosition();
  2131. }
  2132. // Default the response to "no save required"
  2133. int iResult = IDNO;
  2134. //
  2135. // If we are already displaying a "Save As" dialog, dismiss it.
  2136. //
  2137. if (m_hwndQuerySaveDlg != NULL)
  2138. {
  2139. ::SendMessage(m_hwndQuerySaveDlg, WM_COMMAND,
  2140. MAKELONG(IDCANCEL, BN_CLICKED), 0);
  2141. ASSERT(m_hwndQuerySaveDlg == NULL);
  2142. }
  2143. // If any of the pages has changed - ask the user if they want to
  2144. // save the contents of the Whiteboard.
  2145. if (g_bContentsChanged && IsThereAnythingInAnyWorkspace())
  2146. {
  2147. ::SetForegroundWindow(m_hwnd); //bring us to the top first
  2148. // SetForegroundWindow() does not work properly in Memphis when its called during a
  2149. // SendMessage handler, specifically, when conf calls me to shutdown. The window activation
  2150. // state is messed up or something and my window does not pop to the top. So I have to
  2151. // force my window to the top using SetWindowPos. But even after that the titlebar is not
  2152. // highlighted properly. I tried combinations of SetActiveWindow, SetFocus, etc but to no
  2153. // avail. But, at least the dialog is visible so you can clear it thus fixing the
  2154. // bug (NM4db:2103). SetForegroundWindow() works ok for Win95 and NT here without
  2155. // having to use SetWindowPos (it doesn't hurt anyting to do it anyway so I didn't
  2156. // do a platform check).
  2157. ::SetWindowPos(m_hwnd, HWND_TOPMOST, 0,0, 0,0, SWP_NOMOVE | SWP_NOSIZE ); // force to top
  2158. ::SetWindowPos(m_hwnd, HWND_NOTOPMOST, 0,0, 0,0, SWP_NOMOVE | SWP_NOSIZE ); // let go of topmost
  2159. //
  2160. // Display a dialog box with the relevant question
  2161. // LOWORD of user data is "cancel command is allowed"
  2162. // HIWORD of user data is "disable cancel button"
  2163. //
  2164. iResult = (int)DialogBoxParam(g_hInstance,
  2165. bCancelBtn ? MAKEINTRESOURCE(QUERYSAVEDIALOGCANCEL)
  2166. : MAKEINTRESOURCE(QUERYSAVEDIALOG),
  2167. m_hwnd,
  2168. QuerySaveDlgProc,
  2169. MAKELONG(bCancelBtn, FALSE));
  2170. }
  2171. return iResult;
  2172. }
  2173. //
  2174. // QuerySaveDlgProc()
  2175. // Handler for query save dialogs. We save some flags in GWL_USER
  2176. //
  2177. INT_PTR CALLBACK QuerySaveDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  2178. {
  2179. BOOL fHandled = FALSE;
  2180. switch (uMessage)
  2181. {
  2182. case WM_INITDIALOG:
  2183. //
  2184. // Save away our HWND so this dialog can be cancelled if necessary
  2185. //
  2186. g_pMain->m_hwndQuerySaveDlg = hwnd;
  2187. // Remember the flags we passed
  2188. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
  2189. // Should the cancel button be disabled?
  2190. if (HIWORD(lParam))
  2191. ::EnableWindow(::GetDlgItem(hwnd, IDCANCEL), FALSE);
  2192. // Bring us to the front
  2193. ::SetForegroundWindow(hwnd);
  2194. fHandled = TRUE;
  2195. break;
  2196. case WM_CLOSE:
  2197. // Even if the cancel button is disabled, kill the dialog
  2198. ::PostMessage(hwnd, WM_COMMAND, IDCANCEL, 0);
  2199. fHandled = TRUE;
  2200. break;
  2201. case WM_COMMAND:
  2202. switch (GET_WM_COMMAND_ID(wParam, lParam))
  2203. {
  2204. case IDCANCEL:
  2205. //
  2206. // If a dialog doesn't have a cancel button or it's
  2207. // disabled and the user pressed the close btn, we can
  2208. // get here.
  2209. //
  2210. if (!LOWORD(::GetWindowLongPtr(hwnd, GWLP_USERDATA)))
  2211. wParam = MAKELONG(IDNO, HIWORD(wParam));
  2212. // FALL THRU
  2213. case IDYES:
  2214. case IDNO:
  2215. if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
  2216. {
  2217. g_pMain->m_hwndQuerySaveDlg = NULL;
  2218. ::EndDialog(hwnd, GET_WM_COMMAND_ID(wParam, lParam));
  2219. break;
  2220. }
  2221. break;
  2222. }
  2223. fHandled = TRUE;
  2224. break;
  2225. }
  2226. return(fHandled);
  2227. }
  2228. //
  2229. //
  2230. // Function: OnNew
  2231. //
  2232. // Purpose: Clear the workspace and associated filenames
  2233. //
  2234. //
  2235. LRESULT WbMainWindow::OnNew(void)
  2236. {
  2237. int iDoNew;
  2238. if( UsersMightLoseData( NULL, NULL ) ) // bug NM4db:418
  2239. return S_OK;
  2240. // check state before proceeding - if we're already doing a new, then abort
  2241. if (m_uiSubState == SUBSTATE_NEW_IN_PROGRESS)
  2242. {
  2243. // post an error message indicating the whiteboard is busy
  2244. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  2245. return S_OK;
  2246. }
  2247. // if we're currently loading, then cancel the load and proceed (don't
  2248. // prompt to save).
  2249. else if (m_uiSubState == SUBSTATE_LOADING)
  2250. {
  2251. // cancel load, not releasing the page order lock, because
  2252. // we need it immediately afterwards
  2253. CancelLoad(FALSE);
  2254. iDoNew = IDNO;
  2255. }
  2256. // otherwise prompt to save if necessary
  2257. else
  2258. {
  2259. // Get confirmation for the new
  2260. iDoNew = QuerySaveRequired(TRUE);
  2261. }
  2262. if (iDoNew == IDYES)
  2263. {
  2264. // Save the changes
  2265. iDoNew = (int)OnSave(FALSE);
  2266. }
  2267. // If the user did not cancel the operation, clear the drawing area
  2268. if (iDoNew != IDCANCEL)
  2269. {
  2270. //
  2271. // Remember if we had a remote pointer.
  2272. // In OldWB, the remote pointer is a global thing that clearing
  2273. // doesn't get rid of.
  2274. // In T.126WB, it's just an object on a page, so we need to add
  2275. // it back because we're deleting the old pages and creating
  2276. // new ones.
  2277. //
  2278. BOOL bRemote = FALSE;
  2279. if (m_pLocalRemotePointer)
  2280. {
  2281. // Remove remote pointer from pages
  2282. bRemote = TRUE;
  2283. OnRemotePointer();
  2284. }
  2285. ::InvalidateRect(g_pDraw->m_hwnd, NULL, TRUE);
  2286. DeleteAllWorkspaces(TRUE);
  2287. WorkspaceObj * pObj;
  2288. DBG_SAVE_FILE_LINE
  2289. pObj = new WorkspaceObj();
  2290. pObj->AddToWorkspace();
  2291. if (bRemote)
  2292. {
  2293. // Put it back
  2294. OnRemotePointer();
  2295. }
  2296. // Clear the associated file name
  2297. ZeroMemory(m_strFileName, sizeof(m_strFileName));
  2298. // Update the window title with no file name
  2299. UpdateWindowTitle();
  2300. }
  2301. return S_OK;
  2302. }
  2303. //
  2304. //
  2305. // Function: OnNextPage
  2306. //
  2307. // Purpose: Move to the next worksheet in the pages list
  2308. //
  2309. //
  2310. LRESULT WbMainWindow::OnNextPage(void)
  2311. {
  2312. // Go to the next page
  2313. if(g_pCurrentWorkspace)
  2314. {
  2315. WBPOSITION pos = g_pCurrentWorkspace->GetMyPosition();
  2316. g_pListOfWorkspaces->GetNext(pos);
  2317. if(pos)
  2318. {
  2319. WorkspaceObj* pWorkspace = (WorkspaceObj*)g_pListOfWorkspaces->GetNext(pos);
  2320. GotoPage(pWorkspace);
  2321. }
  2322. }
  2323. return S_OK;
  2324. }
  2325. //
  2326. //
  2327. // Function: OnPrevPage
  2328. //
  2329. // Purpose: Move to the previous worksheet in the pages list
  2330. //
  2331. //
  2332. LRESULT WbMainWindow::OnPrevPage(void)
  2333. {
  2334. if(g_pCurrentWorkspace)
  2335. {
  2336. WBPOSITION pos = g_pCurrentWorkspace->GetMyPosition();
  2337. g_pListOfWorkspaces->GetPrevious(pos);
  2338. if(pos)
  2339. {
  2340. WorkspaceObj* pWorkspace = (WorkspaceObj*)g_pListOfWorkspaces->GetPrevious(pos);
  2341. GotoPage(pWorkspace);
  2342. }
  2343. }
  2344. return S_OK;
  2345. }
  2346. //
  2347. //
  2348. // Function: OnFirstPage
  2349. //
  2350. // Purpose: Move to the first worksheet in the pages list
  2351. //
  2352. //
  2353. LRESULT WbMainWindow::OnFirstPage(void)
  2354. {
  2355. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnFirstPage");
  2356. WorkspaceObj * pWorkspace = (WorkspaceObj *)g_pListOfWorkspaces->GetHead();
  2357. GotoPage(pWorkspace);
  2358. return S_OK;
  2359. }
  2360. //
  2361. //
  2362. // Function: OnLastPage
  2363. //
  2364. // Purpose: Move to the last worksheet in the pages list
  2365. //
  2366. //
  2367. LRESULT WbMainWindow::OnLastPage(void)
  2368. {
  2369. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnLastPage");
  2370. WorkspaceObj * pWorkspace = (WorkspaceObj *)g_pListOfWorkspaces->GetTail();
  2371. GotoPage(pWorkspace);
  2372. return S_OK;
  2373. }
  2374. //
  2375. //
  2376. // Function: OnGotoPage
  2377. //
  2378. // Purpose: Move to the specified page (if it exists)
  2379. //
  2380. //
  2381. LRESULT WbMainWindow::OnGotoPage(void)
  2382. {
  2383. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnGotoPage");
  2384. // Get the requested page number from the pages group
  2385. UINT uiPageNumber = m_AG.GetCurrentPageNumber() - 1;
  2386. WBPOSITION pos;
  2387. WorkspaceObj* pWorkspace = NULL;
  2388. pos = g_pListOfWorkspaces->GetHeadPosition();
  2389. while(pos && uiPageNumber != 0)
  2390. {
  2391. g_pListOfWorkspaces->GetNext(pos);
  2392. uiPageNumber--;
  2393. }
  2394. if(pos)
  2395. {
  2396. pWorkspace = (WorkspaceObj *)g_pListOfWorkspaces->GetNext(pos);
  2397. GotoPage(pWorkspace);
  2398. }
  2399. return S_OK;
  2400. }
  2401. //
  2402. // Check if remote pointer was on before we go to page
  2403. //
  2404. void WbMainWindow::GotoPage(WorkspaceObj * pNewWorkspace, BOOL bSend)
  2405. {
  2406. //
  2407. // If we were editing text
  2408. //
  2409. if (g_pDraw->TextEditActive())
  2410. {
  2411. g_pDraw->EndTextEntry(TRUE);
  2412. }
  2413. //
  2414. // If we had a remote pointer
  2415. //
  2416. BOOL bRemote = FALSE;
  2417. if(m_pLocalRemotePointer)
  2418. {
  2419. bRemote = TRUE;
  2420. OnRemotePointer();
  2421. }
  2422. //
  2423. // Undraw remote pointers
  2424. //
  2425. T126Obj * pPointer = g_pCurrentWorkspace->GetTail();
  2426. WBPOSITION pos = g_pCurrentWorkspace->GetTailPosition();
  2427. while(pos && pPointer->GraphicTool() == TOOLTYPE_REMOTEPOINTER)
  2428. {
  2429. pPointer->UnDraw();
  2430. pPointer = (T126Obj*) g_pCurrentWorkspace->GetPreviousObject(pos);
  2431. }
  2432. GoPage(pNewWorkspace, bSend);
  2433. //
  2434. // Draw remote pointers back
  2435. //
  2436. pPointer = g_pCurrentWorkspace->GetTail();
  2437. pos = g_pCurrentWorkspace->GetTailPosition();
  2438. while(pos && pPointer->GraphicTool() == TOOLTYPE_REMOTEPOINTER)
  2439. {
  2440. pPointer->Draw();
  2441. pPointer = (T126Obj*) g_pCurrentWorkspace->GetPreviousObject(pos);
  2442. }
  2443. //
  2444. // If we had a remote pointer
  2445. //
  2446. if(bRemote)
  2447. {
  2448. OnRemotePointer();
  2449. }
  2450. }
  2451. //
  2452. //
  2453. // Function: GoPage
  2454. //
  2455. // Purpose: Move to the specified page
  2456. //
  2457. //
  2458. void WbMainWindow::GoPage(WorkspaceObj * pNewWorkspace, BOOL bSend)
  2459. {
  2460. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GotoPage");
  2461. // If we are changing pages
  2462. if (pNewWorkspace != g_pCurrentWorkspace)
  2463. {
  2464. m_drawingArea.CancelDrawingMode();
  2465. // Attach the new page to the drawing area
  2466. m_drawingArea.Attach(pNewWorkspace);
  2467. // set the focus back to the drawing area
  2468. if (!(m_AG.IsChildEditField(::GetFocus())))
  2469. {
  2470. ::SetFocus(m_drawingArea.m_hwnd);
  2471. }
  2472. ::InvalidateRect(m_drawingArea.m_hwnd, NULL, TRUE );
  2473. ::UpdateWindow(m_drawingArea.m_hwnd);
  2474. //
  2475. // Tell the other nodes we moved to a different page.
  2476. //
  2477. if(bSend)
  2478. {
  2479. //
  2480. // Set the view state
  2481. //
  2482. pNewWorkspace->SetViewState(focus_chosen);
  2483. pNewWorkspace->SetViewActionChoice(editView_chosen);
  2484. pNewWorkspace->OnObjectEdit();
  2485. }
  2486. }
  2487. UpdatePageButtons();
  2488. }
  2489. //
  2490. //
  2491. // Function: GotoPosition
  2492. //
  2493. // Purpose: Move to the specified position within the page
  2494. //
  2495. //
  2496. void WbMainWindow::GotoPosition(int x, int y)
  2497. {
  2498. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GotoPosition");
  2499. // Move the drawing area to the new position
  2500. m_drawingArea.GotoPosition(x, y);
  2501. // The user's view has changed
  2502. PositionUpdated();
  2503. }
  2504. //
  2505. //
  2506. // Function: LoadFile
  2507. //
  2508. // Purpose: Load a metafile into the application. Errors are reported
  2509. // to the caller by the return code.
  2510. //
  2511. //
  2512. void WbMainWindow::LoadFile
  2513. (
  2514. LPCSTR szLoadFileName
  2515. )
  2516. {
  2517. UINT uRes;
  2518. // Check we're in idle state
  2519. if (!IsIdle())
  2520. {
  2521. // post an error message indicating the whiteboard is busy
  2522. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  2523. goto UserPointerCleanup;
  2524. }
  2525. if (*szLoadFileName)
  2526. {
  2527. // Change the cursor to "wait"
  2528. ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  2529. // Set the state to say that we are loading a file
  2530. SetSubstate(SUBSTATE_LOADING);
  2531. // Load the file
  2532. uRes = ContentsLoad(szLoadFileName);
  2533. if (uRes != 0)
  2534. {
  2535. DefaultExceptionHandler(WBFE_RC_WB, uRes);
  2536. goto UserPointerCleanup;
  2537. }
  2538. // Set the window title to the new file name
  2539. lstrcpy(m_strFileName, szLoadFileName);
  2540. // Update the window title with the new file name
  2541. g_bContentsChanged = FALSE;
  2542. }
  2543. UserPointerCleanup:
  2544. // Set the state to say that we are loading a file
  2545. SetSubstate(SUBSTATE_IDLE);
  2546. // Restore the cursor
  2547. ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  2548. }
  2549. //
  2550. //
  2551. // Function: OnDropFiles
  2552. //
  2553. // Purpose: Files have been dropped onto the Whiteboard window
  2554. //
  2555. //
  2556. void WbMainWindow::OnDropFiles(HDROP hDropInfo)
  2557. {
  2558. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnDropFiles");
  2559. UINT uiFilesDropped = 0;
  2560. UINT eachfile;
  2561. PT126WB_FILE_HEADER_AND_OBJECTS pHeader = NULL;
  2562. // Get the total number of files dropped
  2563. uiFilesDropped = ::DragQueryFile(hDropInfo, (UINT) -1, NULL, (UINT) 0);
  2564. // release mouse capture in case we report any errors (message boxes
  2565. // won't repsond to mouse clicks if we don't)
  2566. ReleaseCapture();
  2567. for (eachfile = 0; eachfile < uiFilesDropped; eachfile++)
  2568. {
  2569. // Retrieve each file name
  2570. char szDropFileName[256];
  2571. ::DragQueryFile(hDropInfo, eachfile,
  2572. szDropFileName, 256);
  2573. TRACE_MSG(("Loading file: %s", szDropFileName));
  2574. OnOpen(szDropFileName);
  2575. }
  2576. ::DragFinish(hDropInfo);
  2577. }
  2578. //
  2579. //
  2580. // Function: OnOpen
  2581. //
  2582. // Purpose: Load a metafile into the application.
  2583. //
  2584. //
  2585. LRESULT WbMainWindow::OnOpen(LPCSTR szLoadFileName)
  2586. {
  2587. int iOnSave;
  2588. if(g_pDraw->IsLocked() || !g_pDraw->IsSynced())
  2589. {
  2590. DefaultExceptionHandler(WBFE_RC_WB, WB_RC_BAD_STATE);
  2591. return S_FALSE;
  2592. }
  2593. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnOpen");
  2594. if( UsersMightLoseData( NULL, NULL ) ) // bug NM4db:418
  2595. return S_OK;
  2596. // Check we're in idle state
  2597. if ((m_uiSubState == SUBSTATE_NEW_IN_PROGRESS))
  2598. {
  2599. // post an error message indicating the whiteboard is busy
  2600. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  2601. return S_OK;
  2602. }
  2603. // Don't prompt to save file if we're already loading
  2604. if (m_uiSubState != SUBSTATE_LOADING)
  2605. {
  2606. // Check whether there are changes to be saved
  2607. iOnSave = QuerySaveRequired(TRUE);
  2608. }
  2609. else
  2610. {
  2611. iOnSave = IDNO;
  2612. }
  2613. if (iOnSave == IDYES)
  2614. {
  2615. // User wants to save the drawing area contents
  2616. int iResult = (int)OnSave(TRUE);
  2617. if (iResult == IDOK)
  2618. {
  2619. }
  2620. else
  2621. {
  2622. // cancelled out of Save As, so cancel the open operation
  2623. iOnSave = IDCANCEL;
  2624. }
  2625. }
  2626. // Only continue if the user has not cancelled the operation
  2627. if (iOnSave != IDCANCEL)
  2628. {
  2629. //
  2630. // If the filename was passed
  2631. //
  2632. if(szLoadFileName)
  2633. {
  2634. LoadFile(szLoadFileName);
  2635. }
  2636. else
  2637. {
  2638. OPENFILENAME ofn;
  2639. TCHAR szFileName[_MAX_PATH];
  2640. TCHAR szFileTitle[64];
  2641. TCHAR strLoadFilter[2*_MAX_PATH];
  2642. TCHAR strDefaultExt[_MAX_PATH];
  2643. TCHAR strDefaultPath[2*_MAX_PATH];
  2644. TCHAR * pStr;
  2645. UINT strSize = 0;
  2646. UINT totalSize;
  2647. // Build the filter for loadable files
  2648. pStr = strLoadFilter;
  2649. totalSize = 2*_MAX_PATH;
  2650. // These must be NULL separated, with a double NULL at the end
  2651. strSize = ::LoadString(g_hInstance, IDS_FILTER_WHT, pStr, totalSize) + 1;
  2652. pStr += strSize;
  2653. ASSERT(totalSize > strSize);
  2654. totalSize -= strSize;
  2655. strSize = ::LoadString(g_hInstance, IDS_FILTER_WHT_SPEC, pStr, totalSize) + 1;
  2656. pStr += strSize;
  2657. ASSERT(totalSize > strSize);
  2658. totalSize -= strSize;
  2659. strSize = ::LoadString(g_hInstance, IDS_FILTER_ALL, pStr, totalSize) + 1;
  2660. pStr += strSize;
  2661. ASSERT(totalSize > strSize);
  2662. totalSize -= strSize;
  2663. strSize = ::LoadString(g_hInstance, IDS_FILTER_ALL_SPEC, pStr, totalSize) + 1;
  2664. pStr += strSize;
  2665. ASSERT(totalSize > strSize);
  2666. totalSize -= strSize;
  2667. *pStr = 0;
  2668. //
  2669. // Setup the OPENFILENAME struct
  2670. //
  2671. ZeroMemory(&ofn, sizeof(ofn));
  2672. ofn.lStructSize = sizeof(ofn);
  2673. ofn.hwndOwner = m_hwnd;
  2674. // No file name supplied to begin with
  2675. szFileName[0] = 0;
  2676. ofn.lpstrFile = szFileName;
  2677. ofn.nMaxFile = _MAX_PATH;
  2678. // Default Extension: .NMW
  2679. ::LoadString(g_hInstance, IDS_EXT_WHT, strDefaultExt, sizeof(strDefaultExt));
  2680. ofn.lpstrDefExt = strDefaultExt;
  2681. // Default file title is empty
  2682. szFileTitle[0] = 0;
  2683. ofn.lpstrFileTitle = szFileTitle;
  2684. ofn.nMaxFileTitle = 64;
  2685. // Open flags
  2686. ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_EXPLORER;
  2687. ofn.hInstance = g_hInstance;
  2688. // Filter
  2689. ofn.lpstrFilter = strLoadFilter;
  2690. // Default path
  2691. if (GetDefaultPath(strDefaultPath, sizeof(strDefaultPath)))
  2692. ofn.lpstrInitialDir = strDefaultPath;
  2693. // Get user input, continue only if the user selects the OK button
  2694. if (::GetOpenFileName(&ofn))
  2695. {
  2696. // Change the cursor to "wait"
  2697. ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  2698. // if we're currently loading a file, cancel it, not releasing
  2699. // the page order lock, because we need it immediately afterwards
  2700. if (m_uiSubState == SUBSTATE_LOADING)
  2701. {
  2702. CancelLoad(FALSE);
  2703. }
  2704. // Load the file
  2705. LoadFile(ofn.lpstrFile);
  2706. }
  2707. }
  2708. }
  2709. // Update the window title with no file name
  2710. UpdateWindowTitle();
  2711. return S_OK;
  2712. }
  2713. //
  2714. //
  2715. // Function: GetFileName
  2716. //
  2717. // Purpose: Get a file name for saving the contents
  2718. //
  2719. //
  2720. int WbMainWindow::GetFileName(void)
  2721. {
  2722. OPENFILENAME ofn;
  2723. int iResult;
  2724. TCHAR szFileTitle[64];
  2725. TCHAR strSaveFilter[2*_MAX_PATH];
  2726. TCHAR strDefaultExt[_MAX_PATH];
  2727. TCHAR strDefaultPath[2 * _MAX_PATH];
  2728. TCHAR szFileName[2*_MAX_PATH];
  2729. TCHAR * pStr;
  2730. UINT strSize = 0;
  2731. UINT totalSize;
  2732. //
  2733. // If we are already displaying a "Save As" dialog, dismiss it and create
  2734. // a new one. This can happen if Win95 shuts down whilst WB is
  2735. // displaying the "Save As" dialog and the use selects "Yes" when asked
  2736. // whether they want to save the contents - a second "Save As dialog
  2737. // appears on top of the first.
  2738. //
  2739. if (m_bInSaveDialog)
  2740. {
  2741. CancelSaveDialog();
  2742. }
  2743. // Build the filter for save files
  2744. pStr = strSaveFilter;
  2745. totalSize = 2*_MAX_PATH;
  2746. // These must be NULL separated, with a double NULL at the end
  2747. strSize = ::LoadString(g_hInstance, IDS_FILTER_WHT, pStr, totalSize) + 1;
  2748. pStr += strSize;
  2749. ASSERT(totalSize > strSize);
  2750. totalSize -= strSize;
  2751. strSize = ::LoadString(g_hInstance, IDS_FILTER_WHT_SPEC, pStr, totalSize) + 1;
  2752. pStr += strSize;
  2753. ASSERT(totalSize > strSize);
  2754. totalSize -= strSize;
  2755. strSize = ::LoadString(g_hInstance, IDS_FILTER_ALL, pStr, totalSize) + 1;
  2756. pStr += strSize;
  2757. ASSERT(totalSize > strSize);
  2758. totalSize -= strSize;
  2759. strSize = ::LoadString(g_hInstance, IDS_FILTER_ALL_SPEC, pStr, totalSize) + 1;
  2760. pStr += strSize;
  2761. ASSERT(totalSize > strSize);
  2762. totalSize -= strSize;
  2763. *pStr = 0;
  2764. //
  2765. // Setup the OPENFILENAME struct
  2766. //
  2767. ZeroMemory(&ofn, sizeof(ofn));
  2768. ofn.lStructSize = sizeof(ofn);
  2769. ofn.hwndOwner = m_hwnd;
  2770. lstrcpy(szFileName, m_strFileName);
  2771. ofn.lpstrFile = szFileName;
  2772. ofn.nMaxFile = _MAX_PATH;
  2773. // Build the default extension string
  2774. ::LoadString(g_hInstance, IDS_EXT_WHT, strDefaultExt, sizeof(strDefaultExt));
  2775. ofn.lpstrDefExt = strDefaultExt;
  2776. szFileTitle[0] = 0;
  2777. ofn.lpstrFileTitle = szFileTitle;
  2778. ofn.nMaxFileTitle = 64;
  2779. // Save flags
  2780. ofn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN |
  2781. OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
  2782. ofn.hInstance = g_hInstance;
  2783. // Filter
  2784. ofn.lpstrFilter = strSaveFilter;
  2785. // Default path
  2786. if (GetDefaultPath(strDefaultPath, sizeof(strDefaultPath)))
  2787. ofn.lpstrInitialDir = strDefaultPath;
  2788. m_bInSaveDialog = TRUE;
  2789. if (::GetSaveFileName(&ofn))
  2790. {
  2791. // The user selected OK
  2792. iResult = IDOK;
  2793. lstrcpy(m_strFileName, szFileName);
  2794. }
  2795. else
  2796. {
  2797. iResult = IDCANCEL;
  2798. }
  2799. m_bInSaveDialog = FALSE;
  2800. return iResult;
  2801. }
  2802. //
  2803. //
  2804. // Function: OnSave
  2805. //
  2806. // Purpose: Save the contents of the Whiteboard using the current file
  2807. // name (or prompting for a new name if there is no current).
  2808. //
  2809. //
  2810. LRESULT WbMainWindow::OnSave(BOOL bPrompt)
  2811. {
  2812. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnSave");
  2813. LRESULT iResult = IDOK;
  2814. // save the old file name in case there's an error
  2815. TCHAR strOldName[2*MAX_PATH];
  2816. UINT fileNameSize = lstrlen(m_strFileName);
  2817. lstrcpy(strOldName, m_strFileName);
  2818. BOOL bNewName = FALSE;
  2819. if (!IsIdle())
  2820. {
  2821. // post an error message indicating the whiteboard is busy
  2822. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  2823. return(iResult);
  2824. }
  2825. // Check whether there is a filename available for use
  2826. if (!fileNameSize || (bPrompt))
  2827. {
  2828. // Get user input, continue only if the user selects the OK button
  2829. iResult = GetFileName();
  2830. if (iResult == IDOK)
  2831. {
  2832. // entering a blank file name is treated as cancelling the save
  2833. if (!lstrlen(m_strFileName))
  2834. {
  2835. lstrcpy(m_strFileName, strOldName);
  2836. iResult = IDCANCEL;
  2837. }
  2838. else
  2839. {
  2840. // flag that we've changed the contents file name
  2841. bNewName = TRUE;
  2842. }
  2843. }
  2844. }
  2845. // Now save the file
  2846. if ((iResult == IDOK) && lstrlen(m_strFileName))
  2847. {
  2848. WIN32_FIND_DATA findFileData;
  2849. HANDLE hFind;
  2850. // Get attributes
  2851. hFind = ::FindFirstFile(m_strFileName, &findFileData);
  2852. if (hFind != INVALID_HANDLE_VALUE)
  2853. {
  2854. ::FindClose(hFind);
  2855. // This is a read-only file; we can't change its contents
  2856. if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  2857. {
  2858. WARNING_OUT(("Dest file %s is read only", m_strFileName));
  2859. ::Message(NULL, IDS_SAVE, IDS_SAVE_READ_ONLY);
  2860. // If the file name was changed for this save then undo
  2861. // the change
  2862. if (bNewName)
  2863. {
  2864. lstrcpy(m_strFileName, strOldName);
  2865. bNewName = FALSE;
  2866. }
  2867. // Change the return code to indicate no save was made
  2868. iResult = IDCANCEL;
  2869. return(iResult);
  2870. }
  2871. }
  2872. // Change the cursor to "wait"
  2873. ::SetCursor(::LoadCursor(NULL,IDC_WAIT));
  2874. // Write the file
  2875. if (ContentsSave(m_strFileName) != 0)
  2876. {
  2877. // Show that an error occurred saving the file.
  2878. WARNING_OUT(("Error saving file"));
  2879. ::Message(NULL, IDS_SAVE, IDS_SAVE_ERROR);
  2880. // If the file name was changed for this save then undo
  2881. // the change
  2882. if (bNewName)
  2883. {
  2884. lstrcpy(m_strFileName, strOldName);
  2885. bNewName = FALSE;
  2886. }
  2887. // Change the return code to indicate no save was made
  2888. iResult = IDCANCEL;
  2889. }
  2890. else
  2891. {
  2892. g_bContentsChanged = FALSE;
  2893. }
  2894. // Restore the cursor
  2895. ::SetCursor(::LoadCursor(NULL,IDC_ARROW));
  2896. }
  2897. // if the contents file name has changed as a result of the save then
  2898. // update the window title
  2899. if (bNewName)
  2900. {
  2901. UpdateWindowTitle();
  2902. }
  2903. return(iResult);
  2904. }
  2905. //
  2906. // CancelSaveDialog()
  2907. // This cancels the save as dialog if up and we need to kill it to continue.
  2908. // We walk back up the owner chain in case the save dialog puts up help or
  2909. // other owned windows.
  2910. //
  2911. void WbMainWindow::CancelSaveDialog(void)
  2912. {
  2913. WBFINDDIALOG wbf;
  2914. ASSERT(m_bInSaveDialog);
  2915. wbf.hwndOwner = m_hwnd;
  2916. wbf.hwndDialog = NULL;
  2917. EnumThreadWindows(::GetCurrentThreadId(), WbFindCurrentDialog, (LPARAM)&wbf);
  2918. if (wbf.hwndDialog)
  2919. {
  2920. // Found it!
  2921. ::SendMessage(wbf.hwndDialog, WM_COMMAND, IDCANCEL, 0);
  2922. }
  2923. m_bInSaveDialog = FALSE;
  2924. }
  2925. BOOL CALLBACK WbFindCurrentDialog(HWND hwndNext, LPARAM lParam)
  2926. {
  2927. WBFINDDIALOG * pwbf = (WBFINDDIALOG *)lParam;
  2928. // Is this a dialog, owned by the main window?
  2929. if ((::GetClassLong(hwndNext, GCW_ATOM) == 0x8002) &&
  2930. (::GetWindow(hwndNext, GW_OWNER) == pwbf->hwndOwner))
  2931. {
  2932. pwbf->hwndDialog = hwndNext;
  2933. return(FALSE);
  2934. }
  2935. return(TRUE);
  2936. }
  2937. //
  2938. //
  2939. // Function: OnClose
  2940. //
  2941. // Purpose: Close the Whiteboard
  2942. //
  2943. //
  2944. void WbMainWindow::OnClose()
  2945. {
  2946. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnClose");
  2947. int iOnSave = IDOK;
  2948. m_drawingArea.CancelDrawingMode();
  2949. m_AG.SaveSettings();
  2950. // If we got here, by way of OnDestroy from the DCL cores or
  2951. // by system shutdown, then assume that user responded already to the
  2952. // save-changes dialog that would have poped up during conf's global shutdown
  2953. // message. We don't need to ask 'em again. What tangled webs......
  2954. if ((!m_bQuerySysShutdown) && (IsIdle()))
  2955. {
  2956. // Check whether there are changes to be saved
  2957. iOnSave = QuerySaveRequired(TRUE);
  2958. if (iOnSave == IDYES)
  2959. {
  2960. // User wants to save the drawing area contents
  2961. iOnSave = (int)OnSave(TRUE);
  2962. }
  2963. }
  2964. // If the exit was not cancelled, close the application
  2965. if (iOnSave != IDCANCEL)
  2966. {
  2967. // Close the application
  2968. ::PostQuitMessage(0);
  2969. }
  2970. }
  2971. //
  2972. //
  2973. // Function: OnClearPage
  2974. //
  2975. // Purpose: Clear the Whiteboard drawing area. The user is prompted to
  2976. // choose clearing of foreground, background or both.
  2977. //
  2978. //
  2979. LRESULT WbMainWindow::OnClearPage(BOOL bClearAll)
  2980. {
  2981. LRESULT iResult;
  2982. BOOL bWasPosted;
  2983. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnClearPage");
  2984. if( UsersMightLoseData( &bWasPosted, NULL ) ) // bug NM4db:418
  2985. return S_OK;
  2986. if( bWasPosted )
  2987. iResult = IDYES;
  2988. else
  2989. iResult = ::Message(NULL, bClearAll == FALSE ? IDS_DELETE_PAGE : IDS_CLEAR_CAPTION, bClearAll == FALSE ? IDS_DELETE_PAGE_MESSAGE : IDS_CLEAR_MESSAGE, MB_YESNO | MB_ICONQUESTION);
  2990. if ((iResult == IDYES) && bClearAll)
  2991. {
  2992. OnSelectAll();
  2993. OnDelete();
  2994. TRACE_MSG(("User requested clear of page"));
  2995. }
  2996. return iResult;
  2997. }
  2998. //
  2999. //
  3000. // Function: OnDelete
  3001. //
  3002. // Purpose: Delete the current selection
  3003. //
  3004. //
  3005. LRESULT WbMainWindow::OnDelete()
  3006. {
  3007. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnDelete");
  3008. // cleanup select logic in case object context menu called us (bug 426)
  3009. m_drawingArea.SetLClickIgnore( FALSE );
  3010. // Delete the currently selected graphics and add to m_LastDeletedGraphic
  3011. m_drawingArea.EraseSelectedDrawings();
  3012. return S_OK;
  3013. }
  3014. //
  3015. //
  3016. // Function: OnUndelete
  3017. //
  3018. // Purpose: Undo the last delete operation
  3019. //
  3020. //
  3021. LRESULT WbMainWindow::OnUndelete()
  3022. {
  3023. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnUndelete");
  3024. // If there is a deleted graphic to restore
  3025. T126Obj * pObj;
  3026. pObj = (T126Obj *)g_pTrash->RemoveHead();
  3027. while (pObj != NULL)
  3028. {
  3029. if(!AddT126ObjectToWorkspace(pObj))
  3030. {
  3031. return S_FALSE;
  3032. }
  3033. if(pObj->GetMyWorkspace() == g_pCurrentWorkspace)
  3034. {
  3035. pObj->Draw(FALSE);
  3036. }
  3037. //
  3038. // Make sure it gets added back as unselected. It was selected
  3039. // when deleted.
  3040. //
  3041. pObj->ClearDeletionFlags();
  3042. pObj->SetAllAttribs();
  3043. pObj->SetViewState(unselected_chosen);
  3044. pObj->SendNewObjectToT126Apps();
  3045. pObj = (T126Obj *) g_pTrash->RemoveHead();
  3046. }
  3047. return S_OK;
  3048. }
  3049. //
  3050. //
  3051. // Function: OnSelectAll
  3052. //
  3053. // Purpose: Select all the objects in the current page
  3054. //
  3055. //
  3056. LRESULT WbMainWindow::OnSelectAll( void )
  3057. {
  3058. // Unselect every oject first.
  3059. m_drawingArea.RemoveMarker();
  3060. // turn off any selections
  3061. // cleanup select logic in case object context menu called us (bug 426)
  3062. m_drawingArea.SetLClickIgnore( FALSE );
  3063. // inhibit normal select-tool action
  3064. m_bSelectAllInProgress = TRUE;
  3065. //put us in select-tool mode first
  3066. OnSelectTool(IDM_SELECT);
  3067. // back to normal
  3068. m_bSelectAllInProgress = FALSE;
  3069. // now, select everything
  3070. m_drawingArea.SelectMarkerFromRect( NULL );
  3071. return S_OK;
  3072. }
  3073. //
  3074. //
  3075. // Function: OnCut
  3076. //
  3077. // Purpose: Cut the current selection
  3078. //
  3079. //
  3080. LRESULT WbMainWindow::OnCut()
  3081. {
  3082. // Copy all the selected graphics to the clipboard
  3083. BOOL bResult = CLP_Copy();
  3084. // If an error occurred during the copy, report it now
  3085. if (!bResult)
  3086. {
  3087. ::Message(NULL, IDM_CUT, IDS_COPY_ERROR);
  3088. return S_FALSE;
  3089. }
  3090. //
  3091. // Erase the selected objects
  3092. //
  3093. OnDelete();
  3094. return S_OK;
  3095. }
  3096. //
  3097. // OnCopy()
  3098. // Purpose: Copy the current selection to the clipboard
  3099. //
  3100. //
  3101. LRESULT WbMainWindow::OnCopy(void)
  3102. {
  3103. // Copy all the selected graphics to the clipboard
  3104. BOOL bResult = CLP_Copy();
  3105. // If an error occurred during the copy, report it now
  3106. if (!bResult)
  3107. {
  3108. ::Message(NULL, IDS_COPY, IDS_COPY_ERROR);
  3109. return S_FALSE;
  3110. }
  3111. return S_OK;
  3112. }
  3113. //
  3114. //
  3115. // Function: OnPaste
  3116. //
  3117. // Purpose: Paste the contents of the clipboard into the drawing pane
  3118. //
  3119. //
  3120. LRESULT WbMainWindow::OnPaste()
  3121. {
  3122. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnPaste");
  3123. BOOL bResult = CLP_Paste();
  3124. // If an error occurred during the copy, report it now
  3125. if (!bResult)
  3126. {
  3127. ::Message(NULL, IDS_PASTE, IDS_PASTE_ERROR);
  3128. return S_FALSE;
  3129. }
  3130. return S_OK;
  3131. }
  3132. //
  3133. //
  3134. // Function: OnScrollAccelerator
  3135. //
  3136. // Purpose: Called when a scroll accelerator is used
  3137. //
  3138. //
  3139. LRESULT WbMainWindow::OnScrollAccelerator(UINT uiMenuId)
  3140. {
  3141. int iScroll;
  3142. // Locate the scroll messages to be sent in the conversion table
  3143. for (iScroll = 0; iScroll < ARRAYSIZE(s_MenuToScroll); iScroll++)
  3144. {
  3145. if (s_MenuToScroll[iScroll].uiMenuId == uiMenuId)
  3146. {
  3147. // Found it;
  3148. break;
  3149. }
  3150. }
  3151. // Send the messages
  3152. if (iScroll < ARRAYSIZE(s_MenuToScroll))
  3153. {
  3154. while ((s_MenuToScroll[iScroll].uiMenuId == uiMenuId) && (iScroll < ARRAYSIZE(s_MenuToScroll)))
  3155. {
  3156. // Tell the drawing pane to scroll
  3157. ::PostMessage(m_drawingArea.m_hwnd, s_MenuToScroll[iScroll].uiMessage,
  3158. s_MenuToScroll[iScroll].uiScrollCode, 0);
  3159. iScroll++;
  3160. }
  3161. // Indicate that scrolling has completed (in both directions)
  3162. ::PostMessage(m_drawingArea.m_hwnd, WM_HSCROLL, SB_ENDSCROLL, 0L);
  3163. ::PostMessage(m_drawingArea.m_hwnd, WM_VSCROLL, SB_ENDSCROLL, 0L);
  3164. }
  3165. return S_OK;
  3166. }
  3167. //
  3168. //
  3169. // Function: OnZoom
  3170. //
  3171. // Purpose: Zoom or unzoom the drawing area
  3172. //
  3173. //
  3174. LRESULT WbMainWindow::OnZoom()
  3175. {
  3176. // If the drawing area is currently zoomed
  3177. if (m_drawingArea.Zoomed())
  3178. {
  3179. // Tell the tool bar of the new selection
  3180. m_TB.PopUp(IDM_ZOOM);
  3181. UncheckMenuItem(IDM_ZOOM);
  3182. }
  3183. else
  3184. {
  3185. // Tell the tool bar of the new selection
  3186. m_TB.PushDown(IDM_ZOOM);
  3187. CheckMenuItem(IDM_ZOOM);
  3188. }
  3189. // Zoom/unzoom the drawing area
  3190. m_drawingArea.Zoom();
  3191. // Restore the focus to the drawing area
  3192. ::SetFocus(m_drawingArea.m_hwnd);
  3193. return S_OK;
  3194. }
  3195. LRESULT WbMainWindow::OnLock()
  3196. {
  3197. // If the drawing area is currently Locked
  3198. if (m_drawingArea.IsLocked())
  3199. {
  3200. m_TB.PopUp(IDM_LOCK);
  3201. UncheckMenuItem(IDM_LOCK);
  3202. }
  3203. else
  3204. {
  3205. m_TB.PushDown(IDM_LOCK);
  3206. CheckMenuItem(IDM_LOCK);
  3207. g_pNMWBOBJ->m_LockerID = g_MyMemberID;
  3208. }
  3209. m_drawingArea.SetLock(!m_drawingArea.IsLocked());
  3210. TogleLockInAllWorkspaces(m_drawingArea.IsLocked(), TRUE);
  3211. EnableToolbar( TRUE );
  3212. return S_OK;
  3213. }
  3214. //
  3215. //
  3216. // Function: OnSelectTool
  3217. //
  3218. // Purpose: Select the current tool
  3219. //
  3220. //
  3221. LRESULT WbMainWindow::OnSelectTool(UINT uiMenuId)
  3222. {
  3223. UncheckMenuItem(m_currentMenuTool);
  3224. CheckMenuItem( uiMenuId);
  3225. UINT uiIndex;
  3226. // Save the new menu Id
  3227. m_currentMenuTool = uiMenuId;
  3228. // Tell the tool bar of the new selection
  3229. m_TB.PushDown(m_currentMenuTool);
  3230. // Get the new tool
  3231. m_pCurrentTool = m_ToolArray[TOOL_INDEX(m_currentMenuTool)];
  3232. // Set the current attributes
  3233. if( !m_bSelectAllInProgress )
  3234. {
  3235. m_AG.SetChoiceColor(m_pCurrentTool->GetColor() );
  3236. ::SendMessage(m_hwnd, WM_COMMAND, IDM_COLOR, 0L);
  3237. }
  3238. // Report the change of tool to the attributes group
  3239. m_AG.DisplayTool(m_pCurrentTool);
  3240. // Select the new tool into the drawing area
  3241. m_drawingArea.SelectTool(m_pCurrentTool);
  3242. // Restore the focus to the drawing area
  3243. ::SetFocus(m_drawingArea.m_hwnd);
  3244. return S_OK;
  3245. }
  3246. //
  3247. //
  3248. // Function: OnSelectColor
  3249. //
  3250. // Purpose: Set the current color
  3251. //
  3252. //
  3253. LRESULT WbMainWindow::OnSelectColor(void)
  3254. {
  3255. // Tell the attributes group of the new selection and get the
  3256. // new color value selected ino the current tool.
  3257. m_AG.SelectColor(m_pCurrentTool);
  3258. // Select the changed tool into the drawing area
  3259. m_drawingArea.SelectTool(m_pCurrentTool);
  3260. // If there is an object marked for changing
  3261. if (m_drawingArea.GraphicSelected() || m_drawingArea.TextEditActive())
  3262. {
  3263. // Update the object
  3264. m_drawingArea.SetSelectionColor(m_pCurrentTool->GetColor());
  3265. }
  3266. // Restore the focus to the drawing area
  3267. ::SetFocus(m_drawingArea.m_hwnd);
  3268. return S_OK;
  3269. }
  3270. //
  3271. //
  3272. // Function: OnSelectWidth
  3273. //
  3274. // Purpose: Set the current nib width
  3275. //
  3276. //
  3277. LRESULT WbMainWindow::OnSelectWidth(UINT uiMenuId)
  3278. {
  3279. // cleanup select logic in case object context menu called us (bug 426)
  3280. m_drawingArea.SetLClickIgnore( FALSE );
  3281. // Save the new pen width
  3282. m_currentMenuWidth = uiMenuId;
  3283. // Tell the attributes display of the new selection
  3284. m_WG.PushDown(uiMenuId - IDM_WIDTHS_START);
  3285. if (m_pCurrentTool != NULL)
  3286. {
  3287. m_pCurrentTool->SetWidthIndex(uiMenuId - IDM_WIDTHS_START);
  3288. }
  3289. // Tell the drawing pane of the new selection
  3290. m_drawingArea.SelectTool(m_pCurrentTool);
  3291. // If there is an object marked for changing
  3292. if (m_drawingArea.GraphicSelected())
  3293. {
  3294. // Update the object
  3295. m_drawingArea.SetSelectionWidth(uiMenuId - IDM_WIDTHS_START);
  3296. }
  3297. // Restore the focus to the drawing area
  3298. ::SetFocus(m_drawingArea.m_hwnd);
  3299. return S_OK;
  3300. }
  3301. //
  3302. //
  3303. // Function: OnChooseFont
  3304. //
  3305. // Purpose: Let the user select a font
  3306. //
  3307. //
  3308. LRESULT WbMainWindow::OnChooseFont(void)
  3309. {
  3310. HDC hdc;
  3311. LOGFONT lfont;
  3312. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnChooseFont");
  3313. // cleanup select logic in case object context menu called us (bug 426)
  3314. m_drawingArea.SetLClickIgnore( FALSE );
  3315. // It is only really sensible to be here when a text tool is selected.
  3316. // This is achieved by graying the Font selection menu entry when
  3317. // anything other than a text tool is in use.
  3318. // Get the font details from the current tool
  3319. ::GetObject(m_pCurrentTool->GetFont(), sizeof(LOGFONT), &lfont);
  3320. lfont.lfClipPrecision |= CLIP_DFA_OVERRIDE;
  3321. //
  3322. // The Font dialog is passed a LOGFONT structure which it uses to
  3323. // initialize all of its fields (face name, weight etc).
  3324. //
  3325. // The face name passed in the LOGFONT structure is checked by the dialog
  3326. // against the facenames of all available fonts. If the name does not
  3327. // match one of the available fonts, no name is displayed.
  3328. //
  3329. // WB stores the LOGFONT structure specifying the font used for a text
  3330. // object in the object. This LOGFONT is selected into a DC where the
  3331. // GDIs font mapper decides which physical font most closely matches the
  3332. // required logical font. On boxes where the original font is not
  3333. // supported the font is substituted for the closest matching font
  3334. // available.
  3335. //
  3336. // So, if we pass the LOGFONT structure for a font which is not supported
  3337. // into the Font dialog, no facename is displayed. To bypass this we
  3338. //
  3339. // - select the logical font into a DC
  3340. //
  3341. // - determine the textmetrics and get the face name of the physical font
  3342. // chosen by the Font Mapper
  3343. //
  3344. // - use these textmetrics to create a LOGFONT structure which matches
  3345. // the substituted font!
  3346. //
  3347. // The resulting LOGFONT will have the correct weight, dimensions and
  3348. // facename for the substituted font.
  3349. //
  3350. hdc = ::CreateCompatibleDC(NULL);
  3351. if (hdc != NULL)
  3352. {
  3353. TEXTMETRIC tm;
  3354. HFONT hFont;
  3355. HFONT hOldFont;
  3356. hFont = ::CreateFontIndirect(&lfont);
  3357. //
  3358. // Get the face name and text metrics of the selected font.
  3359. //
  3360. hOldFont = SelectFont(hdc, hFont);
  3361. if (hOldFont == NULL)
  3362. {
  3363. WARNING_OUT(("Failed to select font into DC"));
  3364. }
  3365. else
  3366. {
  3367. ::GetTextMetrics(hdc, &tm);
  3368. ::GetTextFace(hdc, LF_FACESIZE, lfont.lfFaceName);
  3369. //
  3370. // Restore the old font back into the DC.
  3371. //
  3372. SelectFont(hdc, hOldFont);
  3373. //
  3374. // Create a LOGFONT structure which matches the Text metrics
  3375. // of the font used by the DC so that the font dialog manages
  3376. // to initialise all of its fields properly, even for
  3377. // substituted fonts...
  3378. //
  3379. lfont.lfHeight = tm.tmHeight;
  3380. lfont.lfWidth = tm.tmAveCharWidth;
  3381. lfont.lfWeight = tm.tmWeight;
  3382. lfont.lfItalic = tm.tmItalic;
  3383. lfont.lfUnderline = tm.tmUnderlined;
  3384. lfont.lfStrikeOut = tm.tmStruckOut;
  3385. lfont.lfCharSet = tm.tmCharSet;
  3386. //ADDED BY RAND - to make lfHeight be a char height. This makes
  3387. // the font dlg show the same pt size that is
  3388. // displayed in the sample font toolbar
  3389. if( lfont.lfHeight > 0 )
  3390. {
  3391. lfont.lfHeight = -(lfont.lfHeight - tm.tmInternalLeading);
  3392. }
  3393. }
  3394. ::DeleteDC(hdc);
  3395. if (hFont != NULL)
  3396. {
  3397. ::DeleteFont(hFont);
  3398. }
  3399. }
  3400. else
  3401. {
  3402. WARNING_OUT(("Failed to get DC to select font into"));
  3403. }
  3404. CHOOSEFONT cf;
  3405. TCHAR szStyleName[64];
  3406. ZeroMemory(&cf, sizeof(cf));
  3407. ZeroMemory(szStyleName, sizeof(szStyleName));
  3408. cf.lStructSize = sizeof(cf);
  3409. cf.lpszStyle = szStyleName;
  3410. cf.rgbColors = m_pCurrentTool->GetColor() & 0x00ffffff; // blow off palette bits (NM4db:2304)
  3411. cf.Flags = CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS |
  3412. CF_NOVERTFONTS;
  3413. cf.lpLogFont = &lfont;
  3414. cf.hwndOwner = m_hwnd;
  3415. // Call up the ChooseFont dialog from COM DLG
  3416. if (::ChooseFont(&cf))
  3417. {
  3418. lfont.lfClipPrecision |= CLIP_DFA_OVERRIDE;
  3419. //ADDED BY RAND - set color selected in dialog.
  3420. m_pCurrentTool->SetColor(cf.rgbColors);
  3421. m_AG.DisplayTool( m_pCurrentTool );
  3422. ::SendMessage(m_hwnd, WM_COMMAND,
  3423. (WPARAM)MAKELONG( IDM_COLOR, BN_CLICKED ),
  3424. (LPARAM)0 );
  3425. // Inform the drawing pane of the new selection
  3426. HFONT hNewFont;
  3427. hNewFont = ::CreateFontIndirect(&lfont);
  3428. if (!hNewFont)
  3429. {
  3430. ERROR_OUT(("Failed to create font"));
  3431. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  3432. return S_FALSE;
  3433. }
  3434. //
  3435. // We need to set the text editor font after inserting it in the DC
  3436. // and querying the metrics, otherwise we may get a font with different
  3437. // metrics in zoomed mode
  3438. //
  3439. HFONT hNewFont2;
  3440. HDC hDC = m_drawingArea.GetCachedDC();
  3441. TEXTMETRIC textMetrics;
  3442. m_drawingArea.PrimeFont(hDC, hNewFont, &textMetrics);
  3443. lfont.lfHeight = textMetrics.tmHeight;
  3444. lfont.lfWidth = textMetrics.tmAveCharWidth;
  3445. lfont.lfPitchAndFamily = textMetrics.tmPitchAndFamily;
  3446. ::GetTextFace(hDC, sizeof(lfont.lfFaceName),
  3447. lfont.lfFaceName);
  3448. TRACE_MSG(("Font face name %s", lfont.lfFaceName));
  3449. // Inform the drawing pane of the new selection
  3450. hNewFont2 = ::CreateFontIndirect(&lfont);
  3451. if (!hNewFont2)
  3452. {
  3453. ERROR_OUT(("Failed to create font"));
  3454. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  3455. return S_FALSE;
  3456. }
  3457. m_drawingArea.SetSelectionColor(cf.rgbColors);
  3458. m_drawingArea.SetSelectionFont(hNewFont2);
  3459. if (m_pCurrentTool != NULL)
  3460. {
  3461. m_pCurrentTool->SetFont(hNewFont2);
  3462. }
  3463. m_drawingArea.SelectTool(m_pCurrentTool);
  3464. //
  3465. // discard the new font
  3466. //
  3467. m_drawingArea.UnPrimeFont( hDC );
  3468. // Delete the fonts we created--everybody above makes copies
  3469. ::DeleteFont(hNewFont2);
  3470. ::DeleteFont(hNewFont);
  3471. }
  3472. // Restore the focus to the drawing area
  3473. ::SetFocus(m_drawingArea.m_hwnd);
  3474. return S_OK;
  3475. }
  3476. //
  3477. //
  3478. // Function: OnToolBarToggle
  3479. //
  3480. // Purpose: Let the user toggle the tool bar on/off
  3481. //
  3482. //
  3483. LRESULT WbMainWindow::OnToolBarToggle(void)
  3484. {
  3485. RECT rectWnd;
  3486. // Toggle the flag
  3487. m_bToolBarOn = !m_bToolBarOn;
  3488. // Make the necessary updates
  3489. if (m_bToolBarOn)
  3490. {
  3491. // The tool bar was hidden, so show it
  3492. ::ShowWindow(m_TB.m_hwnd, SW_SHOW);
  3493. // The tool window is fixed so we must resize the other panes in
  3494. // the window to make room for it
  3495. ResizePanes();
  3496. // Check the associated menu item
  3497. CheckMenuItem(IDM_TOOL_BAR_TOGGLE);
  3498. }
  3499. else
  3500. {
  3501. // The tool bar was visible, so hide it
  3502. ::ShowWindow(m_TB.m_hwnd, SW_HIDE);
  3503. ResizePanes();
  3504. // Uncheck the associated menu item
  3505. UncheckMenuItem(IDM_TOOL_BAR_TOGGLE);
  3506. }
  3507. // Make sure things reflect current tool
  3508. m_AG.DisplayTool(m_pCurrentTool);
  3509. // Write the new option value to the options file
  3510. OPT_SetBooleanOption(OPT_MAIN_TOOLBARVISIBLE,
  3511. m_bToolBarOn);
  3512. ::GetWindowRect(m_hwnd, &rectWnd);
  3513. ::MoveWindow(m_hwnd, rectWnd.left, rectWnd.top, rectWnd.right - rectWnd.left, rectWnd.bottom - rectWnd.top, TRUE);
  3514. return S_OK;
  3515. }
  3516. //
  3517. //
  3518. // Function: OnStatusBarToggle
  3519. //
  3520. // Purpose: Let the user toggle the help bar on/off
  3521. //
  3522. //
  3523. void WbMainWindow::OnStatusBarToggle(void)
  3524. {
  3525. RECT rectWnd;
  3526. // Toggle the flag
  3527. m_bStatusBarOn = !m_bStatusBarOn;
  3528. // Make the necessary updates
  3529. if (m_bStatusBarOn)
  3530. {
  3531. // Resize the panes to give room for the help bar
  3532. ResizePanes();
  3533. // The help bar was hidden, so show it
  3534. ::ShowWindow(m_hwndSB, SW_SHOW);
  3535. // Check the associated menu item
  3536. CheckMenuItem(IDM_STATUS_BAR_TOGGLE);
  3537. }
  3538. else
  3539. {
  3540. // The help bar was visible, so hide it
  3541. ::ShowWindow(m_hwndSB, SW_HIDE);
  3542. // Uncheck the associated menu item
  3543. UncheckMenuItem(IDM_STATUS_BAR_TOGGLE);
  3544. // Resize the panes to take up the help bar space
  3545. ResizePanes();
  3546. }
  3547. // Write the new option value to the options file
  3548. OPT_SetBooleanOption(OPT_MAIN_STATUSBARVISIBLE, m_bStatusBarOn);
  3549. ::GetWindowRect(m_hwnd, &rectWnd);
  3550. ::MoveWindow(m_hwnd, rectWnd.left, rectWnd.top, rectWnd.right - rectWnd.left, rectWnd.bottom - rectWnd.top, TRUE);
  3551. }
  3552. //
  3553. //
  3554. // Function: OnAbout
  3555. //
  3556. // Purpose: Show the about box for the Whiteboard application. This
  3557. // method is called whenever a WM_COMMAND with IDM_ABOUT
  3558. // is issued by Windows.
  3559. //
  3560. //
  3561. LRESULT WbMainWindow::OnAbout()
  3562. {
  3563. ::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(ABOUTBOX), m_hwnd,
  3564. AboutDlgProc, 0);
  3565. return S_OK;
  3566. }
  3567. INT_PTR AboutDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  3568. {
  3569. BOOL fHandled = FALSE;
  3570. switch (uMessage)
  3571. {
  3572. case WM_INITDIALOG:
  3573. {
  3574. TCHAR szFormat[256];
  3575. TCHAR szVersion[512];
  3576. ::GetDlgItemText(hwnd, IDC_ABOUTVERSION, szFormat, 256);
  3577. wsprintf(szVersion, szFormat, VER_PRODUCTRELEASE_STR,
  3578. VER_PRODUCTVERSION_STR);
  3579. ::SetDlgItemText(hwnd, IDC_ABOUTVERSION, szVersion);
  3580. fHandled = TRUE;
  3581. break;
  3582. }
  3583. case WM_COMMAND:
  3584. switch (GET_WM_COMMAND_ID(wParam, lParam))
  3585. {
  3586. case IDOK:
  3587. case IDCANCEL:
  3588. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  3589. {
  3590. case BN_CLICKED:
  3591. ::EndDialog(hwnd, IDCANCEL);
  3592. break;
  3593. }
  3594. break;
  3595. }
  3596. fHandled = TRUE;
  3597. break;
  3598. }
  3599. return(fHandled);
  3600. }
  3601. void WbMainWindow::UpdateWindowTitle(void)
  3602. {
  3603. TCHAR szCaption[MAX_PATH * 2];
  3604. TCHAR szFileName[MAX_PATH * 2];
  3605. UINT captionID;
  3606. if (! g_pNMWBOBJ->IsInConference())
  3607. {
  3608. captionID = IDS_WB_NOT_IN_CALL_WINDOW_CAPTION;
  3609. }
  3610. else
  3611. {
  3612. captionID = IDS_WB_IN_CALL_WINDOW_CAPTION;
  3613. }
  3614. ::LoadString(g_hInstance, captionID, szFileName, sizeof(szFileName) );
  3615. wsprintf(szCaption, szFileName, GetFileNameStr(), g_pNMWBOBJ->m_cOtherMembers);
  3616. SetWindowText(m_hwnd, szCaption);
  3617. }
  3618. //
  3619. //
  3620. // Function: SelectWindow
  3621. //
  3622. // Purpose: Let the user select a window for grabbing
  3623. //
  3624. //
  3625. HWND WbMainWindow::SelectWindow(void)
  3626. {
  3627. POINT mousePos; // Mouse position
  3628. HWND hwndSelected = NULL; // Window clicked on
  3629. MSG msg; // Current message
  3630. // Load the grabbing cursors
  3631. HCURSOR hGrabCursor = ::LoadCursor(g_hInstance, MAKEINTRESOURCE( GRABCURSOR ) );
  3632. // Capture the mouse
  3633. UT_CaptureMouse(m_hwnd);
  3634. // Ensure we receive all keyboard messages.
  3635. ::SetFocus(m_hwnd);
  3636. // Reset the CancelMode state
  3637. ResetCancelMode();
  3638. // Change to the grab cursor
  3639. HCURSOR hOldCursor = ::SetCursor(hGrabCursor);
  3640. // Trap all mouse messages until a WM_LBUTTONUP is received
  3641. for ( ; ; )
  3642. {
  3643. // Wait for the next message
  3644. ::WaitMessage();
  3645. // Cancel if we have been sent a WM_CANCELMODE message
  3646. if (CancelModeSent())
  3647. {
  3648. break;
  3649. }
  3650. // If it is a mouse message, process it
  3651. if (::PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
  3652. {
  3653. if (msg.message == WM_LBUTTONUP)
  3654. {
  3655. // Get mouse position
  3656. mousePos.x = (short)LOWORD(msg.lParam);
  3657. mousePos.y = (short)HIWORD(msg.lParam);
  3658. // Convert to screen coordinates
  3659. ::ClientToScreen(m_hwnd, &mousePos);
  3660. // Get the window under the mouse
  3661. hwndSelected = ::WindowFromPoint(mousePos);
  3662. // Leave the loop
  3663. break;
  3664. }
  3665. }
  3666. // Cancel if ESCAPE is pressed.
  3667. // or if another window receives the focus
  3668. else if (::PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
  3669. {
  3670. if (msg.wParam == VK_ESCAPE)
  3671. {
  3672. break;
  3673. }
  3674. }
  3675. }
  3676. // Release the mouse
  3677. UT_ReleaseMouse(m_hwnd);
  3678. // Restore the cursor
  3679. ::SetCursor(hOldCursor);
  3680. return(hwndSelected);
  3681. }
  3682. //
  3683. //
  3684. // Function: OnGrabWindow
  3685. //
  3686. // Purpose: Allows the user to grab a bitmap of a window
  3687. //
  3688. //
  3689. LRESULT WbMainWindow::OnGrabWindow(void)
  3690. {
  3691. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnGrabWindow");
  3692. if (::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(WARNSELECTWINDOW),
  3693. m_hwnd, WarnSelectWindowDlgProc, 0) != IDOK)
  3694. {
  3695. // User cancelled; bail out
  3696. return S_OK;;
  3697. }
  3698. // Hide the application windows
  3699. ::ShowWindow(m_hwnd, SW_HIDE);
  3700. HWND mainUIhWnd = FindWindow("MPWClass\0" , NULL);
  3701. if(IsWindowVisible(mainUIhWnd))
  3702. {
  3703. ::UpdateWindow(mainUIhWnd);
  3704. }
  3705. // Get window selection from the user
  3706. HWND hwndSelected = SelectWindow();
  3707. if (hwndSelected != NULL)
  3708. {
  3709. // Walk back to the find the 'real' window ancestor
  3710. HWND hwndParent;
  3711. // The following piece of code attempts to find the frame window
  3712. // enclosing the selected window. This allows us to bring the
  3713. // enclosing window to the top, bringing the child window with it.
  3714. DWORD dwStyle;
  3715. while ((hwndParent = ::GetParent(hwndSelected)) != NULL)
  3716. {
  3717. // If we have reached a stand-alone window, stop the search
  3718. dwStyle = ::GetWindowLong(hwndSelected, GWL_STYLE);
  3719. if ( ((dwStyle & WS_POPUP) == WS_POPUP)
  3720. || ((dwStyle & WS_THICKFRAME) == WS_THICKFRAME)
  3721. || ((dwStyle & WS_DLGFRAME) == WS_DLGFRAME))
  3722. {
  3723. break;
  3724. }
  3725. // Move up to the parent window
  3726. hwndSelected = hwndParent;
  3727. }
  3728. // Bring the selected window to the top
  3729. ::BringWindowToTop(hwndSelected);
  3730. ::UpdateWindow(hwndSelected);
  3731. // Get an image copy of the window
  3732. RECT areaRect;
  3733. ::GetWindowRect(hwndSelected, &areaRect);
  3734. BitmapObj* dib;
  3735. DBG_SAVE_FILE_LINE
  3736. dib = new BitmapObj(TOOLTYPE_FILLEDBOX);
  3737. dib->FromScreenArea(&areaRect);
  3738. if(dib->m_lpbiImage == NULL)
  3739. {
  3740. delete dib;
  3741. return S_FALSE;
  3742. }
  3743. // Add the new grabbed bitmap
  3744. AddCapturedImage(dib);
  3745. // Force the selection tool to be selected
  3746. ::PostMessage(m_hwnd, WM_COMMAND, IDM_TOOLS_START, 0L);
  3747. }
  3748. // Show the windows again
  3749. ::ShowWindow(m_hwnd, SW_SHOW);
  3750. // Restore the focus to the drawing area
  3751. ::SetFocus(m_drawingArea.m_hwnd);
  3752. return S_OK;
  3753. }
  3754. //
  3755. // WarnSelectWindowDlgProc()
  3756. // This puts up the warning/explanation dialog. We use the default settings
  3757. // or whatever the user chose last time this dialog was up.
  3758. //
  3759. INT_PTR CALLBACK WarnSelectWindowDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  3760. {
  3761. BOOL fHandled = FALSE;
  3762. switch (uMessage)
  3763. {
  3764. case WM_INITDIALOG:
  3765. {
  3766. if (OPT_GetBooleanOption( OPT_MAIN_SELECTWINDOW_NOTAGAIN,
  3767. DFLT_MAIN_SELECTWINDOW_NOTAGAIN))
  3768. {
  3769. // End this right away, the user doesn't want a warning
  3770. ::EndDialog(hwnd, IDOK);
  3771. }
  3772. fHandled = TRUE;
  3773. break;
  3774. }
  3775. case WM_COMMAND:
  3776. switch (GET_WM_COMMAND_ID(wParam, lParam))
  3777. {
  3778. case IDOK:
  3779. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  3780. {
  3781. case BN_CLICKED:
  3782. //
  3783. // Update settings -- note that we don't have to write out
  3784. // FALSE--we wouldn't be in the dialog in the first place
  3785. // if the current setting weren't already FALSE.
  3786. //
  3787. if (::IsDlgButtonChecked(hwnd, IDC_SWWARN_NOTAGAIN))
  3788. {
  3789. OPT_SetBooleanOption(OPT_MAIN_SELECTWINDOW_NOTAGAIN, TRUE);
  3790. }
  3791. ::EndDialog(hwnd, IDOK);
  3792. break;
  3793. }
  3794. break;
  3795. case IDCANCEL:
  3796. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  3797. {
  3798. case BN_CLICKED:
  3799. ::EndDialog(hwnd, IDCANCEL);
  3800. break;
  3801. }
  3802. break;
  3803. }
  3804. fHandled = TRUE;
  3805. break;
  3806. }
  3807. return(fHandled);
  3808. }
  3809. //
  3810. //
  3811. // Function: ShowAllWindows
  3812. //
  3813. // Purpose: Show or hide the main window and associated windows
  3814. //
  3815. //
  3816. void WbMainWindow::ShowAllWindows(int iShow)
  3817. {
  3818. // Show/hide the main window
  3819. ::ShowWindow(m_hwnd, iShow);
  3820. // Show/hide the tool window
  3821. if (m_bToolBarOn)
  3822. {
  3823. ::ShowWindow(m_TB.m_hwnd, iShow);
  3824. }
  3825. }
  3826. //
  3827. //
  3828. // Function: OnGrabArea
  3829. //
  3830. // Purpose: Allows the user to grab a bitmap of an area of the screen
  3831. //
  3832. //
  3833. LRESULT WbMainWindow::OnGrabArea(void)
  3834. {
  3835. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnGrabArea");
  3836. if (::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(WARNSELECTAREA),
  3837. m_hwnd, WarnSelectAreaDlgProc, 0) != IDOK)
  3838. {
  3839. // User cancelled, so bail out
  3840. return S_OK;;
  3841. }
  3842. // Hide the application windows
  3843. ::ShowWindow(m_hwnd, SW_HIDE);
  3844. HWND mainUIhWnd = FindWindow("MPWClass\0" , NULL);
  3845. if(IsWindowVisible(mainUIhWnd))
  3846. {
  3847. ::UpdateWindow(mainUIhWnd);
  3848. }
  3849. // Load the grabbing cursors
  3850. HCURSOR hGrabCursor = ::LoadCursor(g_hInstance, MAKEINTRESOURCE( PENCURSOR ) );
  3851. // Capture the mouse
  3852. UT_CaptureMouse(m_hwnd);
  3853. // Ensure we receive all keyboard messages.
  3854. ::SetFocus(m_hwnd);
  3855. // Reset the CancelMode status
  3856. ResetCancelMode();
  3857. // Change to the grab cursor
  3858. HCURSOR hOldCursor = ::SetCursor(hGrabCursor);
  3859. // Let the user select the area to be grabbed
  3860. RECT rect;
  3861. int tmp;
  3862. GetGrabArea(&rect);
  3863. // Normalize coords
  3864. if (rect.right < rect.left)
  3865. {
  3866. tmp = rect.left;
  3867. rect.left = rect.right;
  3868. rect.right = tmp;
  3869. }
  3870. if (rect.bottom < rect.top)
  3871. {
  3872. tmp = rect.top;
  3873. rect.top = rect.bottom;
  3874. rect.bottom = tmp;
  3875. }
  3876. BitmapObj* dib;
  3877. DBG_SAVE_FILE_LINE
  3878. dib = new BitmapObj(TOOLTYPE_FILLEDBOX);
  3879. if (!::IsRectEmpty(&rect))
  3880. {
  3881. // Get a bitmap copy of the screen area
  3882. dib->FromScreenArea(&rect);
  3883. }
  3884. // Show the windows again now - if we do it later we get the bitmap to
  3885. // be added re-drawn twice (once on the window show and once when the
  3886. // graphic added indication arrives).
  3887. ::ShowWindow(m_hwnd, SW_SHOW);
  3888. ::UpdateWindow(m_hwnd);
  3889. if (!::IsRectEmpty(&rect) && dib->m_lpbiImage)
  3890. {
  3891. // Add the bitmap
  3892. AddCapturedImage(dib);
  3893. // Force the selection tool to be selected
  3894. ::PostMessage(m_hwnd, WM_COMMAND, IDM_TOOLS_START, 0L);
  3895. }
  3896. else
  3897. {
  3898. delete dib;
  3899. dib = NULL;
  3900. }
  3901. // Release the mouse
  3902. UT_ReleaseMouse(m_hwnd);
  3903. // Restore the cursor
  3904. ::SetCursor(hOldCursor);
  3905. // Restore the focus to the drawing area
  3906. ::SetFocus(m_drawingArea.m_hwnd);
  3907. if(dib)
  3908. {
  3909. dib->Draw();
  3910. }
  3911. return S_OK;
  3912. }
  3913. //
  3914. // WarnSelectArea dialog handler
  3915. //
  3916. INT_PTR CALLBACK WarnSelectAreaDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  3917. {
  3918. BOOL fHandled = FALSE;
  3919. switch (uMessage)
  3920. {
  3921. case WM_INITDIALOG:
  3922. if (OPT_GetBooleanOption(OPT_MAIN_SELECTAREA_NOTAGAIN,
  3923. DFLT_MAIN_SELECTAREA_NOTAGAIN))
  3924. {
  3925. // End this right away, the user doesn't want a warning
  3926. ::EndDialog(hwnd, IDOK);
  3927. }
  3928. fHandled = TRUE;
  3929. break;
  3930. case WM_COMMAND:
  3931. switch (GET_WM_COMMAND_ID(wParam, lParam))
  3932. {
  3933. case IDOK:
  3934. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  3935. {
  3936. case BN_CLICKED:
  3937. //
  3938. // Update settings -- note that we don't have to write out
  3939. // FALSE--we wouldn't be in the dialog in the first place
  3940. // if the current setting weren't already FALSE.
  3941. //
  3942. if (::IsDlgButtonChecked(hwnd, IDC_SAWARN_NOTAGAIN))
  3943. {
  3944. OPT_SetBooleanOption(OPT_MAIN_SELECTAREA_NOTAGAIN, TRUE);
  3945. }
  3946. ::EndDialog(hwnd, IDOK);
  3947. break;
  3948. }
  3949. break;
  3950. case IDCANCEL:
  3951. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  3952. {
  3953. case BN_CLICKED:
  3954. ::EndDialog(hwnd, IDCANCEL);
  3955. break;
  3956. }
  3957. }
  3958. fHandled = TRUE;
  3959. break;
  3960. }
  3961. return(fHandled);
  3962. }
  3963. //
  3964. //
  3965. // Function: GetGrabArea
  3966. //
  3967. // Purpose: Allows the user to grab a bitmap of an area of the screen
  3968. //
  3969. //
  3970. void WbMainWindow::GetGrabArea(LPRECT lprect)
  3971. {
  3972. POINT mousePos; // Mouse position
  3973. MSG msg; // Current message
  3974. BOOL tracking = FALSE; // Flag indicating mouse button is down
  3975. HDC hDC = NULL;
  3976. POINT grabStartPoint; // Start point (when mouse button is pressed)
  3977. POINT grabEndPoint; // End point (when mouse button is released)
  3978. POINT grabCurrPoint; // Current mouse position
  3979. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GetGrabArea");
  3980. // Set the result to an empty rectangle
  3981. ::SetRectEmpty(lprect);
  3982. // Create the rectangle to be used for tracking
  3983. DrawObj* pRectangle = NULL;
  3984. DBG_SAVE_FILE_LINE
  3985. pRectangle = new DrawObj(rectangle_chosen, TOOLTYPE_SELECT);
  3986. if(NULL == pRectangle)
  3987. {
  3988. ERROR_OUT(("Failed to allocate DrawObj"));
  3989. goto GrabAreaCleanup;
  3990. }
  3991. pRectangle->SetPenColor(RGB(0,0,0), TRUE);
  3992. pRectangle->SetFillColor(RGB(255,255,255), FALSE);
  3993. pRectangle->SetLineStyle(PS_DOT);
  3994. pRectangle->SetPenThickness(1);
  3995. // Get the DC for tracking
  3996. HWND hDesktopWnd = ::GetDesktopWindow();
  3997. hDC = ::GetWindowDC(hDesktopWnd);
  3998. if (hDC == NULL)
  3999. {
  4000. WARNING_OUT(("NULL desktop DC"));
  4001. goto GrabAreaCleanup;
  4002. }
  4003. RECT rect;
  4004. // Trap all mouse messages until a WM_LBUTTONUP is received
  4005. for ( ; ; )
  4006. {
  4007. // Wait for the next message
  4008. ::WaitMessage();
  4009. // Cancel if we have been sent a WM_CANCELMODE message
  4010. if (CancelModeSent())
  4011. {
  4012. TRACE_MSG(("canceling grab"));
  4013. // Erase the last tracking rectangle
  4014. if (!EqualPoint(grabStartPoint, grabEndPoint))
  4015. {
  4016. rect.top = grabStartPoint.y;
  4017. rect.left = grabStartPoint.x;
  4018. rect.bottom = grabEndPoint.y;
  4019. rect.right = grabEndPoint.x;
  4020. pRectangle->SetRect(&rect);
  4021. pRectangle->SetBoundsRect(&rect);
  4022. pRectangle->Draw(hDC);
  4023. }
  4024. break;
  4025. }
  4026. // If it is a mouse message, process it
  4027. if (::PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
  4028. {
  4029. // Get mouse position
  4030. TRACE_MSG( ("msg = %x, lParam = %0x", msg.message, msg.lParam) );
  4031. mousePos.x = (short)LOWORD(msg.lParam);
  4032. mousePos.y = (short)HIWORD(msg.lParam);
  4033. TRACE_MSG( ("mousePos = %d,%d", mousePos.x, mousePos.y) );
  4034. // Convert to screen coordinates
  4035. ::ClientToScreen(m_hwnd, &mousePos);
  4036. grabCurrPoint = mousePos;
  4037. switch (msg.message)
  4038. {
  4039. // Starting the grab
  4040. case WM_LBUTTONDOWN:
  4041. // Save the starting position
  4042. TRACE_MSG(("grabbing start position"));
  4043. grabStartPoint = mousePos;
  4044. grabEndPoint = mousePos;
  4045. tracking = TRUE;
  4046. break;
  4047. // Completing the rectangle
  4048. case WM_LBUTTONUP:
  4049. {
  4050. tracking = FALSE;
  4051. // Check that there is an area to capture
  4052. TRACE_MSG(("grabbing end position"));
  4053. if (EqualPoint(grabStartPoint, grabCurrPoint))
  4054. {
  4055. TRACE_MSG(("start == end, skipping grab"));
  4056. goto GrabAreaCleanup;
  4057. }
  4058. // Erase the last tracking rectangle
  4059. if (!EqualPoint(grabStartPoint, grabEndPoint))
  4060. {
  4061. rect.top = grabStartPoint.y;
  4062. rect.left = grabStartPoint.x;
  4063. rect.bottom = grabEndPoint.y;
  4064. rect.right = grabEndPoint.x;
  4065. pRectangle->SetRect(&rect);
  4066. pRectangle->SetBoundsRect(&rect);
  4067. pRectangle->Draw(hDC);
  4068. }
  4069. // Update the rectangle object
  4070. rect.top = grabStartPoint.y;
  4071. rect.left = grabStartPoint.x;
  4072. rect.bottom = grabCurrPoint.y;
  4073. rect.right = grabCurrPoint.x;
  4074. pRectangle->SetRect(&rect);
  4075. pRectangle->SetBoundsRect(&rect);
  4076. pRectangle->GetBoundsRect(lprect);
  4077. // We are done
  4078. goto GrabAreaCleanup;
  4079. }
  4080. break;
  4081. // Continuing the rectangle
  4082. case WM_MOUSEMOVE:
  4083. if (tracking)
  4084. {
  4085. TRACE_MSG(("tracking grab"));
  4086. // Erase the last tracking rectangle
  4087. if (!EqualPoint(grabStartPoint, grabEndPoint))
  4088. {
  4089. rect.top = grabStartPoint.y;
  4090. rect.left = grabStartPoint.x;
  4091. rect.bottom = grabEndPoint.y;
  4092. rect.right = grabEndPoint.x;
  4093. pRectangle->SetRect(&rect);
  4094. pRectangle->SetBoundsRect(&rect);
  4095. pRectangle->Draw(hDC);
  4096. }
  4097. // Draw the new rectangle
  4098. if (!EqualPoint(grabStartPoint, grabCurrPoint))
  4099. {
  4100. // Save the new box end point
  4101. grabEndPoint = grabCurrPoint;
  4102. // Draw the rectangle
  4103. TRACE_MSG( ("grabStartPoint = %d,%d",
  4104. grabStartPoint.x, grabStartPoint.y) );
  4105. TRACE_MSG( ("grabEndPoint = %d,%d",
  4106. grabEndPoint.x, grabEndPoint.y) );
  4107. rect.top = grabStartPoint.y;
  4108. rect.left = grabStartPoint.x;
  4109. rect.bottom = grabEndPoint.y;
  4110. rect.right = grabEndPoint.x;
  4111. pRectangle->SetRect(&rect);
  4112. pRectangle->SetBoundsRect(&rect);
  4113. pRectangle->Draw(hDC);
  4114. }
  4115. }
  4116. break;
  4117. }
  4118. }
  4119. // Cancel if ESCAPE is pressed.
  4120. else if (::PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
  4121. {
  4122. if( ((msg.message == WM_KEYUP)||(msg.message == WM_SYSKEYUP))&&
  4123. (msg.wParam == VK_ESCAPE) )
  4124. {
  4125. TRACE_MSG(("grab cancelled by ESC"));
  4126. // Erase the last tracking rectangle
  4127. if (!EqualPoint(grabStartPoint, grabEndPoint))
  4128. {
  4129. rect.top = grabStartPoint.y;
  4130. rect.left = grabStartPoint.x;
  4131. rect.bottom = grabEndPoint.y;
  4132. rect.right = grabEndPoint.x;
  4133. pRectangle->SetRect(&rect);
  4134. pRectangle->Draw(hDC);
  4135. }
  4136. break;
  4137. }
  4138. }
  4139. }
  4140. GrabAreaCleanup:
  4141. // Release the device context (if we have it)
  4142. if (hDC != NULL)
  4143. {
  4144. ::ReleaseDC(hDesktopWnd, hDC);
  4145. }
  4146. delete pRectangle;
  4147. }
  4148. //
  4149. //
  4150. // Function: AddCapturedImage
  4151. //
  4152. // Purpose: Add a bitmap to the contents (adding a new page for it
  4153. // if necessary).
  4154. //
  4155. //
  4156. void WbMainWindow::AddCapturedImage(BitmapObj* dib)
  4157. {
  4158. // Position the grabbed object at the top left of the currently visible
  4159. // area.
  4160. RECT rcVis;
  4161. m_drawingArea.GetVisibleRect(&rcVis);
  4162. dib->MoveTo(rcVis.left, rcVis.top);
  4163. dib->Draw();
  4164. // Add the new grabbed bitmap
  4165. dib->AddToWorkspace();
  4166. }
  4167. //
  4168. //
  4169. // Function: OnPrint
  4170. //
  4171. // Purpose: Print the contents of the drawing pane
  4172. //
  4173. //
  4174. LRESULT WbMainWindow::OnPrint()
  4175. {
  4176. BOOL bPrintError = FALSE;
  4177. PRINTDLG pd;
  4178. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnPrint");
  4179. if (!IsIdle())
  4180. {
  4181. // post an error message indicating the whiteboard is busy
  4182. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  4183. return S_FALSE;
  4184. }
  4185. //
  4186. // Initialize the PRINTDLG structure
  4187. //
  4188. ZeroMemory(&pd, sizeof(pd));
  4189. pd.lStructSize = sizeof(pd);
  4190. pd.hInstance = g_hInstance;
  4191. pd.hwndOwner = m_hwnd;
  4192. pd.Flags = PD_ALLPAGES | PD_RETURNDC | PD_PAGENUMS |
  4193. PD_HIDEPRINTTOFILE | PD_NOSELECTION;
  4194. pd.nMinPage = 1;
  4195. pd.nMaxPage = (WORD)g_numberOfWorkspaces;
  4196. pd.nFromPage = pd.nMinPage;
  4197. pd.nToPage = pd.nMaxPage;
  4198. // Put up the COMMDLG print dialog
  4199. if (::PrintDlg(&pd))
  4200. {
  4201. int nStartPage, nEndPage;
  4202. // Get the start and end page numbers to be printed
  4203. if (pd.Flags & PD_PAGENUMS)
  4204. {
  4205. nStartPage = pd.nFromPage;
  4206. nEndPage = pd.nToPage;
  4207. }
  4208. else
  4209. {
  4210. nStartPage = pd.nMinPage;
  4211. nEndPage = pd.nMaxPage;
  4212. }
  4213. // Check whether any pages are to be printed
  4214. if (nStartPage <= pd.nMaxPage)
  4215. {
  4216. // Ensure that the start and end pages lie within range.
  4217. nStartPage = max(nStartPage, pd.nMinPage);
  4218. nEndPage = min(nEndPage, pd.nMaxPage);
  4219. // Get the printer and output port names.
  4220. // These are written to the dialog for the user to see
  4221. // in the OnInitDialog member.
  4222. TCHAR szDeviceName[2*_MAX_PATH];
  4223. LPDEVNAMES lpDev;
  4224. // Device name
  4225. if (pd.hDevNames == NULL)
  4226. {
  4227. szDeviceName[0] = 0;
  4228. }
  4229. else
  4230. {
  4231. lpDev = (LPDEVNAMES)::GlobalLock(pd.hDevNames);
  4232. wsprintf(szDeviceName, "%s %s",
  4233. (LPCTSTR)lpDev + lpDev->wDeviceOffset,
  4234. (LPCTSTR)lpDev + lpDev->wOutputOffset);
  4235. ::GlobalUnlock(pd.hDevNames);
  4236. }
  4237. //
  4238. // Tell the printer we are starting the print.
  4239. // Note that the printer object handles the cancellation dialog.
  4240. WbPrinter printer(szDeviceName);
  4241. TCHAR szJobName[_MAX_PATH];
  4242. ::LoadString(g_hInstance, IDS_PRINT_NAME, szJobName, _MAX_PATH);
  4243. int nPrintResult = printer.StartDoc(pd.hDC, szJobName, nStartPage);
  4244. if (nPrintResult < 0)
  4245. {
  4246. WARNING_OUT(("Print result %d", nPrintResult));
  4247. bPrintError = TRUE;
  4248. }
  4249. else
  4250. {
  4251. // Find out how many copies to print
  4252. int copyNum;
  4253. copyNum = 0;
  4254. while ((copyNum < pd.nCopies) && !bPrintError)
  4255. {
  4256. // Loop through all pages
  4257. int nPrintPage = 0;
  4258. WBPOSITION pos;
  4259. WorkspaceObj * pWorkspace = NULL;
  4260. pos = g_pListOfWorkspaces->GetHeadPosition();
  4261. while(pos)
  4262. {
  4263. pWorkspace = (WorkspaceObj*) g_pListOfWorkspaces->GetNext(pos);
  4264. nPrintPage++;
  4265. if (nPrintPage >= nStartPage && nPrintPage <= nEndPage // We are in the range
  4266. && pWorkspace && pWorkspace->GetHead() != NULL) // is there anything in the workspace
  4267. {
  4268. // Tell the printer we are starting a new page
  4269. printer.StartPage(pd.hDC, nPrintPage);
  4270. if (!printer.Error())
  4271. {
  4272. RECT rectArea;
  4273. rectArea.left = 0;
  4274. rectArea.top = 0;
  4275. rectArea.right = DRAW_WIDTH;
  4276. rectArea.bottom = DRAW_HEIGHT;
  4277. // Print the page
  4278. PG_Print(pWorkspace, pd.hDC, &rectArea);
  4279. // Inform the printer that the page is complete
  4280. printer.EndPage(pd.hDC);
  4281. }
  4282. else
  4283. {
  4284. bPrintError = TRUE;
  4285. break;
  4286. }
  4287. }
  4288. }
  4289. copyNum++;
  4290. }
  4291. // The print has completed
  4292. nPrintResult = printer.EndDoc(pd.hDC);
  4293. if (nPrintResult < 0)
  4294. {
  4295. WARNING_OUT(("Print result %d", nPrintResult));
  4296. bPrintError = TRUE;
  4297. }
  4298. // reset the error if the user cancelled the print
  4299. if (printer.Aborted())
  4300. {
  4301. WARNING_OUT(("User cancelled print"));
  4302. bPrintError = FALSE;
  4303. }
  4304. }
  4305. }
  4306. }
  4307. // Inform the user if an error occurred
  4308. if (bPrintError)
  4309. {
  4310. // display a message informing the user the job terminated
  4311. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_PRINTER, 0);
  4312. }
  4313. //
  4314. // Cleanup the hDevMode, hDevNames, and hdc blocks if allocated
  4315. //
  4316. if (pd.hDevMode != NULL)
  4317. {
  4318. ::GlobalFree(pd.hDevMode);
  4319. pd.hDevMode = NULL;
  4320. }
  4321. if (pd.hDevNames != NULL)
  4322. {
  4323. ::GlobalFree(pd.hDevNames);
  4324. pd.hDevNames = NULL;
  4325. }
  4326. if (pd.hDC != NULL)
  4327. {
  4328. ::DeleteDC(pd.hDC);
  4329. pd.hDC = NULL;
  4330. }
  4331. return S_OK;
  4332. }
  4333. //
  4334. //
  4335. // Function: InsertPageAfter
  4336. //
  4337. // Purpose: Insert a new page after the specified page.
  4338. //
  4339. //
  4340. void WbMainWindow::InsertPageAfter(WorkspaceObj * pCurrentWorkspace)
  4341. {
  4342. //
  4343. // Create a standard workspace
  4344. //
  4345. if(g_numberOfWorkspaces < WB_MAX_WORKSPACES)
  4346. {
  4347. //
  4348. // If we were editing text
  4349. //
  4350. if (g_pDraw->TextEditActive())
  4351. {
  4352. g_pDraw->EndTextEntry(TRUE);
  4353. }
  4354. BOOL bRemote = FALSE;
  4355. if(m_pLocalRemotePointer)
  4356. {
  4357. bRemote = TRUE;
  4358. OnRemotePointer();
  4359. }
  4360. WorkspaceObj * pObj;
  4361. DBG_SAVE_FILE_LINE
  4362. pObj = new WorkspaceObj();
  4363. pObj->AddToWorkspace();
  4364. if(bRemote)
  4365. {
  4366. OnRemotePointer();
  4367. }
  4368. }
  4369. }
  4370. //
  4371. //
  4372. // Function: OnInsertPageAfter
  4373. //
  4374. // Purpose: Insert a new page after the current page
  4375. //
  4376. //
  4377. LRESULT WbMainWindow::OnInsertPageAfter()
  4378. {
  4379. // Insert the new page
  4380. InsertPageAfter(g_pCurrentWorkspace);
  4381. return S_OK;
  4382. }
  4383. //
  4384. //
  4385. // Function: OnDeletePage
  4386. //
  4387. // Purpose: Delete the current page
  4388. //
  4389. //
  4390. LRESULT WbMainWindow::OnDeletePage()
  4391. {
  4392. //
  4393. // Clear the page
  4394. //
  4395. if(g_pListOfWorkspaces->GetHeadPosition() == g_pListOfWorkspaces->GetTailPosition())
  4396. {
  4397. OnClearPage(TRUE);
  4398. }
  4399. else
  4400. {
  4401. LRESULT result = OnClearPage(FALSE);
  4402. //
  4403. // If we had more pages move to the previous page
  4404. //
  4405. if(result == IDYES)
  4406. {
  4407. //
  4408. // Deleted locally
  4409. //
  4410. g_pCurrentWorkspace->DeletedLocally();
  4411. //
  4412. // If the text editor is active
  4413. //
  4414. if(m_drawingArea.TextEditActive())
  4415. {
  4416. m_drawingArea.DeactivateTextEditor();
  4417. }
  4418. BOOL remotePointerIsOn = FALSE;
  4419. if(g_pMain->m_pLocalRemotePointer)
  4420. {
  4421. g_pMain->OnRemotePointer();
  4422. remotePointerIsOn = TRUE;
  4423. }
  4424. //
  4425. // Remove the workspace and point current to the correct one.
  4426. //
  4427. WorkspaceObj * pWorkspace = RemoveWorkspace(g_pCurrentWorkspace);
  4428. g_pMain->GoPage(pWorkspace);
  4429. if(remotePointerIsOn)
  4430. {
  4431. g_pMain->OnRemotePointer();
  4432. }
  4433. }
  4434. }
  4435. return S_OK;
  4436. }
  4437. //
  4438. //
  4439. // Function: OnRemotePointer
  4440. //
  4441. // Purpose: Create a remote pointer
  4442. //
  4443. //
  4444. LRESULT WbMainWindow::OnRemotePointer(void)
  4445. {
  4446. if(m_pLocalRemotePointer == NULL)
  4447. {
  4448. BitmapObj* remotePtr;
  4449. DBG_SAVE_FILE_LINE
  4450. m_pLocalRemotePointer = new BitmapObj(TOOLTYPE_REMOTEPOINTER);
  4451. if(g_pMain->m_localRemotePointerPosition.x < 0 && g_pMain->m_localRemotePointerPosition.y < 0 )
  4452. {
  4453. // Position the remote pointer in center of the drawing area
  4454. RECT rcVis;
  4455. m_drawingArea.GetVisibleRect(&rcVis);
  4456. m_localRemotePointerPosition.x = rcVis.left + (rcVis.right - rcVis.left)/2;
  4457. m_localRemotePointerPosition.y = rcVis.top + (rcVis.bottom - rcVis.top)/2;
  4458. }
  4459. m_pLocalRemotePointer->MoveTo(m_localRemotePointerPosition.x ,m_localRemotePointerPosition.y);
  4460. COLORREF color;
  4461. color = g_crDefaultColors[g_MyIndex + 1];
  4462. m_pLocalRemotePointer->CreateColoredIcon(color);
  4463. //
  4464. // If we couldn't create an image for teh remote pointer bitmap
  4465. //
  4466. if(m_pLocalRemotePointer->m_lpbiImage == NULL)
  4467. {
  4468. delete m_pLocalRemotePointer;
  4469. m_pLocalRemotePointer = NULL;
  4470. return S_FALSE;
  4471. }
  4472. m_pLocalRemotePointer->Draw(FALSE);
  4473. // Add the new grabbed bitmap
  4474. m_pLocalRemotePointer->AddToWorkspace();
  4475. m_TB.PushDown(IDM_REMOTE);
  4476. CheckMenuItem(IDM_REMOTE);
  4477. // Start the timer for updating the graphic (this is only for updating
  4478. // the graphic when the user stops moving the pointer but keeps the
  4479. // mouse button down).
  4480. ::SetTimer(g_pDraw->m_hwnd, TIMER_REMOTE_POINTER_UPDATE, DRAW_REMOTEPOINTERDELAY, NULL);
  4481. }
  4482. else
  4483. {
  4484. ::KillTimer(g_pDraw->m_hwnd, TIMER_REMOTE_POINTER_UPDATE);
  4485. m_pLocalRemotePointer->DeletedLocally();
  4486. g_pCurrentWorkspace->RemoveT126Object(m_pLocalRemotePointer);
  4487. m_pLocalRemotePointer = NULL;
  4488. m_TB.PopUp(IDM_REMOTE);
  4489. UncheckMenuItem(IDM_REMOTE);
  4490. }
  4491. return S_OK;
  4492. }
  4493. //
  4494. //
  4495. // Function: OnSync
  4496. //
  4497. // Purpose: Sync or unsync the Whiteboard with other users
  4498. //
  4499. //
  4500. LRESULT WbMainWindow::OnSync(void)
  4501. {
  4502. // Determine whether we are currently synced
  4503. if (m_drawingArea.IsSynced())
  4504. {
  4505. // currently synced, so unsync
  4506. Unsync();
  4507. }
  4508. else
  4509. {
  4510. // currently unsynced, so sync
  4511. Sync();
  4512. }
  4513. m_drawingArea.SetSync(!m_drawingArea.IsSynced());
  4514. EnableToolbar( TRUE );
  4515. m_AG.EnablePageCtrls(TRUE);
  4516. return S_OK;
  4517. }
  4518. //
  4519. //
  4520. // Function: Sync
  4521. //
  4522. // Purpose: Sync the Whiteboard with other users
  4523. //
  4524. //
  4525. void WbMainWindow::Sync(void)
  4526. {
  4527. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::Sync");
  4528. m_TB.PushDown(IDM_SYNC);
  4529. CheckMenuItem(IDM_SYNC);
  4530. GotoPage(g_pConferenceWorkspace);
  4531. } // Sync
  4532. //
  4533. //
  4534. // Function: Unsync
  4535. //
  4536. // Purpose: Unsync the Whiteboard with other users
  4537. //
  4538. //
  4539. void WbMainWindow::Unsync(void)
  4540. {
  4541. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::Unsync");
  4542. m_TB.PopUp(IDM_SYNC);
  4543. UncheckMenuItem(IDM_SYNC);
  4544. } // Unsync
  4545. LRESULT WbMainWindow::OnConfShutdown( WPARAM, LPARAM )
  4546. {
  4547. if (OnQueryEndSession())
  4548. {
  4549. ::SendMessage(m_hwnd, WM_CLOSE, 0, 0); // do close immediately
  4550. // :
  4551. // DON'T DO ANYTHING else at this point except for exit.
  4552. return( 0 );// tell conf ok to shutdown
  4553. }
  4554. else
  4555. return( (LRESULT)g_cuEndSessionAbort ); // don't shutdown
  4556. }
  4557. //
  4558. //
  4559. // Function: OnQueryEndSession
  4560. //
  4561. // Purpose: Ensure user is prompted to save changes when windows is
  4562. // ended.
  4563. //
  4564. //
  4565. LRESULT WbMainWindow::OnQueryEndSession(void)
  4566. {
  4567. HWND hwndPopup;
  4568. if ((hwndPopup = ::GetLastActivePopup(m_hwnd)) != m_hwnd)
  4569. {
  4570. ::Message(NULL, IDS_DEFAULT, IDS_CANTCLOSE );
  4571. ::BringWindowToTop(hwndPopup);
  4572. return( FALSE );
  4573. }
  4574. // If changes are required then prompt the user to save
  4575. int iDoNew = IDYES;
  4576. if (IsIdle())
  4577. {
  4578. iDoNew = QuerySaveRequired(TRUE);
  4579. if (iDoNew == IDYES)
  4580. {
  4581. // Save the changes
  4582. iDoNew = (int)OnSave(FALSE);
  4583. }
  4584. }
  4585. // remember what we did so OnClose can act appropriately
  4586. m_bQuerySysShutdown = (iDoNew != IDCANCEL);
  4587. // If the user did not cancel, let windows exit
  4588. return( m_bQuerySysShutdown );
  4589. }
  4590. //
  4591. //
  4592. // Function: UnlockDrawingArea
  4593. //
  4594. // Purpose: Unlock the drawing area and enable the appropriate buttons
  4595. //
  4596. //
  4597. //
  4598. void WbMainWindow::UnlockDrawingArea()
  4599. {
  4600. m_drawingArea.Unlock();
  4601. {
  4602. EnableToolbar( TRUE );
  4603. m_AG.EnablePageCtrls(TRUE);
  4604. }
  4605. //
  4606. // Show the tool attributes group.
  4607. //
  4608. m_AG.DisplayTool(m_pCurrentTool);
  4609. }
  4610. //
  4611. //
  4612. // Function: LockDrawingArea
  4613. //
  4614. // Purpose: Lock the drawing area and enable the appropriate buttons
  4615. //
  4616. //
  4617. //
  4618. void WbMainWindow::LockDrawingArea()
  4619. {
  4620. m_drawingArea.Lock();
  4621. if(g_pNMWBOBJ->m_LockerID != g_MyMemberID)
  4622. {
  4623. // Disable tool-bar buttons that cannot be used while locked
  4624. EnableToolbar( FALSE );
  4625. m_AG.EnablePageCtrls(FALSE);
  4626. //
  4627. // Hide the tool attributes
  4628. //
  4629. if (m_WG.m_hwnd != NULL)
  4630. {
  4631. ::ShowWindow(m_WG.m_hwnd, SW_HIDE);
  4632. }
  4633. m_AG.Hide();
  4634. }
  4635. }
  4636. void WbMainWindow::EnableToolbar( BOOL bEnable )
  4637. {
  4638. if (bEnable)
  4639. {
  4640. m_TB.Enable(IDM_SELECT);
  4641. // don't allow text editing in zoom mode
  4642. if( m_drawingArea.Zoomed() )
  4643. m_TB.Disable(IDM_TEXT);
  4644. else
  4645. m_TB.Enable(IDM_TEXT);
  4646. m_TB.Enable(IDM_PEN);
  4647. m_TB.Enable(IDM_HIGHLIGHT);
  4648. m_TB.Enable(IDM_LINE);
  4649. m_TB.Enable(IDM_ZOOM);
  4650. m_TB.Enable(IDM_BOX);
  4651. m_TB.Enable(IDM_FILLED_BOX);
  4652. m_TB.Enable(IDM_ELLIPSE);
  4653. m_TB.Enable(IDM_FILLED_ELLIPSE);
  4654. m_TB.Enable(IDM_ERASER);
  4655. m_TB.Enable(IDM_GRAB_AREA);
  4656. m_TB.Enable(IDM_GRAB_WINDOW);
  4657. //
  4658. // If we are not synced we can't lock the other nodes
  4659. //
  4660. if(g_pDraw->IsSynced())
  4661. {
  4662. m_TB.PushDown(IDM_SYNC);
  4663. m_TB.Enable(IDM_LOCK);
  4664. }
  4665. else
  4666. {
  4667. m_TB.PopUp(IDM_SYNC);
  4668. m_TB.Disable(IDM_LOCK);
  4669. }
  4670. if(m_drawingArea.IsLocked())
  4671. {
  4672. m_TB.Disable(IDM_SYNC);
  4673. }
  4674. else
  4675. {
  4676. m_TB.Enable(IDM_SYNC);
  4677. }
  4678. m_TB.Enable(IDM_REMOTE);
  4679. }
  4680. else
  4681. {
  4682. m_TB.Disable(IDM_SELECT);
  4683. m_TB.Disable(IDM_PEN);
  4684. m_TB.Disable(IDM_HIGHLIGHT);
  4685. m_TB.Disable(IDM_TEXT);
  4686. m_TB.Disable(IDM_LINE);
  4687. m_TB.Disable(IDM_ZOOM);
  4688. m_TB.Disable(IDM_BOX);
  4689. m_TB.Disable(IDM_FILLED_BOX);
  4690. m_TB.Disable(IDM_ELLIPSE);
  4691. m_TB.Disable(IDM_FILLED_ELLIPSE);
  4692. m_TB.Disable(IDM_ERASER);
  4693. m_TB.Disable(IDM_REMOTE);
  4694. m_TB.Disable(IDM_GRAB_AREA);
  4695. m_TB.Disable(IDM_GRAB_WINDOW);
  4696. m_TB.Disable(IDM_LOCK);
  4697. m_TB.Disable(IDM_SYNC);
  4698. }
  4699. }
  4700. //
  4701. //
  4702. // Function: UpdatePageButtons
  4703. //
  4704. // Purpose: Enable or disable the page buttons, according to the current
  4705. // state.
  4706. //
  4707. //
  4708. //
  4709. void WbMainWindow::UpdatePageButtons()
  4710. {
  4711. BOOL bEnable = TRUE;
  4712. if(!g_pCurrentWorkspace)
  4713. {
  4714. g_numberOfWorkspaces = 0;
  4715. bEnable = FALSE;
  4716. }
  4717. else
  4718. {
  4719. //
  4720. // Can we update this workspace
  4721. //
  4722. bEnable = g_pCurrentWorkspace->GetUpdatesEnabled();
  4723. //
  4724. // If it is locked, is it locked by us
  4725. //
  4726. if(!bEnable)
  4727. {
  4728. bEnable |= g_pNMWBOBJ->m_LockerID == g_MyMemberID;
  4729. }
  4730. }
  4731. m_AG.EnablePageCtrls(bEnable);
  4732. WBPOSITION pos;
  4733. WorkspaceObj * pWorkspace;
  4734. UINT pageNumber = 0;
  4735. pos = g_pListOfWorkspaces->GetHeadPosition();
  4736. while(pos)
  4737. {
  4738. pageNumber++;
  4739. pWorkspace = (WorkspaceObj*)g_pListOfWorkspaces->GetNext(pos);
  4740. if(g_pCurrentWorkspace == pWorkspace)
  4741. {
  4742. break;
  4743. }
  4744. }
  4745. m_AG.SetCurrentPageNumber(pageNumber);
  4746. m_AG.SetLastPageNumber(g_numberOfWorkspaces);
  4747. EnableToolbar( bEnable );
  4748. }
  4749. //
  4750. //
  4751. // Function: CancelLoad
  4752. //
  4753. // Purpose: Cancel any load in progress
  4754. //
  4755. //
  4756. void WbMainWindow::CancelLoad(BOOL bReleaseLock)
  4757. {
  4758. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::CancelLoad");
  4759. // reset file name to untitled
  4760. ZeroMemory(m_strFileName, sizeof(m_strFileName));
  4761. // reset the whiteboard substate
  4762. SetSubstate(SUBSTATE_IDLE);
  4763. }
  4764. //
  4765. //
  4766. // Function: IsIdle
  4767. //
  4768. // Purpose: Returns true if the main window is idle (in a call and not
  4769. // loading a file/performing a new)
  4770. //
  4771. //
  4772. BOOL WbMainWindow::IsIdle()
  4773. {
  4774. return(m_uiSubState == SUBSTATE_IDLE);
  4775. }
  4776. //
  4777. //
  4778. // Function: SetSubstate
  4779. //
  4780. // Purpose: Sets the substate, informing the page sorter dialog of the
  4781. // change, if necessary.
  4782. //
  4783. //
  4784. void WbMainWindow::SetSubstate(UINT newSubState)
  4785. {
  4786. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::SetSubstate");
  4787. // substate only valid if in a call
  4788. if (newSubState != m_uiSubState)
  4789. {
  4790. DBG_SAVE_FILE_LINE
  4791. m_uiSubState = newSubState;
  4792. // Trace the substate change
  4793. switch (m_uiSubState)
  4794. {
  4795. case SUBSTATE_IDLE:
  4796. TRACE_DEBUG(("set substate to IDLE"));
  4797. break;
  4798. case SUBSTATE_LOADING:
  4799. TRACE_DEBUG(("set substate to LOADING"));
  4800. break;
  4801. case SUBSTATE_SAVING:
  4802. TRACE_DEBUG(("set substate to SAVING"));
  4803. break;
  4804. case SUBSTATE_NEW_IN_PROGRESS:
  4805. TRACE_DEBUG(("set substate to NEW_IN_PROGRESS"));
  4806. break;
  4807. default:
  4808. ERROR_OUT(("Unknown substate %hd",m_uiSubState));
  4809. break;
  4810. }
  4811. // update the page buttons (may have become enabled/disabled)
  4812. UpdatePageButtons();
  4813. }
  4814. }
  4815. //
  4816. //
  4817. // Function: PositionUpdated
  4818. //
  4819. // Purpose: Called when the drawing area position has changed.
  4820. // change, if necessary.
  4821. //
  4822. //
  4823. void WbMainWindow::PositionUpdated()
  4824. {
  4825. RECT rectDraw;
  4826. m_drawingArea.GetVisibleRect(&rectDraw);
  4827. g_pDraw->InvalidateSurfaceRect(&rectDraw,FALSE);
  4828. }
  4829. //
  4830. //
  4831. // Function : OnEndSession
  4832. //
  4833. // Purpose : Called when Windows is exiting
  4834. //
  4835. //
  4836. void WbMainWindow::OnEndSession(BOOL bEnding)
  4837. {
  4838. if (bEnding)
  4839. {
  4840. ::PostQuitMessage(0);
  4841. }
  4842. else
  4843. {
  4844. m_bQuerySysShutdown = FALSE; // never mind, cancel OnClose special handling
  4845. }
  4846. }
  4847. //
  4848. // Function: OnCancelMode()
  4849. //
  4850. // Purpose: Called whenever a WM_CANCELMODE message is sent to the frame
  4851. // window.
  4852. // WM_CANCELMODE is sent when another app or dialog receives the
  4853. // input focus. The frame simply records that a WM_CANCELMODE
  4854. // message has been sent. This fact is used by the SelectWindow
  4855. // code to determine if it should cancel the selecting of a
  4856. // window
  4857. //
  4858. //
  4859. void WbMainWindow::OnCancelMode()
  4860. {
  4861. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnCancelMode");
  4862. m_cancelModeSent = TRUE;
  4863. //
  4864. // Note: Not passed to the default handler as the default action on
  4865. // WM_CANCELMODE is to release mouse capture - we shall do this
  4866. // explicitly.
  4867. //
  4868. // blow off any dragging that might be in progress (bug 573)
  4869. POINT pt;
  4870. ::GetCursorPos( &pt );
  4871. ::ScreenToClient(m_drawingArea.m_hwnd, &pt);
  4872. ::SendMessage(m_drawingArea.m_hwnd, WM_LBUTTONUP, 0, MAKELONG( pt.x, pt.y ) );
  4873. }
  4874. void WbMainWindow::LoadCmdLine(LPCSTR szFilename)
  4875. {
  4876. int iOnSave;
  4877. if (szFilename && *szFilename)
  4878. {
  4879. if( UsersMightLoseData( NULL, NULL ) ) // bug NM4db:418
  4880. return;
  4881. // Don't prompt to save file if we're already loading
  4882. if (m_uiSubState != SUBSTATE_LOADING )
  4883. {
  4884. // Check whether there are changes to be saved
  4885. iOnSave = QuerySaveRequired(TRUE);
  4886. }
  4887. else
  4888. {
  4889. return;
  4890. }
  4891. if (iOnSave == IDYES)
  4892. {
  4893. // User wants to save the drawing area contents
  4894. int iResult = (int)OnSave(TRUE);
  4895. if( iResult == IDOK )
  4896. {
  4897. }
  4898. else
  4899. {
  4900. // cancelled out of save, so cancel the open operation
  4901. return;
  4902. }
  4903. }
  4904. // load filename
  4905. if( iOnSave != IDCANCEL )
  4906. LoadFile(szFilename);
  4907. }
  4908. }
  4909. //
  4910. // OnNotify()
  4911. // Handles TTN_NEEDTEXTA and TTN_NEEDTEXTW
  4912. //
  4913. void WbMainWindow::OnNotify(UINT id, NMHDR * pNM)
  4914. {
  4915. UINT nID;
  4916. HWND hwnd = NULL;
  4917. POINT ptCurPos;
  4918. UINT nTipStringID;
  4919. if (!pNM)
  4920. return;
  4921. if (pNM->code == TTN_NEEDTEXTA)
  4922. {
  4923. TOOLTIPTEXTA *pTA = (TOOLTIPTEXTA *)pNM;
  4924. // get id and hwnd
  4925. if( pTA->uFlags & TTF_IDISHWND )
  4926. {
  4927. // idFrom is actually the HWND of the tool
  4928. hwnd = (HWND)pNM->idFrom;
  4929. nID = ::GetDlgCtrlID(hwnd);
  4930. }
  4931. else
  4932. {
  4933. nID = (UINT)pNM->idFrom;
  4934. }
  4935. // get tip string id
  4936. nTipStringID = GetTipId(hwnd, nID);
  4937. if (nTipStringID == 0)
  4938. return;
  4939. // give it to em
  4940. pTA->lpszText = MAKEINTRESOURCE( nTipStringID );
  4941. pTA->hinst = g_hInstance;
  4942. }
  4943. else if (pNM->code == TTN_NEEDTEXTW)
  4944. {
  4945. TOOLTIPTEXTW *pTW = (TOOLTIPTEXTW *)pNM;
  4946. // get id and hwnd
  4947. if( pTW->uFlags & TTF_IDISHWND )
  4948. {
  4949. // idFrom is actually the HWND of the tool
  4950. hwnd = (HWND)pNM->idFrom;
  4951. nID = ::GetDlgCtrlID(hwnd);
  4952. }
  4953. else
  4954. {
  4955. nID = (UINT)pNM->idFrom;
  4956. }
  4957. // get tip string id
  4958. nTipStringID = GetTipId(hwnd, nID );
  4959. if (nTipStringID == 0)
  4960. return;
  4961. // give it to em
  4962. pTW->lpszText = (LPWSTR) MAKEINTRESOURCE( nTipStringID );
  4963. pTW->hinst = g_hInstance;
  4964. }
  4965. }
  4966. //
  4967. // GetTipId()
  4968. // Finds the tooltip for a control in Whiteboard
  4969. //
  4970. UINT WbMainWindow::GetTipId(HWND hwndTip, UINT nID)
  4971. {
  4972. WbTool * pTool;
  4973. BOOL bCheckedState;
  4974. int nTipID;
  4975. int nTipStringID;
  4976. int i;
  4977. // find tip stuff relevant for nID
  4978. nTipID = -1;
  4979. for( i=0; i<((sizeof g_tipIDsArray)/(sizeof (TIPIDS) )); i++ )
  4980. {
  4981. if( g_tipIDsArray[i].nID == nID )
  4982. {
  4983. nTipID = i;
  4984. break;
  4985. }
  4986. }
  4987. // valid?
  4988. if( nTipID < 0 )
  4989. return( 0 );
  4990. // get checked state
  4991. switch( g_tipIDsArray[ nTipID ].nCheck )
  4992. {
  4993. case TB:
  4994. bCheckedState =
  4995. (::SendMessage(m_TB.m_hwnd, TB_ISBUTTONCHECKED, nID, 0) != 0);
  4996. break;
  4997. case BT:
  4998. if (hwndTip != NULL)
  4999. {
  5000. bCheckedState =
  5001. (::SendMessage(hwndTip, BM_GETSTATE, 0, 0) & 0x0003) == 1;
  5002. }
  5003. else
  5004. bCheckedState = FALSE;
  5005. break;
  5006. case NA:
  5007. default:
  5008. bCheckedState = FALSE;
  5009. break;
  5010. }
  5011. // get tip string id
  5012. if( bCheckedState )
  5013. nTipStringID = g_tipIDsArray[ nTipID ].nDownTipID;
  5014. else
  5015. nTipStringID = g_tipIDsArray[ nTipID ].nUpTipID;
  5016. // done
  5017. return( nTipStringID );
  5018. }
  5019. // gets default path if no saves or opens have been done yet
  5020. // Returns FALSE if last default should be reused
  5021. BOOL WbMainWindow::GetDefaultPath(LPTSTR csDefaultPath , UINT size)
  5022. {
  5023. DWORD dwType;
  5024. DWORD dwBufLen = size;
  5025. HKEY hDefaultKey = NULL;
  5026. BOOL bRet =FALSE;
  5027. if( !lstrlen(m_strFileName) )
  5028. {
  5029. // a name has not been picked yet in this session, use path
  5030. // to "My Documents"
  5031. if( (RegOpenKeyEx( HKEY_CURRENT_USER,
  5032. "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
  5033. 0,
  5034. KEY_READ,
  5035. &hDefaultKey )
  5036. != ERROR_SUCCESS) ||
  5037. (RegQueryValueEx( hDefaultKey,
  5038. "Personal",
  5039. NULL,
  5040. &dwType,
  5041. (BYTE *)csDefaultPath,
  5042. &dwBufLen )
  5043. != ERROR_SUCCESS))
  5044. {
  5045. // reg failed, use desktop
  5046. LPITEMIDLIST pidl;
  5047. if(SUCCEEDED(SHGetSpecialFolderLocation(GetDesktopWindow(),CSIDL_DESKTOPDIRECTORY,&pidl)))
  5048. {
  5049. bRet= SHGetPathFromIDList(pidl,csDefaultPath);
  5050. }
  5051. if( hDefaultKey != NULL )
  5052. RegCloseKey( hDefaultKey );
  5053. }
  5054. else
  5055. {
  5056. bRet = TRUE;
  5057. }
  5058. }
  5059. return bRet;
  5060. }
  5061. void WbMainWindow::OnSysColorChange( void )
  5062. {
  5063. if (g_pCurrentWorkspace != NULL)
  5064. {
  5065. PG_ReinitPalettes();
  5066. ::InvalidateRect(m_hwnd, NULL, TRUE );
  5067. ::UpdateWindow(m_hwnd);
  5068. }
  5069. m_TB.RecolorButtonImages();
  5070. m_AG.RecolorButtonImages();
  5071. }
  5072. //
  5073. // posts a do-you-wana-do-that message if other users are in the conference
  5074. //
  5075. BOOL WbMainWindow::UsersMightLoseData( BOOL *pbWasPosted, HWND hwnd )
  5076. {
  5077. if (g_pNMWBOBJ->GetNumberOfMembers() > 0)
  5078. {
  5079. if( pbWasPosted != NULL )
  5080. *pbWasPosted = TRUE;
  5081. return( ::Message(hwnd, IDS_DEFAULT, IDS_MSG_USERSMIGHTLOSE, MB_YESNO | MB_ICONEXCLAMATION ) != IDYES );
  5082. }
  5083. if( pbWasPosted != NULL )
  5084. *pbWasPosted = FALSE;
  5085. return( FALSE );
  5086. }
  5087. //
  5088. //
  5089. // Name: ContentsSave
  5090. //
  5091. // Purpose: Save the contents of the WB.
  5092. //
  5093. // Returns: Error code
  5094. //
  5095. //
  5096. UINT WbMainWindow::ContentsSave(LPCSTR pFileName)
  5097. {
  5098. UINT result = 0;
  5099. UINT index;
  5100. HANDLE hFile;
  5101. ULONG cbSizeWritten;
  5102. T126WB_FILE_HEADER t126Header;
  5103. WB_OBJ endOfFile;
  5104. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::ContentsSave");
  5105. //
  5106. // Open the file
  5107. //
  5108. m_hFile = CreateFile(pFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  5109. FILE_ATTRIBUTE_NORMAL, 0);
  5110. if (m_hFile == INVALID_HANDLE_VALUE)
  5111. {
  5112. result = WB_RC_CREATE_FAILED;
  5113. ERROR_OUT(("Error creating file, win32 err=%d", GetLastError()));
  5114. goto CleanUp;
  5115. }
  5116. //
  5117. // Create the file header.
  5118. //
  5119. memcpy(t126Header.functionProfile, T126WB_FP_NAME,sizeof(T126WB_FP_NAME));
  5120. t126Header.length = sizeof(T126WB_FILE_HEADER) + g_numberOfWorkspaces*sizeof(UINT);
  5121. t126Header.version = T126WB_VERSION;
  5122. t126Header.numberOfWorkspaces = g_numberOfWorkspaces;
  5123. //
  5124. // Save the header
  5125. //
  5126. if (!WriteFile(m_hFile, (void *) &t126Header, sizeof(T126WB_FILE_HEADER), &cbSizeWritten, NULL))
  5127. {
  5128. result = WB_RC_WRITE_FAILED;
  5129. ERROR_OUT(("Error writing length to file, win32 err=%d", GetLastError()));
  5130. goto CleanUp;
  5131. }
  5132. WorkspaceObj* pWorkspace;
  5133. WBPOSITION pos;
  5134. index = 0;
  5135. pos = g_pListOfWorkspaces->GetHeadPosition();
  5136. while(pos)
  5137. {
  5138. pWorkspace = (WorkspaceObj*)g_pListOfWorkspaces->GetNext(pos);
  5139. ASSERT(pWorkspace);
  5140. UINT numberOfObjects = pWorkspace->EnumerateObjectsInWorkspace();
  5141. //
  5142. // Save the number of objects in each page
  5143. //
  5144. if (!WriteFile(m_hFile, (void *) &numberOfObjects, sizeof(numberOfObjects), &cbSizeWritten, NULL))
  5145. {
  5146. result = WB_RC_WRITE_FAILED;
  5147. ERROR_OUT(("Error writing length to file, win32 err=%d", GetLastError()));
  5148. goto CleanUp;
  5149. }
  5150. index++;
  5151. }
  5152. ASSERT(index == g_numberOfWorkspaces);
  5153. //
  5154. // Loop through the pages, saving each as we go
  5155. //
  5156. g_bSavingFile = TRUE;
  5157. ResendAllObjects();
  5158. //
  5159. // The Last Object to be saved is the current workspace
  5160. //
  5161. g_pCurrentWorkspace->OnObjectEdit();
  5162. //
  5163. // If we have successfully written the contents, we write an end-of-page
  5164. // marker to the file.
  5165. //
  5166. ZeroMemory(&endOfFile, sizeof(endOfFile));
  5167. endOfFile.length = sizeof(endOfFile);
  5168. endOfFile.type = TYPE_T126_END_OF_FILE;
  5169. //
  5170. // Write the end-of-file object
  5171. //
  5172. if (!WriteFile(m_hFile, (void *) &endOfFile, sizeof(endOfFile), &cbSizeWritten, NULL))
  5173. {
  5174. result = WB_RC_WRITE_FAILED;
  5175. ERROR_OUT(("Error writing length to file, win32 err=%d", GetLastError()));
  5176. goto CleanUp;
  5177. }
  5178. CleanUp:
  5179. //
  5180. // Close the file
  5181. //
  5182. if (m_hFile != INVALID_HANDLE_VALUE)
  5183. {
  5184. CloseHandle(m_hFile);
  5185. }
  5186. //
  5187. // If an error occurred in saving the contents to file, and the file was
  5188. // opened, then delete it.
  5189. //
  5190. if (result != 0)
  5191. {
  5192. //
  5193. // If the file was opened successfully, delete it
  5194. //
  5195. if (m_hFile != INVALID_HANDLE_VALUE)
  5196. {
  5197. DeleteFile(pFileName);
  5198. }
  5199. }
  5200. g_bSavingFile = FALSE;
  5201. return(result);
  5202. }
  5203. //
  5204. //
  5205. // Name: ObjectSave
  5206. //
  5207. // Purpose: Save a structure to file
  5208. //
  5209. // Returns: Error code
  5210. //
  5211. //
  5212. UINT WbMainWindow::ObjectSave(UINT type, LPBYTE pData, UINT length)
  5213. {
  5214. ASSERT(m_hFile != INVALID_HANDLE_VALUE);
  5215. UINT result = 0;
  5216. ULONG cbSizeWritten;
  5217. WB_OBJ objectHeader;
  5218. objectHeader.length = sizeof(WB_OBJ) + length;
  5219. objectHeader.type = type;
  5220. //
  5221. // Save the Header
  5222. //
  5223. if (! WriteFile(m_hFile, (void *) &objectHeader, sizeof(WB_OBJ), &cbSizeWritten, NULL))
  5224. {
  5225. result = WB_RC_WRITE_FAILED;
  5226. ERROR_OUT(("Error writing length to file, win32 err=%d", GetLastError()));
  5227. goto bail;
  5228. }
  5229. ASSERT(cbSizeWritten == sizeof(WB_OBJ));
  5230. //
  5231. // Save the object data
  5232. //
  5233. if (! WriteFile(m_hFile, pData, length, &cbSizeWritten, NULL))
  5234. {
  5235. result = WB_RC_WRITE_FAILED;
  5236. ERROR_OUT(("Error writing data to file, win32 err=%d", GetLastError()));
  5237. goto bail;
  5238. }
  5239. ASSERT(cbSizeWritten == length);
  5240. bail:
  5241. return result;
  5242. }
  5243. //
  5244. //
  5245. // Function: ContentsLoad
  5246. //
  5247. // Purpose: Load a file and delete the current workspaces
  5248. //
  5249. //
  5250. UINT WbMainWindow::ContentsLoad(LPCSTR pFileName)
  5251. {
  5252. BOOL bRemote;
  5253. UINT result = 0;
  5254. PT126WB_FILE_HEADER_AND_OBJECTS pHeader = NULL;
  5255. //
  5256. // Validate the file, and get a handle to it.
  5257. // If there is an error, then no file handle is returned.
  5258. //
  5259. pHeader = ValidateFile(pFileName);
  5260. if (pHeader == NULL)
  5261. {
  5262. result = WB_RC_BAD_FILE_FORMAT;
  5263. goto bail;
  5264. }
  5265. delete pHeader;
  5266. //
  5267. // Remember if remote pointer is on
  5268. //
  5269. bRemote = FALSE;
  5270. if (m_pLocalRemotePointer)
  5271. {
  5272. // Remove remote pointer from pages
  5273. bRemote = TRUE;
  5274. OnRemotePointer();
  5275. }
  5276. //
  5277. // Just before loading anything delete all the workspaces
  5278. //
  5279. ::InvalidateRect(g_pDraw->m_hwnd, NULL, TRUE);
  5280. DeleteAllWorkspaces(TRUE);
  5281. result = ObjectLoad();
  5282. //
  5283. // Put remote pointer back if it was on
  5284. //
  5285. if (bRemote)
  5286. {
  5287. OnRemotePointer();
  5288. }
  5289. //
  5290. // The workspaces may have being saved as locked
  5291. // Unlock all workspaces, and make sure the drawing area is unlocked
  5292. //
  5293. TogleLockInAllWorkspaces(FALSE, FALSE); // Not locked, don't send updates
  5294. UnlockDrawingArea();
  5295. ResendAllObjects();
  5296. bail:
  5297. if(INVALID_HANDLE_VALUE != m_hFile)
  5298. {
  5299. CloseHandle(m_hFile);
  5300. }
  5301. return(result);
  5302. }
  5303. //
  5304. //
  5305. // Function: ObjectLoad
  5306. //
  5307. // Purpose: Load t126 ASN1 objects from the file
  5308. //
  5309. //
  5310. UINT WbMainWindow::ObjectLoad(void)
  5311. {
  5312. UINT result = 0;
  5313. LPSTR pData = NULL;
  5314. UINT length;
  5315. DWORD cbSizeRead;
  5316. BOOL readFileOk = TRUE;
  5317. WB_OBJ objectHeader;
  5318. while(readFileOk)
  5319. {
  5320. //
  5321. // Read objects header info
  5322. //
  5323. readFileOk = ReadFile(m_hFile, (void *) &objectHeader, sizeof(WB_OBJ), &cbSizeRead, NULL);
  5324. if ( !readFileOk )
  5325. {
  5326. //
  5327. // Make sure we return a sensible error.
  5328. //
  5329. ERROR_OUT(("reading object length, win32 err=%d, length=%d", GetLastError(), sizeof(WB_OBJ)));
  5330. result = WB_RC_BAD_FILE_FORMAT;
  5331. goto bail;
  5332. }
  5333. ASSERT(cbSizeRead == sizeof(WB_OBJ));
  5334. //
  5335. // Read the object's raw data
  5336. //
  5337. length = objectHeader.length - sizeof(WB_OBJ);
  5338. DBG_SAVE_FILE_LINE
  5339. pData = (LPSTR)new BYTE[length];
  5340. readFileOk = ReadFile(m_hFile, (LPBYTE) pData, length, &cbSizeRead, NULL);
  5341. if(! readFileOk)
  5342. {
  5343. //
  5344. // Make sure we return a sensible error.
  5345. //
  5346. ERROR_OUT(("Reading object from file: win32 err=%d, asked for %d got %d bytes", GetLastError(), length, cbSizeRead));
  5347. result = WB_RC_BAD_FILE_FORMAT;
  5348. goto bail;
  5349. }
  5350. ASSERT(cbSizeRead == length);
  5351. //
  5352. // It is an ASN1 t126 object
  5353. //
  5354. if(objectHeader.type == TYPE_T126_ASN_OBJECT)
  5355. {
  5356. //
  5357. // Try decoding and adding it to the workspace
  5358. //
  5359. if(!T126_MCSSendDataIndication(length, (LPBYTE)pData, g_MyMemberID, TRUE))
  5360. {
  5361. result = WB_RC_BAD_FILE_FORMAT;
  5362. goto bail;
  5363. }
  5364. }
  5365. //
  5366. // If it is an end of file do a last check
  5367. //
  5368. else if(objectHeader.type == TYPE_T126_END_OF_FILE)
  5369. {
  5370. if(objectHeader.length != sizeof(WB_OBJ))
  5371. {
  5372. result = WB_RC_BAD_FILE_FORMAT;
  5373. }
  5374. goto bail;
  5375. }
  5376. else
  5377. {
  5378. ERROR_OUT(("Don't know object type =%d , size=%d ; skipping to next object", objectHeader.type, length));
  5379. }
  5380. delete [] pData;
  5381. pData = NULL;
  5382. }
  5383. bail:
  5384. if(pData)
  5385. {
  5386. delete [] pData;
  5387. }
  5388. return(result);
  5389. }
  5390. //
  5391. //
  5392. // Function: ValidateFile
  5393. //
  5394. // Purpose: Open a T126 file and check if it is valid, if it is the it will
  5395. // return a pointer to the header structure
  5396. //
  5397. //
  5398. PT126WB_FILE_HEADER_AND_OBJECTS WbMainWindow::ValidateFile(LPCSTR pFileName)
  5399. {
  5400. UINT result = 0;
  5401. PT126WB_FILE_HEADER pFileHeader = NULL;
  5402. PT126WB_FILE_HEADER_AND_OBJECTS pCompleteFileHeader = NULL;
  5403. UINT length;
  5404. ULONG cbSizeRead;
  5405. BOOL fileOpen = FALSE;
  5406. DBG_SAVE_FILE_LINE
  5407. pFileHeader = new T126WB_FILE_HEADER[1];
  5408. if(pFileHeader == NULL)
  5409. {
  5410. WARNING_OUT(("Could not allocate memory to read the file header opening file, win32 err=%d", GetLastError()));
  5411. result = WB_RC_CREATE_FAILED;
  5412. goto bail;
  5413. }
  5414. //
  5415. // Open the file
  5416. //
  5417. m_hFile = CreateFile(pFileName, GENERIC_READ, 0, NULL,
  5418. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  5419. if (m_hFile == INVALID_HANDLE_VALUE)
  5420. {
  5421. WARNING_OUT(("Error opening file, win32 err=%d", GetLastError()));
  5422. result = WB_RC_CREATE_FAILED;
  5423. goto bail;
  5424. }
  5425. //
  5426. // Show that we have opened the file successfully
  5427. //
  5428. fileOpen = TRUE;
  5429. //
  5430. // Read the file header
  5431. //
  5432. if (! ReadFile(m_hFile, (void *) pFileHeader, sizeof(T126WB_FILE_HEADER), &cbSizeRead, NULL))
  5433. {
  5434. WARNING_OUT(("Error reading file header, win32 err=%d", GetLastError()));
  5435. result = WB_RC_READ_FAILED;
  5436. goto bail;
  5437. }
  5438. if (cbSizeRead != sizeof(T126WB_FILE_HEADER))
  5439. {
  5440. WARNING_OUT(("Could not read file header"));
  5441. result = WB_RC_BAD_FILE_FORMAT;
  5442. goto bail;
  5443. }
  5444. //
  5445. // Validate the file header
  5446. //
  5447. if (memcmp(pFileHeader->functionProfile, T126WB_FP_NAME, sizeof(T126WB_FP_NAME)))
  5448. {
  5449. WARNING_OUT(("Bad function profile in file header"));
  5450. result = WB_RC_BAD_FILE_FORMAT;
  5451. goto bail;
  5452. }
  5453. //
  5454. // Check for version
  5455. //
  5456. if( pFileHeader->version < T126WB_VERSION)
  5457. {
  5458. WARNING_OUT(("Bad version number"));
  5459. result = WB_RC_BAD_FILE_FORMAT;
  5460. goto bail;
  5461. }
  5462. DBG_SAVE_FILE_LINE
  5463. pCompleteFileHeader = (PT126WB_FILE_HEADER_AND_OBJECTS) new BYTE[sizeof(T126WB_FILE_HEADER) + pFileHeader->numberOfWorkspaces*sizeof(UINT)];
  5464. memcpy(pCompleteFileHeader, pFileHeader, sizeof(T126WB_FILE_HEADER));
  5465. //
  5466. // Read the rest of the file header
  5467. //
  5468. if(! ReadFile(m_hFile, (void *) &pCompleteFileHeader->numberOfObjects[0], pFileHeader->numberOfWorkspaces*sizeof(UINT), &cbSizeRead, NULL))
  5469. {
  5470. if(cbSizeRead != pFileHeader->numberOfWorkspaces)
  5471. result = WB_RC_BAD_FILE_FORMAT;
  5472. goto bail;
  5473. }
  5474. TRACE_DEBUG(("Opening file with %d workspaces", pFileHeader->numberOfWorkspaces));
  5475. #ifdef _DEBUG
  5476. INT i;
  5477. for(i = 0; i < (INT)pFileHeader->numberOfWorkspaces; i++)
  5478. {
  5479. TRACE_DEBUG(("Workspace %d contains %d objects", i+1, pCompleteFileHeader->numberOfObjects[i] ));
  5480. }
  5481. #endif
  5482. bail:
  5483. //
  5484. // Close the file if there has been an error
  5485. //
  5486. if ( (fileOpen) && (result != 0))
  5487. {
  5488. CloseHandle(m_hFile);
  5489. m_hFile = INVALID_HANDLE_VALUE;
  5490. }
  5491. //
  5492. // Delete allocated file header
  5493. //
  5494. if(pFileHeader)
  5495. {
  5496. delete [] pFileHeader;
  5497. }
  5498. //
  5499. // if there was an error delete the return header
  5500. //
  5501. if(result != 0)
  5502. {
  5503. if(pCompleteFileHeader)
  5504. {
  5505. delete [] pCompleteFileHeader;
  5506. pCompleteFileHeader = NULL;
  5507. }
  5508. }
  5509. return pCompleteFileHeader;
  5510. }
  5511. //
  5512. //
  5513. // Function: GetFileNameStr
  5514. //
  5515. // Purpose: Return a plain file name string
  5516. //
  5517. //
  5518. LPSTR WbMainWindow::GetFileNameStr(void)
  5519. {
  5520. UINT size = 2*_MAX_FNAME;
  5521. if(m_pTitleFileName)
  5522. {
  5523. delete m_pTitleFileName;
  5524. m_pTitleFileName = NULL;
  5525. }
  5526. DBG_SAVE_FILE_LINE
  5527. m_pTitleFileName = new TCHAR[size];
  5528. if (!m_pTitleFileName)
  5529. {
  5530. ERROR_OUT(("GetWindowTitle: failed to allocate TitleFileName"));
  5531. return(NULL);
  5532. }
  5533. // Set title to either the "Untitled" string, or the loaded file name
  5534. if( (!lstrlen(m_strFileName))|| (GetFileTitle( m_strFileName, m_pTitleFileName, (WORD)size ) != 0) )
  5535. {
  5536. ::LoadString(g_hInstance, IDS_UNTITLED , m_pTitleFileName, 2*_MAX_FNAME);
  5537. }
  5538. return (LPSTR)m_pTitleFileName;
  5539. }
  5540.