home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / mslang / ttips2 / tooltip.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-13  |  13.2 KB  |  484 lines

  1. #include "stdafx.h"
  2. #include "tooltip.h"
  3. #include "popuptip.h"
  4. #include "resource.h"
  5. #include <afxpriv.h>
  6.  
  7. #ifdef _DEBUG
  8. #undef THIS_FILE
  9. static char BASED_CODE THIS_FILE[] = __FILE__;
  10. #endif
  11.  
  12. IMPLEMENT_DYNAMIC(CToolTipBar, CToolBar)
  13.  
  14. #define new DEBUG_NEW 
  15.  
  16. BEGIN_MESSAGE_MAP(CToolTipBar, CToolBar)
  17.     //{{AFX_MSG_MAP(CToolTipBar)
  18.     ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
  19.     ON_WM_LBUTTONDOWN()
  20.     ON_WM_LBUTTONUP()
  21.     //}}AFX_MSG_MAP
  22. END_MESSAGE_MAP()
  23.  
  24. CToolTipBar::CToolTipBar()
  25. {   
  26.     m_bDirty = FALSE;    // haven't done a tip window
  27.     m_dwTicks = 0;        // haven't moved over toolbar
  28.     m_uIdCache = 0;        // no previous toolbar button
  29.     m_pPopup = NULL;    // no tip window displayed (or created)
  30.     m_strPopupClassName = ::AfxRegisterWndClass(CS_SAVEBITS,
  31.                           ::AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  32.                           
  33.     m_pFont = new CFont;
  34.     if (m_pFont)
  35.         SetupFont();
  36.         
  37.     GetToolbarOptions();
  38.     m_bMousePressed = FALSE;
  39. }
  40.  
  41. CToolTipBar::~CToolTipBar()
  42. {
  43.     WriteToolbarOptions();
  44.     if (m_pFont)
  45.         delete m_pFont;
  46.     m_pIDXCustom.RemoveAll();
  47. }
  48.                           
  49. void CToolTipBar::SetupFont()
  50. {
  51.     CFont*   pTipFont;
  52.     LOGFONT  lf;
  53.     
  54.     if (!m_pFont)
  55.         return;
  56.         
  57.     pTipFont = CFont::FromHandle((HFONT)::GetStockObject(SYSTEM_FONT));
  58.     pTipFont->GetObject(sizeof(LOGFONT), &lf);
  59.    
  60.     lf.lfHeight -= 2;
  61.     lf.lfWidth = 0;
  62.     lf.lfWeight = FW_NORMAL;
  63.     
  64.     if (!m_bSystemFont)    
  65.         lstrcpy(lf.lfFaceName,"MS Sans Serif");
  66.     
  67.     m_pFont->DeleteObject();
  68.     if (!m_pFont->CreateFontIndirect(&lf)) {
  69.         delete m_pFont;
  70.         m_pFont = NULL;
  71.     }
  72. }
  73.  
  74. void CToolTipBar::AddCustomButton(UINT nIDXControl)
  75. {
  76.     m_pIDXCustom.Add(nIDXControl);
  77. }
  78.  
  79. BOOL CToolTipBar::DoIdle(LONG lCount)
  80. {
  81.     CWnd* pMain = AfxGetMainWnd();
  82.  
  83. // If our window is disabled, iconic, we have disable tips, or the mouse
  84. // is pressed, or it not our specific instance ... get out of here ...    
  85.     if (!pMain->IsWindowEnabled() ||
  86.          pMain->IsIconic() ||
  87.         !IsWindowVisible() ||
  88.         !(m_bFlyby | m_bTips) || m_bMousePressed ||
  89.         !(AfxGetInstanceHandle() ==
  90.         (HINSTANCE)::GetWindowWord(::GetActiveWindow(),GWW_HINSTANCE)) ) {
  91.         CleanDirty(TRUE);
  92.         return FALSE;
  93.     }
  94. //   
  95. // Get the location of the mouse, see if it is over my toolbar window
  96. //
  97.     POINT ptCur;
  98.     GetCursorPos(&ptCur);  
  99.     
  100.     RECT rcSelf;   
  101.     GetWindowRect(&rcSelf);
  102.     if (!PtInRect(&rcSelf, ptCur)) {                            
  103.         CleanDirty(TRUE);
  104.         return FALSE;
  105.     }   
  106. //
  107. // This test makes sure that we do not popup tool tips over the top of any
  108. // non-modal windows which are overlapping our current button.  Basically,
  109. // if the mouse is pointing at a window that is not ours, we're gonna
  110. // get lost ... the actual test is done later after the uId for a custom
  111. // dialog item is found (if there is one), but we have to do this test
  112. // before doing ScreenToClient
  113. //
  114.     BOOL bNotOurWindow = FALSE;
  115.     HWND hMouseWindow = ::WindowFromPoint(ptCur);
  116.     ScreenToClient(&ptCur);
  117. //
  118. // First check to see if we're in any 
  119. // customer control area, such as a COMBOBOX
  120. // We have stored the index into the toolbar of the separator where
  121. // a control is (I.E., a COMBOBOX).  With the index we can get the command
  122. // that the box represents.
  123. //
  124.     BOOL bCustom = FALSE;
  125.     int  nIdx;
  126.     
  127.     if  (m_pIDXCustom.GetSize() > 0) {
  128.         // Test each custom button
  129.         CRect rect;
  130.         for (int i = 0 ; i < m_pIDXCustom.GetSize(); ++i) {
  131.             GetItemRect(m_pIDXCustom[i], &rect);  // Get button's rect
  132.             if (rect.PtInRect(ptCur))  {         // It this where we are?
  133.                 nIdx = m_pIDXCustom[i];           // then use it's ID
  134.                 bCustom = TRUE;                  // and tell the world we got one.
  135.                 break;
  136.             }
  137.         }
  138.     }
  139. //
  140. // If it is not a custom area and not our window then we don't want to 
  141. // display a tip, even if the mouse is on top of our window.  There is 
  142. // probably someone else (a non-modal dialog perhaps) on top of us.
  143. //    
  144.     if (!bCustom)
  145.         nIdx =  HitTest(ptCur);
  146.  
  147.     TRACE1("\nHitest found index: %d",nIdx);
  148.     if (nIdx == -1) {
  149.         CleanDirty(FALSE);    // Don't blank out the cache cause we're
  150.         if (m_uIdCache > 0) // still on the toolbar (just not on a button)
  151.             m_uIdCache = -1;// In case they go back to the previous button
  152.         return FALSE;        // not over a button
  153.     }   
  154.    
  155.     UINT uId;
  156.     UINT uStyle;
  157.     int nImage;
  158.          
  159.     GetButtonInfo(nIdx, uId, uStyle, nImage);
  160. //
  161. // If we think we're doing a custom control but we're not in our window 
  162. //    or
  163. // we think we're doing a button and we're not in the button's window ...
  164. //
  165.        if ((bCustom &&
  166.            (hMouseWindow != GetDlgItem(uId)->GetSafeHwnd())) ||
  167.            (!bCustom && (hMouseWindow != GetSafeHwnd()))) {
  168.         CleanDirty(TRUE);
  169.         return FALSE;
  170.     }
  171. //    
  172. // If we're on the same button then we don't need to do this again   
  173. //
  174.     if (uId == m_uIdCache) {
  175.         m_dwTicks = 0;
  176.         return FALSE;
  177.     }
  178.     DWORD dwNow = GetTickCount();
  179.     
  180.     //did we just move over a different button        
  181.     if (m_uIdCache && (uId != m_uIdCache)) {
  182.         CleanDirty(TRUE);
  183.         dwNow = m_nWait + m_dwTicks; // no sense in waiting again
  184.     }
  185.     
  186.     if (m_dwTicks == 0)    
  187.         m_dwTicks = dwNow; 
  188.     //
  189.     // See if enough time has passed or if we are just doing flybys and
  190.     // not popups then do it immediately ...
  191.     //   
  192.     else if (!m_bTips || (dwNow - m_dwTicks) > m_nWait) {
  193.         // it's time to display the tip
  194.         if (m_bFlyby) {
  195.             pMain->PostMessage(WM_SETMESSAGESTRING, uId, (LPARAM)NULL);                           
  196.         }
  197.         m_uIdCache = uId;                                                                             
  198.         m_dwTicks = 0;
  199.         m_bDirty = TRUE; 
  200.         
  201.         if (m_pPopup)
  202.             m_pPopup->PostMessage(WM_CLOSE);   
  203.         m_pPopup = NULL;
  204.          
  205.         if (!m_bTips)
  206.             return FALSE;
  207.          
  208.         char szTipHold[32];  //it's just a tip
  209.        
  210.         //try to get the menu name from parent window's menu
  211.         CMenu *pMenu = GetParent()->GetMenu(); 
  212.  
  213.         if (pMenu
  214.             && (pMenu->GetMenuString(uId, szTipHold, sizeof(szTipHold),
  215.                 MF_BYCOMMAND))) {  
  216.             //put a null at the end just in case it was truncated
  217.             szTipHold[sizeof(szTipHold) -1] = '\0';
  218.          
  219.             //some menu items have ...'s after them, it doesn't look good
  220.             char* pszTab = strstr(szTipHold, "...");
  221.             if (pszTab)
  222.                 *pszTab = '\0';
  223.              
  224.             //look for a tab replace it with a null if found
  225.             pszTab = strchr(szTipHold, '\t');
  226.             if (pszTab)
  227.                 *pszTab = '\0';
  228.              
  229.             //what about & ??
  230.             char *ptr1 = szTipHold;
  231.             char *ptr2 = szTipHold;
  232.             while (*ptr1 != '\0') {
  233.                 if(*ptr1 != '&') {
  234.                     *ptr2 = *ptr1;
  235.                     ++ptr2;
  236.                 }
  237.                 ++ptr1;
  238.             }
  239.             *ptr2 = '\0';
  240.         }
  241.         // Since there was no menu item for this button we will attempt to
  242.         // get a string table entry for it.  If one is there then the way
  243.         // this works is it looks for the tip somewhere in the line in ()s
  244.         // e.g., Change to (Bold) font   ... display Bold as the tip
  245.         // otherwise it just grabs the first word
  246.         else {
  247.             char szTipWork[64]; // temp string buffer
  248.             
  249.             TRACE1("\nAttempt to LoadString(%d)",uId);
  250.             if (::LoadString(::AfxGetInstanceHandle(),
  251.                     uId,
  252.                     szTipWork, // These messages may be longer
  253.                     sizeof(szTipWork)) ) {
  254.                     
  255.                 TRACE1("\nString Loaded (%s)",szTipWork);
  256.                 char *ptr1, *ptr2;
  257.                 if ((ptr1 = strchr (szTipWork,'(')) != NULL) {
  258.                     ++ptr1;
  259.                     if ((ptr2 = strchr (szTipWork, ')')) != NULL)
  260.                         *ptr2 = '\0';
  261.                 }
  262.                 else {
  263.                     ptr1 = szTipWork;
  264.                     if ((ptr2 = strchr (szTipWork, ' ')) != NULL)
  265.                         *ptr2 = '\0';
  266.                 }
  267.                 strncpy (szTipHold, ptr1, sizeof(szTipHold) - 1);
  268.                 szTipHold[sizeof(szTipHold) -1] = '\0';
  269.             }
  270.             else
  271.                 strcpy(szTipHold,"Not Defined");
  272.         }
  273.         
  274.         m_pPopup = new CPopupTip (m_strPopupClassName);
  275.         if (!m_pPopup) // can't popup window
  276.             return TRUE;
  277.          
  278.         m_pPopup->SetDisplay(szTipHold);
  279.         m_pPopup->SetFont(m_pFont);
  280.       
  281.         GetItemRect(nIdx, &rcSelf);
  282.         ClientToScreen(&rcSelf);
  283.         
  284.         // this will display the popup window
  285.         m_pPopup->PopItUp(GetBoxPosition(rcSelf), m_nStyleFlag);
  286.     }  
  287.     return TRUE;
  288. }                      
  289.                                                                              
  290. LRESULT CToolTipBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM lParam)
  291. {    
  292.     if (DoIdle(0))
  293.        PostMessage(NULL);  // pump myself a message - not ready to sleep
  294.    return CToolBar::OnIdleUpdateCmdUI(wParam, lParam);
  295. }
  296.  
  297. void CToolTipBar::SetTipWait (UINT nNewWait = TTIPS_DEFAULT_TIME)
  298. {
  299.     m_nWait = nNewWait;
  300. }
  301.  
  302. void CToolTipBar::SetToolbarDisplay (BOOL bNewToolbarDisplay = TRUE)
  303.     m_bToolbarDisplay = bNewToolbarDisplay;  
  304.     ShowWindow( m_bToolbarDisplay ? SW_SHOW : SW_HIDE );
  305. }
  306.  
  307. void CToolTipBar::SetFlyby (BOOL bNewFlyby = TRUE)
  308. {
  309.     m_bFlyby = bNewFlyby;
  310. }
  311.  
  312. void CToolTipBar::SetTips (BOOL bNewTips = TRUE)
  313. {
  314.     m_bTips = bNewTips;
  315. }
  316.  
  317. void CToolTipBar::SetTipStyle (UINT nNewStyle = TTIPS_SQUARESTYLE)
  318. {
  319.     m_nStyleFlag = nNewStyle;
  320. }
  321.         
  322. void CToolTipBar::SetTipFont (BOOL bNewSystemFont = TRUE)
  323. {
  324.     m_bSystemFont = bNewSystemFont;
  325.     SetupFont();
  326. }
  327.  
  328. UINT CToolTipBar::GetTipWait ()
  329. {
  330.     return m_nWait;
  331. }
  332.  
  333. BOOL CToolTipBar::GetFlyby ()
  334. {
  335.     return m_bFlyby;
  336. }
  337.  
  338. BOOL CToolTipBar::GetTips ()
  339. {
  340.     return m_bTips;
  341. }
  342.  
  343. UINT CToolTipBar::GetTipStyle ()
  344. {
  345.     return m_nStyleFlag;
  346. }   
  347.  
  348. BOOL CToolTipBar::GetTipFont ()
  349. {
  350.     return m_bSystemFont;
  351. }
  352.  
  353. BOOL CToolTipBar::GetToolbarDisplay()
  354. {   
  355.     return m_bToolbarDisplay;
  356. }
  357.  
  358. void CToolTipBar::OnLButtonDown(UINT nFlags, CPoint point)
  359. {
  360.     CleanDirty(TRUE);
  361.     m_bMousePressed = TRUE;
  362.     CToolBar::OnLButtonDown(nFlags, point);
  363. }
  364.  
  365. void CToolTipBar::OnLButtonUp(UINT nFlags, CPoint point)
  366. {
  367.     m_bMousePressed = FALSE;
  368.     CToolBar::OnLButtonUp(nFlags, point);
  369. }
  370.  
  371. void CToolTipBar::CleanDirty(int ClearCache)
  372. {
  373.     if (m_bDirty) {
  374.         AfxGetApp()->m_pMainWnd->PostMessage(WM_SETMESSAGESTRING,
  375.             AFX_IDS_IDLEMESSAGE, (LPARAM)NULL);                           
  376.         m_bDirty = FALSE;
  377.         if (m_pPopup) {
  378.             m_pPopup->PostMessage(WM_CLOSE);
  379.             m_pPopup = NULL;
  380.         }   
  381.     }
  382.     if (ClearCache)
  383.         m_uIdCache = 0;
  384.     m_dwTicks = 0;                                                                             
  385. }
  386.  
  387. void CToolTipBar::GetToolbarOptions()
  388. {
  389. //
  390. // Get current tip information from the app.ini file (if it is there)
  391. //
  392.     CWinApp *pApp = AfxGetApp();   
  393.  
  394.     m_bFlyby = pApp->GetProfileInt(SZTIPINI_SECTION, SZTIPINI_FLYBY, 1);
  395.     m_bTips = pApp->GetProfileInt(SZTIPINI_SECTION, SZTIPINI_TIPS, 1);
  396.     m_nStyleFlag = pApp->GetProfileInt(SZTIPINI_SECTION, SZTIPINI_ROUND, TTIPS_SQUARESTYLE);
  397.     m_nWait = pApp->GetProfileInt(SZTIPINI_SECTION, SZTIPINI_WAIT, TTIPS_DEFAULT_TIME);
  398.     m_bToolbarDisplay = pApp->GetProfileInt(SZTIPINI_SECTION, SZTIPINI_DISPLAY, 1);
  399.     m_bSystemFont = pApp->GetProfileInt(SZTIPINI_SECTION, SZTIPINI_FONT, 0);
  400. }
  401.  
  402. void CToolTipBar::WriteToolbarOptions()
  403. {
  404. //        
  405. // Write the current settings back to the app.ini file
  406. //
  407.     CWinApp *pApp = AfxGetApp();   
  408.  
  409.     pApp->WriteProfileInt(SZTIPINI_SECTION, SZTIPINI_FLYBY, m_bFlyby ? 1:0);
  410.     pApp->WriteProfileInt(SZTIPINI_SECTION, SZTIPINI_TIPS, m_bTips ? 1:0);
  411.     pApp->WriteProfileInt(SZTIPINI_SECTION, SZTIPINI_ROUND, m_nStyleFlag);
  412.     pApp->WriteProfileInt(SZTIPINI_SECTION, SZTIPINI_WAIT, m_nWait);
  413.     pApp->WriteProfileInt(SZTIPINI_SECTION, SZTIPINI_DISPLAY,
  414.          m_bToolbarDisplay ? 1:0);
  415.     pApp->WriteProfileInt(SZTIPINI_SECTION, SZTIPINI_FONT,
  416.          m_bSystemFont ? 1:0);
  417. }
  418.  
  419. POINT CToolTipBar::GetBoxPosition(CRect rcSelf)
  420. {   
  421. //
  422. // Cursor pointer bitmap structure ...
  423. // The memory location contains this structure first then the actual bitmap
  424. //
  425.     struct CURSOR_INFO {
  426.         POINT pntHotSpot;
  427.         WORD nWidth;
  428.         WORD nHeight;
  429.         BYTE byPlanes;
  430.         BYTE byBitsPix;
  431.     } CursorInfo;
  432.     
  433.     POINT pBoxPosition, ptCur;
  434.     GetCursorPos(&pBoxPosition);  
  435.     ptCur = pBoxPosition;
  436.     
  437.     HCURSOR hcur = GetCursor();
  438.     
  439.     void far *pcurmem = LockResource ((HGLOBAL) hcur);
  440.     if(pcurmem == NULL)
  441.         return pBoxPosition; // Couldn't lock resource ...
  442.         
  443.     long far *prows = (long far*) pcurmem + 3;
  444.     CursorInfo = *(struct CURSOR_INFO far*) pcurmem;
  445.     UINT i = 0;
  446. //
  447. // There are 12 bytes in the header info and the bitmap follows.  We
  448. // are looking up from the bottom to see where to put the tooltip box.
  449. // 1 bit == 1 pixel so
  450. // 4 bytes == 1 row of 32 pixels
  451. // That's why I use a long for each row
  452. //    
  453.     for (i=CursorInfo.nHeight - 1; i >= 0; i--) {
  454.         if (*(prows+i) != 0xffffffff)
  455.             break; // found some bits eh ...
  456.     }
  457.     pBoxPosition.y += (i + 1);
  458. //
  459. // Need to check to see if the box is going to be off the screen on the
  460. // bottom.  Then move the box to the top of the toolbar button if it is
  461. // not going to fit on the screen otherwise.
  462. //        
  463.     int ScreenBottom = GetSystemMetrics(SM_CYSCREEN);
  464.     if ((pBoxPosition.y + CursorInfo.nHeight) > (WORD)ScreenBottom) {
  465.     
  466.         LOGFONT lf;
  467.         m_pFont->GetObject(sizeof(LOGFONT),&lf);
  468.  
  469.         pBoxPosition = rcSelf.TopLeft();
  470.         pBoxPosition.x = ptCur.x;
  471.         
  472.         // back off size of text plus 5 for frame and just to space it a bit
  473.         pBoxPosition.y -= (lf.lfHeight + 5);
  474.         if (m_nStyleFlag == TTIPS_3DSTYLE)
  475.             pBoxPosition.y -= 5;
  476.         if (m_bSystemFont == TRUE)
  477.             pBoxPosition.y -= 2; // This font is just slightly larger
  478.     }        
  479.     UnlockResource ((HGLOBAL) hcur);
  480.     return pBoxPosition;    
  481. }
  482.  
  483.