📄 dwautohide.h
字号:
// Copyright (c) 2002
// Sergey Klimov (kidd@ukr.net)
// WTL Docking windows
//
// This code is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name is included. If
// the source code in this file is used in any commercial application
// then a simple email woulod be nice.
#ifndef __WTL_DW__DWAUTOHIDE_H__
#define __WTL_DW__DWAUTOHIDE_H__
#define DF_AUTO_HIDE_FEATURES
#include <queue>
#include <deque>
#include "ssec.h"
#include "DockMisc.h"
#include "ExtDockingWindow.h"
namespace dockwins{
typedef CDockingWindowTraits<COutlookLikeCaption,
WS_CAPTION | WS_CHILD |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS,WS_EX_TOOLWINDOW>
COutlookLikeAutoHidePaneTraits;
template <class TAutoHidePaneTraits,class TSplitterBar,/* DWORD TDockFrameStyle=0,*/
DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0>
struct CDockingFrameTraitsT : CWinTraits <t_dwStyle,t_dwExStyle>
{
typedef TSplitterBar CSplitterBar;
typedef TAutoHidePaneTraits CAutoHidePaneTraits;
};
typedef CDockingFrameTraitsT< COutlookLikeAutoHidePaneTraits,CSimpleSplitterBar<5>,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> CDockingFrameTraits;
typedef CDockingFrameTraitsT<COutlookLikeAutoHidePaneTraits, CSimpleSplitterBarEx<6>,
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,0> CDockingSiteTraits;
struct IPinnedLabel
{
typedef CDockingSide CSide;
enum
{
leftBorder=3,
rightBorder=3,
labelEdge=2,
labelPadding=5, // padding between the labels
captionPadding=3 // padding between border of the label and the lable caption
};
class CPinnedWindow
{
public:
CPinnedWindow()
:m_hWnd(NULL),m_icon(0),m_txt(0),m_width(0)
{
}
CPinnedWindow(const CPinnedWindow& ref)
{
this->operator=(ref);
}
~CPinnedWindow()
{
delete [] m_txt;
}
CPinnedWindow& operator = (const CPinnedWindow& ref)
{
m_hWnd=ref.m_hWnd;
m_icon=ref.m_icon;
m_width=ref.m_width;
m_txt=ref.m_txt;
ref.m_txt=0;
return *this;
}
int Assign(HWND hWnd,unsigned long width)
{
assert(::IsWindow(hWnd));
m_hWnd=hWnd;
m_width=width;
m_icon=reinterpret_cast<HICON>(::SendMessage(hWnd, WM_GETICON, FALSE, 0));
if(m_icon == NULL)
m_icon = reinterpret_cast<HICON>(::GetClassLong(hWnd, GCL_HICONSM));
delete [] m_txt;
int len=0;
try
{
len=::GetWindowTextLength(hWnd)+1;
m_txt=new TCHAR[len];
::GetWindowText(hWnd,m_txt,len);
} catch(std::bad_alloc& /*e*/)
{
m_txt=0;
}
return len;
}
HWND Wnd() const
{
return m_hWnd;
}
HICON Icon() const
{
return m_icon;
}
LPCTSTR Text() const
{
return m_txt;
}
unsigned long Width() const
{
return m_width;
}
void Width(unsigned long width)
{
m_width=width;
}
void PrepareForDock(HDOCKBAR hBar,bool bHorizontal)
{
::ShowWindow(m_hWnd,SW_HIDE);
DWORD style = ::GetWindowLong(m_hWnd,GWL_STYLE);
DWORD newStyle = style&(~(WS_POPUP | WS_CAPTION))|WS_CHILD;
::SetWindowLong(m_hWnd, GWL_STYLE, newStyle);
::SetParent(m_hWnd,hBar);
::SendMessage(m_hWnd,WM_NCACTIVATE,TRUE,NULL);
::SendMessage(m_hWnd,WMDF_NDOCKSTATECHANGED,
MAKEWPARAM(TRUE,bHorizontal),
reinterpret_cast<LPARAM>(hBar));
}
void PrepareForUndock(HDOCKBAR hBar)
{
::ShowWindow(m_hWnd,SW_HIDE);
DWORD style = ::GetWindowLong(m_hWnd,GWL_STYLE);
DWORD newStyle = style&(~WS_CHILD) | WS_POPUP | WS_CAPTION;
::SetWindowLong(m_hWnd, GWL_STYLE, newStyle);
::SetParent(m_hWnd,NULL);
::SendMessage(m_hWnd,WMDF_NDOCKSTATECHANGED,
FALSE,
reinterpret_cast<LPARAM>(hBar));
}
void DrawLabel(CDC& dc,const CRect& rc,const CSide& side) const
{
CRect rcOutput(rc);
rcOutput.DeflateRect(captionPadding,captionPadding);
if(m_icon!=NULL)
{
CDWSettings settings;
CSize szIcon(settings.CXMinIcon(),settings.CYMinIcon());
if(side.IsHorizontal())
{
if(rc.Width()>szIcon.cx+2*captionPadding)
{
POINT pt={rcOutput.left,rc.top+(rc.Height()-szIcon.cx)/2};
rcOutput.left+=szIcon.cx+captionPadding;
dc.DrawIconEx(pt,m_icon,szIcon);
}
}
else
{
if(rc.Height()>szIcon.cy+2*captionPadding)
{
POINT pt={rc.left+(rc.Width()-szIcon.cy)/2,rcOutput.top};
rcOutput.top+=szIcon.cy+captionPadding;
dc.DrawIconEx(pt,m_icon,szIcon);
}
}
}
DrawEllipsisText(dc,m_txt,_tcslen(m_txt),&rcOutput,side.IsHorizontal());
}
protected:
unsigned long m_width;
HWND m_hWnd;
HICON m_icon;
mutable LPTSTR m_txt;
};
class CCmp
{
public:
CCmp(HWND hWnd):m_hWnd(hWnd)
{
}
bool operator() (const IPinnedLabel* ptr) const
{
return ptr->IsOwner(m_hWnd);
}
protected:
HWND m_hWnd;
};
virtual ~IPinnedLabel(){}
virtual IPinnedLabel* Remove(HWND hWnd,HDOCKBAR hBar)=0;
virtual bool UnPin(HWND hWnd,HDOCKBAR hBar,DFDOCKPOS* pHdr)=0;
virtual long Width() const=0;
virtual void Width(long width)=0;
virtual long DesiredWidth(CDC& dc) const=0;
virtual bool GetDockingPosition(DFDOCKPOS* pHdr) const=0;
virtual CPinnedWindow* ActivePinnedWindow()=0;
virtual CPinnedWindow* FromPoint(long x,bool bActivate)=0;
virtual bool IsOwner(HWND hWnd) const=0;
virtual void Draw(CDC& dc,const CRect& rc,const CSide& side) const=0;
};
class CSinglePinnedLabel : public IPinnedLabel
{
public:
CSinglePinnedLabel(DFPINUP* pHdr,bool bHorizontal)
:m_width(0)
{
assert( (pHdr->n==0) || (pHdr->n==1) );
m_wnd.Assign(pHdr->hdr.hWnd,pHdr->nWidth);
m_wnd.PrepareForDock(pHdr->hdr.hBar,bHorizontal);
}
CSinglePinnedLabel(const CPinnedWindow& wnd)
:m_wnd(wnd),m_width(0)
{
}
virtual IPinnedLabel* Remove(HWND hWnd,HDOCKBAR hBar)
{
assert(IsOwner(hWnd));
m_wnd.PrepareForUndock(hBar);
return 0;
}
virtual bool UnPin(HWND hWnd,HDOCKBAR hBar,DFDOCKPOS* pHdr)
{
GetDockingPosition(pHdr);
bool bRes=(Remove(hWnd,hBar)==0);
if(bRes)
{
pHdr->hdr.code=DC_SETDOCKPOSITION;
::SendMessage(pHdr->hdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr));
}
return bRes;
}
virtual long Width() const
{
return m_width;
}
virtual void Width(long width)
{
m_width=width;
}
virtual long DesiredWidth(CDC& dc) const
{
SIZE sz;
LPCTSTR text=m_wnd.Text();
bool bRes=(GetTextExtentPoint32(dc, text,_tcslen(text),&sz)!=FALSE);
assert(bRes);
unsigned long width=sz.cx+2*captionPadding;
if(m_wnd.Icon()!=NULL)
{
CDWSettings settings;
width+=settings.CXMinIcon()+captionPadding;
}
bRes;
return width;
}
virtual CPinnedWindow* ActivePinnedWindow()
{
return &m_wnd;
}
virtual CPinnedWindow* FromPoint(long x,bool /*bActivate*/)
{
assert(x>=0 && x<Width() );
return ActivePinnedWindow();
}
virtual void Draw(CDC& dc,const CRect& rc,const CSide& side) const
{
dc.Rectangle(&rc);
m_wnd.DrawLabel(dc,rc,side);
}
virtual bool IsOwner(HWND hWnd) const
{
return m_wnd.Wnd()==hWnd;
}
virtual bool GetDockingPosition(DFDOCKPOS* pHdr) const
{
assert(pHdr->hdr.hWnd==m_wnd.Wnd());
pHdr->nBar=0;
pHdr->nWidth=m_wnd.Width();
pHdr->nHeight=1;
pHdr->nIndex=0;
pHdr->fPctPos=0;
return true;
}
protected:
CPinnedWindow m_wnd;
long m_width;
};
class CMultyPinnedLabel : public IPinnedLabel
{
enum {npos=ULONG_MAX/*std::numeric_limits<unsigned long>::max()*/};
public:
CMultyPinnedLabel(DFPINUP* pHdr,bool bHorizontal)
:m_width(0)
{
assert(pHdr->n>1);
m_n=pHdr->n;
m_tabs=new CPinnedWindow[m_n];
int maxLen=0;
for(unsigned long i=0;i<m_n;i++)
{
int len=m_tabs[i].Assign(pHdr->phWnds[i],pHdr->nWidth);
m_tabs[i].PrepareForDock(pHdr->hdr.hBar,bHorizontal);
if(len>maxLen)
{
maxLen=len;
m_longestTextTab=i;
}
if(pHdr->phWnds[i]==pHdr->hdr.hWnd)
m_activeTab=i;
}
}
~CMultyPinnedLabel()
{
delete [] m_tabs;
}
virtual bool UnPin(HWND hWnd,HDOCKBAR hBar,DFDOCKPOS* pHdr)
{
assert(pHdr->hdr.hWnd==hWnd);
GetDockingPosition(pHdr);
pHdr->hdr.hWnd=m_tabs[0].Wnd();
pHdr->hdr.code=DC_SETDOCKPOSITION;
m_tabs[0].PrepareForUndock(hBar);
::SendMessage(pHdr->hdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr));
pHdr->hdr.hBar=pHdr->hdr.hWnd;
for(unsigned long i=1;i<m_n;i++)
{
pHdr->nIndex=i;
pHdr->hdr.hWnd=m_tabs[i].Wnd();
m_tabs[i].PrepareForUndock(hBar);
::SendMessage(pHdr->hdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr));
}
pHdr->hdr.code=DC_ACTIVATE;
pHdr->hdr.hWnd=m_tabs[m_activeTab].Wnd();
::SendMessage(pHdr->hdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(&(pHdr->hdr)));
return true;
}
virtual IPinnedLabel* Remove(HWND hWnd,HDOCKBAR hBar)
{
assert(IsOwner(hWnd));
IPinnedLabel* ptr=this;
try
{
if(m_n==2)
{
unsigned long i=(m_tabs[0].Wnd()!=hWnd);
ptr=new CSinglePinnedLabel(m_tabs[i]);
m_tabs[!i].PrepareForUndock(hBar);
}
else
{
CPinnedWindow* ptr=m_tabs;
m_tabs=new CPinnedWindow[m_n-1];
unsigned long j=0;
unsigned int maxLen=0;
for(unsigned long i=0;i<m_n;i++)
{
if(ptr[i].Wnd()!=hWnd)
{
if(maxLen<_tcslen(ptr[i].Text()))
m_longestTextTab=j;
m_tabs[j++]=ptr[i];
}
else
ptr[i].PrepareForUndock(hBar);
}
if(m_activeTab==--m_n)
--m_activeTab;
delete [] ptr;
}
}
catch(std::bad_alloc& /*e*/)
{
}
return ptr;
}
unsigned long Locate(HWND hWnd) const
{
for(unsigned long i=0;i<m_n;i++)
if(m_tabs[i].Wnd()==hWnd)
return i;
return (unsigned long)npos;
}
virtual bool IsOwner(HWND hWnd) const
{
return (Locate(hWnd)!=npos);
}
virtual long Width() const
{
return m_width;
}
virtual void Width(long width)
{
m_width=width;
if(m_width<m_passiveTabWidth*long(m_n))
{
if(m_width<long(m_n))
m_passiveTabWidth=0;
else
m_passiveTabWidth=m_width/m_n;
}
}
virtual long DesiredWidth(CDC& dc) const
{
SIZE sz;
LPCTSTR text=m_tabs[m_longestTextTab].Text();
bool bRes=(GetTextExtentPoint32(dc, text,_tcslen(text),&sz)!=FALSE);
assert(bRes);
bRes;
long width=sz.cx+2*captionPadding;
CDWSettings settings;
width+=settings.CXMinIcon()+captionPadding;
m_passiveTabWidth=settings.CXMinIcon()+2*captionPadding;
width+=m_passiveTabWidth*(m_n-1);
return width;
}
virtual CPinnedWindow* ActivePinnedWindow()
{
return m_tabs+m_activeTab;
}
virtual CPinnedWindow* FromPoint(long x,bool bActivate)
{
assert(x>=0 && x<Width() );
unsigned long i=m_activeTab;
if(x<long(m_activeTab)*m_passiveTabWidth)
i=x/m_passiveTabWidth;
else
{
long width=Width()-(m_n-m_activeTab-1)*m_passiveTabWidth;
if( width<x )
i+=(x-width)/m_passiveTabWidth+1;
}
assert(m_activeTab<m_n);
if(bActivate)
m_activeTab=i;
return m_tabs+i;
}
void DrawPassiveTab(unsigned long i,CDC& dc,const CRect& rc,const CSide& side) const
{
CRect rcOutput(rc);
rcOutput.DeflateRect(captionPadding,captionPadding);
HICON icon=m_tabs[i].Icon();
CDWSettings settings;
CSize sz(settings.CXMinIcon(),settings.CYMinIcon());
if( icon!=0
&& (sz.cx<=(rc.Width()-2*captionPadding))
&& (sz.cy<=(rc.Height()-2*captionPadding)) )
{
POINT pt={rcOutput.left,rcOutput.top};
dc.DrawIconEx(pt,icon,sz);
}
else
{
LPCTSTR text=m_tabs[i].Text();
DrawEllipsisText(dc,text,_tcslen(text),&rcOutput,side.IsHorizontal());
}
}
void DrawActiveTab(unsigned long i,CDC& dc,const CRect& rc,const CSide& side) const
{
m_tabs[i].DrawLabel(dc,rc,side.IsHorizontal());
}
virtual void Draw(CDC& dc,const CRect& rc,const CSide& side) const
{
CRect rcOutput(rc);
dc.Rectangle(&rcOutput);
long* pLeft;
long* pRight;
long* px;
long* py;
if(side.IsHorizontal())
{
pLeft=&rcOutput.left;
pRight=&rcOutput.right;
px=&rcOutput.left;
py=&rcOutput.bottom;
}
else
{
pLeft=&rcOutput.top;
pRight=&rcOutput.bottom;
px=&rcOutput.right;
py=&rcOutput.top;
}
for(unsigned long i=0;i<m_n;i++)
{
if(i==m_activeTab)
{
*pRight=*pLeft+m_width-m_passiveTabWidth*(m_n-1);
assert(*pRight<=(side.IsHorizontal() ? rcOutput.right : rcOutput.bottom));
DrawActiveTab(i,dc,rcOutput,side.IsHorizontal());
}
else
{
*pRight=*pLeft+m_passiveTabWidth;
assert(*pRight<=(side.IsHorizontal() ? rcOutput.right : rcOutput.bottom));
DrawPassiveTab(i,dc,rcOutput,side);
}
dc.MoveTo(rcOutput.left, rcOutput.top);
dc.LineTo(*px,*py);
*pLeft=*pRight;
}
}
virtual bool GetDockingPosition(DFDOCKPOS* pHdr) const
{
unsigned long i=Locate(pHdr->hdr.hWnd);
bool bRes=(i!=npos);
if(bRes)
{
if(m_activeTab==i)
pHdr->dwDockSide|=CDockingSide::sActive;
pHdr->nBar=0;
pHdr->nWidth=m_tabs[i].Width();
pHdr->nHeight=1;
pHdr->nIndex=i;
pHdr->fPctPos=0;
}
return bRes;
}
protected:
unsigned long m_n;
CPinnedWindow* m_tabs;
long m_width;
mutable long m_passiveTabWidth;
unsigned long m_activeTab;
unsigned long m_longestTextTab;
};
class CAutoHideBar: protected CRect
{
typedef CRect baseClass;
protected:
typedef IPinnedLabel* CPinnedLabelPtr;
typedef std::deque<CPinnedLabelPtr> CBunch;
typedef CBunch::const_iterator const_iterator;
public:
typedef IPinnedLabel::CSide CSide;
CAutoHideBar()
{
SetRectEmpty();
}
// Bug fix, refer to
// <http://www.codeproject.com/wtl/wtldockingwindows.asp?mode=all&userid=36446&select=1377220&df=100&forumid=3244&mpp=50&msg=1377220>
static void DestroyPinnedLabel(CPinnedLabelPtr ptr)
{
delete ptr;
}
~CAutoHideBar()
{
void (*pDelete)(CPinnedLabelPtr)=&DestroyPinnedLabel;
std::for_each(m_bunch.begin(),m_bunch.end(),pDelete);
}
operator const CRect& () const
{
return *this;
}
bool IsPtIn(const CPoint& pt) const
{
return (PtInRect(pt)!=FALSE);
}
const CSide& Orientation() const
{
return m_side;
}
bool IsVisible() const
{
return !m_bunch.empty();
}
bool IsHorizontal() const
{
return Orientation().IsHorizontal();
}
bool IsTop() const
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -