📄 autohidebar.cpp
字号:
/////////////////////////////////////////////////////////////////////////
//
// CAutoHideBar Version 1.2
//
// Created: Mar 30, 2004
//
/////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 by Cuick. All rights reserved.
//
// This code is free for personal and commercial use, providing this
// notice remains intact in the source files and all eventual changes are
// clearly marked with comments.
//
// Send bug reports, bug fixes, enhancements, requests, flames, etc. to
// Cuick@163.net
//
// Hint: These classes are intended to be used as base classes. Do not
// simply add your code to these file - instead create a new class
// derived from CDockPageBar classes and put there what you need. See
// CTestBar classes in the demo projects for examples.
// Modify this file only to fix bugs, and don't forget to send me a copy.
/////////////////////////////////////////////////////////////////////////
// Acknowledgements:
//
//////////////////////////////////////////////////////////////////////////
//Updates
//////////////////////////////////////////////////////////////////////////
// Author | Date | Description
//========================================================================
// Tony |2006-09-04 | Bugfixs:
//=======================| 1.add Timer TID_AUTO_HIDE_DELAY to prevent two
//tony__cb@hotmail.com | AHFloatWnds being displayed at the same time.
// | 2.focus switch problems(especially between AHFloatwnd and
// | DockPageBar).
// | 3.frequence screen flash on sizing the DockPageBar.
// | 4.resize the AHFloatWnds with the wider than the mainframe.
// | 5.link problems related with static MFC lib
// | by setting a new compile flag STATIC_MFC_LINK
// | 6.Verify the pWnd's style in CDockPageBar::AddPage function,
// | to make sure pWnd to have the WS_CHILD style, and to avoid
// | the window management disorder in clean up.
// | ------------------------------------------------
// | Improvements and new features:
// | 1.add the slide in/out animation display for AHFloatWnds
// | (the API ::AnimateWindow doesnt work for the self-draw window)
// | 2.make a lot of detail display changes(border,caption bar,...)
// | to have nicer windows
// | 3.add the new docking detection algorithm(accurate docking)
// | just as MS VC2003, but with the limitation that
// | the horizontal docking always has the higher priority.
// | 4.add the support for MDI style Frame
// | 5.rewrite the NcPaint,NcCalClient,OnNcLButtonXXXX,OnNcHitTest part
// | for CDockPageBar to draw the caption(griper),and item tab button
// | in the NcPaint.
// | 6.disable the DragShowContent mode in CSizingControlBar and
// | the OnNcPaint in CDockPageBar when sizing the bar to avoid
// | the dirty & flashy display
#include "stdafx.h"
#include "AutoHideBar.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAHFloatWnd Implementation Start
CAHFloatWnd::CAHFloatWnd()
{
m_font.CreatePointFont(85, "Tahoma");
m_Title = "AutoHideFloatWnd";
m_bCursorInAutoHideBarItem=FALSE;
m_animDispParam.slideStep=0;
m_animDispParam.slideStepCount=0;
m_animDispParam.bInAnimateDisplay=FALSE;
m_animDispParam.timerId=0;
m_activePageItem=NULL;
}
CAHFloatWnd::~CAHFloatWnd()
{
}
BEGIN_MESSAGE_MAP(CAHFloatWnd, CWnd)
//{{AFX_MSG_MAP(CAHFloatWnd)
ON_WM_NCCALCSIZE()
ON_WM_SIZE()
ON_WM_NCPAINT()
ON_WM_NCMOUSEMOVE()
ON_WM_NCHITTEST()
ON_WM_MOUSEACTIVATE()
ON_WM_NCLBUTTONUP()
ON_WM_TIMER()
ON_WM_NCLBUTTONDOWN()
ON_WM_SHOWWINDOW()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
ON_WM_GETMINMAXINFO()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAHFloatWnd message handlers
void CAHFloatWnd::GetBorderWidths(DWORD dwStyle,BORDER_WIDTH & borderWidth)
{
switch(dwStyle&0xFF00)
{
case CBRS_LEFT:
{
borderWidth.cx_left=0;
borderWidth.cx_right=::GetSystemMetrics(SM_CXFRAME);
borderWidth.cy_top=2;
borderWidth.cy_bottom=0;
}
break;
case CBRS_RIGHT:
{
borderWidth.cx_left=::GetSystemMetrics(SM_CXFRAME);
borderWidth.cx_right=1;
borderWidth.cy_top=2;
borderWidth.cy_bottom=0;
}
break;
case CBRS_TOP:
{
borderWidth.cx_left=0;
borderWidth.cx_right=1;
borderWidth.cy_top=2;
borderWidth.cy_bottom=3;
}
break;
case CBRS_BOTTOM:
{
borderWidth.cx_left=0;
borderWidth.cx_right=1;
borderWidth.cy_top=2;
borderWidth.cy_bottom=2;
}
break;
default:
{
borderWidth.cx_left=borderWidth.cx_right=borderWidth.cy_top=borderWidth.cy_bottom=0;
}
break;
}
}
void CAHFloatWnd::StartAnimateDisplay( DWORD dwFlag,DWORD dwTime)
{
m_animDispParam.bInAnimateDisplay=TRUE;
m_animDispParam.slideStepCount=max(1,dwTime/50);
if(TID_SLIDE_IN==dwFlag){
m_animDispParam.slideStep=m_animDispParam.slideStepCount-1;
if(m_activePageItem)
GetWindowRect(&(m_activePageItem->m_lastAHFloatWndRect));
KillTimer(TID_AUTO_HIDE_DELAY);
}else{
SetTimer(TID_AUTO_HIDE_DELAY,AUTO_HIDE_DELAY_TIMES, NULL);
m_animDispParam.slideStep=0;
}
//Reset previous animate display timer
if(m_animDispParam.timerId!=0)
KillTimer(m_animDispParam.timerId);
m_animDispParam.timerId=dwFlag;
SetTimer(dwFlag,50,NULL);
}
void CAHFloatWnd::DoSlideStep()
{
CRect rc(m_animDispParam.rect);
switch(m_dwStyle&CBRS_ALIGN_ANY)
{
case CBRS_ALIGN_LEFT:
rc.OffsetRect((m_animDispParam.slideStep + 1)*rc.Width()/m_animDispParam.slideStepCount-rc.Width(),0);
break;
case CBRS_ALIGN_RIGHT:
rc.OffsetRect(rc.Width()-(m_animDispParam.slideStep + 1)*rc.Width()/m_animDispParam.slideStepCount,0);
break;
case CBRS_ALIGN_TOP:
rc.OffsetRect(0,(m_animDispParam.slideStep + 1)*rc.Height()/m_animDispParam.slideStepCount-rc.Height());
break;
case CBRS_ALIGN_BOTTOM:
rc.OffsetRect(0,rc.Height()-(m_animDispParam.slideStep + 1)*rc.Height()/m_animDispParam.slideStepCount);
break;
}
SetWindowPos(NULL, rc.left, rc.top, rc.Width(), rc.Height(),SWP_NOZORDER|SWP_SHOWWINDOW);
Invalidate(FALSE);
}
void CAHFloatWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)
{
CWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
CRect rc(&lpncsp->rgrc[0]);
BORDER_WIDTH borderWidth;
GetBorderWidths(m_dwStyle,borderWidth);
rc.DeflateRect(-::GetSystemMetrics(SM_CXFRAME),-::GetSystemMetrics(SM_CXFRAME),
-::GetSystemMetrics(SM_CXFRAME),-::GetSystemMetrics(SM_CXFRAME));
rc.DeflateRect(borderWidth.cx_left+1,CAPTION_HEIGHT+borderWidth.cy_top*2+1, borderWidth.cx_right+1,borderWidth.cy_bottom+1);
lpncsp->rgrc[0] = rc;
//Non Clinet coordinate refered to the windows's topleft
m_captionRect.left=borderWidth.cx_left;
m_captionRect.right=m_captionRect.left+rc.Width();
m_captionRect.top=borderWidth.cy_top;
m_captionRect.bottom=m_captionRect.top+CAPTION_HEIGHT;
}
void CAHFloatWnd::OnNcPaint()
{
//CWnd::OnNcPaint();
CWindowDC dc(this);
//Get bounding rect of the client coordinate
CRect rcBar,rect;
GetWindowRect(rcBar);//Screen coordinate
rcBar.OffsetRect (-rcBar.TopLeft ());//Logic coordinate
rect = rcBar;
BORDER_WIDTH borderWidth;
GetBorderWidths(m_dwStyle,borderWidth);
//Draw the flat frame border
//|-----------------------------|
//| |
//| |
//| |
//| |
//|-----------------------------|
rect.right = borderWidth.cx_left;
dc.FillSolidRect(&rect, ::GetSysColor(COLOR_BTNFACE));
//----------------
rect = rcBar;
rect.top = rect.bottom - borderWidth.cy_bottom;
dc.FillSolidRect(&rect, ::GetSysColor(COLOR_BTNFACE));
//|
//|
//|
rect = rcBar;
rect.left = rect.right - borderWidth.cx_right;
dc.FillSolidRect(&rect, ::GetSysColor(COLOR_BTNFACE));
//-----------------
rect=rcBar;
rect.bottom = rect.top + CAPTION_HEIGHT + borderWidth.cy_top*2;
dc.FillSolidRect(&rect, ::GetSysColor(COLOR_BTNFACE));
CRect clientBorderRc=rcBar;
//if (IsHorzDocked())
clientBorderRc.DeflateRect(borderWidth.cx_left,CAPTION_HEIGHT+borderWidth.cy_top*2
,borderWidth.cx_right+1,borderWidth.cy_bottom+1);
//else
// clientBorderRc.DeflateRect(1,CAPTION_HEIGHT,3,3);
CPen penRect(PS_SOLID, 1, RGB(128,128,128));
HPEN oldPen = (HPEN)dc.SelectObject (&penRect);
dc.MoveTo(clientBorderRc.TopLeft());
dc.LineTo(clientBorderRc.right,clientBorderRc.top);
dc.LineTo(clientBorderRc.right,clientBorderRc.bottom);
dc.LineTo(clientBorderRc.left,clientBorderRc.bottom);
dc.LineTo(clientBorderRc.left,clientBorderRc.top);
dc.SelectObject (oldPen);
//Draw the single border 3D side adage
CPen pen1(PS_SOLID,1,RGB(128,128,128)); //DarkGrey
CPen pen2(PS_SOLID,1,RGB(0,0,0)); //Black
CPen pen3(PS_SOLID,1,RGB(255,255,255)); //White
CPen pen4(PS_SOLID,1,::GetSysColor(COLOR_BTNFACE));//LightGrey
HPEN pOldPen=NULL;
switch(m_dwStyle&0xFF00) // CBRS_ALIGN_ANY|CBRS_BORDER_ANY == 0xFF00
{
case CBRS_TOP:
{
pOldPen = (HPEN)dc.SelectObject (&pen2);
CPoint pt=rcBar.BottomRight();
pt.Offset(-2,-1);
dc.MoveTo(pt);
pt.Offset(1-rcBar.Width(),0);
dc.LineTo(pt);
dc.SelectObject (&pen1);
pt=rcBar.BottomRight();
pt.Offset(-2,-2);
dc.MoveTo(pt);
pt.Offset(1-rcBar.Width(),0);
dc.LineTo(pt);
}
break;
case CBRS_LEFT:
{
pOldPen = (HPEN)dc.SelectObject (&pen2);
CPoint pt=rcBar.BottomRight();
pt.Offset(-1,0);
dc.MoveTo(pt);
pt.Offset(0,-rcBar.Height());
dc.LineTo(pt);
dc.SelectObject (&pen1);
pt=rcBar.BottomRight();
pt.Offset(-2,0);
dc.MoveTo(pt);
pt.Offset(0,-rcBar.Height());
dc.LineTo(pt);
}
break;
case CBRS_BOTTOM:
{
pOldPen = (HPEN)dc.SelectObject (&pen4);
CPoint pt=rcBar.TopLeft();
dc.MoveTo(pt);
pt.Offset(rcBar.Width()-1,0);
dc.LineTo(pt);
dc.SelectObject (&pen3);
pt=rcBar.TopLeft();
pt.Offset(0,1);
dc.MoveTo(pt);
pt.Offset(rcBar.Width()-1,0);
dc.LineTo(pt);
}
break;
case CBRS_RIGHT:
{
pOldPen = (HPEN)dc.SelectObject (&pen4);
CPoint pt=rcBar.TopLeft();
pt.Offset(1,0);
dc.MoveTo(pt);
pt.Offset(0,rcBar.Height()-1);
dc.LineTo(pt);
dc.SelectObject (&pen3);
pt=rcBar.TopLeft();
pt.Offset(2,0);
dc.MoveTo(pt);
pt.Offset(0,rcBar.Height()-1);
dc.LineTo(pt);
}
break;
default:
break;
}
if (pOldPen!=NULL)
dc.SelectObject(pOldPen);
//Draw the caption
CRect gripper = rect;
CRect rcbtn = m_biHide.GetRect();
gripper.DeflateRect(borderWidth.cx_left,borderWidth.cy_top,
borderWidth.cx_right,borderWidth.cy_top);
CDC* pDC = &dc;
HFONT oldFont = (HFONT)pDC->SelectObject (m_font);
int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
COLORREF crOldText;
if(TRUE == m_isActive) // active state
{
CBrush brush(RGB(10,36,106));
pDC->FillRect(&gripper, &brush);
crOldText = pDC->SetTextColor(RGB(255,255,255));
}
else
{
CPen pen(PS_SOLID, 1, RGB(128,128,128));
HPEN poldPen = (HPEN)pDC->SelectObject (&pen);
// Draw better caption rect
// ------------------------------
//| |
// ------------------------------
// ------------------------------>
CPoint pt=gripper.TopLeft();
pt.Offset(1,0);
pDC->MoveTo (pt);
pDC->LineTo (gripper.right-1 ,gripper.top );
// ------------------------------>
pt=gripper.TopLeft();
pt.Offset(1,gripper.Height());
pDC->MoveTo (pt);
pDC->LineTo (gripper.right-1 ,gripper.bottom );
// ^
// |
// |
pt=gripper.BottomRight();
pt.Offset(-1,-1);
pDC->MoveTo (pt);
pDC->LineTo (gripper.right-1 ,gripper.top);
//^
//|
//|
pt=gripper.BottomRight();
pt.Offset(-gripper.Width(),-1);
pDC->MoveTo(pt);
pDC->LineTo (gripper.left ,gripper.top);
crOldText = pDC->SetTextColor(RGB(0,0,0));
}
gripper.left += 4;
gripper.top += 2;
// Draw caption text
if (!m_Title.IsEmpty())
{
CString sText = m_Title;
int l = sText.GetLength();
int i;
for(i=0;i<10 && pDC->GetTextExtent(sText).cx > (gripper.Width() - 30);i++,l-=2)
sText = sText.Left(l-2);
if(i > 0)
{
sText = sText.Left(l-2);
sText += "...";
}
pDC->TextOut (gripper.left, gripper.top, sText);
}
pDC->SetTextColor (crOldText);
pDC->SetBkMode(nPrevBkMode);
pDC->SelectObject(oldFont);
if(rcBar.Width()<pDC->GetTextExtent(m_Title).cx+17+13)
return;
//Draw the hide & close button
CPoint ptOrgBtn;
ptOrgBtn = CPoint(gripper.right - 15, gripper.top);
m_biHide.Move(ptOrgBtn);
m_biHide.Paint(pDC, m_isActive);
ptOrgBtn.x -= 17;
m_stud.Move (ptOrgBtn);
m_stud.Paint(pDC, m_isActive);
}
void CAHFloatWnd::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
CWnd* pWnd = GetWindow(GW_CHILD);
if (pWnd != NULL)
{
pWnd->MoveWindow(0, 0, cx, cy);
}
SendMessage(WM_NCPAINT);
}
void CAHFloatWnd::OnNcMouseMove(UINT nHitTest, CPoint point)
{
BOOL bNeedPaint = FALSE;
CPoint pt;
::GetCursorPos(&pt);
///////////////////////////////////////////////////////////
// hit close
BOOL bHit = (OnNcHitTest(pt) == HTHIDE);
BOOL bLButtonDown = (::GetKeyState(VK_LBUTTON) < 0);
BOOL bWasPushed = m_biHide.bPushed;
m_biHide.bPushed = bHit && bLButtonDown;
BOOL bWasRaised = m_biHide.bRaised;
m_biHide.bRaised = bHit && !bLButtonDown;
bNeedPaint |= (m_biHide.bPushed ^ bWasPushed) ||
(m_biHide.bRaised ^ bWasRaised);
////////////////////////////////////////////////////////////
// hit stud
bHit = (OnNcHitTest(pt) == HTSTUD);
bWasPushed = m_stud.bPushed;
m_stud.bPushed = bHit && bLButtonDown;
bWasRaised = m_stud.bRaised;
m_stud.bRaised = bHit && !bLButtonDown;
bNeedPaint |= (m_stud.bPushed ^ bWasPushed) ||
(m_stud.bRaised ^ bWasRaised);
if (bNeedPaint)
SendMessage(WM_NCPAINT);
m_bCursorInAutoHideBarItem=FALSE;
CWnd::OnNcMouseMove(nHitTest, point);
}
LRESULT CAHFloatWnd::OnNcHitTest(CPoint point)
{
CRect rcBar;
GetWindowRect(rcBar);
UINT nRet = CWnd::OnNcHitTest(point);
CRect rc = m_biHide.GetRect();
rc.OffsetRect(rcBar.TopLeft());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -