#include "stdafx.h"
#include "CeTab.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CeTabCtrl
CeTabCtrl::~CeTabCtrl()
{
}
BOOL CeTabCtrl::Create(DWORD dwStyle, const RECT& rect, HWND hWndParent, UINT nID, HINSTANCE hInst)
{
return CeWnd::Create(WC_TABCONTROL, hWndParent, rect, NULL, dwStyle, 0, nID, hInst);
}
BOOL CeTabCtrl::InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem,
int nImage, LPARAM lParam, DWORD dwState,
DWORD dwStateMask)
{
TCITEM item;
item.mask = nMask;
item.dwState = dwState;
item.dwStateMask = dwStateMask;
item.pszText = (LPTSTR) lpszItem;
item.cchTextMax = lstrlen(lpszItem);
item.iImage = nImage;
item.lParam = lParam;
return InsertItem(nItem, &item);
}
BOOL CeTabCtrl::InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, int nImage, LPARAM lParam)
{
return InsertItem(nMask, nItem, lpszItem, nImage, lParam, 0, 0);
}
/////////////////////////////////////////////////////////////////////////////
// CeTabSheet
CeTabSheet::CeTabSheet()
{
m_dwTabStyle = 0;
m_hInst = NULL;
m_nActivePage = -1;
}
CeTabSheet::Create(DWORD dwStyle, const RECT& rect, HWND hWndParent, UINT nID, HINSTANCE hInst)
{
m_hInst = hInst;
// mask off the styles we never use, save them for the tab control create
// however...
m_dwTabStyle = dwStyle & 0xffff;
dwStyle &= 0xffff0000;
return CeWnd::Create(NULL, hWndParent, rect, NULL, dwStyle, 0, nID, hInst);
}
CeTabSheet::~CeTabSheet()
{
}
/////////////////////////////////////////////////////////////////////////////
// CeTabSheet message handlers
void CeTabSheet::AddPage(CeTabPage* pPage, int nBitmap /*=-1*/)
{
ASSERT(pPage != NULL);
ASSERT(pPage->GetID() != 0); // did you forget to overload this
m_arPages.Add(&pPage);
if (m_hWnd == NULL)
// adding before creation, will be added at create time
return;
int nItem; // page's item number
if (! (m_dwTabStyle & TCS_VERTICAL))
{
// add the item to the end of the tab
if ( ! (nItem = m_tabCtrl.InsertItem( m_tabCtrl.GetItemCount(), pPage->GetTabTitle(), nBitmap)) )
{
// show it and set whatever internal info we need
SetActivePage(nItem);
}
}
else
{
// add the item to the end of the tab
if ( ! (nItem = m_tabCtrl.InsertItem( m_tabCtrl.GetItemCount(), _T(""), nBitmap)) )
{
// show it and set whatever internal info we need
SetActivePage(nItem);
}
}
}
int CeTabSheet::FindPage(CeTabPage *pPage) const
{
for (int ii = 0; ii < m_arPages.GetSize(); ii++)
if (m_arPages[ii] == pPage)
return ii;
return -1;
}
BOOL CeTabSheet::SetActivePage(CeTabPage* pPage)
{
ASSERT(pPage != NULL);
int nPage = FindPage(pPage);
return (nPage < 0) ? FALSE: SetActivePage(nPage);
}
BOOL CeTabSheet::SetActivePage(int nPage)
{
if (nPage == m_nActivePage)
return TRUE;
CeTabPage* pActive = GetPage(m_nActivePage);
if (pActive)
{
if(! pActive->OnKillActive())
// can't go there...
return FALSE;
// call as documented for MFC
pActive->OnOK();
}
CeTabPage* pPage = GetPage(nPage);
CeRect rectWnd;
// calc the area available for children
GetPageRect(rectWnd);
// not created yet? do that
if (! ::IsWindow(pPage->m_hWnd))
{
// first display do create
if (! pPage->Create(pPage->GetID(), m_hWnd, m_hInst))
return FALSE;
}
// don't bother with the return value...
if (! pPage->OnSetActive())
return FALSE;
// set position before tab, tab will now be after
// all pages, the z-order of the pages doesn't matter since
// they are always hidden when not active
pPage->SetWindowPos(HWND_TOP, rectWnd, SWP_NOACTIVATE);
// Hide the current window and then change the current window
if (m_nActivePage >= 0)
{
// for sanity
GetPage(m_nActivePage)->EnableWindow(FALSE);
GetPage(m_nActivePage)->ShowWindow(FALSE);
}
pPage->MoveWindow(rectWnd);
pPage->EnableWindow(TRUE);
pPage->ShowWindow(TRUE);
pPage->Invalidate();
m_nActivePage = nPage;
// don't set focus to tab control
// SetFocus();
return TRUE;
}
void CeTabSheet::RemovePage(CeTabPage *pPage)
{
int nPage = FindPage(pPage);
RemovePage(nPage);
}
void CeTabSheet::RemovePage(int nPage)
{
if (m_arPages.GetCount() <= nPage)
// non-existant page
return;
// hide the window and disable it if it has been created
// otherwise it will get in the way, the caller
// can close it if necessary, otherwise it will be reused
// if added back in without creation
CeTabPage* pPage = m_arPages[nPage];
if (pPage->IsWindow())
{
pPage->ShowWindow(SW_HIDE);
pPage->EnableWindow(FALSE);
}
// remove the page from array
m_arPages.Remove(nPage);
// remove the tab from control
m_tabCtrl.DeleteItem(nPage);
// fix up current page if neccessary
if (nPage == m_nActivePage)
if (m_arPages.GetSize() > 0)
SetActivePage(0);
else
m_nActivePage = -1;
}
void CeTabSheet::Apply()
{
for (int ii = 0; ii < m_arPages.GetSize(); ii++)
{
if ((NULL != m_arPages[ii]) && (NULL != m_arPages[ii]->m_hWnd))
{
m_arPages[ii]->OnApply();
}
}
}
void CeTabSheet::Reset()
{
for (int ii = 0; ii < m_arPages.GetSize(); ii++)
{
if ((NULL != m_arPages[ii]) && (NULL != m_arPages[ii]->m_hWnd))
{
m_arPages[ii]->OnReset();
}
}
}
LRESULT CeTabSheet::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
switch (uMsg)
{
case WM_SETFONT:
bHandled = true;
if (m_tabCtrl.m_hWnd)
m_tabCtrl.SetFont((HFONT) wParam, LOWORD(lParam));
break;
}
return 0;
}
LRESULT CeTabSheet::OnNotify(int nCtrlId, LPNMHDR pNMH, bool& bHandled)
{
if (1000 == pNMH->idFrom)
{
switch (pNMH->code)
{
case TCN_SELCHANGE:
bHandled = true;
return OnNotifyTabChanged();
case TCN_SELCHANGING:
bHandled = true;
return OnNotifyTabChanging();
}
}
return TRUE;
}
LRESULT CeTabSheet::OnNotifyTabChanged()
{
int nCurSel = m_tabCtrl.GetCurSel();
if (nCurSel != -1)
SetActivePage(nCurSel);
// OK
return 0;
}
LRESULT CeTabSheet::OnNotifyTabChanging()
{
CeTabPage *pPage = GetActivePage();
// if (pPage && ! pPage->UpdateData())
// // failed data transfer
// return 1;
return 0;
}
int CeTabSheet::OnCreate(LPCREATESTRUCT lpCS, bool& bHandled)
{
//
// Style note: right and bottom are the same, verticle changes it, bottom
// doesn't work in the emulator though
// TCS_RIGHT |
// TCS_BOTTOM |
// TCS_VERTICAL |
//
if (m_dwTabStyle == 0)
m_dwTabStyle = TCS_TABS | TCS_SINGLELINE | TCS_RAGGEDRIGHT | TCS_FOCUSNEVER;
m_dwTabStyle |= (WS_VISIBLE | WS_CHILD);
CeRect rc(lpCS->x, lpCS->y, lpCS->x + lpCS->cx, lpCS->y + lpCS->cy);
if (! m_tabCtrl.Create(m_dwTabStyle, rc, m_hWnd, 1000, m_hInst))
return -1;
// check for delayed creat and do so here
if (m_arPages.GetSize() > 0)
{
int nItem; // page's item number
for (int ii = 0; ii < m_arPages.GetSize(); ii++)
{
if (! (m_dwTabStyle & TCS_VERTICAL))
{
// add the item to the end of the tab
if ( ! (nItem = m_tabCtrl.InsertItem( m_tabCtrl.GetItemCount(), m_arPages[ii]->GetTabTitle())) )
{
// show it and set whatever internal info we need
SetActivePage(nItem);
}
}
else
{
// add the item to the end of the tab
if ( ! (nItem = m_tabCtrl.InsertItem( m_tabCtrl.GetItemCount(), _T(""))) )
{
// show it and set whatever internal info we need
SetActivePage(nItem);
}
}
}
}
bHandled = false; // allow call to the default
return 0;
}
void CeTabSheet::OnPaint( bool& bHandled )
{
bHandled = false;
}
/*
BOOL CeTabSheet::OnEraseBkgnd(CDC* pDC)
{
if (GetPageCount() > 0)
{
CRect rectWnd;
// get the area available for children
GetPageRect(rectWnd);
// exclude it from painting
pDC->ExcludeClipRect(rectWnd);
}
// Don't erase the children's area, we will
// be either on top or below, if below we're painted last
// and will over write, if on top then it will flash
// more than neccassary if we do it so let the
// child page erase instead
return KXTabCtrl::OnEraseBkgnd(pDC);
}
*/
void CeTabSheet::OnSize( UINT nType, int cx, int cy, bool& bHandled )
{
// Do base class adjustments
CeRect rcClient;
GetClientRect(rcClient);
// m_tabCtrl.SetWindowPos(NULL, rcClient, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER);
m_tabCtrl.SetWindowPos(NULL, rcClient, SWP_NOACTIVATE|SWP_NOZORDER);
if (m_tabCtrl.GetItemCount() <= 0)
return;
// Size the active page to fit within borders
CeRect rectWnd;
GetPageRect(rectWnd);
// Note: want to keep Z-order, move and resize....
CeTabPage* pActive = GetActivePage();
if (pActive)
{
pActive->SetWindowPos(NULL, rectWnd, SWP_NOACTIVATE|SWP_NOZORDER);
pActive->Invalidate();
}
}
/*
BOOL CeTabSheet::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
if (m_tabCtrl.ModifyStyle(dwRemove, dwAdd, nFlags))
{
// Reposition child windows
CeRect rectWnd;
// calc the area available for children
GetPageRect(rectWnd);
HWND hWndInsertAfter = m_hWnd;
for (int ii = 0; ii < m_arPages.GetSize(); ii++)
{
// Note: want to keep Z-order, move and resize....
// required to keep the tab order in line....
CeTabPage* pPage = GetPage(ii);
if (! ::IsWindow(pPage->m_hWnd))
continue;
pPage->SetWindowPos(hWndInsertAfter,
rectWnd.left, rectWnd.top, rectWnd.Width(), rectWnd.Height(),
SWP_NOACTIVATE|SWP_NOREDRAW);
pWndInsertAfter = pPage->m_hWnd;
}
// fix ordering
// if (GetStyle() & (KTCS_RIGHT|KTCS_BOTTOM))
// {
// // tab goes AFTER all pages, move it back
// SetWindowPos(pWndInsertAfter, 0, 0, 0, 0,
// SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOREDRAW);
// }
GetPage(m_nActivePage)->Invalidate();
return TRUE;
}
return FALSE;
}
*/
void CeTabSheet::GetPageRect(LPRECT lpRect)
{
m_tabCtrl.GetClientRect(lpRect);
m_tabCtrl.AdjustRect(FALSE, lpRect);
}