home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / general / dlgcbr32 / mdlsmain.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  16.0 KB  |  528 lines

  1. // Dlgcbr32.cpp : Defines the class behaviors for CModelessMain.
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include <afxpriv.h>
  15. #include "mdlsmain.h"
  16.  
  17. #ifdef _DEBUG
  18. #define new DEBUG_NEW
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. /////////////////////////////////////////////////////////////////////////////
  24. // CModelessMain
  25.  
  26. IMPLEMENT_DYNAMIC(CModelessMain, CModelessDialog)
  27.  
  28. BEGIN_MESSAGE_MAP(CModelessMain, CModelessDialog)
  29.     //{{AFX_MSG_MAP(CModelessMain)
  30.     ON_WM_CLOSE()
  31.     ON_WM_PAINT()
  32.     ON_WM_ERASEBKGND()
  33.     ON_WM_QUERYDRAGICON()
  34.     ON_WM_ENTERIDLE()
  35.     ON_WM_INITMENUPOPUP()
  36.     ON_WM_MENUSELECT()
  37.     ON_MESSAGE(WM_SETMESSAGESTRING, OnSetMessageString)
  38.     ON_MESSAGE(WM_POPMESSAGESTRING, OnPopMessageString)
  39.     //}}AFX_MSG_MAP
  40.     ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
  41.     ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
  42.  
  43.     // Standard View menu options
  44.     ON_COMMAND(ID_VIEW_STATUS_BAR, OnStatusBarCheck)
  45.     ON_COMMAND(ID_VIEW_TOOLBAR, OnToolBarCheck)
  46.     ON_UPDATE_COMMAND_UI(ID_VIEW_STATUS_BAR, OnUpdateStatusBarMenu)
  47.     ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR, OnUpdateToolBarMenu)
  48.  
  49.     // Standard status bar mode indicators
  50.     ON_UPDATE_COMMAND_UI(ID_INDICATOR_CAPS, OnUpdateKeyIndicator)
  51.     ON_UPDATE_COMMAND_UI(ID_INDICATOR_NUM, OnUpdateKeyIndicator)
  52.     ON_UPDATE_COMMAND_UI(ID_INDICATOR_SCRL, OnUpdateKeyIndicator)
  53.  
  54. END_MESSAGE_MAP()
  55.  
  56. /////////////////////////////////////////////////////////////////////////////
  57. // CModelessMain Construction/Destruction
  58.  
  59. CModelessMain::CModelessMain()
  60. {
  61.     m_hIcon = NULL;
  62.  
  63.     m_nIDTracking     = 0;
  64.     m_nIDLastMessage  = 0;
  65.  
  66.     m_lpaIDStatusBar  = NULL;
  67.     m_cIDStatusBar    = 0;
  68.  
  69.     m_lpaIDToolBar    = NULL;
  70.     m_cIDToolBar      = 0;
  71.     m_nIDBitmap       = 0;
  72. }
  73.  
  74. CModelessMain::~CModelessMain()
  75. {
  76. }
  77.  
  78. ////////////////////////////////////////////////////////////////////////////
  79. // CModelessMain::Create
  80. //      Create saves away information about the status bar and toolbar,
  81. //      loads the dialog icon, and creates the dialog window.  It assumes
  82. //      the dialog icon has the same resource ID as the dialog template
  83. //      itself.
  84.  
  85. BOOL CModelessMain::Create(UINT nIDTemplate,
  86.                            const UINT FAR* lpaIDStatus, int cIDStatus,
  87.                            const UINT FAR* lpaIDToolbar, int cIDToolbar,
  88.                            UINT nIDBitmap)
  89. {
  90.     m_hIcon = AfxGetApp()->LoadIcon(nIDTemplate);
  91.  
  92.     m_lpaIDStatusBar = lpaIDStatus;
  93.     m_cIDStatusBar   = cIDStatus;
  94.  
  95.     m_lpaIDToolBar   = lpaIDToolbar;
  96.     m_cIDToolBar     = cIDToolbar;
  97.     m_nIDBitmap      = nIDBitmap;
  98.  
  99.     return CModelessDialog::Create(nIDTemplate);
  100. }
  101.  
  102. BOOL CModelessMain::Create(LPCSTR lpszTemplateName,
  103.                            const UINT FAR* lpaIDStatus, int cIDStatus,
  104.                            const UINT FAR* lpaIDToolbar, int cIDToolbar,
  105.                            UINT nIDBitmap)
  106. {
  107.     ASSERT(lpszTemplateName != NULL);
  108.  
  109.     m_hIcon = AfxGetApp()->LoadIcon(lpszTemplateName);
  110.  
  111.     m_lpaIDStatusBar = lpaIDStatus;
  112.     m_cIDStatusBar   = cIDStatus;
  113.  
  114.     m_lpaIDToolBar   = lpaIDToolbar;
  115.     m_cIDToolBar     = cIDToolbar;
  116.     m_nIDBitmap      = nIDBitmap;
  117.  
  118.     return CModelessDialog::Create(lpszTemplateName);
  119. }
  120.  
  121.  
  122. /////////////////////////////////////////////////////////////////////////////
  123. // CModelessMain::OnClose
  124. //      OnClose handles the WM_CLOSE message by posting a WM_QUIT message
  125. //      (so the app shuts down), after performing default processing to
  126. //      actually close the window.
  127.  
  128. void CModelessMain::OnClose()
  129. {
  130.     CModelessDialog::OnClose();
  131.     PostQuitMessage(0);
  132. }
  133.  
  134. /////////////////////////////////////////////////////////////////////////////
  135. // CModelessMain::OnInitDialog
  136. //      OnInitDialog centers the dialog on the screen and creates the status
  137. //      and toolbars.  To make sure the control bars don't overlap any
  138. //      dialog controls, the dialog's client area is expanded by the amount
  139. //      of space required for the control bars.
  140.  
  141. BOOL CModelessMain::OnInitDialog()
  142. {
  143.     CModelessDialog::OnInitDialog();
  144.  
  145.     // Create status bar at the bottom of the dialog window
  146.     if (m_statusBar.Create(this))
  147.     {
  148.         m_statusBar.SetIndicators(m_lpaIDStatusBar, m_cIDStatusBar);
  149.         OnSetMessageString(AFX_IDS_IDLEMESSAGE);
  150.  
  151.         // Make a sunken or recessed border around the first pane
  152.         m_statusBar.SetPaneInfo(0, m_statusBar.GetItemID(0),
  153.             SBPS_STRETCH, NULL );
  154.     }
  155.  
  156.     // Create toolbar at the top of the dialog window
  157.     if (m_toolBar.Create(this))
  158.     {
  159.         m_toolBar.LoadBitmap(m_nIDBitmap);
  160.         m_toolBar.SetButtons(m_lpaIDToolBar, m_cIDToolBar);
  161.     }
  162.  
  163.     m_toolBar.SetBarStyle(m_toolBar.GetBarStyle() |
  164.         CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
  165.  
  166.     // We need to resize the dialog to make room for control bars.
  167.     // First, figure out how big the control bars are.
  168.     CRect rcClientStart;
  169.     CRect rcClientNow;
  170.     GetClientRect(rcClientStart);
  171.     RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST,
  172.                    0, reposQuery, rcClientNow);
  173.  
  174.     // Now move all the controls so they are in the same relative
  175.     // position within the remaining client area as they would be
  176.     // with no control bars.
  177.     CPoint ptOffset(rcClientNow.left - rcClientStart.left,
  178.                     rcClientNow.top - rcClientStart.top);
  179.  
  180.     CRect  rcChild;
  181.     CWnd* pwndChild = GetWindow(GW_CHILD);
  182.     while (pwndChild)
  183.     {
  184.         pwndChild->GetWindowRect(rcChild);
  185.         ScreenToClient(rcChild);
  186.         rcChild.OffsetRect(ptOffset);
  187.         pwndChild->MoveWindow(rcChild, FALSE);
  188.         pwndChild = pwndChild->GetNextWindow();
  189.     }
  190.  
  191.     // Adjust the dialog window dimensions
  192.     CRect rcWindow;
  193.     GetWindowRect(rcWindow);
  194.     rcWindow.right += rcClientStart.Width() - rcClientNow.Width();
  195.     rcWindow.bottom += rcClientStart.Height() - rcClientNow.Height();
  196.     MoveWindow(rcWindow, FALSE);
  197.  
  198.     // And position the control bars
  199.     RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);
  200.  
  201.     // Set the icon for this dialog.  The framework does this automatically
  202.     //  when the application's main window is not a dialog
  203.     SetIcon(m_hIcon, TRUE);         // Set big icon
  204.     SetIcon(m_hIcon, FALSE);        // Set small icon
  205.  
  206.     // Finally, center the dialog on the screen
  207.     CenterWindow();
  208.     return TRUE;
  209. }
  210.  
  211. /////////////////////////////////////////////////////////////////////////////
  212. // CModelessMain::OnPaint
  213. // CModelessMain::OnEraseBkgnd
  214. // CModelessMain::OnQueryDragIcon
  215. //      These functions are used to display a custom icon for the dialog.
  216. //
  217. //      These functions use a technique described in KB article Q87976
  218. //      to display a custom icon for our dialog window.  We assume that
  219. //      the icon has been loaded into m_hIcon.
  220.  
  221. void CModelessMain::OnPaint()
  222. {
  223.     CPaintDC dc(this);
  224.     if (IsIconic() && m_hIcon)
  225.     {
  226.         // Erase the icon background when placed over other app window
  227.         DefWindowProc(WM_ICONERASEBKGND, (WORD)dc.m_hDC, 0L);
  228.  
  229.         // Center the icon
  230.         CRect rc;
  231.         GetClientRect(&rc);
  232.         rc.left = (rc.right - ::GetSystemMetrics(SM_CXICON))/2;
  233.         rc.top  = (rc.bottom - ::GetSystemMetrics(SM_CYICON))/2;
  234.  
  235.         // Draw the icon
  236.         dc.DrawIcon(rc.left, rc.top, m_hIcon);
  237.     }
  238. }
  239.  
  240. BOOL CModelessMain::OnEraseBkgnd(CDC* pDC)
  241. {
  242.     if (IsIconic() && m_hIcon)
  243.         return TRUE;
  244.     else
  245.         return CModelessDialog::OnEraseBkgnd(pDC);
  246. }
  247.  
  248. HCURSOR CModelessMain::OnQueryDragIcon()
  249. {
  250.     return (HCURSOR)m_hIcon;
  251. }
  252.  
  253. /////////////////////////////////////////////////////////////////////////////
  254. // CModelessMain::OnInitMenuPopup
  255. //      OnInitMenuPopup updates the state of items on a popup menu.
  256. //
  257. //      This code is based on CFrameWnd::OnInitMenuPopup.  We assume the
  258. //      application does not support context sensitive help.
  259.  
  260. void CModelessMain::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
  261. {
  262.     if (!bSysMenu)
  263.     {
  264.         ASSERT(pPopupMenu != NULL);
  265.  
  266.         // check the enabled state of various menu items
  267.         CCmdUI state;
  268.         state.m_pMenu = pPopupMenu;
  269.         ASSERT(state.m_pOther == NULL);
  270.  
  271.         state.m_nIndexMax = pPopupMenu->GetMenuItemCount();
  272.         for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
  273.              state.m_nIndex++)
  274.         {
  275.             state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);
  276.             if (state.m_nID == 0)
  277.                 continue; // menu separator or invalid cmd - ignore it
  278.  
  279.             ASSERT(state.m_pOther == NULL);
  280.             ASSERT(state.m_pMenu != NULL);
  281.             if (state.m_nID == (UINT)-1)
  282.             {
  283.                 // possibly a popup menu, route to first item of that popup
  284.                 state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);
  285.                 if (state.m_pSubMenu == NULL ||
  286.                     (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
  287.                     state.m_nID == (UINT)-1)
  288.                 {
  289.                     continue; // first item of popup can't be routed to
  290.                 }
  291.                 state.DoUpdate(this, FALSE);  // popups are never auto disabled
  292.             }
  293.             else
  294.             {
  295.                 // normal menu item
  296.                 // Auto enable/disable if command is _not_ a system command
  297.                 state.m_pSubMenu = NULL;
  298.                 state.DoUpdate(this, state.m_nID < 0xF000);
  299.             }
  300.         }
  301.     }
  302. }
  303.  
  304. /////////////////////////////////////////////////////////////////////////////
  305. // CModelessMain::OnEnterIdle
  306. //      OnEnterIdle updates the status bar when there's nothing better to do.
  307. //      This code is based on CFrameWnd::OnEnterIdle.
  308.  
  309. void CModelessMain::OnEnterIdle(UINT nWhy, CWnd* pWho)
  310. {
  311.     if (nWhy != MSGF_MENU || m_nIDTracking == m_nIDLastMessage)
  312.         return;
  313.  
  314.     OnSetMessageString(m_nIDTracking);
  315.     ASSERT(m_nIDTracking == m_nIDLastMessage);
  316. }
  317.  
  318. /////////////////////////////////////////////////////////////////////////////
  319. // CModelessMain::OnMenuSelect
  320. //      OnMenuSelect updates the status bar message, based on the state
  321. //      of the dialog menu.
  322. //
  323. //      This code is based on CFrameWnd::OnMenuSelect.  We assume the
  324. //      application does not support context sensitive help.
  325.  
  326. void CModelessMain::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
  327. {
  328.     // set the tracking state
  329.     if (nFlags == 0xFFFF)
  330.     {
  331.         // cancel menu operation (go back to idle now)
  332.         m_nIDTracking = AFX_IDS_IDLEMESSAGE;
  333.         OnSetMessageString(m_nIDTracking);  // set string now
  334.         ASSERT(m_nIDTracking == m_nIDLastMessage);
  335.     }
  336.     else if (nItemID == 0 ||
  337.              nFlags & (MF_SEPARATOR|MF_POPUP|MF_MENUBREAK|MF_MENUBARBREAK))
  338.     {
  339.         // nothing should be displayed
  340.         m_nIDTracking = 0;
  341.     }
  342.     else if (nItemID >= 0xF000 && nItemID < 0xF1F0)
  343.     {
  344.         // special string table entries for system commands
  345.         m_nIDTracking = ID_COMMAND_FROM_SC(nItemID);
  346.         ASSERT(m_nIDTracking >= AFX_IDS_SCFIRST &&
  347.                m_nIDTracking < AFX_IDS_SCFIRST + 31);
  348.     }
  349.     else
  350.     {
  351.         // track on idle
  352.         m_nIDTracking = nItemID;
  353.     }
  354. }
  355.  
  356. /////////////////////////////////////////////////////////////////////////////
  357. // CModelessMain::OnSetMessageString
  358. //      OnSetMessageString updates the status bar text.
  359. //
  360. //      This code is based on CFrameWnd::OnSetMessageString.  We assume
  361. //      a string ID is always passed in wParam.
  362.  
  363. LRESULT CModelessMain::OnSetMessageString(WPARAM wParam, LPARAM lParam)
  364. {
  365.     UINT    nIDMsg = (UINT)wParam;
  366.     CString strMsg;
  367.  
  368.     if (nIDMsg)
  369.     {
  370.         if (strMsg.LoadString(nIDMsg) != 0)
  371.             m_statusBar.SetWindowText(strMsg);
  372.         else
  373.             TRACE1("Warning: no message line prompt for ID %x%04X\n", nIDMsg);
  374.     }
  375.  
  376.     UINT nIDLast     = m_nIDLastMessage;
  377.     m_nIDLastMessage = nIDMsg;
  378.     m_nIDTracking    = nIDMsg;
  379.     return nIDLast;
  380.  
  381. }
  382.  
  383. /////////////////////////////////////////////////////////////////////////////
  384. // CModelessMain::OnStatusBarCheck
  385. //      OnStatusBarCheck toggles the status of the status bar when the
  386. //      corresponding View option is selected from the menu.
  387.  
  388. void CModelessMain::OnStatusBarCheck()
  389. {
  390.     m_statusBar.ShowWindow(m_statusBar.IsWindowVisible() ? SW_HIDE : SW_SHOWNA);
  391. }
  392.  
  393. /////////////////////////////////////////////////////////////////////////////
  394. // CModelessMain::OnUpdateStatusBarMenu
  395. //      OnUpdateStatusBarMenu checks or unchecks the View option,
  396. //      depending on whether or not the status bar is visible.
  397.  
  398. void CModelessMain::OnUpdateStatusBarMenu(CCmdUI* pCmdUI)
  399. {
  400.     ASSERT(pCmdUI->m_nID == ID_VIEW_STATUS_BAR);
  401.     pCmdUI->SetCheck(m_statusBar.IsWindowVisible());
  402. }
  403.  
  404. /////////////////////////////////////////////////////////////////////////////
  405. // CModelessMain::OnToolBarCheck
  406. //      OnToolBarCheck toggles the status of the toolbar when the
  407. //      corresponding View option is selected from the menu.
  408.  
  409. void CModelessMain::OnToolBarCheck()
  410. {
  411.     m_toolBar.ShowWindow(m_toolBar.IsWindowVisible() ? SW_HIDE : SW_SHOWNA);
  412. }
  413.  
  414. /////////////////////////////////////////////////////////////////////////////
  415. // CModelessMain::OnUpdateToolBarMenu
  416. //      OnUpdateToolBarMenu checks or unchecks the View option,
  417. //      depending on whether or not the toolbar is visible.
  418.  
  419. void CModelessMain::OnUpdateToolBarMenu(CCmdUI* pCmdUI)
  420. {
  421.     ASSERT(pCmdUI->m_nID == ID_VIEW_TOOLBAR);
  422.     pCmdUI->SetCheck(m_toolBar.IsWindowVisible());
  423. }
  424.  
  425. /////////////////////////////////////////////////////////////////////////////
  426. // CModelessMain::OnUpdateKeyIndicator
  427. //      OnUpdateKeyIndicator enables or disables one of the key indicators
  428. //      in a status bar.  It recognizes the CAPS, NUM, and SCRL keys.
  429.  
  430. void CModelessMain::OnUpdateKeyIndicator(CCmdUI* pCmdUI)
  431. {
  432.     UINT nVK;
  433.  
  434.     switch (pCmdUI->m_nID)
  435.     {
  436.     case ID_INDICATOR_CAPS:
  437.         nVK = VK_CAPITAL;
  438.         break;
  439.  
  440.     case ID_INDICATOR_NUM:
  441.         nVK = VK_NUMLOCK;
  442.         break;
  443.  
  444.     case ID_INDICATOR_SCRL:
  445.         nVK = VK_SCROLL;
  446.         break;
  447.  
  448.     default:
  449.         TRACE1("Warning: OnUpdateKeyIndicator - unknown indicator 0x%04X\n",
  450.             pCmdUI->m_nID);
  451.         pCmdUI->ContinueRouting();
  452.         return; // not for us
  453.     }
  454.  
  455.     pCmdUI->Enable(::GetKeyState(nVK) & 1);
  456.         // enable static text based on toggled key state
  457.     ASSERT(pCmdUI->m_bEnableChanged);
  458. }
  459.  
  460. /////////////////////////////////////////////////////////////////////////////
  461. // CModelessMain::OnPopMessageString
  462. //      Resets status bar message string.  This code is based on
  463. //      CFrameWnd::OnPopMessageString
  464.  
  465. LRESULT CModelessMain::OnPopMessageString(WPARAM wParam, LPARAM lParam)
  466. {
  467.     if (m_nFlags & WF_NOPOPMSG)
  468.         return 0;
  469.  
  470.     return SendMessage(WM_SETMESSAGESTRING, wParam, lParam);
  471. }
  472.  
  473. /////////////////////////////////////////////////////////////////////////////
  474. // CModelessMain::OnToolTipText
  475. //      Handles TTN_NEEDTEXT message to display tooltips for the toolbar.
  476. //      This code is based on CFrameWnd::OnToolTipText
  477.  
  478. BOOL CModelessMain::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
  479. {
  480.     ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
  481.  
  482.     // allow top level routing frame to handle the message
  483.     if (GetRoutingFrame() != NULL)
  484.         return FALSE;
  485.  
  486.     // need to handle both ANSI and UNICODE versions of the message
  487.     TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
  488.     TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
  489.     TCHAR szFullText[256];
  490.     CString strTipText;
  491.     UINT nID = pNMHDR->idFrom;
  492.     if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
  493.         pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
  494.     {
  495.         // idFrom is actually the HWND of the tool
  496.         nID = ((UINT)(WORD)::GetDlgCtrlID((HWND)nID));
  497.     }
  498.  
  499.     if (nID != 0) // will be zero on a separator
  500.     {
  501.         AfxLoadString(nID, szFullText);
  502.             // this is the command id, not the button index
  503.         AfxExtractSubString(strTipText, szFullText, 1, '\n');
  504.     }
  505. #ifndef _UNICODE
  506.     if (pNMHDR->code == TTN_NEEDTEXTA)
  507.         lstrcpyn(pTTTA->szText, strTipText,
  508.             (sizeof(pTTTA->szText)/sizeof(pTTTA->szText[0])));
  509.     else
  510.         _mbstowcsz(pTTTW->szText, strTipText,
  511.             (sizeof(pTTTW->szText)/sizeof(pTTTW->szText[0])));
  512. #else
  513.     if (pNMHDR->code == TTN_NEEDTEXTA)
  514.         _wcstombsz(pTTTA->szText, strTipText,
  515.             (sizeof(pTTTA->szText)/sizeof(pTTTA->szText[0])));
  516.     else
  517.         lstrcpyn(pTTTW->szText, strTipText,
  518.             (sizeof(pTTTW->szText)/sizeof(pTTTW->szText[0])));
  519. #endif
  520.     *pResult = 0;
  521.  
  522.     // bring the tooltip window above other popup windows
  523.     ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
  524.         SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
  525.  
  526.     return TRUE;    // message was handled
  527. }
  528.