// HWTIP.H : Contains HWTIP.DLL implementation and initialization
//             code.
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1995 HW FOX WORKSHOP
// All rights reserved.
//
/////////////////////////////////////////////////////////////////////
//#include <afxwin.h>  
//#include <afxext.h>
#include "stdafx.h"
#include "hwtip.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#undef _POPUP

static BOOL bContinue=0;
static BOOL bInHide=0;
static POINT pointHide;
static POINT pointPos;
/////////////////////////////////////////////////////////////////////////////
// CTipToolBar


CTipToolBar::CTipToolBar()   
            
{
}

CTipToolBar::~CTipToolBar()
{
}
  
                         
BOOL CTipToolBar::Create(      CWnd *pParent,
                         CStatusBar *pStatusBar/*=NULL*/,
                                 int nTotalToolID,
                                UINT uReserve)
{             
  m_uMessage=uReserve;  
  m_pStatusBar=pStatusBar;
  m_pBtnID=NULL;
  m_pBtnEx=NULL;
  m_nCount=nTotalToolID;
  bCapture=0;   
  m_bActive=0;  
  m_nTimeCount=0;
  m_OldID=0;
  m_bOpenWnd=0;
  hMem=0;
  return CToolBar::Create(pParent);
}
BOOL CTipToolBar::SetButtons( UINT far * lpArrayID,int nIDCount,
                              UINT far * lpArrayEx/*=NULL*/)
                             
{                  
 if(lpArrayID==NULL && m_nCount>0)
   {                      
    if(hMem==0)
      {
	    if((hMem=GlobalAlloc(GPTR,m_nCount*sizeof(UINT)*2))==NULL)
	      { 
	       TRACE("Alloc tip memory failure\n");
	       return 0;
	      }
	    m_pBtnID=(UINT far *)GlobalLock(hMem);
	    m_pBtnEx=&m_pBtnID[m_nCount];
	  }  
   } 
 else
   {
	 m_pBtnID=lpArrayID;
	 m_pBtnEx=lpArrayEx;
   }	 
 m_nCount=nIDCount;
 bCapture=0;
 return CToolBar::SetButtons(lpArrayID,nIDCount);
}                           

void CTipToolBar::SetButtonInfo( int nIndex,
                                UINT nID,
                                UINT nStyle,
                                 int iImage,
                                UINT nExID)        // for tip card explaination
{
 if(m_pBtnID && m_pBtnEx)
   {                  
		    m_nCount  =nIndex+1;
	  m_pBtnID[nIndex]=nID;
	  m_pBtnEx[nIndex]=nExID;
		    bCapture  =0;
   }  

 CToolBar::SetButtonInfo(nIndex,nID,nStyle,iImage);
}                           

void CTipToolBar::UpdateBtnInfo(UINT far * lpArrayID,//every button id include
                                                     //separator.
                                int        nIDCount, //how many buttons
                                UINT far * lpArrayEx)//each button 
{
 m_pBtnID=lpArrayID;
 m_pBtnEx=lpArrayEx;
 m_nCount=nIDCount;
 bCapture=0;
}                                                          

