www.pudn.com > tabandSplitter.rar > VisualFx.cpp


/*############################################################################# 
# VISUALFX.CPP 
# 
# SCA Software International S.A. 
# http://www.scasoftware.com 
# scaadmin@scasoftware.com 
# 
# Copyright (c) 1999 SCA Software International S.A. 
# 
# Date: 03.01.2000 
# Author: Zoran M.Todorovic 
# 
# This software is provided "AS IS", without a warranty of any kind. 
# You are free to use/modify this code but leave this header intact. 
# 
#############################################################################*/ 
 
#include "stdafx.h" 
#include         // Needed for WM_SIZEPARENT 
 
#include "VisualFx.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#endif 
 
//============================================================================= 
// class TTabItem 
// 
//============================================================================= 
 
// Create a tab item  
TTabItem::TTabItem(CWnd *pParent, LPCTSTR szLabel) 
{ 
  m_pWnd = NULL; 
  m_nMinX = m_nMaxX = 0; 
  m_bVisible = TRUE; 
  m_bEnabled = TRUE; 
  m_bWndEnabled = TRUE; 
  RECT rect; 
  ::ZeroMemory(&rect,sizeof(RECT)); 
  m_pCaption = new CStatic; 
  ASSERT(m_pCaption); 
  m_pCaption->Create(szLabel, WS_CHILD|SS_CENTER|WS_VISIBLE,rect,pParent); 
} 
 
TTabItem::TTabItem(const TTabItem& obj) 
{ 
  *this = obj; 
} 
 
TTabItem& TTabItem::operator=(const TTabItem& obj) 
{ 
  m_pWnd = obj.m_pWnd; 
  m_pCaption = obj.m_pCaption; 
  m_bWndEnabled = obj.m_bWndEnabled; 
  m_bEnabled = obj.m_bEnabled; 
  m_bVisible = obj.m_bVisible; 
  m_nMinX = obj.m_nMinX; 
  m_nMaxX = obj.m_nMaxX; 
  return *this; 
} 
 
TTabItem::~TTabItem() 
{ 
  // This is done in TVisualFramework::Destroy() 
  //if (m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) 
  //  delete m_pWnd; 
  ASSERT(m_pCaption); 
  delete m_pCaption; 
} 
 
// Set rectangle for tab caption 
void TTabItem::SetRect(CRect& rect) 
{ 
  ASSERT(m_pCaption); 
  m_pCaption->MoveWindow(&rect); 
} 
 
// Set font for tab caption 
void TTabItem::SetFont(CFont *pFont) 
{ 
  ASSERT(m_pCaption); 
  ASSERT(pFont); 
  m_pCaption->SetFont(pFont,FALSE); 
} 
 
// Get tab caption text 
CString TTabItem::GetText(void) 
{ 
  ASSERT(m_pCaption); 
  CString str; 
  m_pCaption->GetWindowText(str); 
  return str; 
} 
 
int TTabItem::GetLength(void) 
{ 
  return m_nMaxX - m_nMinX; 
} 
 
// Set tab caption text 
void TTabItem::SetText(LPCTSTR szLabel) 
{ 
  ASSERT(m_pCaption); 
  ASSERT(szLabel); 
  m_pCaption->SetWindowText(szLabel); 
} 
 
// Enable/disable a window 
void TTabItem::Enable(BOOL bEnable) 
{ 
  m_bWndEnabled = bEnable; 
} 
 
// Enable/disable tab caption 
void TTabItem::EnableTab(BOOL bEnable) 
{ 
  ASSERT(m_pCaption); 
  m_bEnabled = bEnable; 
  m_pCaption->EnableWindow(m_bEnabled); 
} 
 
// Show/hide tab caption 
void TTabItem::ShowTab(BOOL bShow) 
{ 
  ASSERT(m_pCaption); 
  m_bVisible = bShow; 
  m_pCaption->ShowWindow(bShow ? SW_SHOW : SW_HIDE); 
} 
 
CWnd *TTabItem::GetSafeWnd(void) 
{ 
  return (m_pWnd && ::IsWindow(m_pWnd->m_hWnd)) ? m_pWnd : NULL; 
} 
 
//============================================================================= 
// class TTabWnd 
// 
//============================================================================= 
 
#define TABWND_DEFAULT_ID 0x2578 
#define TABWND_HEIGHT     30    // Height of the gray border between the toolbar  
                                // and the client area 
#define TAB_HEIGHT        20    // Height on the normal tab 
#define TABSEL_HEIGHT     20    // Height of the selected tab 
#define TAB_SPACE         6     // Add to tab caption text width 
#define TAB_DEPL          4     // Distance between the tabs and the client area 
#define TAB_MAXLEN        200 
 
IMPLEMENT_DYNCREATE(TTabWnd,CWnd) 
 
BEGIN_MESSAGE_MAP(TTabWnd, CWnd) 
  //{{AFX_MSG_MAP(TTabWnd) 
  ON_MESSAGE(WM_SIZEPARENT, OnSizeParent) 
  ON_WM_ERASEBKGND() 
  ON_WM_PAINT() 
  ON_WM_LBUTTONUP() 
  ON_WM_DESTROY() 
  ON_WM_SIZE() 
	ON_WM_CREATE() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
TTabWnd::TTabWnd() 
{ 
  m_nSelectedTab = 0; 
  m_bLockFlag = FALSE; 
  m_nTabPos = TP_BOTTOM; 
  // cache most used resources 
  m_BrushBlack.CreateSolidBrush(RGB(0,0,0)); 
  m_BrushLGray.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)); 
  m_PenBlack.CreatePen(PS_SOLID, 1, (COLORREF)0); 
  m_PenLGray.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_BTNFACE)); 
  m_PenWhite.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_BTNHIGHLIGHT)); 
  m_PenWhite2.CreatePen(PS_SOLID, 2, ::GetSysColor(COLOR_BTNHIGHLIGHT)); 
  m_PenDGray.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_BTNSHADOW)); 
  m_PenDGray2.CreatePen(PS_SOLID, 2, ::GetSysColor(COLOR_BTNSHADOW)); 
} 
 
TTabWnd::~TTabWnd() 
{ 
} 
 
// Find a tab within this tab window 
TTabItem *TTabWnd::findTabItem(int nIndex) 
{ 
  int nNdx = 0; 
  TTabItemList::iterator iterator; 
  for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { 
    if (nNdx == nIndex) 
      return (*iterator); 
    nNdx ++; 
  } 
  return NULL; 
} 
 
// Create a tab window 
BOOL TTabWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,  
                     DWORD dwStyle, const RECT& prect, CWnd* pParentWnd,  
                     UINT nID, CCreateContext *pContext) 
{ 
  ASSERT(pParentWnd); 
 
  dwStyle &= ~WS_BORDER; 
  CRect rect(prect); 
  if (!CWnd::Create(NULL, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext)) 
    return FALSE; 
  if (pParentWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { 
    ((CFrameWnd*)pParentWnd)->ModifyStyleEx(WS_EX_CLIENTEDGE,0,SWP_FRAMECHANGED); 
    ((CFrameWnd*)pParentWnd)->RecalcLayout(); 
  } 
  ResizeTab(); 
  return TRUE; 
} 
 
int TTabWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CWnd::OnCreate(lpCreateStruct) == -1) 
		return -1; 
	 
  createFont(); 
	return 0; 
} 
 
void TTabWnd::OnDestroy()  
{ 
  CWnd::OnDestroy(); 
  TTabItemList::iterator iterator; 
  for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator ++) { 
    delete (*iterator); 
  } 
  m_TabList.clear(); 
  // This is done in TVisualFramework 
  //if (GetParent()->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) 
  //  delete this; 
} 
 
// Virtual function to check whether switch to new tab can be done 
BOOL TTabWnd::CanSetActivePane(CWnd *pOldPane, CWnd *pNewPane) 
{ 
  return TRUE; 
} 
 
// Virtual function (after the switch is done) 
void TTabWnd::OnSetActivePane(CWnd *pOldPane, CWnd *pNewPane) 
{ 
} 
 
// Create fonts for tab labels 
void TTabWnd::createFont() 
{ 
	NONCLIENTMETRICS metrics; 
	metrics.cbSize = sizeof(metrics); 
  ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0); 
 
  CWindowDC wdc(NULL); 
  int nLPixY = GetDeviceCaps(wdc.m_hDC, LOGPIXELSY); 
 
	m_Font.CreateFontIndirect(&metrics.lfStatusFont); 
} 
 
// Add a tab to this window 
TTabItem *TTabWnd::addTab(CWnd *pWnd, LPCTSTR szLabel) 
{ 
  ASSERT(pWnd); 
  ASSERT(szLabel); 
 
  TTabItem *pItem = new TTabItem(this,szLabel); 
  pItem->m_pWnd = pWnd; 
  m_TabList.insert(m_TabList.end(), pItem); 
  return pItem; 
} 
 
int TTabWnd::GetTabLength() 
{ 
  int nLength = 0; 
  TTabItemList::iterator iterator; 
  for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { 
    nLength += (*iterator)->GetLength(); 
  } 
  return nLength; 
} 
 
// Get index of currently selected tab 
int TTabWnd::GetTabIndex(void) 
{ 
  return m_nSelectedTab; 
} 
 
// Get number of tabs 
int TTabWnd::GetTabCount(void) 
{ 
  return m_TabList.size(); 
} 
 
// Get index of the tab associated with specified window 
int TTabWnd::GetTabIndex(CWnd *pWnd) 
{ 
  ASSERT(pWnd); 
 
  int nIndex = 0; 
  TTabItem *pItem; 
  TTabItemList::iterator iterator; 
  for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { 
    pItem = *iterator; 
    if (pItem->m_pWnd == pWnd) 
      return nIndex; 
    nIndex ++; 
  } 
  return -1; 
} 
 
