// 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 "stdafx.h" 
#include "tipcore.h"
//#include "foxbar.h"

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

static AFX_TIP_DATA afxdata;
//  the draw border styles may be combined

//const   int CX_BORDER= 1;
//const   int CY_BORDER= 1;
#define BORDER_ANY     0x0F00 
#define CX_BORDER  1
#define CY_BORDER  1
/////////////////////////////////////////////////////////////////////////////
// CTipToolBar
CTipToolBar::CTipToolBar()   
            
{
   m_pTip=0; 
   m_nDelayTime=15;
   m_nTimeCount=0;   
   m_bSetTimer=0;
   m_BtnID=0; 
   m_OldBtnID=0; 
}

CTipToolBar::~CTipToolBar()
{
}


void CTipToolBar::FilterTipMessage(MSG *pMsg)
{                                   
 if(m_dwStyle==TWS_TIPS)
 {
  if(pMsg->message==WM_MOUSEMOVE||pMsg->message==WM_NCMOUSEMOVE)
  {    
    if(pMsg->hwnd==GetSafeHwnd())
    { 
      if(!m_bSetTimer )                        
      {              
        m_bSetTimer=1;  
        m_nDelayTime=15;
        SetTimer(m_TimerID,55,NULL);
      } 
    }
    else  
      ReleaseTip(TRUE);
  }
  else if(pMsg->message==WM_KEYDOWN||
          pMsg->message==WM_SYSKEYDOWN||
          pMsg->message==WM_LBUTTONDOWN||
          pMsg->message==WM_MBUTTONDOWN||
          pMsg->message==WM_RBUTTONDOWN||
          pMsg->message==WM_LBUTTONUP||
          pMsg->message==WM_MBUTTONUP||
          pMsg->message==WM_RBUTTONUP)  
       {        
          ReleaseTip();  
       }        
  }        
}

 
BOOL CTipToolBar::Create( CWnd *pParent, UINT ex_Style)
{                        
  m_dwStyle=ex_Style;
  return CToolBar::Create(pParent);
}

void CTipToolBar::SetBackColor(COLORREF colorRef)
{                               
  if(afxdata.g_Brush.GetSafeHandle())
     afxdata.g_Brush.DeleteObject();

  afxdata.g_Brush.CreateSolidBrush(colorRef);   
}
                     
void CTipToolBar::SetDelayTime(int nTimes)
{
  m_nDelayTime=nTimes;
}   

void CTipToolBar::SetTipFont(LOGFONT *logFont)
{                                    
  if(afxdata.g_Font.GetSafeHandle()&&logFont)
     afxdata.g_Font.DeleteObject();           
  if(logFont)                           
    afxdata.g_Font.CreateFontIndirect(logFont);

}                 

void CTipToolBar::ReleaseTip(BOOL bOut/*=0*/)
{       
  CPoint point;
  GetCursorPos(&point);

  if(::WindowFromPoint(point)!=m_hWnd)
	m_OldBtnID=0;
  m_nTimeCount=0;
  
  if(m_pTip)
    if(m_pTip->IsWindowVisible())
       m_pTip->ShowWindow(SW_HIDE);
	 
  CWnd *pWnd=(AfxGetApp()->m_pMainWnd)->GetDlgItem(AFX_IDW_STATUS_BAR);
  if(pWnd)
     pWnd->SetWindowText(" ");
} 

inline AFX_TBBUTTON* CTipToolBar::GetButtonPtr(int nIndex) const
{
	ASSERT(nIndex >= 0 && nIndex < m_nCount);
	ASSERT(m_pData != NULL);
	return ((AFX_TBBUTTON*)m_pData) + nIndex;
}

BEGIN_MESSAGE_MAP(CTipToolBar, CToolBar)
	ON_WM_MOUSEMOVE()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTipToolBar message handler

/* BorderPaint ----------------------------------------------------*/
/*-----------------------------------------------------------------*/
void CTipToolBar::BorderPaint(CDC* pDC)
{
	ASSERT_VALID(this);
	ASSERT_VALID(pDC);

	DWORD dwStyle = GetStyle();
	if (dwStyle & BORDER_ANY)
	{
		// draw border line on sides
		CRect rect;
		GetClientRect(&rect);
		ASSERT(rect.top == 0 && rect.left == 0);
		HBRUSH hbrFrame = CreateSolidBrush(RGB(255,255,255));//GetSysColor(COLOR_WINDOWFRAME));
		if (hbrFrame != NULL)
		{
			HGDIOBJ hOldBrush = pDC->SelectObject(hbrFrame);
			if (hOldBrush != NULL)
			{
				if (dwStyle & CBRS_LEFT)
					pDC->PatBlt(0, 0, CX_BORDER, rect.bottom, PATCOPY);
				if (dwStyle & CBRS_TOP)
					pDC->PatBlt(0, 0, rect.right, CY_BORDER, PATCOPY);
				if (dwStyle & CBRS_RIGHT)
					pDC->PatBlt(rect.right, 0, -CX_BORDER, rect.bottom,
						PATCOPY);
				if (dwStyle & CBRS_BOTTOM)
					pDC->PatBlt(0, rect.bottom, rect.right, -CY_BORDER,
						PATCOPY);
				pDC->SelectObject(hOldBrush);
			}
			DeleteObject(hbrFrame);
		}
	}

}