BOOL CTipToolBar::PreTranslateMessage(MSG *PMsg)
{                     
 if( PMsg->message == WM_KEYDOWN ||
     PMsg->message == WM_KEYUP ||
     PMsg->message == WM_SYSKEYDOWN||
     PMsg->message == WM_SYSKEYUP )
   { //m_OldID=0;

	   if(bCapture)
	     { ReleaseCapture();
	        bCapture=0;}
	   
	   if(PMsg->message == WM_SYSKEYDOWN && 
	      PMsg->wParam == VK_MENU)
         if(((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
	          MDIGetActive() )
	       {  
            bInHide=1;
            pointHide=pointPos;
            ((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
	        MDIGetActive()->SetFocus();
            ((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
            MDIGetActive()->PostMessage(WM_SYSKEYDOWN,VK_MENU);
           }
	      
	   ReleaseTip();  
	   switch(PMsg->wParam)
	      {
	       case VK_UP:
	       case VK_DOWN:
	       case VK_LEFT:
	       case VK_RIGHT:
	            return 0;
	       default:
	           break;
	      }      
	      
   }
 return CToolBar::PreTranslateMessage(PMsg);
}

void CTipToolBar::ReleaseTip()
{
 m_pTip->ShowWindow(SW_HIDE);
 m_pTip->MoveWindow(0,0,1,1);
 AfxGetApp()->m_pMainWnd->SendMessage(m_uMessage);
}
BEGIN_MESSAGE_MAP(CTipToolBar, CToolBar)
	//{{AFX_MSG_MAP(CTipToolBar)
	ON_WM_MOUSEMOVE()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDOWN()
	ON_WM_MBUTTONUP()
	ON_WM_MBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_RBUTTONDOWN()
	ON_WM_MOUSEACTIVATE()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTipToolBar message handlers                
int CTipToolBar::OnMouseActivate(CWnd * pWnd,UINT nH, UINT nM)
{                                                
 if(nM == WM_MBUTTONDOWN ||
    nM == WM_MBUTTONUP ||
    nM == WM_RBUTTONDOWN||
    nM == WM_RBUTTONUP )  
 {
    bInHide=1;
    pointHide=pointPos;

   if(bCapture)  
     {
      ReleaseCapture();
      bCapture=0;
     }      

   m_nTimeCount=0;
   if(m_bActive)
     {         
      m_bActive=0;
      KillTimer(m_TimerID);  
     } 

   ReleaseTip();
   
   if(m_pStatusBar)
      m_pStatusBar->SetWindowText("");
   
   bContinue=0;  
 }   

 return CToolBar::OnMouseActivate( pWnd, nH, nM);
}
void CTipToolBar::OnKeyDown(UINT nC,UINT nR,UINT nF)
{                                    
 CToolBar ::OnKeyDown(nC, nR, nF);

 if(bCapture)
   { ReleaseCapture();
     bCapture=0;}
/*
  if(m_bActive)
    {         
      m_bActive=0;
      KillTimer(m_TimerID);  
    } 
  m_nTimeCount=0;
  m_pTip->ShowWindow(SW_HIDE);

  if(m_pStatusBar)
     m_pStatusBar->SetWindowText("");
*/
    bInHide=1;
    pointHide=pointPos;
   
  if(((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
	  MDIGetActive() )
	{  
      ((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
	   MDIGetActive()->SetFocus();
       ((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
       MDIGetActive()->PostMessage(WM_KEYDOWN,nC);
    }
}
void CTipToolBar::OnKeyUp(UINT nC,UINT nR,UINT nF)
{
  if(bCapture)
    { ReleaseCapture();
      bCapture=0;}
/*
  m_nTimeCount=0;

  if(m_bActive)
    {         
      m_bActive=0;
      KillTimer(m_TimerID);  
    } 
  m_pTip->ShowWindow(SW_HIDE);
  if(m_pStatusBar)
     m_pStatusBar->SetWindowText("");
*/ 
   m_bKey=1;        
   bInHide=1;
   pointHide=pointPos;

  if(((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
	  MDIGetActive() )
	{  
      ((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
	   MDIGetActive()->SetFocus();
       ((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
       MDIGetActive()->PostMessage(WM_KEYUP,nC);//,
    }
    
  CToolBar ::OnKeyUp(nC, nR, nF);
   
} 

void CTipToolBar::OnTimer(UINT )
{              
 m_nTimeCount++;    
 if(m_nTimeCount>14)
   { 
                            
    if(m_nIdx < UINT(m_nCount) && m_bActive==1)
      {     
	   bInHide=0;    
	   ShowTipCard(m_BtnID,m_Point);
	   bContinue=1;
      }     
    m_nTimeCount=0;
    m_bActive=0;  
    KillTimer(m_TimerID);  
   } 
}

void CTipToolBar::OnLButtonDown(UINT nFlags, CPoint point)
{
/*
   if( m_pBtnID==NULL  ||  m_pBtnEx==NULL)
	   goto exit_lbutton;
*/
    bInHide=1;
    pointHide=pointPos;

   if(bCapture)  
     {
      ReleaseCapture();
      bCapture=0;
     }      

   m_nTimeCount=0;
   if(m_bActive)
     {         
      m_bActive=0;
      KillTimer(m_TimerID);  
     } 

   ReleaseTip();
   
   if(m_pStatusBar)
      m_pStatusBar->SetWindowText("");
   
//   m_OldID=0;
   bContinue=0;
//exit_lbutton:   
   CToolBar::OnLButtonDown(nFlags,point);
}

void CTipToolBar::OnLButtonUp(UINT uFlags,CPoint point)
{
   CToolBar::OnLButtonUp(uFlags,point);

   if( m_pBtnID==NULL  ||  m_pBtnEx==NULL)
	   return;

   if(bCapture)   
     {
      ReleaseCapture();
      bCapture=0;
     } 

   m_nTimeCount=0;
   if(m_bActive)
     {         
      m_bActive=0;
      KillTimer(m_TimerID);  
     } 

   ReleaseTip();
   
   if(m_pStatusBar)
      m_pStatusBar->SetWindowText("");

    bInHide=1;
    pointHide=pointPos;

//   m_OldID=0;  
   bContinue=0; 
}
void CTipToolBar::OnMButtonDown(UINT nFlags, CPoint point)
{
/*
   if( m_pBtnID==NULL  ||  m_pBtnEx==NULL)
	   goto exit_lbutton;
*/
    bInHide=1;
    pointHide=pointPos;

   if(bCapture)  
     {
      ReleaseCapture();
      bCapture=0;
     }      

   m_nTimeCount=0;
   if(m_bActive)
     {         
      m_bActive=0;
      KillTimer(m_TimerID);  
     } 

   ReleaseTip();
   
   if(m_pStatusBar)
      m_pStatusBar->SetWindowText("");
   
//   m_OldID=0;
   bContinue=0;
//exit_lbutton:   
   CToolBar::OnMButtonDown(nFlags,point);
}

void CTipToolBar::OnMButtonUp(UINT uFlags,CPoint point)
{
   CToolBar::OnMButtonUp(uFlags,point);

   if( m_pBtnID==NULL  ||  m_pBtnEx==NULL)
	   return;

   if(bCapture)   
     {
      ReleaseCapture();
      bCapture=0;
     } 

   m_nTimeCount=0;
   if(m_bActive)
     {         
      m_bActive=0;
      KillTimer(m_TimerID);  
     } 

   ReleaseTip();
   
   if(m_pStatusBar)
      m_pStatusBar->SetWindowText("");

    bInHide=1;
    pointHide=pointPos;

//   m_OldID=0;  
   bContinue=0; 
}
void CTipToolBar::OnRButtonDown(UINT nFlags, CPoint point)
{
/*
   if( m_pBtnID==NULL  ||  m_pBtnEx==NULL)
	   goto exit_lbutton;
*/
    bInHide=1;
    pointHide=pointPos;

   if(bCapture)  
     {
      ReleaseCapture();
      bCapture=0;
     }      

   m_nTimeCount=0;
   if(m_bActive)
     {         
      m_bActive=0;
      KillTimer(m_TimerID);  
     } 

   ReleaseTip();
   
   if(m_pStatusBar)
      m_pStatusBar->SetWindowText("");
   
//   m_OldID=0;
   bContinue=0;
//exit_lbutton:   
   CToolBar::OnRButtonDown(nFlags,point);
}

void CTipToolBar::OnRButtonUp(UINT uFlags,CPoint point)
{
   CToolBar::OnRButtonUp(uFlags,point);
   
   if( m_pBtnID==NULL  ||  m_pBtnEx==NULL)
	   return;

   if(bCapture)   
     {
      ReleaseCapture();
      bCapture=0;
     } 

   m_nTimeCount=0;
   if(m_bActive)
     {         
      m_bActive=0;
      KillTimer(m_TimerID);  
     } 

   ReleaseTip();
   
   if(m_pStatusBar)
      m_pStatusBar->SetWindowText("");

    bInHide=1;
    pointHide=pointPos;

//   m_OldID=0;  
   bContinue=0; 
}

void CTipToolBar::OnMouseMove(UINT nFlags, CPoint point)
{
  CToolBar::OnMouseMove(nFlags, point);
  // TODO: Add your message handler code here and/or call default
  UINT ID;       
  pointPos=point;

  if(//nFlags  == MK_LBUTTON ||
	 //nFlags  == MK_MBUTTON ||
	 //nFlags  == MK_RBUTTON ||
	 m_pBtnID==NULL        ||
	 m_pBtnEx==NULL)
	 return;
   
   if(::GetActiveWindow()!=AfxGetApp()->m_pMainWnd->m_hWnd) 
	 {  m_bOpenWnd=1;
	    m_nTimeCount=0;
        bInHide=1; 
        pointHide=pointPos;
	    if(bCapture)
	      { ReleaseCapture();                   
            bCapture=0;}            
	    if(m_bActive)
	      { m_bActive=0;
	        KillTimer(m_TimerID);} 
	    ReleaseTip();
	    if(m_pStatusBar)
	       m_pStatusBar->SetWindowText("");
	     m_OldID=0;              
	     bContinue=0;
	     return;}
   else
	 m_bOpenWnd=0;                                   
	  
//////////////////////////////////////////////////////	  
   CRect rectClient;
   GetClientRect(&rectClient);
	
   if(rectClient.PtInRect(point)==0)
	 {  
	  m_nTimeCount=0;    
	  if(bCapture)
	    { ReleaseCapture();                   
          bCapture=0;}            
	  if(m_bActive)
	    {m_bActive=0;
	     KillTimer(m_TimerID);} 
      ReleaseTip();
	  if(m_pStatusBar)
	     m_pStatusBar->SetWindowText("");
	  m_bKey=0;    
	  bContinue=0;   
	  bInHide=0;
	  m_bTipShow=0;
/*
	    if(((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
	       MDIGetActive())
           ((CMDIFrameWnd *)(AfxGetApp()->m_pMainWnd))->
	        MDIGetActive()->SetFocus();   
*/
	   return;
     }  
//////////////////////////////////////////////////////
   if( bInHide )
     { 
       if( pointHide.x!=pointPos.x ||
           pointHide.y!=pointPos.y )
         {
          bInHide=0;
          m_OldID=0;
         }
       else
       return;  
     }                                             
//////////////////////////////////////////////////////	  
 CRect rect,rectOld,rectOut;             //////////
 int nCount=GetCount();
 GetItemRect(nCount-1,&rectOut);
 for(int i=0;i<nCount;i++)
    { GetItemRect(i,&rect);
      rectOld=rect;
      rect.left+=3;
      rect.right-=3;
      rect.top+=3;
      rect.bottom-=3;
      
      if((!rect.PtInRect(point) && rectOld.PtInRect(point))
          || point.x > rectOut.right)
	    { m_nTimeCount=0;
	      m_OldID=0;
	      if(m_bActive)
		    { m_bActive=0;
		      KillTimer(m_TimerID);} 
		  //if(!bContinue)    
             ReleaseTip();
		  if(m_pStatusBar)
	         m_pStatusBar->SetWindowText("");
	         
	     return;} //end if                   
	       
	     if(rect.PtInRect(point))
	       {ID=GetItemID(i);
	        
		     if(ID==ID_SEPARATOR) 
		       {m_nTimeCount=0;
                if(m_bActive)
				  {m_bActive=0;
				   KillTimer(m_TimerID);}      
                ReleaseTip();
		        if(m_pStatusBar)
	               m_pStatusBar->SetWindowText("");
		        return;}
		      else  
		        {m_bKey=0;
		         
	             if(m_OldID!=ID)
	               {  
	                
	                m_OldID=ID; 
	                m_nTimeCount=0;
		            if(m_bActive==1)
		              {KillTimer(m_TimerID);
		               m_bActive=0; }  
		         
		             m_Point   = point; 
		             m_nIdx    = i;
		             m_BtnID   = ID;

	                if( m_bKey==0)
		              {
		               if(bCapture==0)
						  {SetCapture(); 
						   bCapture=1;
						   m_bTipShow=1;
						   bContinue=0;}

		                
		                if(bContinue)
		                  { m_nTimeCount=12;}
		                   // ShowTipCard(ID,point);
		                   // return;}
		                          
		                if(SetTimer(m_TimerID,55,NULL)==NULL)
	                     {   
	                      return;}//if((SetTimer(m_TimerID,100,NULL)==NULL))
	                    m_bActive = 1;  
	                  }  
		                
		             return;  
	                }//display 
	                
	             return;
		       }     
	       }//if(rect.PtInRect(point))
	   }	   
}

void CTipToolBar::ShowTipCard(UINT ID,POINT point)  
{       
 if(m_bOpenWnd) 
   {m_bOpenWnd=0; 
    return;}  
        
 if(ID==NULL || bInHide) 
    return;  

 if(bCapture==0)
   {SetCapture(); 
    bCapture=1;
    m_bTipShow=1;
    bContinue=0;}
               
 if(!m_bTipShow)              
    return;
    
  SetFocus();  
  point.y+=20;
  char szText[256];   
  CString stringID;
  CString stringEx;
   
  *szText=0;                      
  for(int i=0;i<m_nCount;i++)
     {if(m_pBtnID[i]==ID)
        {if(m_pBtnEx[i]==0)
            return;
         if(!stringEx.LoadString(m_pBtnEx[i]))
            lstrcpy(szText,"No Explain");
         else
            lstrcpy(szText,stringEx.GetBuffer(stringEx.GetLength()));
        }    
 
     }               
         
  if(stringID.LoadString(ID))
     if(m_pStatusBar)                            
        m_pStatusBar->SetWindowText((LPCSTR)stringID.GetBuffer(
                                     stringID.GetLength()));
     
  // if(!bContinue)    
   m_pTip->ShowWindow(SW_HIDE);
   DrawContent(szText,point); 
   AfxGetApp()->m_pMainWnd->SendMessage(m_uMessage);
}    

void CTipToolBar::DrawContent(LPSTR lpText,POINT point)
{ 
  char      szText[256];
  lstrcpyn(szText,lpText,255);
  CDC       *pDC = new CDC;
  CClientDC dc(m_pTip);
  CFont     font;   

   LOGFONT logFont;
  _fmemset(&logFont,0,sizeof(LOGFONT));
  logFont.lfHeight=16;
  logFont.lfWidth=7;
  logFont.lfWeight=200;
  lstrcpy(logFont.lfFaceName,"System");//"Arail");
  font.CreateFontIndirect(&logFont);
  pDC->CreateCompatibleDC(&dc);
  pDC->SaveDC();
  pDC->SelectObject(&font);  
  int nWidth=pDC->GetTextExtent(szText,lstrlen(szText)).cx+15;
  int nHeight=pDC->GetTextExtent(szText,lstrlen(szText)).cy+4;
  

  pDC->RestoreDC(-1);
  pDC->DeleteDC();
  delete pDC;
  CRect rect,rectWin;
  GetClientRect(&rect);
  GetParent()->GetClientRect(&rectWin);
  #ifdef _POPUP
  GetParent()->ClientToScreen(&rectWin);
  int y=rectWin.top+rect.Height()+2; 
  #else
  int y=rectWin.top+rect.Height()+2; 
  #endif
  
  int x=point.x-nWidth/2;
  if(x<0)x=0;                               
  
/////////////////////////////////////////////  
  CRect rectTip,rectFrame,r;///////         
  int cx = GetSystemMetrics(SM_CXSCREEN);
  int cy = GetSystemMetrics(SM_CYSCREEN);
  GetParent()->GetClientRect(&rectFrame);
  GetParent()->ClientToScreen(&rectFrame);
  rectFrame.left=rectFrame.left>=0 ? rectFrame.left : 0;
  rectFrame.right=rectFrame.right<=cx ? rectFrame.right : cx;
  rectFrame.bottom = rectFrame.bottom<=cy ? rectFrame.bottom : cy;
  
  rectTip.SetRect(x,y,x+nWidth,y+nHeight);
  GetParent()->ClientToScreen(&rectTip);
  r=rectTip;
  if(rectTip.left<rectFrame.left)
    { rectTip.left=rectFrame.left;
      rectTip.right=rectTip.left+r.Width();}

  if(rectTip.right>rectFrame.right)
    { rectTip.right=rectFrame.right;
      rectTip.left=rectTip.right-r.Width();}
   
  if(rectTip.bottom>rectFrame.bottom)
    {rectTip.bottom=rectFrame.bottom;
     rectTip.top=rectTip.bottom-r.Height();}

      
#ifndef _POPUP
  GetParent()->ScreenToClient(&rectTip);
#endif      
//////////////////////////////////////////    
  m_pTip->GetContent(szText); ////////////
  m_pTip->MoveWindow(rectTip.left,rectTip.top,nWidth,nHeight);
  m_pTip->ShowWindow(SW_SHOW);
  font.DeleteObject();
}

int CTipToolBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CToolBar::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	CRect rect(0,0,100,100);
	m_pTip = new CTipStatic(GetParent());
	return 0;
}

void CTipToolBar::OnDestroy()
{                         
    if(hMem)
      {GlobalUnlock(hMem);
       GlobalFree(hMem);}

	m_pTip->DestroyWindow;
	delete m_pTip;
	CToolBar::OnDestroy();
	
}

/////////////////////////////////////////////////////////////////////////////
// CTipStstic

CTipStatic::CTipStatic(CWnd *pParent)
{ 
  m_Brush.CreateSolidBrush(RGB(255,255,128));
  
  LOGFONT logFont;
  _fmemset(&logFont,0,sizeof(LOGFONT));
  logFont.lfHeight=14;
  logFont.lfWidth=7;
  logFont.lfWeight=100;
  lstrcpy(logFont.lfFaceName,"System");//"Arail");
  m_Font.CreateFontIndirect(&logFont);
  CRect rect(0,0,100,100);
  DWORD dwStyle=WS_CHILD;
  #ifdef _POPUP
  dwStyle=WS_POPUP;
  #endif
  Create(NULL,dwStyle,rect,pParent,0);
}

CTipStatic::~CTipStatic()
{
 m_Font.DeleteObject();
}      

BEGIN_MESSAGE_MAP(CTipStatic,CButton)//CWnd)// CDialog)
	//{{AFX_MSG_MAP(CTipStstic)
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTStstic message handlers
void CTipStatic::OnPaint()
{
  CPaintDC dc(this); // device context for painting
	// TODO: Add your message handler code here
  CRect rect;
  dc.SaveDC();
  dc.SelectObject(&m_Font);
  dc.SelectObject(&m_Brush);
  GetClientRect(&rect);
  dc.Rectangle(&rect);      
  dc.SetBkMode(TRANSPARENT);
  dc.DrawText(szText,lstrlen(szText),&rect,DT_CENTER);
  dc.RestoreDC(-1);
	// Do not call CWnd::OnPaint() for painting messages
}