// Get pointer to window associated with the specified tab index 
CWnd *TTabWnd::GetTabWnd(int index) 
{ 
  TTabItem *pItem = findTabItem(index); 
  ASSERT(pItem); 
  return ::IsWindow(pItem->m_pWnd->m_hWnd) ? pItem->m_pWnd : NULL; 
} 
 
// Get tab caption text of the specified tab 
CString TTabWnd::GetTabLabel(int nIndex) 
{ 
  TTabItem *pItem = findTabItem(nIndex); 
  ASSERT(pItem); 
  return pItem->GetText(); 
} 
 
// Set text of tab caption 
void TTabWnd::SetTabLabel(int nIndex, LPCTSTR szLabel) 
{ 
  ASSERT(szLabel); 
  TTabItem *pItem = findTabItem(nIndex); 
  ASSERT(pItem); 
  pItem->SetText(szLabel); 
  invalidateTabArea(); 
} 
 
// Enable/disable a view 
void TTabWnd::Enable(int nIndex, BOOL bEnable) 
{ 
  TTabItem *pItem = findTabItem(nIndex); 
  ASSERT(pItem); 
  pItem->Enable(bEnable); 
  //pItem->m_pWnd->EnableWindow(bEnable); 
} 
 
// Cannot disable currently selected tab 
void TTabWnd::EnableTab(int nIndex, BOOL bEnable) 
{ 
  ASSERT(nIndex != m_nSelectedTab); 
  TTabItem *pItem = findTabItem(nIndex); 
  ASSERT(pItem); 
  pItem->EnableTab(bEnable); 
  invalidateTabArea(); 
} 
 
// Cannot make invisible currently selected tab 
void TTabWnd::ShowTab(int nIndex, BOOL bShow) 
{ 
  ASSERT(nIndex != m_nSelectedTab); 
  TTabItem *pItem = findTabItem(nIndex); 
  ASSERT(pItem); 
  pItem->ShowTab(bShow); 
  invalidateTabArea(); 
} 
 
// Is tab enabled 
BOOL TTabWnd::IsTabEnabled(int nIndex) 
{ 
  TTabItem *pItem = findTabItem(nIndex); 
  ASSERT(pItem); 
  return pItem->m_bEnabled; 
} 
 
// Is tab visible 
BOOL TTabWnd::IsTabVisible(int nIndex) 
{ 
  TTabItem *pItem = findTabItem(nIndex); 
  ASSERT(pItem); 
  return pItem->m_bVisible; 
} 
 
// Set font 
void TTabWnd::SetFont(CFont *pFont) 
{ 
  ASSERT(pFont); 
  CWnd::SetFont(pFont); 
  m_Font.DeleteObject(); 
  LOGFONT lf; 
  pFont->GetLogFont(&lf); 
  m_Font.CreateFontIndirect(&lf); 
  invalidateTabArea(); 
} 
 
// Set position of tabs (top or bottom) 
void TTabWnd::SetTabPos(TTabPos nTabPos) 
{ 
  m_nTabPos = nTabPos; 
} 
 
// Invalidate rectangle to redraw tabs 
void TTabWnd::invalidateTabArea(void) 
{ 
  CRect rect; 
  switch (m_nTabPos) { 
  case TP_TOP:  
    InvalidateRect(&CRect(0, 0, 32000, TABWND_HEIGHT));  
    break; 
  case TP_BOTTOM: 
    GetClientRect(&rect); 
    InvalidateRect(&CRect(CPoint(0,rect.Height()-TABWND_HEIGHT),  
                          CSize(32000,TABWND_HEIGHT))); 
    break; 
  }; 
} 
 
// Draws a selected tab and returns its height 
int TTabWnd::drawSelTabTop(CDC *pDC, int x, CRect& client, TTabItem *pItem) 
{ 
  ASSERT(pItem); 
  ASSERT(pDC); 
 
  CString str = pItem->GetText(); 
  CSize textSize = pDC->GetTextExtent(str); 
  textSize.cx += 10; 
  if (textSize.cx > TAB_MAXLEN) 
    textSize.cx = TAB_MAXLEN; 
  int y = TABWND_HEIGHT - TABSEL_HEIGHT - TAB_DEPL; 
 
  // black border, no bottom line 
  pDC->SelectObject(&m_PenBlack); 
  pDC->MoveTo(x,y+TABSEL_HEIGHT-1); 
  pDC->LineTo(x,y); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-1, y); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-1, y+TABSEL_HEIGHT); 
 
  // left and upper border in white, double line 
  pDC->SelectObject(&m_PenWhite2); 
  pDC->MoveTo(x+2,y+TABSEL_HEIGHT-1); 
  pDC->LineTo(x+2,y+2); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-4, y+2); 
 
  // right border, dark gray, double line 
  pDC->SelectObject(&m_PenDGray2); 
  pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y+2); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TABSEL_HEIGHT-1); 
 
  // clean up 
  pDC->SelectObject(&m_PenLGray); 
  pDC->MoveTo(x-1, y+TABSEL_HEIGHT); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE, y+TABSEL_HEIGHT); 
  pDC->MoveTo(x-1, y+TABSEL_HEIGHT+1); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE, y+TABSEL_HEIGHT+1); 
 
  // a black line to far left and right 
  pDC->SelectObject(&m_PenBlack); 
  pDC->MoveTo(0, y+TABSEL_HEIGHT-1); 
  pDC->LineTo(x, y+TABSEL_HEIGHT-1); 
  pDC->MoveTo(x+textSize.cx+TAB_SPACE+1, y+TABSEL_HEIGHT-1); 
  pDC->LineTo(client.right, y+TABSEL_HEIGHT-1); 
 
  // and a white double line 
  pDC->SelectObject(&m_PenWhite2); 
  if (x!=0) { 
    pDC->MoveTo(0, y+TABSEL_HEIGHT+1); 
    pDC->LineTo(x, y+TABSEL_HEIGHT+1); 
  } 
  pDC->MoveTo(x+textSize.cx+TAB_SPACE, y+TABSEL_HEIGHT+1); 
  pDC->LineTo(client.right, y+TABSEL_HEIGHT+1); 
 
  // gray inside 
  pDC->FillSolidRect(x+3, y+3,textSize.cx+TAB_SPACE-6, TABSEL_HEIGHT,  
                  ::GetSysColor(COLOR_BTNFACE)); 
 
  CRect rect(CPoint(x+TAB_SPACE/2, y+(TAB_HEIGHT-textSize.cy)/2+1), textSize); 
  pItem->SetFont(&m_Font); 
  pItem->SetRect(rect); 
   
  return textSize.cx+TAB_SPACE; 
} 
 
// Draw a selected tab at the bottom 
int TTabWnd::drawSelTabBottom(CDC *pDC, int x, CRect& client, TTabItem *pItem) 
{ 
  ASSERT(pItem); 
  ASSERT(pDC); 
 
  CString str = pItem->GetText(); 
  CSize textSize = pDC->GetTextExtent(str); 
  textSize.cx += 10; 
  if (textSize.cx > TAB_MAXLEN) 
    textSize.cx = TAB_MAXLEN; 
 
  int y = client.Height() - TABWND_HEIGHT + TAB_DEPL; 
 
  // black border, no bottom line 
  pDC->SelectObject(&m_PenBlack); 
  pDC->MoveTo(x,y); 
  pDC->LineTo(x,y+TABSEL_HEIGHT); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-1, y+TABSEL_HEIGHT); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-1, y); 
 
  // left border in white, double line 
  pDC->SelectObject(&m_PenWhite2); 
  pDC->MoveTo(x+2,y); 
  pDC->LineTo(x+2,y+TABSEL_HEIGHT-1); 
 
  // right and bottom border, dark gray, double line 
  pDC->SelectObject(&m_PenDGray2); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-4, y+TABSEL_HEIGHT-1); 
  pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TABSEL_HEIGHT-1); 
 
  // a black line to far left and right 
  pDC->SelectObject(&m_PenBlack); 
  pDC->MoveTo(0, y); 
  pDC->LineTo(x, y); 
  pDC->MoveTo(x+textSize.cx+TAB_SPACE, y); 
  pDC->LineTo(client.right, y); 
 
  // and a gray line to far left and right 
  pDC->SelectObject(&m_PenDGray); 
  if (x != 0) { 
    pDC->MoveTo(0, y-1); 
    pDC->LineTo(x, y-1); 
  } 
  pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y-1); 
  pDC->LineTo(client.right, y-1); 
 
  // gray inside 
  pDC->FillSolidRect(x+3,y,textSize.cx+TAB_SPACE-6, TABSEL_HEIGHT-2,  
                    ::GetSysColor(COLOR_BTNFACE)); 
 
  CRect rect(CPoint(x+TAB_SPACE/2, y+(TAB_HEIGHT-textSize.cy)/2), textSize); 
  pItem->SetFont(&m_Font); 
  pItem->SetRect(rect); 
   
  return textSize.cx+TAB_SPACE; 
} 
 
// Draws an unselected tab and returs its height 
int TTabWnd::drawTabTop(CDC *pDC, int x, CRect& client, TTabItem *pItem) 
{ 
  ASSERT(pItem); 
  ASSERT(pDC); 
 
  CString str = pItem->GetText(); 
  CSize textSize = pDC->GetTextExtent(str); 
  textSize.cx += 10; 
  if (textSize.cx > TAB_MAXLEN) 
    textSize.cx = TAB_MAXLEN; 
 
  int y = TABWND_HEIGHT-TAB_HEIGHT-TAB_DEPL; 
   
  // black border 
  pDC->FrameRect(&CRect(CPoint(x,y), CSize(textSize.cx+TAB_SPACE, TAB_HEIGHT)),  
                  &m_BrushBlack); 
 
  pDC->SelectObject(&m_PenWhite); 
  pDC->MoveTo(x+1, y+1); 
  pDC->LineTo(x+1, y+TAB_HEIGHT-1); 
  pDC->MoveTo(x+1, y+1); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+1); 
 
  pDC->SelectObject(&m_PenDGray); 
  pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y+1); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TAB_HEIGHT-1); 
 
  pDC->FillRect(&CRect(CPoint(x+2,y+2), CSize(textSize.cx+TAB_SPACE-4, TAB_HEIGHT-3)),  
                &m_BrushLGray); 
 
  // clean up 
  int dy = TABSEL_HEIGHT-TAB_HEIGHT; 
  pDC->FillSolidRect(x, y-dy, textSize.cx+TAB_SPACE, dy, GetSysColor(COLOR_BTNFACE)); 
 
  CRect rect(CPoint(x+TAB_SPACE/2, y+(TAB_HEIGHT-textSize.cy)/2+1), textSize); 
  pItem->SetFont(&m_Font); 
  pItem->SetRect(rect); 
   
  return textSize.cx+TAB_SPACE; 
} 
 
// Draw an unselected tab at the bottom 
int TTabWnd::drawTabBottom(CDC *pDC, int x, CRect& client, TTabItem *pItem) 
{ 
  ASSERT(pItem); 
  ASSERT(pDC); 
 
  CString str = pItem->GetText(); 
  CSize textSize = pDC->GetTextExtent(str); 
  textSize.cx += 10; 
  if (textSize.cx > TAB_MAXLEN) 
    textSize.cx = TAB_MAXLEN; 
 
  int y = client.Height() - TABWND_HEIGHT + TAB_DEPL; 
 
  // black border 
  pDC->FrameRect(&CRect(CPoint(x,y), CSize(textSize.cx+TAB_SPACE, TAB_HEIGHT+1)),  
                  &m_BrushBlack); 
 
  // Gray border bottom and right side 
  pDC->SelectObject(&m_PenDGray); 
  pDC->MoveTo(x+1, y+TAB_HEIGHT-1); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TAB_HEIGHT-1); 
  pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y); 
  pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TAB_HEIGHT-1); 
 
  pDC->FillRect(&CRect(CPoint(x+1,y+1), CSize(textSize.cx+TAB_SPACE-4, TAB_HEIGHT-3)),  
                &m_BrushLGray); 
 
  CRect rect(CPoint(x+TAB_SPACE/2, y+(TAB_HEIGHT-textSize.cy)/2), textSize); 
  pItem->SetFont(&m_Font); 
  pItem->SetRect(rect); 
   
  return textSize.cx+TAB_SPACE; 
} 
 
// Draw edge arround client area 
void TTabWnd::drawClient(CDC *pDc, CRect& rect) 
{ 
  ASSERT(pDc); 
 
  CWnd *pParent = GetParent(); 
  ASSERT(pParent); 
  switch (m_nTabPos) { 
  case TP_TOP: 
    if (pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { 
      pDc->DrawEdge(&rect, EDGE_ETCHED, BF_TOP); 
    } 
    pDc->Draw3dRect(0,TABWND_HEIGHT, rect.right, rect.bottom-TABWND_HEIGHT, 
                   ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHIGHLIGHT)); 
    pDc->Draw3dRect(1,TABWND_HEIGHT+1, rect.right-2, rect.bottom-TABWND_HEIGHT-2, 
                    0, ::GetSysColor(COLOR_3DLIGHT)); 
    break; 
  case TP_BOTTOM: 
    if (pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { 
      pDc->DrawEdge(&rect, EDGE_ETCHED, BF_BOTTOM); 
    } 
    pDc->Draw3dRect(0,0, rect.right, rect.bottom-TABWND_HEIGHT+1, 
                   ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHIGHLIGHT)); 
    pDc->Draw3dRect(1,1, rect.right-2, rect.bottom-TABWND_HEIGHT-1, 
                    0, ::GetSysColor(COLOR_3DLIGHT)); 
    break; 
  } 
} 
 
void TTabWnd::OnPaint() 
{ 
  CPaintDC dc(this); // device context for painting 
  CRect client; 
 
  GetClientRect(&client); 
  drawClient(&dc, client); 
 
  int x = 0, nIndex = 0; 
  TTabItemList::iterator iterator; 
  for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { 
    TTabItem *pItem = *iterator; 
    ASSERT(pItem != NULL); 
    if (pItem->m_bVisible) { 
      pItem->m_nMinX = x; 
      if (nIndex != m_nSelectedTab) { 
        switch (m_nTabPos) { 
        case TP_TOP: x += drawTabTop(&dc, x, client, pItem); break; 
        case TP_BOTTOM: x += drawTabBottom(&dc, x, client, pItem); break; 
        } 
      } else { 
        switch (m_nTabPos) { 
        case TP_TOP: x += drawSelTabTop(&dc, x, client, pItem); break; 
        case TP_BOTTOM: x += drawSelTabBottom(&dc, x, client, pItem); break; 
        } 
      } 
    } 
    pItem->m_nMaxX = x; 
    nIndex ++; 
  } 
} 
 
// Returns tab index that holds specified point 
int TTabWnd::HitTest(CPoint& point) 
{ 
  return HitTest(point.x,point.y); 
} 
 
// Returns tab index that holds specified point 
int TTabWnd::HitTest(int x, int y) 
{ 
  int notsel_y_min, sel_y_min, y_max; 
  CRect rect; 
 
  GetClientRect(&rect); 
  switch (m_nTabPos) { 
  case TP_TOP: 
    notsel_y_min = TABWND_HEIGHT - TAB_HEIGHT - TAB_DEPL; 
    sel_y_min = TABWND_HEIGHT - TABSEL_HEIGHT - TAB_DEPL; 
    y_max = TABWND_HEIGHT - TAB_DEPL; 
    break; 
  case TP_BOTTOM: 
    notsel_y_min = rect.Height() - TABWND_HEIGHT + TAB_DEPL; 
    sel_y_min = rect.Height() - TABWND_HEIGHT + TAB_DEPL; 
    y_max = rect.Height() - TABWND_HEIGHT + TAB_DEPL + TAB_HEIGHT; 
    break; 
  }; 
 
  int nIndex = 0; 
  TTabItemList::iterator iterator; 
  for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { 
    TTabItem *pItem = (*iterator); 
    if (pItem->m_bEnabled && pItem->m_bVisible) { 
      if (nIndex != m_nSelectedTab && (y < notsel_y_min || y > y_max))  
        continue; 
      if (nIndex == m_nSelectedTab && (y < sel_y_min || y > y_max))  
        continue; 
      if (x >= pItem->m_nMinX && x <= pItem->m_nMaxX) 
        return nIndex; 
    } 
    nIndex++; 
  } 
  return -1; 
} 
 
// Switch focus to specified tab index 
BOOL TTabWnd::SetActivePane(int nIndex, BOOL bActivate) 
{ 
  if (nIndex == -1) 
    return FALSE; 
  if (nIndex == m_nSelectedTab) 
    return TRUE; 
 
  TTabItem *pNewPane = findTabItem(nIndex); 
  if (!pNewPane->m_bEnabled || !pNewPane->m_bVisible) 
    return FALSE; 
  TTabItem *pOldPane = NULL; 
  if (m_nSelectedTab != -1) 
    pOldPane = findTabItem(m_nSelectedTab); 
  if (CanSetActivePane(pOldPane ? pOldPane->m_pWnd : NULL, pNewPane->m_pWnd)) { 
    // Deactivate old pane 
    if (m_nSelectedTab != -1) { 
      pOldPane->m_pWnd->EnableWindow(FALSE); 
      pOldPane->m_pWnd->ShowWindow(SW_HIDE); 
    } 
    // Activate new pane 
    pNewPane->m_pWnd->EnableWindow(pNewPane->m_bWndEnabled ? TRUE : FALSE); 
    pNewPane->m_pWnd->ShowWindow(SW_SHOW); 
    pNewPane->m_pWnd->SetFocus(); 
    // Save index of new pane 
    m_nSelectedTab = nIndex; 
    // Invalidate tab 
    invalidateTabArea(); 
    // Inform derived class 
    OnSetActivePane(pOldPane ? pOldPane->m_pWnd : NULL, pNewPane->m_pWnd); 
    // Update frame window 
    if (bActivate) { 
      CWnd *pParent = GetParent(); 
      while (pParent && !pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) 
        pParent = pParent->GetParent(); 
      ASSERT(pParent != NULL); 
      updateFrame((CFrameWnd*)pParent, pNewPane->m_pWnd); 
    } 
    return TRUE; 
  } 
  return FALSE; 
} 
 
// Update frame window active view based on newly selected tab item 
BOOL TTabWnd::updateFrame(CFrameWnd *pFrame, CWnd *pWnd) 
{ 
  ASSERT(pFrame); 
  ASSERT(pWnd); 
 
  if (pWnd->IsKindOf(RUNTIME_CLASS(CView))) { 
    // New tab item is a view 
    pFrame->SetActiveView((CView*)pWnd); 
    return TRUE; 
  } else if (pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { 
    CSplitterWnd *pSplitter = (CSplitterWnd*)pWnd; 
    CWnd *pView = pSplitter->GetActivePane(); 
    if (pView == NULL) { 
      CWnd *pTmpView; 
      for (int x = 0; x < pSplitter->GetRowCount(); x ++) { 
        for (int y = 0; y < pSplitter->GetColumnCount(); y ++) { 
          pTmpView = pSplitter->GetPane(x,y); 
          if (pTmpView->IsWindowEnabled()) { 
            if (updateFrame(pFrame, pTmpView)) 
              return TRUE; 
          } 
        } 
      } 
    } 
    if (pView == NULL) 
      pView = pSplitter->GetPane(0,0); 
    pFrame->SetActiveView((CView*)pView); 
  } else if (pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
    TTabWnd *pTab = (TTabWnd*)pWnd; 
    int nIndex = pTab->GetTabIndex(); 
    CWnd *pTabWnd = pTab->GetTabWnd(nIndex); 
    if (updateFrame(pFrame, pTabWnd)) 
      return TRUE; 
  } 
  return FALSE; 
} 
 
// Resize tab 
void TTabWnd::ResizeTab(int cx, int cy) 
{ 
  CRect rect; 
  CWnd *pParent = (CWnd*)GetParent(); 
  ASSERT(pParent); 
  pParent->GetClientRect(&rect);  
 
  if (pParent->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { 
    CSplitterWnd *splitter = (CSplitterWnd*)pParent; 
    ASSERT(pParent); 
    int row,col; 
    splitter->IsChildPane(this,row,col); 
    splitter->RecalcLayout(); 
  } else if (pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { 
    m_bLockFlag = TRUE; 
    pParent->RepositionBars(0, 0xFFFF, AFX_IDW_PANE_FIRST, CWnd::reposQuery, &rect); 
    MoveWindow(rect.left,rect.top,rect.Width(),rect.Height()); 
    m_bLockFlag = FALSE; 
  } 
 
  m_bLockFlag = TRUE; // reentrancy check (might get called recursivly from OnSize) 
  CWnd *pWnd; 
  TTabItemList::iterator iterator; 
  for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { 
    pWnd = (*iterator)->m_pWnd; 
    if (cx == -1 && cy == -1) { 
      switch (m_nTabPos) { 
      case TP_TOP: 
        pWnd->MoveWindow(1, TABWND_HEIGHT+1,  
                         rect.Width()-2, rect.Height()-TABWND_HEIGHT-2); 
        break; 
      case TP_BOTTOM: 
        pWnd->MoveWindow(1, 0, rect.Width()-2, rect.Height()-TABWND_HEIGHT); 
        break; 
      } 
    } else { 
      switch (m_nTabPos) { 
      case TP_TOP: 
        pWnd->MoveWindow(1, TABWND_HEIGHT+1, cx, cy-TABWND_HEIGHT-2); 
        break; 
      case TP_BOTTOM: 
        pWnd->MoveWindow(1, 0, cx, cy-TABWND_HEIGHT); 
        break; 
      } 
    } 
  } 
  m_bLockFlag=FALSE; 
} 
 
// Erase area where the tabs are displayed 
BOOL TTabWnd::OnEraseBkgnd(CDC* pDC) 
{ 
  ASSERT(pDC); 
 
  CRect rect; 
  GetClientRect(&rect); 
  switch (m_nTabPos) { 
  case TP_TOP: 
    pDC->FillSolidRect(&CRect(0, 0, rect.right, TABWND_HEIGHT),  
                      ::GetSysColor(COLOR_BTNFACE)); 
    break; 
  case TP_BOTTOM: 
    pDC->FillSolidRect(&CRect(0, rect.bottom-TABWND_HEIGHT-3, rect.right, rect.bottom),  
                      ::GetSysColor(COLOR_BTNFACE)); 
    break; 
  } 
  return TRUE; 
} 
 
// Handle couse click on tabs 
void TTabWnd::OnLButtonUp(UINT nFlags, CPoint point) 
{ 
  int nNewTab = HitTest(point.x, point.y); 
  SetActivePane(nNewTab); 
  CWnd::OnLButtonUp(nFlags, point); 
} 
 
// Handle resize 
LRESULT TTabWnd::OnSizeParent(WPARAM, LPARAM lParam) 
{ 
  if (m_bLockFlag) 
    return 0; 
  ResizeTab(); 
  return 0; 
} 
 
// Handle resize 
void TTabWnd::OnSize(UINT nType, int cx, int cy)  
{ 
  CWnd::OnSize(nType, cx, cy); 
  ResizeTab(cx,cy); 
} 
 
// Create a CView derived class as a tab 
TTabItem *TTabWnd::CreatePane(LPCTSTR lpszLabel, CRuntimeClass *pViewClass,  
                                 CCreateContext *pContext) 
{ 
  CRect rect, client; 
  ASSERT(pViewClass && pContext); 
 
  CWnd *pWnd = (CWnd*)pViewClass->CreateObject(); 
  if (!pWnd)  
    return NULL; 
   
  GetClientRect(&client); 
  rect.left = 0; 
  rect.top = TABWND_HEIGHT+2; 
  rect.right = client.right; 
  rect.bottom = client.bottom; 
 
  int dwStyle = AFX_WS_DEFAULT_VIEW; 
  if (GetParent()->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { 
    dwStyle &= ~WS_BORDER; 
  } 
 
  if (!pWnd->Create(NULL, NULL, dwStyle, rect, this, 13576+m_TabList.size(), pContext)) 
  { 
    TRACE0("Warning: couldn't create client area for tab view\n"); 
    // pWnd will be cleaned up by PostNcDestroy 
    return NULL; 
  } 
 
  // Insert new tab object into the list 
  TTabItem *pTab = addTab(pWnd,lpszLabel); 
  ASSERT(pTab); 
  if (m_TabList.size() != 1) { 
    pWnd->EnableWindow(FALSE); 
    pWnd->ShowWindow(SW_HIDE); 
  /* 
  // Framework is responsible to set the active view 
  } else { 
    CWnd *pParent = GetParent(); 
    if (pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { 
      ((CFrameWnd*)pParent)->SetActiveView((CView*)pWnd); 
    } else if (pParent->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { 
      ((CSplitterWnd*)pParent)->SetActivePane(0,0,pWnd); 
    } 
  */ 
  } 
  return pTab; 
} 
 
// Create a splitter window as a tab 
TTabItem *TTabWnd::CreatePane(LPCTSTR lpszLabel, int nRows, int nCols,  
                                 CWnd *pWnd, UINT nID) 
{ 
  ASSERT(pWnd); 
  ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); 
 
  // Moved to TVisualFramework to handle creation of CSplitterWnd derived classes 
  //CSplitterWnd *pWnd = new CSplitterWnd; 
  //if (!pWnd)  
  //  return NULL; 
 
  int dwStyle = AFX_WS_DEFAULT_VIEW; 
  dwStyle &= ~WS_BORDER; 
 
  CSplitterWnd *pSplitter = (CSplitterWnd*)pWnd; 
  if (!pSplitter->CreateStatic(this, nRows, nCols, dwStyle, nID)) { 
    TRACE0("Warning: couldn't create client area for tab view\n"); 
    // pWnd will be cleaned up by PostNcDestroy 
    return NULL; 
  } 
 
  TTabItem *pTab = addTab(pWnd,lpszLabel); 
  ASSERT(pTab); 
  if (m_TabList.size() != 1) { 
    pWnd->EnableWindow(FALSE); 
    pWnd->ShowWindow(SW_HIDE); 
  }  
 
  /* 
  // Framework will set the active view 
  CWnd *paneWnd = pWnd->GetActivePane(); 
  if (paneWnd) { 
    ((CFrameWnd*)GetParent())->SetActiveView((CView*)paneWnd); 
  } else { 
    paneWnd = pWnd->GetPane(0,0); 
    pWnd->SetActivePane(0,0); 
    ((CFrameWnd*)GetParent())->SetActiveView((CView*)paneWnd); 
  } 
  */ 
 
  return pTab; 
} 
 
//============================================================================= 
// class TVisualObject 
// 
//============================================================================= 
 
// Private constructor 
TVisualObject::TVisualObject() 
{ 
} 
 
// Create a plain view 
TVisualObject::TVisualObject(DWORD dwId, CCreateContext *pContext,  
                       CRuntimeClass *pClass) 
{ 
  ASSERT(pContext); 
  ASSERT(pClass); 
  ASSERT(pClass->IsDerivedFrom(RUNTIME_CLASS(CView))); 
 
  zeroAll(); 
  m_dwId = dwId; 
  m_nObjectType = OT_VIEW; 
  m_pContext = pContext; 
  m_pRuntimeClass = pClass; 
  checkStyle(); 
} 
 
// Create a view within a tab window or a tab window 
TVisualObject::TVisualObject(DWORD dwId, LPCTSTR szTitle, CCreateContext *pContext,  
                       CRuntimeClass *pClass, DWORD dwStyle) 
{ 
  ASSERT(szTitle); 
  ASSERT(pContext); 
  ASSERT(pClass); 
 
  zeroAll(); 
  m_dwId = dwId; 
  if (pClass->IsDerivedFrom(RUNTIME_CLASS(TTabWnd))) { 
    m_nObjectType = OT_TAB; 
  } else if (pClass->IsDerivedFrom(RUNTIME_CLASS(CView))) { 
    m_nObjectType = OT_TABVIEW; 
  } else { 
    ASSERT(FALSE); 
  } 
  m_strTitle = szTitle; 
  m_pContext = pContext; 
  m_pRuntimeClass = pClass; 
  m_dwStyle = dwStyle; 
  checkStyle(); 
} 
 
// Create a splitter window 
TVisualObject::TVisualObject(DWORD dwId, LPCTSTR szTitle, int nRows, int nCols,  
                       CCreateContext *pContext, DWORD dwStyle) 
{ 
  ASSERT(szTitle); 
  ASSERT(pContext); 
  ASSERT(nRows); 
  ASSERT(nCols); 
 
  zeroAll(); 
  m_dwId = dwId; 
  m_nObjectType = OT_SPLITTER; 
  m_strTitle = szTitle; 
  m_pContext = pContext; 
  m_nRows = nRows; 
  m_nCols = nCols; 
  m_dwStyle = dwStyle; 
  checkStyle(); 
} 
 
// Create a view within a splitter window 
TVisualObject::TVisualObject(DWORD dwId, int nRow, int nCol, CCreateContext *pContext,  
                       CRuntimeClass *pClass, CSize size, DWORD dwStyle) 
{ 
  ASSERT(pContext); 
  ASSERT(pClass); 
  ASSERT(pClass->IsDerivedFrom(RUNTIME_CLASS(CView)) || 
         pClass->IsDerivedFrom(RUNTIME_CLASS(TTabWnd))); 
 
  zeroAll(); 
  m_dwId = dwId; 
  m_nObjectType = OT_SPLITTERVIEW; 
  m_pContext = pContext; 
  m_pRuntimeClass = pClass; 
  m_nRowIndex = nRow; 
  m_nColIndex = nCol; 
  m_Size = size; 
  m_dwStyle = dwStyle; 
  checkStyle(); 
} 
 
// Create a splitter within a splitter window 
TVisualObject::TVisualObject(DWORD dwId, int nRow, int nCol, int nRows, int nCols,  
                       CCreateContext *pContext, DWORD dwStyle) 
{ 
  ASSERT(pContext); 
  ASSERT(nRows); 
  ASSERT(nCols); 
 
  zeroAll(); 
  m_dwId = dwId; 
  m_nObjectType = OT_SPLITTERSPLITTER; 
  m_pContext = pContext; 
  m_nRowIndex = nRow; 
  m_nColIndex = nCol; 
  m_nRows = nRows; 
  m_nCols = nCols; 
  m_dwStyle = dwStyle; 
  checkStyle(); 
} 
 
TVisualObject::TVisualObject(const TVisualObject& obj) 
{ 
  zeroAll(); 
  *this = obj; 
} 
 
TVisualObject::~TVisualObject() 
{ 
} 
 
TVisualObject& TVisualObject::operator=(const TVisualObject& obj) 
{ 
  // No need to copy m_ObjectList since it is populated after 
  // this code is executed in STL container 
  m_nObjectType = obj.m_nObjectType; 
  m_dwId = obj.m_dwId; 
  m_pWnd = obj.m_pWnd; 
  m_pParent = obj.m_pParent; 
  m_strTitle = obj.m_strTitle; 
  m_nRows = obj.m_nRows; 
  m_nCols = obj.m_nCols; 
  m_nRowIndex = obj.m_nRowIndex; 
  m_nColIndex = obj.m_nColIndex; 
  m_pContext = obj.m_pContext; 
  m_pRuntimeClass = obj.m_pRuntimeClass; 
  m_Size = obj.m_Size; 
  m_bEnabled = obj.m_bEnabled; 
  m_dwStyle = obj.m_dwStyle; 
  m_cHotKey = obj.m_cHotKey; 
  m_pOwner = obj.m_pOwner; 
  m_pFramework = obj.m_pFramework; 
  return *this; 
} 
 
void TVisualObject::zeroAll(void) 
{ 
  // No need to zero m_ObjectList since it is already empty 
  m_nObjectType = OT_UNKNOWN; 
  m_dwId = 0; 
  m_pWnd = NULL; 
  m_pParent = NULL; 
  m_strTitle = _T(""); 
  m_nRows = 0; 
  m_nCols = 0; 
  m_nRowIndex = 0; 
  m_nColIndex = 0; 
  m_pContext = NULL; 
  m_pRuntimeClass = NULL; 
  m_Size = CSize(0,0); 
  m_bEnabled = TRUE; 
  m_dwStyle = 0; 
  m_cHotKey = 0; 
  m_pOwner = NULL; 
  m_pFramework = NULL; 
} 
 
// Check if style is valid 
void TVisualObject::checkStyle(void) 
{ 
  if ((m_dwStyle & TOS_TABTOP) || (m_dwStyle & TOS_TABBOTTOM)) { 
    ASSERT(m_pRuntimeClass); 
    // Tab position valid only for tab window derived classes 
    ASSERT(m_pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(TTabWnd))); 
  } 
  if (m_dwStyle & TOS_SELECTED) { 
    // Selected valid only for tab panes that are not splitters and tabs 
    // In this case, use TVisualFramework::SetActivePane() to set the active pane 
    // once the framework is created 
    if (m_pRuntimeClass == NULL) { 
      // Splitters canot be dynamically create (m_pRuntimeClass is NULL) 
      ASSERT((m_nObjectType != OT_SPLITTER) && (m_nObjectType != OT_SPLITTERVIEW)); 
    } else { 
      ASSERT(!m_pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(TTabWnd))); 
    } 
  } 
} 
 
// Delete the window pointer and optionally destroy the window 
void TVisualObject::Destroy(BOOL bDestroyWindow) 
{ 
  if (m_pWnd) { 
    if (bDestroyWindow) 
      m_pWnd->DestroyWindow(); 
    delete m_pWnd; 
    m_pWnd = NULL; 
  } 
} 
 
// If this object is a tab window or splitter window that it  
// cannot be focused 
BOOL TVisualObject::CanFocus(void) 
{ 
  ASSERT(m_pWnd); 
 
  if (m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd)) || 
      m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) 
  { 
    return FALSE; 
  } 
  return TRUE; 
} 
 
// Set hot key for this tab object 
void TVisualObject::SetHotKey(CHAR cHotKey) 
{ 
  m_cHotKey = cHotKey; 
} 
 
// Optional: Set description  
void TVisualObject::SetDescription(LPCTSTR szDesc) 
{ 
  m_strDescription = szDesc; 
} 
 
// Set this object as active pane 
BOOL TVisualObject::SetActivePane(void) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->SetActivePane(this); 
} 
 
// Set this tab to be active tab (not the active pane) 
BOOL TVisualObject::SetActiveTab(void) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->SetActiveTab(this); 
} 
 
// Enable/disable this object 
BOOL TVisualObject::Enable(BOOL bEnable) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->Enable(this,bEnable); 
} 
 
// Enable/disable tab 
BOOL TVisualObject::EnableTab(BOOL bEnable) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->EnableTab(this,bEnable); 
} 
 
// SHow/hide this object 
BOOL TVisualObject::ShowTab(BOOL bShow) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->ShowTab(this,bShow); 
} 
 
// Is this object enabled 
BOOL TVisualObject::IsEnabled(BOOL& bEnabled) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->IsEnabled(this,bEnabled); 
} 
 
// Is this object enabled 
BOOL TVisualObject::IsTabEnabled(BOOL& bEnabled) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->IsTabEnabled(this,bEnabled); 
} 
 
// Is this object visible 
BOOL TVisualObject::IsTabVisible(BOOL& bVisible) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->IsTabVisible(this,bVisible); 
} 
 
// Returns TRUE if this object is a tab within a tab window 
BOOL TVisualObject::IsTabPane(void) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->IsTabPane(this); 
} 
 
// Returns TRUE if this object is a tab window 
BOOL TVisualObject::IsTabWindow(void) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->IsTabWindow(this); 
} 
 
// Returns TRUE if this object is a pane within a splitter window 
BOOL TVisualObject::IsSplitterPane(void) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->IsSplitterPane(this); 
} 
 
// Returns TRUE if this object is a splitter window 
BOOL TVisualObject::IsSplitterWindow(void) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->IsSplitterWindow(this); 
} 
 
// Returns TRUE if this object is derived from CView  
BOOL TVisualObject::IsView(void) 
{ 
  ASSERT(m_pFramework); 
  return m_pFramework->IsView(this); 
} 
 
// Get object ID 
#ifdef _DEBUG 
DWORD TVisualObject::GetID(void) 
{ 
  return m_dwId; 
} 
#endif 
 
// Get object window 
#ifdef _DEBUG 
CWnd *TVisualObject::GetWnd(void) 
{ 
  return m_pWnd; 
} 
#endif 
 
// Get safe object window 
#ifdef _DEBUG 
CWnd *TVisualObject::GetSafeWnd(void) 
{ 
  return ::IsWindow(m_pWnd->m_hWnd) ? m_pWnd : NULL; 
} 
#endif 
 
#ifdef _DEBUG 
CString TVisualObject::GetTitle(void) 
{ 
  return m_strTitle; 
} 
#endif 
 
#ifdef _DEBUG 
CString TVisualObject::GetDescription(void) 
{ 
  return m_strDescription; 
} 
#endif 
 
#ifdef _DEBUG 
CWnd *TVisualObject::GetParentWnd(void) 
{ 
  return m_pParent; 
} 
#endif 
 
#ifdef _DEBUG 
TVisualFramework *TVisualObject::GetFramework(void) 
{ 
  return m_pFramework; 
} 
#endif 
 
#ifdef _DEBUG 
TVisualObject *TVisualObject::GetOwner(void) 
{ 
  return m_pOwner; 
} 
#endif 
 
//============================================================================= 
// class TVisualFramework 
// 
//============================================================================= 
 
IMPLEMENT_DYNCREATE(TVisualFramework, CCmdTarget) 
 
BEGIN_MESSAGE_MAP(TVisualFramework, CCmdTarget) 
	//{{AFX_MSG_MAP(TVisualFramework) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
TVisualFramework::TVisualFramework() 
{ 
  m_pOwner = NULL; 
  m_bEnableCtrlTab = TRUE; 
} 
 
TVisualFramework::~TVisualFramework() 
{ 
  if (m_ObjectMap.size() && m_ObjectList.size()) { 
    TRACE0(_T(">>> TVisualFramework::Destroy() called in TVisualFramework destructor\n")); 
    TRACE0(_T(">>>   It must be called in CFrameWnd derived class OnDestroy() message handler\n")); 
    Destroy(); 
  } 
} 
 
// Find an object in the map with the specified unique id 
TVisualObject *TVisualFramework::findObject(DWORD dwId) 
{ 
  TVisualObjectMap::iterator iterator; 
  for (iterator = m_ObjectMap.begin(); iterator != m_ObjectMap.end(); iterator++) { 
    if (dwId == iterator->first) 
      return iterator->second; 
  } 
  return NULL; 
} 
 
// Find an object in the map with the specified window 
TVisualObject *TVisualFramework::findObject(CWnd *pWnd) 
{ 
  TVisualObjectMap::iterator iterator; 
  for (iterator = m_ObjectMap.begin(); iterator != m_ObjectMap.end(); iterator++) { 
    if (pWnd == iterator->second->m_pWnd) 
      return iterator->second; 
  } 
  return NULL; 
} 
 
// Add object to the container (this is a root level object) 
// There is only one root level object (either splitter or tab) 
BOOL TVisualFramework::Add(TVisualObject *pObject) 
{ 
  ASSERT(pObject); 
  ASSERT(m_ObjectList.size() == 0);   // Only one root level object allowed 
 
  // Root level object is either a view, splitter or a tab 
  ASSERT((pObject->m_nObjectType == TVisualObject::OT_TAB) ||  
         (pObject->m_nObjectType == TVisualObject::OT_VIEW) ||  
         (pObject->m_nObjectType == TVisualObject::OT_SPLITTER)); 
 
  if (findObject(pObject->m_dwId) == NULL) { 
    m_ObjectList.insert(m_ObjectList.end(), pObject); 
    pObject->m_pFramework = this; 
    m_ObjectMap[pObject->m_dwId] = pObject; 
    return TRUE; 
  } 
  ASSERT(FALSE);    // Duplicate object Id 
  return FALSE; 
} 
 
// Add child object to the specified object 
BOOL TVisualFramework::Add(TVisualObject *pOwner, TVisualObject *pObject) 
{ 
  ASSERT(pObject); 
 
  #ifdef _DEBUG 
  // Validate definition 
  if (pOwner->m_nObjectType == TVisualObject::OT_TAB) { 
    if ((pObject->m_nObjectType != TVisualObject::OT_TABVIEW) &&  
        (pObject->m_nObjectType != TVisualObject::OT_SPLITTER) && 
        (pObject->m_nObjectType != TVisualObject::OT_TAB)) 
    { 
      ASSERT(FALSE); 
    } 
  } else if (pOwner->m_nObjectType == TVisualObject::OT_SPLITTER) { 
    if ((pObject->m_nObjectType != TVisualObject::OT_SPLITTERVIEW) &&  
        (pObject->m_nObjectType != TVisualObject::OT_SPLITTERSPLITTER)) 
    { 
      ASSERT(FALSE); 
    } 
  } else if (pOwner->m_nObjectType == TVisualObject::OT_SPLITTERSPLITTER) { 
    if ((pObject->m_nObjectType != TVisualObject::OT_SPLITTERVIEW) &&  
        (pObject->m_nObjectType != TVisualObject::OT_SPLITTERSPLITTER)) 
    { 
      ASSERT(FALSE); 
    } 
  } else if (pOwner->m_nObjectType == TVisualObject::OT_TABVIEW) { 
    if ((pObject->m_nObjectType != TVisualObject::OT_SPLITTER)) 
    { 
      ASSERT(FALSE); 
    } 
  } 
 
  #endif 
 
  if (findObject(pObject->m_dwId) == NULL) { 
    pOwner->m_ObjectList.insert(pOwner->m_ObjectList.end(), pObject); 
    pObject->m_pOwner = pOwner; 
    pObject->m_pFramework = this; 
    m_ObjectMap[pObject->m_dwId] = pObject; 
    return TRUE; 
  } 
  ASSERT(FALSE);    // Duplicate object Id 
  return FALSE; 
} 
 
// Create all objects within the framework 
BOOL TVisualFramework::Create(CWnd *pWnd) 
{ 
  ASSERT(pWnd); 
  ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))); 
 
  // Save owner for later 
  m_pOwner = pWnd; 
 
  // Disable Ctrl+Tab for MDI applications 
  if (pWnd->IsKindOf(RUNTIME_CLASS(CMDIChildWnd))) 
    m_bEnableCtrlTab = FALSE; 
 
  // Walk thru visual object hierarchy and create windows 
  BOOL rc; 
  TVisualObject *pObject; 
  TVisualObjectList::iterator it; 
  for (it = m_ObjectList.begin(); it != m_ObjectList.end(); it++) { 
    pObject = *it; 
    rc = execCreate(pWnd, pObject); 
    if (rc == FALSE) { 
      TRACE0(_T("Create visual object failed!\n")); 
      return FALSE; 
    } 
  } 
   
  // Walk thru the map and find first object that can be focused 
  // Then set focus 
  TVisualObjectMap::iterator mapit; 
  for (mapit = m_ObjectMap.begin(); mapit != m_ObjectMap.end(); mapit ++) { 
    pObject = mapit->second; 
    if (pObject->CanFocus()) { 
      SetActivePane(pObject); 
      break; 
    } 
  } 
 
  return TRUE; 
} 
 
// Destroy all objects in the framework 
void TVisualFramework::Destroy(void) 
{ 
  TVisualObject *pObject; 
 
  // Recursive delete of all objects 
  TVisualObjectList::iterator it; 
  for (it = m_ObjectList.begin(); it != m_ObjectList.end(); it++) { 
    pObject = *it; 
    execDestroy(pObject); 
  } 
 
  // Delete pointers in object map 
  TVisualObjectMap::iterator mapit; 
  for (mapit = m_ObjectMap.begin(); mapit != m_ObjectMap.end(); mapit++) { 
    pObject = mapit->second; 
    delete pObject; 
  } 
 
  // Empty all containers (for check in destructor) 
  m_ObjectMap.clear(); 
  m_ObjectList.clear(); 
} 
 
// Recursive function to delete all object windows. Does not delete views since 
// they are destroyed by frame. 
void TVisualFramework::execDestroy(TVisualObject *pObject) 
{ 
  if (pObject->m_pWnd && ::IsWindow(pObject->m_pWnd->m_hWnd)) { 
    if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
      TVisualObject *pObj; 
      TVisualObjectList::iterator it; 
      for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { 
        pObj = *it; 
        execDestroy(pObj); 
      } 
      pObject->Destroy(TRUE); 
    } else if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { 
      TVisualObject *pObj; 
      TVisualObjectList::iterator it; 
      for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { 
        pObj = *it; 
        execDestroy(pObj); 
      } 
      pObject->Destroy(TRUE); 
    }  
  } 
} 
 
// Create specified object and all its childs 
BOOL TVisualFramework::execCreate(CWnd *pWnd, TVisualObject *pObject) 
{ 
  ASSERT(pWnd); 
  ASSERT(pObject); 
   
  BOOL rc = FALSE; 
  switch (pObject->m_nObjectType) { 
  case (TVisualObject::OT_SPLITTER):  
    rc = execCreateSplitter(pWnd,pObject); 
    break; 
  case (TVisualObject::OT_SPLITTERVIEW):  
    rc = execCreateSplitterView(pWnd, pObject); 
    break; 
  case (TVisualObject::OT_SPLITTERSPLITTER): 
    rc = execCreateSplitterSplitter(pWnd, pObject); 
    break; 
  case (TVisualObject::OT_TAB): 
    rc = execCreateTabWnd(pWnd, pObject); 
    break; 
  case (TVisualObject::OT_TABVIEW): 
    rc = execCreateTabView(pWnd, pObject); 
    break; 
  case (TVisualObject::OT_VIEW): 
    rc = execCreateView(pWnd, pObject); 
    break; 
  } 
  return rc; 
} 
 
// Create a simple view  
BOOL TVisualFramework::execCreateView(CWnd *pWnd, TVisualObject *pObject) 
{ 
  ASSERT(pWnd); 
  ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))); 
  ASSERT(pObject); 
  ASSERT(pObject->m_pContext); 
  ASSERT(pObject->m_pRuntimeClass); 
 
  CFrameWnd *pFrame = (CFrameWnd*)pWnd; 
  pObject->m_pContext->m_pNewViewClass = pObject->m_pRuntimeClass; 
  pObject->m_pWnd = pFrame->CreateView(pObject->m_pContext); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); 
   
  pObject->m_pParent = pFrame; 
  setTabWndProperties(pObject); 
   
  return TRUE; 
} 
 
// Create a view within a tab window 
BOOL TVisualFramework::execCreateTabView(CWnd *pWnd, TVisualObject *pObject) 
{ 
  ASSERT(pWnd); 
  ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))); 
  ASSERT(pObject); 
  ASSERT(pObject->m_pContext); 
  ASSERT(pObject->m_pRuntimeClass); 
  ASSERT(!pObject->m_strTitle.IsEmpty()); 
 
  TTabWnd *pTab = (TTabWnd*)pWnd; 
  TTabItem *pItem; 
  pItem = pTab->CreatePane(pObject->m_strTitle, pObject->m_pRuntimeClass,  
                            pObject->m_pContext); 
  ASSERT(pItem); 
  pObject->m_pWnd = pItem->GetSafeWnd(); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); 
  pObject->m_pParent = pTab; 
  setTabWndProperties(pObject); 
  return TRUE; 
} 
 
// Create a splitter window 
BOOL TVisualFramework::execCreateSplitter(CWnd *pWnd, TVisualObject *pObject) 
{ 
  ASSERT(pWnd); 
  ASSERT(pObject); 
 
  // Cannot use pObject->m_pRuntimeClass->CreateObject() since splitters  
  // do not support dynamic creation 
  pObject->m_pWnd = CreateSplitter(pObject->m_dwId); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); 
 
  if (pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
    TTabWnd *pTab = (TTabWnd*)pWnd; 
    TTabItem *pItem = pTab->CreatePane(pObject->m_strTitle, pObject->m_nRows,  
                                       pObject->m_nCols, pObject->m_pWnd); 
    ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); 
    pObject->m_pParent = pWnd; 
  } else if (pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { 
    ((CSplitterWnd*)pObject->m_pWnd)->CreateStatic(pWnd,pObject->m_nRows,pObject->m_nCols); 
    ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); 
    pObject->m_pParent = pWnd; 
  } 
  setTabWndProperties(pObject); 
  TVisualObjectList::iterator it; 
  for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { 
    execCreate(pObject->m_pWnd, *it); 
  } 
  return TRUE; 
} 
 
// Create a view within a splitter. Then create all childs of this view. 
BOOL TVisualFramework::execCreateSplitterView(CWnd *pWnd, TVisualObject *pObject) 
{ 
  ASSERT(pWnd); 
  ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); 
  ASSERT(pObject); 
   
  CSplitterWnd *pSplitter = (CSplitterWnd*)pWnd; 
  pSplitter->CreateView(pObject->m_nRowIndex, pObject->m_nColIndex,  
                        pObject->m_pRuntimeClass, pObject->m_Size,  
                        pObject->m_pContext); 
  pObject->m_pWnd = pSplitter->GetPane(pObject->m_nRowIndex, pObject->m_nColIndex); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); 
  pObject->m_pParent = pSplitter; 
  setTabWndProperties(pObject); 
  TVisualObjectList::iterator it; 
  for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { 
    execCreate(pObject->m_pWnd, *it); 
  } 
  return TRUE; 
} 
 
// Create a nested splitter window 
BOOL TVisualFramework::execCreateSplitterSplitter(CWnd *pWnd, TVisualObject *pObject) 
{ 
  ASSERT(pWnd); 
  ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); 
   
  CSplitterWnd *pParent = (CSplitterWnd*)pWnd; 
  // Cannot use pObject->m_pRuntimeClass->CreateObject() since splitters  
  // do not support dynamic creation 
  pObject->m_pWnd = CreateSplitter(pObject->m_dwId); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); 
  CSplitterWnd *pSplitter = (CSplitterWnd*)pObject->m_pWnd; 
  pSplitter->CreateStatic(pParent, pObject->m_nRows, pObject->m_nCols,  
                          WS_CHILD|WS_VISIBLE|WS_BORDER,  
                          pParent->IdFromRowCol(pObject->m_nRowIndex,pObject->m_nColIndex)); 
  ASSERT(::IsWindow(pSplitter->m_hWnd)); 
  pObject->m_pParent = pParent; 
  TVisualObjectList::iterator it; 
  for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { 
    execCreate(pObject->m_pWnd, *it); 
  } 
  return TRUE; 
} 
 
// Create a tab window and all its childs (tabs) 
BOOL TVisualFramework::execCreateTabWnd(CWnd *pWnd, TVisualObject *pObject) 
{ 
  ASSERT(pWnd); 
  ASSERT(pObject); 
   
  if (pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
    TTabWnd *pTab = (TTabWnd*)pWnd; 
    TTabItem *pItem = pTab->CreatePane(pObject->m_strTitle, pObject->m_pRuntimeClass, 
                                       pObject->m_pContext); 
    ASSERT(pItem); 
    pObject->m_pWnd = pItem->GetSafeWnd(); 
    ASSERT(pObject->m_pWnd); 
    ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); 
    pObject->m_pParent = pWnd; 
    setTabWndProperties(pObject); 
  } else { 
    CRect rect; 
    pObject->m_pWnd = (CWnd*)pObject->m_pRuntimeClass->CreateObject(); 
    ASSERT(pObject->m_pWnd); 
    pObject->m_pParent = pWnd; 
    pObject->m_pWnd->Create(NULL,_T(""),WS_VISIBLE|WS_CHILD, 
                                rect,pWnd,TABWND_DEFAULT_ID); 
    ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); 
    setTabWndProperties(pObject); 
  } 
  TVisualObject *pObj; 
  TVisualObjectList::iterator it; 
  for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { 
    pObj = *it; 
    execCreate(pObject->m_pWnd, pObj); 
  } 
  return TRUE; 
} 
 
// Set properties of tab window 
void TVisualFramework::setTabWndProperties(TVisualObject *pObject) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd != NULL); 
 
  // If this is a tab window then set the position of tabs 
  if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
    TTabWnd *pTab = (TTabWnd*)pObject->m_pWnd; 
    if (pObject->m_dwStyle & TVisualObject::TOS_TABTOP) 
      pTab->SetTabPos(TTabWnd::TP_TOP); 
    else if (pObject->m_dwStyle & TVisualObject::TOS_TABBOTTOM) 
      pTab->SetTabPos(TTabWnd::TP_BOTTOM); 
  } 
   
  // If this is a pane within a tab then check if this pane 
  // should be a selected pane 
  ASSERT(pObject->m_pParent); 
  if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
    TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; 
    if (pObject->m_dwStyle & TVisualObject::TOS_SELECTED) { 
      int nIndex = pTab->GetTabIndex(pObject->m_pWnd); 
      pTab->SetActivePane(nIndex); 
    } 
  } 
} 
 
// Get owner pointer (CFrameWnd derived class) 
CWnd *TVisualFramework::GetWnd(void) 
{ 
  return m_pOwner; 
} 
 
// Get safe owner pointer (CFrameWnd derived class) 
CWnd *TVisualFramework::GetSafeWnd(void) 
{ 
  if (m_pOwner && ::IsWindow(m_pOwner->m_hWnd)) 
    return m_pOwner; 
  return NULL; 
} 
 
// Get window associated with the visual object specified with its id 
// Can be any object (view, splitter or tab window) 
CWnd *TVisualFramework::GetObject(DWORD dwId) 
{ 
  TVisualObject *pObject = findObject(dwId); 
  if (pObject == NULL) 
    return NULL; 
  return pObject->m_pWnd; 
} 
 
// Get ID associated with the visual object specified with its window pointer 
// Can be any object (view, splitter or tab window) 
DWORD TVisualFramework::GetObject(CWnd *pWnd) 
{ 
  ASSERT(pWnd); 
  TVisualObject *pObject = findObject(pWnd); 
  if (pObject == NULL) 
    return NULL; 
  return pObject->m_dwId; 
} 
 
// Return a visual object with the specified id 
TVisualObject *TVisualFramework::Get(DWORD dwId) 
{ 
  return findObject(dwId); 
} 
 
// Return a visual object with the specified window 
TVisualObject *TVisualFramework::Get(CWnd *pWnd) 
{ 
  return findObject(pWnd); 
} 
 
// Returns an object that represents the currently active tab within the 
// supplied tab window object. This may not be the active pane 
TVisualObject *TVisualFramework::GetActiveTab(TVisualObject *pObject) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
 
  if (!pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) 
    return NULL; 
 
  TTabWnd *pTab = (TTabWnd*)pObject->m_pWnd; 
  int nIndex = pTab->GetTabIndex(); 
  CWnd *pWnd = pTab->GetTabWnd(nIndex); 
  ASSERT(pWnd); 
   
  return Get(pWnd); 
} 
 
// Set the active tab of the parent tab window. This will not activate the 
// pane associated with the active tab. 
BOOL TVisualFramework::SetActiveTab(TVisualObject *pObject) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(pObject->m_pParent); 
 
  if (!pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) 
    return FALSE; 
 
  TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; 
  int nIndex = pTab->GetTabIndex(pObject->m_pWnd); 
  return pTab->SetActivePane(nIndex,FALSE); 
} 
 
// Returns TRUE if object is a tab within a tab window 
BOOL TVisualFramework::IsTabPane(TVisualObject* pObject) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(pObject->m_pParent); 
 
  if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) 
    return TRUE; 
  return FALSE; 
} 
 
// Returns TRUE if object is a tab window 
BOOL TVisualFramework::IsTabWindow(TVisualObject* pObject) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
 
  if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) 
    return TRUE; 
  return FALSE; 
} 
 
// Returns TRUE if object is a pane within a splitter window 
BOOL TVisualFramework::IsSplitterPane(TVisualObject* pObject) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(pObject->m_pParent); 
 
  if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) 
    return TRUE; 
  return FALSE; 
} 
 
// Returns TRUE if object is a pane within a splitter window 
BOOL TVisualFramework::IsSplitterWindow(TVisualObject* pObject) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
 
  if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) 
    return TRUE; 
  return FALSE; 
} 
 
// Returns TRUE if object is derived from CView 
BOOL TVisualFramework::IsView(TVisualObject *pObject) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
 
  if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CView))) 
    return TRUE; 
  return FALSE; 
} 
 
// Get the count of visual objects 
int TVisualFramework::GetCount(void) 
{ 
  return m_ObjectMap.size(); 
} 
 
// Set font for complete framework 
void TVisualFramework::SetFont(CFont *pFont) 
{ 
  ASSERT(pFont); 
   
  TVisualObject *pObject; 
  TVisualObjectMap::iterator mapit; 
  for (mapit = m_ObjectMap.begin(); mapit != m_ObjectMap.end(); mapit ++) { 
    pObject = mapit->second; 
    if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
      ((TTabWnd*)pObject->m_pWnd)->SetFont(pFont); 
    } else if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TVisualFormView))) { 
      ((TVisualFormView*)pObject->m_pWnd)->SetFont(pFont); 
    } else { 
      pObject->m_pWnd->SetFont(pFont); 
    } 
  } 
} 
 
// Enable/disable CtrlTab for tab window 
void TVisualFramework::EnableCtrlTab(BOOL bEnable) 
{ 
  // If framework is used in an MDI application, then Ctrl+Tab is used to switch 
  // among open windows. If it is enabled, Ctrl+Tab will then switch among  
  // tab panes within the MDI child frame window (this disables default Ctrl+Tab 
  // for MDI windows). 
  // Ctrl+Tab works only if CWinApp derived class overloads PreTranslateMessage 
  // and calles ProcessMessage() of the active TVisualFramework object 
  m_bEnableCtrlTab = bEnable; 
} 
 
// Since CSplitterWnd does not support dynamic creation, this is a chance for 
// derived class to supply CSplitterWnd derived class instead of CSplitterWnd 
CSplitterWnd *TVisualFramework::CreateSplitter(DWORD dwId) 
{ 
  return new CSplitterWnd; 
} 
 
// Set focus to visual object  
BOOL TVisualFramework::SetActivePane(TVisualObject *pObject) 
{ 
  ASSERT(pObject); 
 
  // Cannot set focus to splitter or tab window 
  if (!pObject->CanFocus()) 
    return FALSE; 
 
  // Cannot set focus to disabled window 
  BOOL bEnabled; 
  if (pObject->IsEnabled(bEnabled) && !bEnabled) 
    return FALSE; 
 
  // Build a list that walks thru the object hierarchy from specified  
  // object to the root 
  TVisualObjectList list; 
  TVisualObject *pObj = pObject; 
  while (pObj) { 
    list.insert(list.end(),pObj); 
    pObj = pObj->m_pOwner; 
  } 
   
  // Reverse the list so that we can walk from root to the desired object 
  list.reverse(); 
   
  // Now, walk thru the list and set focus as desired 
  TVisualObjectList::iterator it; 
  for (it = list.begin(); it != list.end(); it ++) { 
    pObj = *it; 
    if (pObj->m_pOwner && pObj->m_pOwner->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
      TTabWnd *pTab = (TTabWnd*)pObj->m_pOwner->m_pWnd; 
      int nIndex = pTab->GetTabIndex(pObj->m_pWnd); 
      if (!pTab->SetActivePane(nIndex))  
        return FALSE; 
    } 
  } 
 
  // Update framework owner 
  CFrameWnd *pFrame = (CFrameWnd*)m_pOwner; 
  pFrame->SetActiveView((CView*)pObject->m_pWnd); 
 
  return TRUE; 
} 
 
// Return a pointer to visual object that represents the currently active pane 
TVisualObject *TVisualFramework::GetActivePane(void) 
{ 
  CFrameWnd *pFrame = (CFrameWnd*)m_pOwner; 
  ASSERT(pFrame); 
  CView *pView = pFrame->GetActiveView(); 
  ASSERT(pView); 
  return findObject(pView); 
} 
 
// Enable/disable a view. Returns TRUE if sucessful 
BOOL TVisualFramework::Enable(TVisualObject *pObject, BOOL bEnable) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
 
  if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CView))) { 
    pObject->m_bEnabled = bEnable; 
    pObject->m_pWnd->EnableWindow(bEnable); 
    if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
      TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; 
      int nIndex = pTab->GetTabIndex(pObject->m_pWnd); 
      pTab->Enable(nIndex, bEnable); 
    } 
    return TRUE; 
  } 
  return FALSE; 
} 
 
// Enable/disable a tab 
BOOL TVisualFramework::EnableTab(TVisualObject *pObject, BOOL bEnable) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(pObject->m_pParent); 
 
  // Check if parent is a tab window 
  if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
    TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; 
    int nIndex = pTab->GetTabIndex(pObject->m_pWnd); 
    if (nIndex == pTab->GetTabIndex()) 
      return FALSE; 
    pTab->EnableTab(nIndex, bEnable); 
    pObject->m_bEnabled = bEnable; 
    return TRUE; 
  } 
  return FALSE; 
} 
 
// Show/hide a tab 
BOOL TVisualFramework::ShowTab(TVisualObject *pObject, BOOL bShow) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(pObject->m_pParent); 
 
  if (!pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) 
    return FALSE; 
 
  TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; 
  int nIndex = pTab->GetTabIndex(pObject->m_pWnd); 
  if (nIndex == pTab->GetTabIndex()) 
    return FALSE; 
 
  pTab->ShowTab(nIndex, bShow); 
  return TRUE; 
} 
 
// Is object enabled. Returns FALSE if this is not a valid call for the supplied 
// object. If return code is TRUE, check bEnabled 
BOOL TVisualFramework::IsEnabled(TVisualObject *pObject, BOOL& bEnabled) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
 
  bEnabled = pObject->m_bEnabled; 
  return TRUE; 
  /* 
  if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CView))) { 
    bEnabled = pObject->m_pWnd->IsWindowEnabled(); 
    return TRUE; 
  } 
  return FALSE; 
  */ 
} 
 
// Is tab enabled. Returns FALSE if this is not a valid call for the supplied 
// object. If return code is TRUE, check bEnabled 
BOOL TVisualFramework::IsTabEnabled(TVisualObject *pObject, BOOL& bEnabled) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(pObject->m_pParent); 
 
  if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
    TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; 
    int nIndex = pTab->GetTabIndex(pObject->m_pWnd); 
    bEnabled = pTab->IsTabEnabled(nIndex); 
    return TRUE; 
  } 
  return FALSE; 
} 
 
// Is tab visible. Returns FALSE if this is not a valid call for the supplied 
// object. If return code is TRUE then check bVisible. 
BOOL TVisualFramework::IsTabVisible(TVisualObject *pObject, BOOL& bVisible) 
{ 
  ASSERT(pObject); 
  ASSERT(pObject->m_pWnd); 
  ASSERT(pObject->m_pParent); 
 
  if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { 
    TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; 
    int nIndex = pTab->GetTabIndex(pObject->m_pWnd); 
    bVisible = pTab->IsTabVisible(nIndex); 
    return TRUE; 
  } 
  return FALSE; 
} 
 
// This should be called from CWinApp derived PreTranslateMessage to handle 
// any framework related messages 
BOOL TVisualFramework::ProcessMessage(MSG *pMsg) 
{ 
  ASSERT(pMsg); 
  if (pMsg->message == WM_KEYDOWN) { 
    // Handle Ctrl+Tab for tab windows 
    if (m_bEnableCtrlTab) { 
      if ((pMsg->wParam == VK_TAB) && (::GetAsyncKeyState(VK_CONTROL) != 0)) { 
        CWnd *pWnd = CWnd::FromHandle(pMsg->hwnd); 
        ASSERT(pWnd); 
        if (pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) 
          return FALSE; 
        // If we are in form view then pWnd is a control 
        while (pWnd && !pWnd->IsKindOf(RUNTIME_CLASS(CView))) 
          pWnd = pWnd->GetParent(); 
        // Find object for this window 
        ASSERT(pWnd); 
        TVisualObject *pObject = findObject(pWnd); 
        ASSERT(pObject != NULL); 
        while (pObject && !pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) 
          pObject = pObject->m_pOwner; 
        if (pObject) { 
          TTabWnd *pTab = (TTabWnd*)pObject->m_pWnd; 
          BOOL bShift = (::GetAsyncKeyState(VK_SHIFT) != 0); 
          int nIndex = pTab->GetTabIndex(); 
          int nNdx = nIndex; 
          // Switch to new pane (skip invisible and disabled) 
          do { 
            if (bShift) { 
              // Does not work 
              nNdx--; 
              if (nNdx < 0) 
                nNdx = pTab->GetTabCount()-1; 
            } else { 
              nNdx ++; 
              if (nNdx == pTab->GetTabCount()) 
                nNdx = 0; 
            } 
          } while (!pTab->SetActivePane(nNdx) && (nNdx != nIndex)); 
          return TRUE; 
        } 
      } 
    } 
  } else if (pMsg->message == WM_SYSKEYDOWN) { 
    // Handle hot keys for views (if defined) 
    TVisualObject *pObject; 
    TVisualObjectMap::iterator mapit; 
    for (mapit = m_ObjectMap.begin(); mapit != m_ObjectMap.end(); mapit ++) { 
      pObject = mapit->second; 
      if (pObject->m_cHotKey == pMsg->wParam) { 
        if (SetActivePane(pObject)) 
          return TRUE; 
      } 
    } 
  } 
 
  return FALSE; 
} 
 
BOOL TVisualFramework::OnCmdMsg(UINT nID, int nCode, void* pExtra,  
                             AFX_CMDHANDLERINFO* pHandlerInfo)  
{ 
	// TODO: Add your specialized code here and/or call the base class 
	 
	return CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); 
} 
 
//============================================================================= 
// class TVisualFormView 
// 
// This class implements the code to set the font for all child controls. 
// If it belongs to the visual framework (as a pane) then setting the font 
// for the framework's panes will automatically set the font for all child 
// controls in the form view. 
//============================================================================= 
 
static BOOL __stdcall setChildFont(HWND hwnd, LPARAM lparam); 
static BOOL __stdcall setChildEnabled(HWND hwnd, LPARAM lparam); 
 
IMPLEMENT_DYNAMIC(TVisualFormView, CFormView) 
 
BEGIN_MESSAGE_MAP(TVisualFormView, CFormView) 
	//{{AFX_MSG_MAP(TVisualFormView) 
	ON_WM_ENABLE() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
TVisualFormView::TVisualFormView(LPCTSTR lpszTemplateName) 
	: CFormView(lpszTemplateName) 
{ 
} 
 
TVisualFormView::TVisualFormView(UINT nIDTemplate) 
	: CFormView(nIDTemplate) 
{ 
} 
 
void TVisualFormView::SetFont(CFont *pFont) 
{ 
  ASSERT(pFont); 
  ::EnumChildWindows(m_hWnd, ::setChildFont, (LPARAM)pFont); 
} 
 
void TVisualFormView::OnEnable(BOOL bEnable)  
{ 
	CFormView::OnEnable(bEnable); 
  ::EnumChildWindows(m_hWnd, ::setChildEnabled, (LPARAM)bEnable); 
} 
 
// lParam is a pointer to CFont object 
BOOL __stdcall setChildFont(HWND hwnd, LPARAM lparam) 
{ 
  CFont *pFont = (CFont*)lparam; 
  ASSERT(pFont); 
  CWnd *pWnd = CWnd::FromHandle(hwnd); 
  ASSERT(pWnd); 
  pWnd->SetFont(pFont); 
  return TRUE; 
} 
 
// lParam is a BOOL 
BOOL __stdcall setChildEnabled(HWND hwnd, LPARAM lparam) 
{ 
  BOOL bEnabled = (BOOL)lparam; 
  CWnd *pWnd = CWnd::FromHandle(hwnd); 
  ASSERT(pWnd); 
  pWnd->EnableWindow(bEnabled); 
  return TRUE; 
} 
 
/*############################################################################# 
# End of file VISUALFX.CPP 
#############################################################################*/