FolderFrame.h
////////////////////////////////////////////////////////////////
// 1999 Microsoft Systems Journal.
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
#ifndef _FOLDERWIN_H
#define _FOLDERWIN_H
#include "ftab.h"
//////////////////
// Window to manage folder tab, view and scroll bars
class CFolderFrame : public CWnd {
DECLARE_DYNAMIC(CFolderFrame)
protected:
CFolderTabCtrl m_wndFolderTabCtrl; // folder tab
CScrollBar m_wndSBHorz; // horizontal scroll bar..
CScrollBar m_wndSBVert; // ... vertical
CScrollBar m_wndSBBox; // ... and box
int m_cxFolderTabCtrl; // width of folder tab
UINT m_nIDRes; // resource ID for tab names
void UpdateBarSize(); // compute width of tab ctrl/scroll bar
public:
CFolderFrame();
virtual ~CFolderFrame();
BOOL Create(CWnd* pParent, CRuntimeClass* pViewClass, CCreateContext* pcc,
UINT nIDRes = 0, int cxFolderTabCtrl=-2,
DWORD dwStyle = WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN);
CScrollBar* GetScrollBar(int nBar) const;
CFolderTabCtrl& GetFolderTabCtrl() { return m_wndFolderTabCtrl; }
CWnd* GetView(UINT nID=AFX_IDW_PANE_FIRST) { return GetDlgItem(nID); }
int GetFolderTabWidth() { return m_cxFolderTabCtrl; }
enum { bestFit=-1, none=-2 };
void SetFolderTabWidth(int w);
void ShowControls(int width);
// virtual overrides
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
// message handlers
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
DECLARE_MESSAGE_MAP()
};
//////////////////
// Derive your view from this
class CFolderView : public CScrollView {
public:
CFolderView() { }
virtual ~CFolderView() { }
// override to use my own scrollbar controls, not built-in
virtual CScrollBar* GetScrollBarCtrl(int nBar) const;
virtual void OnChangedFolder(int iPage);
CFolderFrame* GetFolderFrame() const;
protected:
DECLARE_MESSAGE_MAP()
afx_msg void OnChangedTab(NMFOLDERTAB* nmtab, LRESULT* pRes);
DECLARE_DYNAMIC(CFolderView)
};
#endif // _FOLDERWIN_H
FolderFrame.cpp
////////////////////////////////////////////////////////////////
// 1999 Microsoft Systems Journal
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
#include "stdafx.h"
#include "FolderFrame.h"
#include <afxpriv.h> // for WM_INITIALUPDATE
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const MINSCROLLBARWIDTH = 4*GetSystemMetrics(SM_CXVSCROLL);
IMPLEMENT_DYNAMIC(CFolderFrame, CWnd)
BEGIN_MESSAGE_MAP(CFolderFrame, CWnd)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
END_MESSAGE_MAP()
CFolderFrame::CFolderFrame()
{
m_cxFolderTabCtrl=none;
}
CFolderFrame::~CFolderFrame()
{
}
//////////////////
// pre-creation: use client edge (assumes Win4)
BOOL CFolderFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style |= WS_CLIPCHILDREN;
cs.style &= ~WS_BORDER;
return CWnd::PreCreateWindow(cs);
}
//////////////////
// Create window: register class, create view
BOOL CFolderFrame::Create(CWnd* pParent, CRuntimeClass* pViewClass,
CCreateContext* pcc, UINT nIDRes, int cxFolderTabCtrl, DWORD dwStyle)
{
ASSERT(pParent);
ASSERT(dwStyle & WS_CHILD);
static LPCTSTR lpClassName = NULL;
if (!lpClassName) {
lpClassName = _T("PxlFolderFrame");
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)::DefWindowProc; // will get hooked by MFC
wc.hInstance = AfxGetInstanceHandle();
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL; //CreateSolidBrush(GetSysColor(COLOR_3DFACE));
wc.lpszMenuName = NULL;
wc.lpszClassName = lpClassName;
VERIFY(AfxRegisterClass(&wc));
}
m_nIDRes = nIDRes;
SetFolderTabWidth(cxFolderTabCtrl);
CRect rc(0,0,0,0);
if (!CreateEx(0,lpClassName,NULL,dwStyle,rc,pParent,AFX_IDW_PANE_FIRST))
return FALSE;
CWnd* pView = (CWnd*)pViewClass->CreateObject();
ASSERT(pView);
if (!pView->Create(NULL, NULL, dwStyle, rc, this, AFX_IDW_PANE_FIRST, pcc))
return FALSE;
pView->SendMessage(WM_INITIALUPDATE);
return TRUE;
}
//////////////////
// Now create scroll bars and folder tab control
int CFolderFrame::OnCreate(LPCREATESTRUCT lpcs)
{
CRect rc(0,0,0,0);
VERIFY(m_wndSBHorz.Create(WS_VISIBLE|WS_CHILD|SBS_HORZ,
rc, this, AFX_IDW_HSCROLL_FIRST));
VERIFY(m_wndSBVert.Create(WS_VISIBLE|WS_CHILD|SBS_VERT,
rc, this, AFX_IDW_HSCROLL_FIRST+1));
VERIFY(m_wndSBBox.Create(WS_VISIBLE|WS_CHILD|SBS_SIZEBOX,
rc, this,-1));
CFolderTabCtrl& ftc = m_wndFolderTabCtrl;
VERIFY(ftc.Create(WS_CHILD|WS_VISIBLE, rc, this, 1));
if (m_nIDRes)
ftc.Load(m_nIDRes);
ShowControls(m_cxFolderTabCtrl);
return 0;
}
//////////////////
// window was sized: move view and scroll bars
void CFolderFrame::OnSize(UINT nType, int cx, int cy)
{
CWnd* pView = GetView();
if (pView) {
CRect rc(0,0,cx,cy);
// make sure there's some room for horz scrollbar
int cxFolderTabCtrl = m_cxFolderTabCtrl;
if (cxFolderTabCtrl > (rc.Width()- MINSCROLLBARWIDTH))
cxFolderTabCtrl = rc.Width()- MINSCROLLBARWIDTH;
int cyHScroll = GetSystemMetrics(SM_CYHSCROLL);
int cxVScroll = GetSystemMetrics(SM_CXVSCROLL);
if (cxFolderTabCtrl>=0) {
rc.right -= cxVScroll;
rc.bottom -= cyHScroll;
}
pView->MoveWindow(rc);
if (cxFolderTabCtrl<0)
return;
rc.left = rc.right;
rc.right += cxVScroll;
m_wndSBVert.MoveWindow(rc);
rc.left = max(cxFolderTabCtrl,0);
rc.right -= cxVScroll;
rc.top = rc.bottom;
rc.bottom+= cyHScroll;
m_wndSBHorz.MoveWindow(rc);
if (cxFolderTabCtrl>=0) {
CRect rc2 = rc;
rc2.left = 0;
rc2.right = cxFolderTabCtrl;
m_wndFolderTabCtrl.MoveWindow(rc2);
}
rc.left = rc.right;
rc.right+=cxVScroll;
m_wndSBBox.MoveWindow(rc);
}
}
//////////////////
// Show controls (scroll bars and folder tab control).
void CFolderFrame::ShowControls(int width)
{
if (width == bestFit)
width = m_wndFolderTabCtrl.GetDesiredWidth();
SetFolderTabWidth(width);
int iShow = m_cxFolderTabCtrl>=0 ? SW_SHOW : SW_HIDE;
m_wndSBVert.ShowWindow(iShow);
m_wndSBHorz.ShowWindow(iShow);
m_wndSBBox.ShowWindow(iShow);
m_wndFolderTabCtrl.ShowWindow(iShow);
if (iShow==SW_SHOW)
UpdateBarSize();
}
//////////////////
// Set width of folder tabs.
void CFolderFrame::SetFolderTabWidth(int width)
{
if (width>0) {
CRect rc;
GetClientRect(&rc);
if (width > (rc.Width()- MINSCROLLBARWIDTH))
width = rc.Width()- MINSCROLLBARWIDTH;
}
if (width != m_cxFolderTabCtrl) {
m_cxFolderTabCtrl = width;
UpdateBarSize();
}
}
//////////////////
// Update scrollbars after hide/show or width change: Send WM_SIZE to myself.
// This will force MFC to recalc the layout.
//
void CFolderFrame::UpdateBarSize()
{
CRect rc;
GetClientRect(&rc);
SendMessage(WM_SIZE, 0, MAKELPARAM(rc.Width(), rc.Height()));
}
CScrollBar* CFolderFrame::GetScrollBar(int nBar) const
{
return nBar==SB_HORZ ? const_cast<CScrollBar*>(&m_wndSBHorz)
: nBar==SB_VERT ? const_cast<CScrollBar*>(&m_wndSBVert) : NULL;
}
//////////////////
// pass scroll messages to view
void CFolderFrame::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
GetView()->SendMessage(WM_HSCROLL,
MAKELONG(nSBCode, nPos), (LPARAM)pScrollBar->m_hWnd);
}
void CFolderFrame::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
GetView()->SendMessage(WM_VSCROLL,
MAKELONG(nSBCode, nPos), (LPARAM)pScrollBar->m_hWnd);
}
//////////////////
// command routing: pass commands to view and myself
BOOL CFolderFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
if (GetView()->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
////////////////////////////////////////////////////////////////
// CFolderView
IMPLEMENT_DYNAMIC(CFolderView, CScrollView)
BEGIN_MESSAGE_MAP(CFolderView, CScrollView)
ON_NOTIFY(FTN_TABCHANGED, 1, OnChangedTab)
END_MESSAGE_MAP()
/////////////////
// Get scrollbar: send message to parent
CScrollBar* CFolderView::GetScrollBarCtrl(int nBar) const
{
return GetFolderFrame()->GetScrollBar(nBar);
}
//////////////////
// Changed tab
void CFolderView::OnChangedTab(NMFOLDERTAB* nmtab, LRESULT* pRes)
{
OnChangedFolder(nmtab->iItem);
}
void CFolderView::OnChangedFolder(int iPage)
{
// you must override
}
CFolderFrame* CFolderView::GetFolderFrame() const
{
CFolderFrame* pFolderFrame = (CFolderFrame*)GetParent();
ASSERT(pFolderFrame);
ASSERT_KINDOF(CFolderFrame, pFolderFrame);
return pFolderFrame;
}