|
//==============================================================================
/**
* @file WTLTabViewCtrl.h
*
* Interface for the CWTLTabViewCtrl class.
*
* @author Stephen Jones (Stephen@Jones-net.com)
* @date June 13th, 2002
*
* Copyright 2002, Stephen Jones
*
* History:
* --------
*
* 06/18/2002 Creation
*/
//==============================================================================
//==============================================================================
/**
* @mainpage CWTLTabViewCtrl
*
* @htmlinclude .\CodeProject\TabViewCtrl.html
*/
//==============================================================================
#ifndef INCLUDED_WTLTABVIEWCTRL
#define INCLUDED_WTLTABVIEWCTRL
//==============================================================================
// Includes
//==============================================================================
#ifndef __ATLMISC_H__
#include <atlmisc.h>
#endif
#ifndef __ATLCTRLS_H__
#include <atlctrls.h>
#endif
#ifndef __ATLCRACK_H__
#include <atlcrack.h>
#endif
//==============================================================================
/**
* @class CWTLTabViewCtrl
*
* A WTL class that encapsulates the functionality for managing a tab
* control and associated tab windows.
*
* The standard tab control does not provide facilities for managing the
* child windows associated with each tab. This class encapsulates the
* functionality for automatically managing each tab.
*
* Parent windows must have REFLECT_NOTIFICATIONS() in the message map
* to pass along the TCN_SELCHANGE message.
*
* This class started out as a port of a similar MFC class
* (CSizingTabCtrlBar - author unknown), but turned into a total rewrite.
*/
//==============================================================================
class CWTLTabViewCtrl : public CWindowImpl< CWTLTabViewCtrl, CTabCtrl >
{
//==============================================================================
// Constants
//==============================================================================
private:
const LONG TABVIEW_BORDER; ///< Border Width
const LONG TABVIEW_EDGE; ///< Distance of tab from content
//==============================================================================
// Fields
//==============================================================================
private:
CSimpleArray<CWindow> m_Views; ///< An array of views for the tab
LONG m_ActiveTabIndex; ///< The index of the active tab
CWindow m_ActiveTabWindow; ///< The active tab window
CFont m_HorizFont; ///< Top/Bottom font used by tab control
CFont m_LeftFont; ///< Left font used by tab control
CFont m_RightFont; ///< Right font used by tab control
//==============================================================================
// Construction
//==============================================================================
public:
//==============================================================================
/**
* Constructor:
*/
//==============================================================================
CWTLTabViewCtrl() :
TABVIEW_BORDER ( 3 ),
TABVIEW_EDGE ( 5 ),
m_ActiveTabIndex ( -1 )
{
}
//==============================================================================
/**
* Destructor:
*/
//==============================================================================
virtual ~CWTLTabViewCtrl()
{
}
//==============================================================================
// Public Interface
//==============================================================================
public:
//==============================================================================
/**
* AddTab: Append a tab to the end of the tab control.
*
* @param inLabel
* [in] The label to appear on the tab control.
* @param inTabWindow
* [in] The child window to use as the view for the tab. The window
* must have the WS_CHILD style bit set and the WS_VISIBLE style bit not set.
* @param inActiveFlag
* [in, optional] TRUE to make the tab active, FALSE to just add the tab.
* @param inImage
* [in, optional] The index into the image list for the image to display by the tab label.
* @param inParam
* [in, optional] The param value to associate with the tab.
* @return Zero based index of the new tab, -1 on failure
*/
//==============================================================================
BOOL AddTab( LPCTSTR inLabel, HWND inTabWindow, BOOL inActiveFlag = TRUE, int inImage = -1, LPARAM inParam = 0 )
{
BOOL theReturn;
CWindow theTabWindow( inTabWindow );
// Make sure it's a real window
ATLASSERT( theTabWindow.IsWindow( ) );
// Make sure it's a child window and is not visible
ATLASSERT( ( theTabWindow.GetStyle() & WS_CHILD ) != 0 );
ATLASSERT( ( theTabWindow.GetStyle() & WS_VISIBLE ) == 0 );
// Hide the view window
theTabWindow.EnableWindow( FALSE );
theTabWindow.ShowWindow( SW_HIDE );
// Store the required data for the list
m_Views.Add( theTabWindow );
// Add the tab to the tab control
TC_ITEM theItem = {0};
theItem.mask = TCIF_TEXT;
theItem.pszText = const_cast<char*>( inLabel );
// Add an image for the tab
if ( inImage != -1 )
{
theItem.mask |= TCIF_IMAGE;
theItem.iImage = inImage;
}
// Add the param for the tab
if ( inParam != 0 )
{
theItem.mask |= TCIF_PARAM;
theItem.lParam = inParam;
}
// Insert the item at the end of the tab control
theReturn = InsertItem( 32768, &theItem );
// Set the position for the window
CRect rcChild;
CalcViewRect( &rcChild );
theTabWindow.MoveWindow( rcChild );
// Select the tab that is being added, if desired
LONG theTabIndex = GetTabCount( ) - 1;
if ( inActiveFlag || theTabIndex == 0 )
{
SetActiveTab( theTabIndex );
}
return theReturn;
}
//==============================================================================
/**
* GetTabCount: Return the current number of tabs.
*
* @return The current number of tabs.
*/
//==============================================================================
LONG GetTabCount( )
{
return m_Views.GetSize();
}
//==============================================================================
/**
* GetTab: Get the view window associated with the tab.
*
* @param inTab
* [in] The index of the tab to return the view window.
* @return The handle of the view window.
*/
//==============================================================================
HWND GetTab( int inTab )
{
HWND theTabHwnd = NULL;
if ( inTab >= 0 && inTab < GetTabCount( ) )
{
m_Views[ inTab ];
}
return theTabHwnd;
}
//==============================================================================
/**
* OnTabRemoved: Virtual method that is called when a tab is removed.
*
* @param inTabIndex
* [in] The index of the tab to return the view window.
* @return The handle of the view window.
*/
//==============================================================================
virtual void OnTabRemoved( int inTabIndex )
{
UNREFERENCED_PARAMETER( inTabIndex );
}
//==============================================================================
/**
* RemoveTab: Remove the specified tab.
*
* @param inTab
* [in] The index of the tab to remove.
* @return Returns the HWND of the deleted view window.
*/
//==============================================================================
HWND RemoveTab( int inTab )
{
HWND theTabHwnd = NULL;
LONG theNewTab = -1;
if ( inTab >= 0 && inTab < GetTabCount( ) )
{
// Select a new tab if the tab is active
if ( m_ActiveTabIndex == inTab )
{
m_ActiveTabIndex = -1;
m_ActiveTabWindow = NULL;
if ( GetTabCount( ) > 1 )
{
theNewTab = ( inTab > 0 ) ? ( inTab - 1 ) : 0;
}
}
// Save the window that is begin removed
theTabHwnd = m_Views[ inTab ];
// Virtual method to notify subclasses that a tab was removed
OnTabRemoved( inTab );
// Remove the item from the view list
m_Views.RemoveAt( inTab );
// Remove the tab
if ( IsWindow() )
{
DeleteItem( inTab );
}
SetActiveTab( theNewTab );
}
return theTabHwnd;
}
//==============================================================================
/**
* RemoveAllTabs: Remove all the tabs from the tab control.
*
* @return void
*/
//==============================================================================
void RemoveAllTabs( )
{
LONG theCount = GetTabCount( );
for ( LONG theIndex = theCount - 1; theIndex >= 0; theIndex-- )
{
RemoveTab( theIndex );
}
}
//==============================================================================
/**
* SetActiveTab: Activate the specified tab.
*
* @param inNewTab
* Select the zero based tab at this index.
* @return void
*/
//==============================================================================
void SetActiveTab( int inNewTab )
{
if ( inNewTab >= 0 && inNewTab < GetTabCount( ) && // Validate the tab index range
inNewTab != m_ActiveTabIndex ) // Don't select if already selected
{
// Disable the old tab
if ( m_ActiveTabWindow.IsWindow( ) )
{
m_ActiveTabWindow.EnableWindow( FALSE );
m_ActiveTabWindow.ShowWindow( SW_HIDE );
}
// Enable the new tab
m_ActiveTabWindow = m_Views[ inNewTab ];
m_ActiveTabWindow.EnableWindow( TRUE );
m_ActiveTabWindow.ShowWindow( SW_SHOW );
m_ActiveTabWindow.SetFocus( );
m_ActiveTabWindow.Invalidate( TRUE );
m_ActiveTabIndex = inNewTab;
// Select the tab (if tab programmatically changed)
SetCurSel( m_ActiveTabIndex );
}
}
//==============================================================================
/**
* GetActiveTab: Return the HWND to the active tab.
*
* @return The HWND to the active view.
*/
//==============================================================================
HWND GetActiveTab( )
{
return GetTab( m_ActiveTabIndex );
}
//==============================================================================
/**
* GetActiveTabIndex: Return the index of the active tab.
*
* @return The index of the active tab.
*/
//==============================================================================
LONG GetActiveTabIndex( )
{
return m_ActiveTabIndex;
}
//==============================================================================
/**
* GetTabText: Return the label of the specified tab.
*
* @param inTab
* [in] The index of the tab for which to return the text.
* @param inSize
* [in] The size of the text string buffer.
* @param outText
* [out] The text string buffer.
* @return void
*/
//==============================================================================
void GetTabText( int inTab, int inSize, char* outText )
{
if ( inTab >= 0 && inTab < GetTabCount( ) )
{
// Get tab item info
TCITEM tci;
tci.mask = TCIF_TEXT;
tci.pszText = outText;
tci.cchTextMax = inSize;
GetItem( inTab, &tci );
}
}
#ifdef __ATLSTR_H__
//==============================================================================
/**
* GetTabText: Return the label of the specified tab.
*
* @param inTab
* [in] The index of the tab for which to return the text.
* @return CString containing the tab text.
*/
//==============================================================================
const CString GetTabText( int inTab )
{
CString theTabText;
if ( inTab >= 0 && inTab < GetTabCount( ) )
{
// Get tab item info
char theText[128];
GetTabText( inTab, sizeof( theText ), theText );
theTabText = theText;
}
return theTabText;
}
#endif
//==============================================================================
/**
* GetTabParam: Return the param of the specified tab.
*
* @param inTab
* [in] The index of the tab for which to return the param.
* @return LPARAM
*/
//==============================================================================
LPARAM GetTabParam( int inTab )
{
TCITEM tci = {0};
if ( inTab >= 0 && inTab < GetTabCount( ) )
{
// Get tab item info
tci.mask = TCIF_PARAM;
GetItem( inTab, &tci );
}
return tci.lParam;
}
//==============================================================================
/**
* GetTabImage: Return the param of the specified tab.
*
* @param inTab
* [in] The index of the tab for which to return the image.
* @return int
*/
//==============================================================================
int GetTabImage( int inTab )
{
TCITEM tci = {0};
if ( inTab >= 0 && inTab < GetTabCount( ) )
{
// Get tab item info
tci.mask = TCIF_IMAGE;
GetItem( inTab, &tci );
}
return tci.iImage;
}
//==============================================================================
/**
* ModifyTabStyle: This method modifies the window styles of the CWindow
* object. Styles to be added or removed can be combined by using the
* bitwise OR ( | ) operator.
*
* @param dwRemove
* [in] Specifies the window styles to be removed during style modification.
* @param dwAdd
* [in] Specifies the window styles to be added during style modification.
* @param nFlags
* [in] Window-positioning flags. For a list of possible values,
* see theSetWindowPos function in the Win32 SDK.
*
* If nFlags is nonzero, ModifyStyle calls the Win32 function SetWindowPos,
* and redraws the window by combining nFlags with the following four flags:
*
* SWP_NOSIZE Retains the current size.
* SWP_NOMOVE Retains the current position.
* SWP_NOZORDER Retains the current Z order.
* SWP_NOACTIVATE Does not activate the window.
* To modify a window's extended styles, call ModifyStyleEx.
*
* @return TRUE if the window styles are modified; otherwise, FALSE.
*/
//==============================================================================
BOOL ModifyTabStyle( DWORD dwRemove, DWORD dwAdd, UINT nFlags )
{
// Modify the style
BOOL theReturn = ModifyStyle( dwRemove, dwAdd, nFlags );
// Update all the views in case the window positions changes
UpdateViews( );
// Set the font in case the tab position changed
SetTabFont( dwAdd );
return theReturn;
}
//==============================================================================
// Message Map
//==============================================================================
public:
BEGIN_MSG_MAP_EX(CWTLTabViewCtrl)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)
REFLECTED_NOTIFY_CODE_HANDLER_EX(TCN_SELCHANGE, OnSelectionChanged)
END_MSG_MAP()
//==============================================================================
// Windows Message Handlers
//==============================================================================
protected:
//==============================================================================
/**
* UpdateViews: Update the position of all the contained views.
*
* @return void
*/
//==============================================================================
void UpdateViews( )
{
CRect rcChild;
CalcViewRect( &rcChild );
LONG theCount = GetTabCount( );
for ( LONG theIndex = 0; theIndex < theCount; theIndex++ )
{
m_Views[ theIndex ].MoveWindow( rcChild );
}
}
//==============================================================================
/**
* OnCreate: Called in response to the WM_CREATE message
*
* @return 0
*/
//==============================================================================
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& )
{
LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
// Get the log font.
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
// Top and Bottom Tab Font
m_HorizFont.CreateFontIndirect(&ncm.lfMessageFont);
// Left Tab Font
ncm.lfMessageFont.lfOrientation = 900;
ncm.lfMessageFont.lfEscapement = 900;
m_LeftFont.CreateFontIndirect(&ncm.lfMessageFont);
// Right Tab Font
ncm.lfMessageFont.lfOrientation = 2700;
ncm.lfMessageFont.lfEscapement = 2700;
m_RightFont.CreateFontIndirect(&ncm.lfMessageFont);
// Check styles to determine which font to set
SetTabFont( GetStyle( ) );
return lRet;
}
//==============================================================================
/**
* OnDestroy: Called in response to the WM_DESTROY message
*
* @return 0
*/
//==============================================================================
LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)
{
RemoveAllTabs( );
bHandled = FALSE;
return 0;
}
//==============================================================================
/**
* OnWindowPosChanged: Called in response to the WM_WNDPOSCHANGED message
*
* @return 0
*/
//==============================================================================
LRESULT OnWindowPosChanged(UINT, WPARAM, LPARAM, BOOL& bHandled )
{
UpdateViews( );
bHandled = FALSE;
return 0;
}
//==============================================================================
/**
* OnSelectionChanged: Called in response to the TCN_SELCHANGE message
*
* @return 0
*/
//==============================================================================
LRESULT OnSelectionChanged( LPNMHDR )
{
SetActiveTab( GetCurSel( ) );
return 0;
}
//==============================================================================
// Implementation
//==============================================================================
protected:
//==============================================================================
/**
* CalcViewRect: Calculate the client rect for contained views.
*
* @param pRect
* [out] Returns the new view rect.
* @return void
*/
//==============================================================================
void CalcViewRect(CRect* pRect)
{
GetClientRect( (*pRect) );
if ( pRect->Height() > 0 && pRect->Width() > 0 )
{
// Calculate the Height (or Width) of the tab . . .
// cause it could be Multiline
CRect theTabRect;
GetItemRect( 0, &theTabRect );
LONG theRowCount = GetRowCount( );
LONG theEdgeWidth = ( theTabRect.Width() * theRowCount ) + TABVIEW_EDGE;
LONG theEdgeHeight = ( theTabRect.Height() * theRowCount ) + TABVIEW_EDGE;
// Set the size based on the style
DWORD dwStyle = GetStyle();
if ((dwStyle & TCS_BOTTOM) && !(dwStyle & TCS_VERTICAL)) { // Bottom
(*pRect).top += TABVIEW_BORDER;
(*pRect).left += TABVIEW_BORDER;
(*pRect).right -= TABVIEW_BORDER;
(*pRect).bottom -= theEdgeHeight;
}
else if ((dwStyle & TCS_RIGHT) && (dwStyle & TCS_VERTICAL)) { // Right
(*pRect).top += TABVIEW_BORDER;
(*pRect).left += TABVIEW_BORDER;
(*pRect).right -= theEdgeWidth;
(*pRect).bottom -= TABVIEW_BORDER;
}
else if (dwStyle & TCS_VERTICAL) { // Left
(*pRect).top += TABVIEW_BORDER;
(*pRect).left += theEdgeWidth;
(*pRect).right -= TABVIEW_BORDER;
(*pRect).bottom -= TABVIEW_BORDER;
}
else { // Top
(*pRect).top += theEdgeHeight;
(*pRect).left += TABVIEW_BORDER;
(*pRect).right -= TABVIEW_BORDER;
(*pRect).bottom -= TABVIEW_BORDER;
}
}
}
//==============================================================================
/**
* SetTabFont: Set the font to be used by the tab control.
*
* @param inStyleBits
* [in] The style bits to use to calculate the font to use.
* @return void
*/
//==============================================================================
void SetTabFont( DWORD inStyleBits )
{
if ( inStyleBits & TCS_VERTICAL )
{
if ( inStyleBits & TCS_RIGHT )
{
SetFont( m_RightFont );
}
else
{
SetFont( m_LeftFont );
}
}
else
{
SetFont( m_HorizFont );
}
}
};
#endif // INCLUDED_WTLTABVIEWCTRL
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Stephen Jones is a Lead Software Engineer for Anark Corporation in Boulder, Colorado.