// VViewManager.cpp : implementation file
//
#include "stdafx.h"
#include "resource.h" // main symbols
#include "ViewManager.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define ID_VIEWTAB 1005
#define ID_DEFDOCTIPS _T("A new unsaved file")
#define ID_DEFCAPTION _T("Open File Tabs Bar")
#define ID_TABHEIGHT 26
//
// This function adds a title entry to a popup menu
//
void AddMenuTitle(CMenu* popup, LPCSTR title)
{
// insert a separator item at the top
popup->InsertMenu(0, MF_BYPOSITION | MF_SEPARATOR, 0, title);
// insert title item
// note: item is not selectable (disabled) but not grayed
popup->InsertMenu(0, MF_BYPOSITION | MF_STRING | MF_DISABLED, 0, title);
SetMenuDefaultItem(popup->m_hMenu, 0, TRUE);
}
/////////////////////////////////////////////////////////////////////////////
// CVViewManager
IMPLEMENT_DYNAMIC(CViewManager, CControlBar)
CViewManager::CViewManager()
{
m_bClosing = FALSE;
m_nLMargin = 10;
m_nDockID = 0;
m_bWin2000 = TRUE;
}
CViewManager::~CViewManager()
{
m_arViews.RemoveAll();
m_arViewTitles.RemoveAll();
}
BEGIN_MESSAGE_MAP(CViewManager, CControlBar)
//{{AFX_MSG_MAP(CViewManager)
ON_WM_SIZE()
ON_WM_CREATE()
ON_WM_RBUTTONDOWN()
ON_WM_WINDOWPOSCHANGING()
ON_WM_WINDOWPOSCHANGED()
//}}AFX_MSG_MAP
ON_NOTIFY(TTN_NEEDTEXT, 0, OnViewManagerToolTip)
END_MESSAGE_MAP()
void CViewManager::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
CMDIFrameWnd* pFrame = static_cast<CMDIFrameWnd *>(AfxGetApp()->m_pMainWnd);
if (pFrame == NULL)
return; // this is not meant for us...
// Get the active MDI child window.
CMDIChildWnd* pChild = static_cast<CMDIChildWnd *>(pFrame->GetActiveFrame());
// Get the active view attached to the active MDI child window.
CView* pActiveView = reinterpret_cast<CView *>(pChild->GetActiveView());
if (pActiveView == NULL) //...Is there a view anyway?
{
//...since there is no view hide the tab control, otherwise it looks...guess!
m_ViewTabCtrl.ShowWindow(SW_HIDE);
return;
}
else
{
//...we might have hidden the tab control, show it now
if (!m_ViewTabCtrl.IsWindowVisible())
m_ViewTabCtrl.ShowWindow(SW_SHOW);
}
// Now, we go...
int iSel = -1;
CString strWin;
for (int t = 0; t < m_arViewTitles.GetSize(); t++)
{
CView* pViewAt = static_cast<CView *>(m_arViews.GetAt(t));
pViewAt->GetParent()->GetWindowText(strWin);
// ...if there is window title change since the last update set the new title
if (strWin != m_arViewTitles.GetAt(t))
SetViewName(strWin, pViewAt);
// ...find the active view from the view list
if (pActiveView == static_cast<CView *>(m_arViews.GetAt(t)))
iSel = t;
}
m_ViewTabCtrl.SetCurSel(iSel); // set the tab for the active view
// Be polite! update the dialog controls added to the CSizingControlBar
UpdateDialogControls(pTarget, bDisableIfNoHndler);
}
////////////////////////////////////////////////////////////////////////////
// CViewManager operations
void CViewManager::AddView(const TCHAR* csName, CView* pView)
{
if (m_bClosing)
return;
CString cs(csName);
m_arViews.Add(pView);
m_arViewTitles.Add(cs);
if (m_ViewTabCtrl.GetSafeHwnd())
{
TCITEM tci;
tci.mask = TCIF_TEXT | TCIF_PARAM | TCIF_IMAGE;
tci.pszText = cs.LockBuffer();
tci.lParam = reinterpret_cast<LPARAM>(pView);
tci.iImage = 0; //TODO
m_ViewTabCtrl.InsertItem(m_ViewTabCtrl.GetItemCount(), &tci);
cs.UnlockBuffer();
}
}
void CViewManager::RemoveView(CView* pView)
{
if (m_bClosing || m_arViews.GetSize() <= 0)
return;
int nTabs;
if (m_ViewTabCtrl.GetSafeHwnd())
{
for (nTabs = 0; nTabs < m_ViewTabCtrl.GetItemCount(); nTabs++)
{
TCITEM tci;
tci.mask = TCIF_PARAM;
m_ViewTabCtrl.GetItem(nTabs, &tci);
if (tci.lParam == reinterpret_cast<LPARAM>(pView))
{
m_ViewTabCtrl.DeleteItem(nTabs);
break;
}
}
}
for (nTabs = 0; nTabs < m_arViews.GetSize(); nTabs++)
{
if (static_cast<CView *>(m_arViews.GetAt(nTabs)) == pView)
{
m_arViewTitles.RemoveAt(nTabs);
m_arViews.RemoveAt(nTabs);
return;
}
}
}
void CViewManager::RemoveAll()
{
m_arViews.RemoveAll();
m_arViewTitles.RemoveAll();
}
void CViewManager::SetViewName(const TCHAR* cs, CView* pView)
{
if (m_bClosing || m_arViews.GetSize() <= 0)
return;
int nTabs;
CString csName(cs);
if (m_ViewTabCtrl.GetSafeHwnd())
{
for (nTabs = 0; nTabs < m_ViewTabCtrl.GetItemCount(); nTabs++)
{
TCITEM tci;
tci.mask = TCIF_PARAM;
m_ViewTabCtrl.GetItem(nTabs, &tci);
if (tci.lParam == reinterpret_cast<LPARAM>(pView))
{
tci.mask = TCIF_PARAM | TCIF_TEXT;
tci.pszText = csName.LockBuffer();
m_ViewTabCtrl.SetItem(nTabs, &tci);
csName.UnlockBuffer();
m_ViewTabCtrl.Invalidate();
break;
}
}
}
for (nTabs = 0; nTabs < m_arViews.GetSize(); nTabs++)
{
if (static_cast<CView *>(m_arViews.GetAt(nTabs)) == pView)
{
m_arViewTitles.SetAt(nTabs, csName);
return;
}
}
}
int CViewManager::GetWindowNum()
{
return m_arViews.GetSize();
}
void CViewManager::OnActivateView(const BOOL bActivate, CView* pView)
{
if (bActivate)
{
if (m_ViewTabCtrl.GetSafeHwnd())
{
for (int nTabs = 0; nTabs < m_ViewTabCtrl.GetItemCount(); nTabs++)
{
TCITEM tci;
tci.mask = TCIF_PARAM;
m_ViewTabCtrl.GetItem(nTabs, &tci);
if (tci.lParam == reinterpret_cast<LPARAM>(pView))
{
m_ViewTabCtrl.SetCurSel(nTabs);
m_ViewTabCtrl.Invalidate();
break;
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
// CViewManager message handlers
void CViewManager::OnSize(UINT nType, int cx, int cy)
{
CControlBar::OnSize(nType, cx, cy);
CRect rect, rcClient;
if (m_ViewTabCtrl.GetSafeHwnd())
{
DWORD dwStyle = m_ViewTabCtrl.GetStyle();
if (dwStyle & TCS_BOTTOM)
{
GetClientRect(rect);
GetClientRect(rcClient);
int nxOffset = GetSystemMetrics(SM_CXSIZEFRAME);
m_ViewTabCtrl.SetWindowPos(&wndTop, rcClient.left + nxOffset + m_nLMargin,
rcClient.top, rect.Width() - nxOffset * 5 - m_nLMargin,
ID_TABHEIGHT, SWP_SHOWWINDOW);
m_sizeMRU = CSize(cx, cy);
}
else
{
GetClientRect(rect);
int nxOffset = GetSystemMetrics(SM_CXSIZEFRAME);
m_ViewTabCtrl.SetWindowPos(&wndTop, nxOffset + m_nLMargin, 3,
rect.Width() - nxOffset * 5 - m_nLMargin, ID_TABHEIGHT, SWP_SHOWWINDOW);
m_sizeMRU = CSize(cx, cy);
}
}
}
int CViewManager::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CControlBar::OnCreate(lpCreateStruct) == -1)
return -1;
m_ViewTabImages.Create(16, 16, ILC_MASK, 5, 5);
m_ViewTabCtrl.Create(WS_CHILD | WS_VISIBLE | WS_EX_NOPARENTNOTIFY |
TCS_BUTTONS | TCS_FLATBUTTONS | // pLaY with this!
TCS_TOOLTIPS | TCS_SINGLELINE | TCS_FOCUSNEVER | TCS_FORCELABELLEFT,
CRect(0, 0, 0, 0), this, ID_VIEWTAB);
TabCtrl_SetExtendedStyle(m_ViewTabCtrl.m_hWnd, TCS_EX_FLATSEPARATORS);
m_ViewTabCtrl.SetImageList(&m_ViewTabImages);
// Build the image list here
HICON hIcon = AfxGetApp()->LoadStandardIcon(IDI_APPLICATION);
// HICON hIcon = AfxGetApp()->LoadIcon(IDR_DEMOTYPE);
m_ViewTabImages.Add(hIcon);
// Enable tooltips for all controls
EnableToolTips(TRUE);
return 0;
}
void CViewManager::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
POINT ptScreen = point;
// Convert the mouse point to screen coordinates since that is what is used by
// the TrackPopupMenu() function.
ClientToScreen(&ptScreen);
CMenu cMenu;
cMenu.CreatePopupMenu();
cMenu.AppendMenu(MF_STRING, ID_VIEW_VIEWTAB, _T("Op&en File Tabs"));
cMenu.AppendMenu(MF_STRING, ID_VIEW_FULLSCREEN, _T("F&ull Screen"));
cMenu.AppendMenu(MF_SEPARATOR);
cMenu.AppendMenu(MF_STRING, ID_WINDOW_CLOSE_ALL, _T("C&lose All"));
cMenu.AppendMenu(MF_STRING, ID_WINDOW_SAVE_ALL, _T("&Save All"));
cMenu.AppendMenu(MF_SEPARATOR);
cMenu.AppendMenu(MF_STRING, ID_WINDOW_NEW, _T("&New Windows"));
cMenu.AppendMenu(MF_STRING, ID_WINDOW_ARRANGE, _T("&Arrange Icons"));
cMenu.AppendMenu(MF_STRING, ID_WINDOW_CASCADE, _T("&Cascade Windows"));
cMenu.AppendMenu(MF_STRING, ID_WINDOW_TILE_HORZ, _T("Tile &Horizontally"));
cMenu.AppendMenu(MF_STRING, ID_WINDOW_TILE_VERT, _T("Tile &Vertically"));
cMenu.AppendMenu(MF_SEPARATOR);
cMenu.AppendMenu(MF_STRING, ID_WINDOW_NEXT, _T("Ne&xt Window"));
cMenu.AppendMenu(MF_STRING, ID_WINDOW_PREVIOUS, _T("P&revious Window"));
cMenu.AppendMenu(MF_SEPARATOR);
cMenu.AppendMenu(MF_STRING, ID_WINDOW_MANAGE, _T("&Windows..."));
// insert a separator item at the top
cMenu.InsertMenu(0, MF_BYPOSITION | MF_SEPARATOR, 0, _T(""));
// insert title item
// note: item is not selectable (disabled) but not grayed
cMenu.InsertMenu(0, MF_BYPOSITION | MF_STRING | MF_DISABLED, 0, _T("Open File Tabs Bar"));
::SetMenuDefaultItem(cMenu.m_hMenu, 0, TRUE);
cMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, ptScreen.x, ptScreen.y, AfxGetMainWnd());
cMenu.DestroyMenu();
CControlBar::OnRButtonDown(nFlags, point);
}
BOOL CViewManager::OnViewManagerToolTip(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
TCHITTESTINFO hti;
TOOLTIPTEXT *pTTT = reinterpret_cast<TOOLTIPTEXT *>(pNMHDR);
UINT nID = pNMHDR->idFrom;
// if there are some dialog controls, progress the tooltips
if (pTTT->uFlags & TTF_IDISHWND)
{
// idFrom is actually the HWND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
if (nID)
{
pTTT->lpszText = MAKEINTRESOURCE(nID);
pTTT->hinst = AfxGetResourceHandle();
return TRUE;
}
}
// Now, address the view tab tooltips
hti.pt = CPoint(GetMessagePos());
m_ViewTabCtrl.ScreenToClient(&hti.pt);
int nTab = m_ViewTabCtrl.HitTest(&hti);
if (nTab >= 0)
{
CView* pView = static_cast<CView *> (m_arViews.GetAt(nTab));
ASSERT(pView != NULL);
CDocument* pDoc = pView->GetDocument();
CString strTabText = pDoc->GetPathName();
if (strTabText.IsEmpty()) //... the document is not yet saved?
strTabText = ID_DEFDOCTIPS;
lstrcpy(pTTT->lpszText, strTabText);
return TRUE;
}
return FALSE;
}
BOOL CViewManager::CreateViewManager(CMDIFrameWnd *pMDIFrameWnd, UINT uID)
{
if (!Create(ID_DEFCAPTION, pMDIFrameWnd, m_sizeDefault, uID))
{
TRACE0(_T("Failed to create Tab bar\n"));
return FALSE; // fail to create
}
SetBarStyle(GetBarStyle() | CBRS_TOP |
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
EnableDocking(CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM);
pMDIFrameWnd->DockControlBar(this);
return TRUE;
}
BOOL CViewManager::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd,
CSize sizeDefault, UINT nID, DWORD dwStyle)
{
// must have a parent
ASSERT_VALID(pParentWnd);
// cannot be both fixed and dynamic
// (CBRS_SIZE_DYNAMIC is used for resizng when floating)
ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC)));
m_dwStyle = dwStyle & CBRS_ALL; // save the control bar styles
m_sizeDefault = sizeDefault; // set fixed size
m_sizeMRU = sizeDefault;
// register and create the window - skip CControlBar::Create()
CString strWndclass = ::AfxRegisterWndClass(CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), ::GetSysColorBrush(COLOR_BTNFACE), 0);
dwStyle &= ~CBRS_ALL;
dwStyle |= WS_CLIPCHILDREN | CCS_NOPARENTALIGN | CCS_NOMOVEY | CCS_NORESIZE;
if (!CWnd::Create(strWndclass, lpszWindowName, dwStyle,
CRect(0, 0, 0, 0), pParentWnd, nID))
return FALSE;
return TRUE;
}
CSize CViewManager::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
if (bStretch) // if not docked stretch to fit
return CSize(bHorz ? 32767 : m_sizeDefault.cx, bHorz ? m_sizeDefault.cy : 32767);
CClientDC dc(NULL);
HFONT hFont = reinterpret_cast<HFONT>(SendMessage(WM_GETFONT));
HFONT hOldFont = NULL;
if (hFont != NULL)
hOldFont = reinterpret_cast<HFONT>(dc.SelectObject(hFont));
TEXTMETRIC tm;
VERIFY(dc.GetTextMetrics(&tm));
if (hOldFont != NULL)
dc.SelectObject(hOldFont);
// get border information
CSize size;
CRect rcInside, rcWnd;
rcInside.SetRectEmpty();
CalcInsideRect(rcInside, bHorz);
GetParentFrame()->GetWindowRect(&rcWnd);
size.cx = rcWnd.Width();
size.cy = tm.tmHeight + tm.tmInternalLeading/* - 1 */+
::GetSystemMetrics(SM_CYBORDER) * 5 - rcInside.Height();
return size;
}
CSize CViewManager::CalcDynamicLayout(int nLength, DWORD dwMode)
{
UNREFERENCED_PARAMETER(nLength); // clear that level 4 warning...
if (dwMode & LM_HORZDOCK)
{
ASSERT(dwMode & LM_HORZ);
return CalcFixedLayout(dwMode & LM_STRETCH, dwMode & LM_HORZ);
}
if (m_sizeMRU.cx > m_sizeDefault.cx)
return m_sizeMRU;
else
return m_sizeDefault;
}
void CViewManager::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
lpwndpos->flags |= SWP_FRAMECHANGED;
CControlBar::OnWindowPosChanging(lpwndpos);
UINT nOldDockID = m_nDockID;
m_nDockID = GetParent()->GetDlgCtrlID();
if (nOldDockID == m_nDockID)
return;
else
{
DWORD dwStyle = m_ViewTabCtrl.GetStyle();
switch(m_nDockID)
{
case AFX_IDW_DOCKBAR_TOP:
if (dwStyle & TCS_BOTTOM)
{
DWORD dwNewStyle = dwStyle & ~TCS_BOTTOM;
m_ViewTabCtrl.ModifyStyle(dwStyle, dwNewStyle);
}
break;
case AFX_IDW_DOCKBAR_BOTTOM:
if ((dwStyle & TCS_BOTTOM) == 0)
{
DWORD dwNewStyle = dwStyle | TCS_BOTTOM;
m_ViewTabCtrl.ModifyStyle(dwStyle, dwNewStyle);
}
break;
case AFX_IDW_DOCKBAR_LEFT:
break;
case AFX_IDW_DOCKBAR_RIGHT:
break;
default:
DWORD dwNewStyle = dwStyle & ~TCS_BOTTOM;
m_ViewTabCtrl.ModifyStyle(dwStyle, dwNewStyle);
break;
}
}
}
void CViewManager::DoPaint(CDC* pDC)
{
CRect rect;
GetClientRect(rect);
// clean background
COLORREF clr = ::GetSysColor(COLOR_BTNFACE);
pDC->FillSolidRect(rect, clr);
// draw the gripper
DrawGripper(pDC);
// It is better to let the underlining control bar take the last shot
CControlBar::DoPaint(pDC);
}
void CViewManager::DrawGripper(CDC* pDC)
{
if( (m_dwStyle & CBRS_FLOATING) || m_dwDockStyle == 0 )
return;
COLORREF clrBtnHilight = ::GetSysColor(COLOR_BTNHILIGHT);
COLORREF clrBtnShadow = ::GetSysColor(COLOR_BTNSHADOW);
CRect rcGrip;
GetWindowRect(&rcGrip);
ScreenToClient(&rcGrip);
rcGrip.OffsetRect(-rcGrip.left, -rcGrip.top);
if(m_dwStyle & CBRS_ORIENT_HORZ)
{
// gripper at left
rcGrip.DeflateRect(4, 4);
rcGrip.right = rcGrip.left + 3;
pDC->Draw3dRect(rcGrip, clrBtnHilight, clrBtnShadow);
if (!m_bWin2000)
{
rcGrip.OffsetRect(3, 0);
pDC->Draw3dRect(rcGrip, clrBtnHilight, clrBtnShadow);
}
}
else
{
// gripper at top
rcGrip.DeflateRect(4, 4);
rcGrip.bottom = rcGrip.top + 3;
pDC->Draw3dRect(rcGrip, clrBtnHilight, clrBtnShadow);
if (!m_bWin2000)
{
rcGrip.OffsetRect(0, 3);
pDC->Draw3dRect(rcGrip, clrBtnHilight, clrBtnShadow);
}
}
}
void CViewManager::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)
{
OnSize(0, lpwndpos->cx, lpwndpos->cy);
CControlBar::OnWindowPosChanged(lpwndpos);
}