/* DoPaint --------------------------------------------------------*/
/*-----------------------------------------------------------------*/
void CTipToolBar::DoPaint(CDC* pDC)
{       
	ASSERT_VALID(this);
	ASSERT_VALID(pDC);

//	CControlBar::DoPaint(pDC);      // draw border
    BorderPaint(pDC);
	CRect rect;
	GetClientRect(rect);
	CalcInsideRect(rect);
	// force the full size of the button
	rect.bottom = rect.top + m_sizeButton.cy;

	DrawState ds;
	if (!PrepareDrawButton(ds))
		return;     // something went wrong

	AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
	for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
	{
		ASSERT(pTBB != NULL);
		if (pTBB->nStyle & TBBS_SEPARATOR)
		{
			// separator
			rect.right = rect.left + pTBB->iImage;
		}
		else
		{
			rect.right = rect.left + m_sizeButton.cx;
			if (::RectVisible(pDC->m_hDC, &rect))
			{
				DrawButton(pDC->m_hDC, rect.left, rect.top,
					pTBB->iImage, pTBB->nStyle);
			}
		}
		// adjust for overlap
		rect.left = rect.right - 1;
	}
	EndDrawButton(ds);

}
void CTipToolBar::OnSize(UINT uType, int cx, int cy)
{               
  CToolBar::OnSize(uType, cx, cy);
  GetWindowRect(&m_wndRect);
};

void CTipToolBar::OnTimer(UINT ID)
{               
  if(ID==m_TimerID)
  {      
    int nHit;           
    CPoint point;
    GetCursorPos(&point);
    if((nHit=HitTipTest(point))==HITTYPE_TIP_SUCCESS) 
    {
      m_nTimeCount++;
      if(m_nTimeCount>=m_nDelayTime)
      {    
         if(m_nDelayTime>1)
            m_nDelayTime=1;
         TipProcess(point);
      }   
      
    }  
    else
    {
      ReleaseTip();  
      if(nHit!=HITTYPE_TIP_NOTHING)
      {
         KillTimer(m_TimerID);
         m_bSetTimer=0;
      }   
    }
  }//if(ID==m_TimerID)  
   
}

/* TipProcess -----------------------------------------------------*/
/*-----------------------------------------------------------------*/
void CTipToolBar::TipProcess(CPoint point)
{    
  if(m_OldBtnID==m_BtnID && m_pTip->IsWindowVisible())   
     return;
  else 
  {    
    if(m_OldBtnID==m_BtnID) 
       return;
    m_OldBtnID=m_BtnID;
  }   
     
  ShowTipCard(m_BtnID,point);   
} 
                                         
/* HitTipTest -----------------------------------------------------*/
/*-----------------------------------------------------------------*/
int CTipToolBar::HitTipTest(CPoint point/*screen postion*/)
{
  m_BtnID=(UINT)-1;
    
  if(GetActiveWindow()!=AfxGetApp()->m_pMainWnd)
   	 return HITTYPE_TIP_INACTIVE;

  CWnd* pParent = GetTopLevelParent();
  if(!pParent->IsWindowEnabled())
 	 return HITTYPE_TIP_DISABLED;
        
  HWND hWnd = ::WindowFromPoint(point);
  if(hWnd == NULL || (hWnd != m_hWnd && !::IsChild(m_hWnd, hWnd)))
   	 return HITTYPE_TIP_OUTSIDE;


//	m_BtnID = OnCmdHitTest(point);                                       
//	if(m_BtnID != 0)
//	   return HITTYPE_TIP_SUCCESS;

  ScreenToClient(&point);
	   
  int nHit=HitTest(point);
  if(nHit >= 0)
  {
    AFX_TBBUTTON* pTBB = GetButtonPtr(nHit);
    m_BtnID= pTBB->nID;    
    if(m_BtnID!=ID_SEPARATOR)
      return HITTYPE_TIP_SUCCESS;
  }  

   return HITTYPE_TIP_NOTHING;
	// finally do the hit test on the items within the control bar
}


/* OnCmdHitTest ---------------------------------------------------*/
/*-----------------------------------------------------------------*/
UINT CTipToolBar::OnCmdHitTest(CPoint point)
{
  ASSERT_VALID(this);

	// check child windows first by calling CControlBar
//	::ClientToScreen(m_hWnd, &point);

	// walk through all child windows
	//  (don't use WindowFromPoint, because it ignores disabled windows)
  HWND hWndChild = ::GetWindow(m_hWnd, GW_CHILD);
  while (hWndChild != NULL)
  {
    // see if point is inside window rect of child
    CRect rect;
    ::GetWindowRect(hWndChild, &rect);
    if (rect.PtInRect(point))
    {
      // return positive hit if control ID isn't -1
	  UINT nHit = ::GetDlgCtrlID(hWndChild);
      if (nHit > 0)
	  {
	    return nHit;
	  }
    }
  }//while (hWndChild != NULL)
  hWndChild = ::GetWindow(m_hWnd, GW_HWNDNEXT);

	return 0;    // not found
}

/* ShowTipCard ----------------------------------------------------*/
/*-----------------------------------------------------------------*/
void CTipToolBar::ShowTipCard(UINT ID,POINT point)  
{    
   POINT p;
   CRect rect;
   GetWindowRect(&rect);
   GetCursorPos(&p);
   if(!rect.PtInRect(p))
      return;
                                                      
   if(::GetActiveWindow()!=AfxGetApp()->m_pMainWnd->m_hWnd || ID==0) 
      return;

  CString string;
  CString stringText;

  if(string.LoadString(ID))
    { 
    
      int nIdx=string.Find('\n');  
      
      if(nIdx>=0)
         stringText=string.Mid(0,nIdx);
      else
         return;
         
      CStatusBar *pWnd=(CStatusBar *)AfxGetApp()->m_pMainWnd->
                        GetDescendantWindow(AFX_IDW_STATUS_BAR);
      if(pWnd && stringText.GetLength())
         pWnd->SetWindowText((const char *)stringText);
     
      if(nIdx>=0)
        {           
          stringText=string.Mid(nIdx+1,string.GetLength()-nIdx);
          if(stringText.GetLength())
             DrawContent(stringText,point); 
          else
             return;
        } 
    }  
                                   
}  


void CTipToolBar::DrawContent(LPCSTR lpText,POINT point)
{                  
  
  //char      szText[256];
  //lstrcpy(szText,lpText);
  ASSERT_VALID(this);
  ASSERT_VALID(m_pTip);
  CClientDC dc(m_pTip);
  CFont     font;   

  dc.SelectObject(&afxdata.g_Font);  
  int nWidth=dc.GetTextExtent(lpText,lstrlen(lpText)).cx+15;
  int nHeight=dc.GetTextExtent(lpText,lstrlen(lpText)).cy+4;

  CRect rect,rectWin;
  GetWindowRect(&rect);
  GetParent()->GetWindowRect(&rectWin);
  int y=rect.bottom;//+2; 
  
  int x=point.x-nWidth/2+4;
  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);

  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()-rect.Height();}

  rectTip.top+=2;   
   
//////////////////////////////////////////    
  m_pTip->SetWindowText(lpText);//////////
  m_pTip->SetWindowPos(NULL,//&wndTopMost,
                       rectTip.left,rectTip.top,nWidth,
                       nHeight,
                       SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER);
                         
}

int CTipToolBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CToolBar::OnCreate(lpCreateStruct) == -1)
		return -1;
		
    LOGFONT logFont;
    _fmemset(&logFont,0,sizeof(LOGFONT));
    logFont.lfHeight=14;
    logFont.lfWidth=7;
    logFont.lfWeight=100;
    lstrcpy(logFont.lfFaceName,"System");//"Arail");
                                                  
    CRect rect(0,0,0,0);                                              
	m_pTip = new CTipWnd();
    ((CTipWnd *)m_pTip)->CreateTipWnd(this);

	SetBackColor(RGB(255,255,128));
    SetTipFont(&logFont);
    //SetHeight(m_sizeFixedLayout.cy+2);
    //m_sizeFixedLayout.cy -= 4;
	return 0;
}

void CTipToolBar::OnDestroy()
{                      
    if(m_bSetTimer)
      KillTimer(m_TimerID);                
	m_pTip->DestroyWindow();
	delete m_pTip;
    if(afxdata.g_Brush.GetSafeHandle())
       afxdata.g_Brush.DeleteObject();
    if(afxdata.g_Font.GetSafeHandle())
       afxdata.g_Font.DeleteObject();           

	CToolBar::OnDestroy();
} 
                        

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

CTipWnd::CTipWnd()
{ 
}

CTipWnd::~CTipWnd()
{ 
}
      
BOOL CTipWnd::CreateTipWnd(CWnd *pParent)
{       
 ASSERT(pParent && pParent->m_hWnd); 
 return 
 CreateEx(NULL,
          AfxRegisterWndClass(CS_SAVEBITS|CS_HREDRAW),
          NULL,
          WS_POPUP|WS_BORDER,
	      0,0,0,0,pParent->m_hWnd,0);  

}      

BEGIN_MESSAGE_MAP(CTipWnd, CWnd)
	//{{AFX_MSG_MAP(CTipStstic)
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTStstic message handlers
void CTipWnd::OnPaint()
{
  CPaintDC dc(this); // device context for painting
	// TODO: Add your message handler code here 
  GetWindowText(m_stringText);	
  CRect rect;
  dc.SaveDC();
  dc.SelectObject(&afxdata.g_Font);
  GetClientRect(&rect);
  dc.FillRect(&rect,&afxdata.g_Brush);      
  dc.SetBkMode(TRANSPARENT);
  dc.DrawText((const char *)m_stringText,m_stringText.GetLength(),
              &rect,DT_CENTER|DT_VCENTER);
  dc.RestoreDC(-1);

}

