home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 19.ddi / MFC / SAMPLES / SPEAKN / SPEAKN.CP_ / SPEAKN.CP
Encoding:
Text File  |  1993-02-08  |  8.2 KB  |  297 lines

  1. // speakn.cpp : Defines the class behaviors for the SpeakN application.
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992 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 Microsoft
  9. // QuickHelp and/or WinHelp documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12. //
  13.  
  14. #include "stdafx.h"
  15.  
  16. #include "speakn.h"
  17. #include <mmsystem.h>
  18.  
  19. /////////////////////////////////////////////////////////////////////////////
  20. // Sound helpers
  21.  
  22. static void PlaySound(LPCSTR lpszSound)
  23. {
  24.     HRSRC hRes; // resource handle to wave file
  25.     HGLOBAL hData;
  26.     BOOL bOk = FALSE;
  27.     if ((hRes = ::FindResource(AfxGetResourceHandle(), lpszSound,
  28.       "sound")) != NULL &&
  29.       (hData = ::LoadResource(AfxGetResourceHandle(), hRes)) != NULL)
  30.     {
  31.         // found the resource, play it
  32.         bOk = sndPlaySound((LPCSTR)::LockResource(hData),
  33.             SND_MEMORY|SND_SYNC|SND_NODEFAULT);
  34.         FreeResource(hData);
  35.     }
  36.     if (!bOk)
  37.     {
  38.         static BOOL bReported = FALSE;
  39.         if (!bReported)
  40.         {
  41.             AfxMessageBox("Cannot play sound.\n"
  42.                 "This demo works much better with a sound card.");
  43.             bReported = TRUE;       // once please
  44.         }
  45.     }
  46. }
  47.  
  48. inline static void PlaySound(UINT nIDS)
  49.     { PlaySound(MAKEINTRESOURCE(nIDS)); }
  50.  
  51. /////////////////////////////////////////////////////////////////////////////
  52. // CSpeakNDlg
  53.  
  54. CSpeakNDlg::CSpeakNDlg(BOOL bNoPen)
  55.     : CDialog(bNoPen ? IDD_NOPENDIALOG : CSpeakNDlg::IDD)
  56. {
  57.     m_bNoPen = bNoPen;
  58.     m_lpszNextQuestion = NULL;
  59.     m_bNoAnswerCheck = FALSE;
  60. }
  61.  
  62. BEGIN_MESSAGE_MAP(CSpeakNDlg, CDialog)
  63.     //{{AFX_MSG_MAP(CSpeakNDlg)
  64.     ON_COMMAND(IDC_REPLAY_SOUND, OnReplaySound)
  65.     ON_COMMAND(IDC_GIVE_UP, OnGiveUp)
  66.     ON_COMMAND(IDC_PICTURE, OnReplaySound)
  67.     ON_EN_CHANGE(IDC_INPUT_EDIT, OnUpdateStatus)
  68.     //}}AFX_MSG_MAP
  69. END_MESSAGE_MAP()
  70.  
  71. BOOL CSpeakNDlg::LoadLesson(LPCSTR lpLessonName)
  72. {
  73.     // load lesson from resource
  74.     HRSRC hRes; // resource handle to lesson data
  75.     HGLOBAL hData;
  76.     if ((hRes = ::FindResource(AfxGetResourceHandle(), lpLessonName,
  77.       "lesson")) == NULL ||
  78.       (hData = ::LoadResource(AfxGetResourceHandle(), hRes)) == NULL)
  79.         return FALSE;
  80.     m_lpszNextQuestion = (LPCSTR)::LockResource(hData);
  81.     return TRUE;
  82. }
  83.  
  84. BOOL CSpeakNDlg::OnInitDialog()
  85. {
  86.     ASSERT(m_targetWord.IsEmpty());     // not started yet
  87.  
  88.     // set the font of the prompt text to something bigger
  89.     LOGFONT logfont;
  90.     memset(&logfont, 0, sizeof(logfont));
  91.     logfont.lfHeight = 40;
  92.     logfont.lfWeight = FW_BOLD;
  93.     strcpy(logfont.lfFaceName, "Arial");        // TrueType font
  94.     VERIFY(m_biggerFont.CreateFontIndirect(&logfont));
  95.     PromptText().SetFont(&m_biggerFont);
  96.     InputEdit().SetFont(&m_biggerFont);
  97.  
  98.     // load the bitmaps for bitmap buttons
  99.     VERIFY(m_replayButton.AutoLoad(IDC_REPLAY_SOUND, this));
  100.     InputEdit().ShowWindow(FALSE);      // start with input disabled
  101.  
  102.     // load initial picture
  103.     VERIFY(m_pictureButton.SubclassDlgItem(IDC_PICTURE, this));
  104.     VERIFY(m_pictureButton.LoadBitmaps("intro", NULL, NULL));
  105.  
  106.     // Make the dialog visible, and update
  107.     ShowWindow(TRUE);       // SHOW_OPENWINDOW
  108.     UpdateWindow();
  109.  
  110.     PlaySound(IDSOUND_WELCOME);
  111.     AdvanceLesson();
  112.     return FALSE;       // focus already set
  113. }
  114.  
  115. void CSpeakNDlg::OnReplaySound()
  116. {
  117.     InputEdit().SetFocus();
  118.     PlaySound(m_targetWord);
  119. }
  120.  
  121. void CSpeakNDlg::OnOK()
  122. {
  123.     // check results
  124.     CString result;
  125.     InputEdit().GetWindowText(result);
  126.     if (result != m_targetWord)
  127.     {
  128.         PlaySound(IDSOUND_INCORRECT);
  129.         AfxMessageBox("Please try again");
  130.         return;
  131.     }
  132.     PlaySound(IDSOUND_CORRECT);
  133.     AdvanceLesson();
  134. }
  135.  
  136. void CSpeakNDlg::OnGiveUp()
  137. {
  138.     PlaySound(IDSOUND_GIVEUP);
  139.     SetAnswerText(m_targetWord);        // show answer
  140.     OnReplaySound();
  141.     AdvanceLesson();
  142. }
  143.  
  144. void CSpeakNDlg::SetAnswerText(const char* psz)
  145. {
  146.     // setting the window text for an edit control will cause EN_CHANGE
  147.     //  control notifications, so we lock them out while setting the
  148.     //  text programmatically
  149.     ASSERT(!m_bNoAnswerCheck);
  150.     m_bNoAnswerCheck = TRUE;
  151.     InputEdit().SetWindowText(psz);
  152.     m_bNoAnswerCheck = FALSE;
  153. }
  154.  
  155. /////////////////////////////////////////////////////////////////////////////
  156. // Advancing to the next lesson
  157.  
  158. void CSpeakNDlg::AdvanceLesson()
  159. {
  160.     if (*m_lpszNextQuestion == '\0')
  161.     {
  162.         // out of questions
  163.         PlaySound(IDSOUND_GOODBYE);
  164.         EndDialog(IDOK);
  165.         return;
  166.     }
  167.     // lesson resource points to 1 keyword string per lesson
  168.     m_targetWord = m_lpszNextQuestion;
  169.     m_lpszNextQuestion += m_targetWord.GetLength() + 1;
  170.     m_targetWord.MakeUpper();       // just in case
  171.     int nBoxes = m_targetWord.GetLength();
  172.  
  173.     PlaySound(IDSOUND_QUESTION);
  174.  
  175.     // draw the picture (bitmap with the same name as the target)
  176.     if (!m_pictureButton.LoadBitmaps(m_targetWord))
  177.     {
  178.         AfxMessageBox("Picture unavailable");
  179.         VERIFY(m_pictureButton.LoadBitmaps("intro", NULL, NULL));
  180.             // go back to the initial bitmap
  181.     }
  182.     m_pictureButton.Invalidate(TRUE);
  183.  
  184.     SetAnswerText("");
  185.     if (m_bNoPen)
  186.     {
  187.         InputEdit().ShowWindow(TRUE);
  188.     }
  189.     else
  190.     {
  191.         // InputEdit() is a CBEdit if PenWindows installed
  192.         CBEdit* pEdit = (CBEdit*)&InputEdit();
  193.  
  194.         m_pictureButton.UpdateWindow();     // draw the picture now
  195.  
  196.         // adjust boxed edit item to be centered and the right size
  197.         CRect rect;         // get edit control size
  198.         pEdit->GetWindowRect(&rect);
  199.         ScreenToClient(&rect);                  // in parent coordinate
  200.         int xMid = (rect.left + rect.right) / 2;
  201.         RC rc;              // get pen input info
  202.         VERIFY(pEdit->GetRC(&rc));
  203.         TEXTMETRIC tm;      // get size of font
  204.         {
  205.             CClientDC dc(this);
  206.             CFont* pOldFont = dc.SelectObject(&m_biggerFont);
  207.             dc.GetTextMetrics(&tm);
  208.             dc.SelectObject(pOldFont);
  209.         }
  210.  
  211.         // set input guides to match big font
  212.         const int xGap = 8;
  213.         const int yGap = 8;
  214.         rc.guide.cHorzBox = nBoxes;
  215.         rc.guide.cxBox = tm.tmMaxCharWidth + tm.tmMaxCharWidth / 3; // 4/3
  216.         rc.guide.cyBox = tm.tmHeight;
  217.         rc.guide.cyBase = tm.tmAscent + yGap;               // uppercase
  218.         int cxEdit = rc.guide.cxBox * nBoxes + yGap;        // extra room for sides
  219.         rect.left = xMid - cxEdit / 2;
  220.         rect.right = xMid + cxEdit / 2;
  221.         rect.bottom = rect.top + tm.tmHeight + yGap;        // extra space
  222.         pEdit->MoveWindow(rect);
  223.         VERIFY(pEdit->SetRC(&rc));
  224.         pEdit->Invalidate(TRUE);
  225.     }
  226.     InputEdit().ShowWindow(TRUE);
  227.  
  228.     OnUpdateStatus();               // set appropriate face
  229.     OnReplaySound();                // ask question
  230. }
  231.  
  232. /////////////////////////////////////////////////////////////////////////////
  233. // Happy face status indicator
  234.  
  235. void CSpeakNDlg::OnUpdateStatus()
  236. {
  237.     CString result;
  238.     InputEdit().GetWindowText(result);
  239.  
  240.     UINT nIDI = IDI_FACE_NEUTRAL;       // default
  241.     if (result == m_targetWord)
  242.         nIDI = IDI_FACE_HAPPIER;        // exact match
  243.     else if (result.IsEmpty())
  244.         nIDI = IDI_FACE_NEUTRAL;        // not started yet
  245.     else if (result[0] == m_targetWord[0])
  246.         nIDI = IDI_FACE_HAPPY;          // first letter correct
  247.     else
  248.         nIDI = IDI_FACE_SAD;            // not even close
  249.     HICON hNew = ::LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(nIDI));
  250.     ASSERT(hNew != NULL);
  251.     ::DestroyIcon(StatusFace().SetIcon(hNew));
  252.     UpdateWindow();                 // draw everything now
  253.  
  254.     if (m_bNoAnswerCheck)
  255.         return;     // don't update
  256.  
  257.     if (nIDI == IDI_FACE_HAPPIER)
  258.     {
  259.         // exact match - automatic advance
  260.         OnReplaySound();
  261.         PlaySound(IDSOUND_CORRECT);
  262.         AdvanceLesson();
  263.     }
  264. }
  265.  
  266. /////////////////////////////////////////////////////////////////////////////
  267. // CSpeakNApp
  268.  
  269. BOOL CSpeakNApp::InitInstance()
  270. {
  271.     SetDialogBkColor();     // grey look
  272.  
  273.     BOOL bNoPen = FALSE;
  274.     // Must have PenWindows installed
  275.     if (GetSystemMetrics(SM_PENWINDOWS) == NULL)
  276.     {
  277.         AfxMessageBox("Microsoft Windows for Pen Computing not present.\n"
  278.             "This demo works much better with a pen input device.");
  279.         bNoPen = TRUE;  // no pen-aware controls
  280.     }
  281.  
  282.     // Creates a simple dialog and do it
  283.     CSpeakNDlg mainDlg(bNoPen);
  284.     if (!mainDlg.LoadLesson("SAMPLE1"))
  285.         return FALSE;
  286.     m_pMainWnd = &mainDlg;
  287.     mainDlg.DoModal();
  288.  
  289.     // that's all, quit app
  290.     ::PostQuitMessage(0);
  291.     return TRUE;
  292. }
  293.  
  294. CSpeakNApp theApp;
  295.  
  296. /////////////////////////////////////////////////////////////////////////////
  297.