📄 wndfrmpkg.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__WNDFRMPKG_H__
#define __WTL_DW__WNDFRMPKG_H__
#pragma once
#ifndef __ATLMISC_H__
#error WndFrmPkg.h requires atlmisc.h to be included first
#endif
#include <memory>
#include "ssec.h"
#include "DDTracker.h"
#ifdef USE_BOOST
#include<boost/smart_ptr.hpp>
#endif
namespace dockwins{
class CWndFrame
{
public:
typedef long position;
typedef long distance;
class CCmp
{
public:
CCmp(HWND hWnd) :m_hWnd(hWnd)
{
}
bool operator ()(const CWndFrame& frame) const
{
return (frame.hwnd() == m_hWnd);
}
protected:
HWND m_hWnd;
};
CWndFrame(position pos=0,HWND hWnd=NULL)
:m_hWnd(hWnd),m_pos(pos)
{
}
HWND hwnd() const
{
return m_hWnd;
}
operator position() const
{
return (position)m_pos;
}
CWndFrame& operator += (position val)
{
m_pos+=val;
return *this;
}
CWndFrame& operator -= (position val)
{
m_pos-=val;
return *this;
}
CWndFrame& operator = (position pos)
{
m_pos=pos;
return *this;
}
CWndFrame& operator = (double pos)
{
m_pos=pos;
return *this;
}
double get_real()
{
return m_pos;
}
HDWP DeferFramePos(HDWP hdwp,long x1,long y1,long x2,long y2) const
{
return ::DeferWindowPos(hdwp,hwnd(),
NULL,
x1,y1,
x2-x1,y2-y1,
SWP_NOZORDER | SWP_NOACTIVATE);
}
void GetMinMaxInfo(LPMINMAXINFO pMinMaxInfo) const
{
::SendMessage(m_hWnd,WM_GETMINMAXINFO,NULL,reinterpret_cast<LPARAM>(pMinMaxInfo));
}
distance MinDistance() const
{
DFMHDR dockHdr;
dockHdr.code=DC_GETMINDIST;
dockHdr.hWnd=m_hWnd;
dockHdr.hBar=::GetParent(m_hWnd);
assert(::IsWindow(dockHdr.hBar));
return static_cast<distance>(::SendMessage(dockHdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(&dockHdr)));
}
protected:
double m_pos;
mutable HWND m_hWnd;
};
//template<class T,const T::distance TMinDist=0>
//struct CWndFrameTraits : ssec::spraits<T, T::position, T::distance/*,TMinDist*/>
//{
// typedef ssec::spraits<T,position,position/*,TMinDist*/> baseClass;
// static distance min_distance(const T& x)
// {
// const distance dist=TMinDist;
// return dist+x.MinDistance();
// }
//
//};
template< class TFrame = CWndFrame , class TTraits = CDockingFrameTraits>
class CWndFramesPackageBase
{
typedef typename TFrame CFrame;
typedef typename TTraits CTraits;
typedef typename CTraits::CSplitterBar CSplitterBar;
typedef CWndFramesPackageBase<CFrame,TTraits> thisClass;
protected:
enum {splitterSize=CSplitterBar::sbThickness};
typedef typename CFrame::position position;
#if _MSC_VER >= 1310
template<class T,const typename T::distance TMinDist=0>
#else
template<class T,const T::distance TMinDist=0>
#endif
struct CWndFrameTraits : ssec::spraits<T, typename T::position, typename T::distance/*,TMinDist*/>
{
typedef ssec::spraits<T,position,position/*,TMinDist*/> baseClass;
static distance min_distance(const T& x)
{
const distance dist=TMinDist;
return dist+x.MinDistance();
}
};
typedef CWndFrameTraits<CFrame,splitterSize> CFrameTraits;
typedef ssec::ssection<CFrame,CFrameTraits> CFrames;
typedef typename CFrames::iterator iterator;
typedef typename CFrames::reverse_iterator reverse_iterator;
typedef typename CFrames::const_iterator const_iterator;
typedef typename CFrames::const_reverse_iterator const_reverse_iterator;
typedef ssec::bounds_type<position> CBounds;
protected:
struct CEmbeddedSplitterBar : public CSplitterBar
{
CEmbeddedSplitterBar(bool bHorizontal,position vertex,const CRect& rcClient)
:CSplitterBar(bHorizontal)
{
if(IsHorizontal())
{
top=vertex;
bottom=top+GetThickness();
left=rcClient.left;
right=rcClient.right;
}
else
{
left=vertex;
right=left+GetThickness();
top=rcClient.top;
bottom=rcClient.bottom;
}
}
};
class CEmbeddedSplitterBarPainter
{
public:
CEmbeddedSplitterBarPainter(CDC& dc,bool bHorizontal,const CRect& rc)
:m_dc(dc),m_rc(rc),m_bHorizontal(bHorizontal)
{
}
void operator()(const CFrame& ref) const
{
CEmbeddedSplitterBar splitter(m_bHorizontal,ref,m_rc);
splitter.Draw(m_dc);
}
protected:
const CRect& m_rc;
bool m_bHorizontal;
CDC& m_dc;
};
class CSplitterMoveTrackerBase : public IDDTracker//CDDTrackerBaseT<CSizeTrackerBase>
{
protected:
void SetPosition()
{
assert(m_bounds.bind(m_pos)==m_pos);
m_frames.set_position(m_i,m_pos);
m_owner.Arrange(m_rc);
m_wnd.RedrawWindow(&m_rc,NULL,RDW_INVALIDATE | RDW_UPDATENOW);
}
public:
CSplitterMoveTrackerBase(HWND hWnd,thisClass& owner,const CPoint& pt,const CRect& rc)
:m_wnd(hWnd),m_owner(owner),m_frames(owner.m_frames),m_rc(rc)
{
position pos=owner.IsHorizontal() ? pt.x : pt.y;
m_i=m_frames.locate(pos);
if(m_i!=m_frames.end())
{
m_pos=(*m_i);
m_offset=pos-m_pos;
m_frames.get_effective_bounds(m_i,m_bounds);
}
}
operator iterator() const
{
return m_i;
}
void OnMove(long x, long y)
{
position pos = m_owner.IsHorizontal() ? x : y;
pos=m_bounds.bind(pos-m_offset);
if(pos!=m_pos)
{
m_pos=pos;
Move();
}
}
virtual void Move()=0;
protected:
thisClass& m_owner;
CFrames& m_frames;
iterator m_i;
CBounds m_bounds;
position m_pos;
position m_offset;
const CRect& m_rc;
CWindow m_wnd;
};
friend class CSplitterMoveTrackerBase;
class CSplitterMoveTrackerFull : public CSplitterMoveTrackerBase
{
public:
CSplitterMoveTrackerFull(HWND hWnd,thisClass& owner,const CPoint& pt,const CRect& rc)
:CSplitterMoveTrackerBase(hWnd,owner,pt,rc)
{
}
void Move()
{
SetPosition();
}
};
class CSplitterMoveTrackerGhost : public CSplitterMoveTrackerBase
{
typedef CEmbeddedSplitterBar CSplitterBar;
typedef CSimpleSplitterBarSlider<CSplitterBar> CSlider;
public:
CSplitterMoveTrackerGhost(HWND hWnd,thisClass& owner,
const CPoint& pt,const CRect& rc)
:CSplitterMoveTrackerBase(hWnd,owner,pt,rc),
m_dc(::GetWindowDC(NULL)),m_splitter(!owner.IsHorizontal(),m_pos,rc),m_slider(m_splitter)
{
CPoint point(rc.TopLeft ());
::ClientToScreen(hWnd,&point);
CSize offset(point.x-rc.left,point.y-rc.top);
m_splitter+=offset;
m_ghOffset=owner.IsHorizontal()
?offset.cx
:offset.cy;
}
void BeginDrag()
{
m_splitter.DrawGhostBar(m_dc);
}
void EndDrag(bool bCanceled)
{
m_splitter.CleanGhostBar(m_dc);
if(!bCanceled)
SetPosition();
}
void Move()
{
m_splitter.CleanGhostBar(m_dc);
m_slider=m_pos+m_ghOffset;
m_splitter.DrawGhostBar(m_dc);
}
protected:
position m_ghOffset;
CSplitterBar m_splitter;
CSlider m_slider;
CDC m_dc;
};
template<long add=0>
class CMinMaxInfoAccumulator
{
typedef LPMINMAXINFO (*CFunPtr)(MINMAXINFO& mmInfo,LPMINMAXINFO pMinMaxInfo);
public:
CMinMaxInfoAccumulator(bool bHorizontal)
{
m_pFun=bHorizontal ? &MinMaxInfoH : &MinMaxInfoV;
}
LPMINMAXINFO operator() (LPMINMAXINFO pMinMaxInfo,const CFrame& x) const
{
MINMAXINFO mmInfo;
ZeroMemory(&mmInfo,sizeof(MINMAXINFO));
x.GetMinMaxInfo(&mmInfo);
return (*m_pFun)(mmInfo,pMinMaxInfo);
}
protected:
static LPMINMAXINFO MinMaxInfoH(MINMAXINFO& mmInfo,LPMINMAXINFO pMinMaxInfo)
{
if(pMinMaxInfo->ptMinTrackSize.y<mmInfo.ptMinTrackSize.y)
pMinMaxInfo->ptMinTrackSize.y=mmInfo.ptMinTrackSize.y;
pMinMaxInfo->ptMinTrackSize.x+=mmInfo.ptMinTrackSize.x+add;
return pMinMaxInfo;
}
static LPMINMAXINFO MinMaxInfoV(MINMAXINFO& mmInfo,LPMINMAXINFO pMinMaxInfo)
{
if(pMinMaxInfo->ptMinTrackSize.x<mmInfo.ptMinTrackSize.x)
pMinMaxInfo->ptMinTrackSize.x=mmInfo.ptMinTrackSize.x;
pMinMaxInfo->ptMinTrackSize.y+=mmInfo.ptMinTrackSize.y+add;
return pMinMaxInfo;
}
protected:
CFunPtr m_pFun;
};
protected:
bool ArrangeH(const CRect& rc)
{
HDWP hdwp=reinterpret_cast<HDWP>(TRUE);
const_iterator begin=m_frames.begin();
const_iterator end=m_frames.end();
if(begin!=end)
{
hdwp=BeginDeferWindowPos(m_frames.size());
const_iterator next=begin;
while((hdwp!=NULL)&&(++next!=end))
{
long x=(*begin)+splitterSize;
hdwp=begin->DeferFramePos(hdwp,
x,
rc.top,
(*next),
rc.bottom);
begin=next;
}
if(hdwp!=NULL)
{
long x=(*begin)+splitterSize;
hdwp=begin->DeferFramePos(hdwp,
x,
rc.top,
rc.right,
rc.bottom);
if(hdwp)
hdwp=reinterpret_cast<HDWP>(EndDeferWindowPos(hdwp));
}
}
return hdwp!=NULL;
}
bool ArrangeV(const CRect& rc)
{
HDWP hdwp=reinterpret_cast<HDWP>(TRUE);
const_iterator begin=m_frames.begin();
const_iterator end=m_frames.end();
if(begin!=end)
{
hdwp=BeginDeferWindowPos(m_frames.size());
const_iterator next=begin;
while((hdwp!=NULL)&&(++next!=end))
{
long y=(*begin)+splitterSize;
hdwp=begin->DeferFramePos(hdwp,
rc.left,
y,
rc.right,
(*next));
begin=next;
}
if(hdwp!=NULL)
{
long y=(*begin)+splitterSize;
hdwp=begin->DeferFramePos(hdwp,
rc.left,
y,
rc.right,
rc.bottom);
if(hdwp)
hdwp=reinterpret_cast<HDWP>(EndDeferWindowPos(hdwp));
}
}
return hdwp!=NULL;
}
bool Arrange(const CRect& rcClient)
{
bool bRes;
if(IsHorizontal())
bRes=ArrangeH(rcClient);
else
bRes=ArrangeV(rcClient);
return bRes;
}
CWndFramesPackageBase(bool bHorizontal)
:m_bHorizontal(bHorizontal),m_frames(0,0)
{
}
public:
bool IsHorizontal() const
{
return m_bHorizontal;
}
void SetOrientation(bool bHorizontal)
{
m_bHorizontal=bHorizontal;
}
HCURSOR GetCursor(const CPoint& pt,const CRect& rc) const
{
HCURSOR hCursor=NULL;
position pos=IsHorizontal() ?pt.x :pt.y;
const_iterator i=m_frames.locate(pos);
if(i!=m_frames.end())
{
CEmbeddedSplitterBar splitter(!IsHorizontal(),(*i),rc);
hCursor=splitter.GetCursor(pt);
}
return hCursor;
}
/*
bool StartSliding(HWND hWnd,const CPoint& pt,const CRect& rc,bool bGhostMove)
{
std::auto_ptr<CSplitterMoveTrackerBase> pTracker;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -