Click here to Skip to main content
15,884,913 members
Articles / Desktop Programming / MFC

SolidGraph CAD System

Rate me:
Please Sign up or sign in to vote.
4.97/5 (78 votes)
12 Sep 20062 min read 375.2K   29.8K   209  
A SolidGraph CAD system source code.
#include "StdAfx.h"

#include "EGMDIClient.h"
#include "NewTheme.h"
#include "EGMenu.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define TABS_HEIGHT 24
#define TABS_BKGND RGB(247,243,233)
#define PADDING 3
#define WM_RECALC_BUTTONS WM_USER + 1

#include <algorithm>
#include <functional>

//////////////////////////////////////////////////////////////////////////// 
// Registry keys used for saving/restoring the state
static TCHAR szSection[]      = _T( "MDIClient" );
static TCHAR szDisplayMode[]  = _T( "DisplayMode" );
static TCHAR szBkColor[]      = _T( "BkColor" );
static TCHAR szFileName[]     = _T( "FileName" );
static TCHAR szOriginX[]      = _T( "OriginX" );
static TCHAR szOriginY[]      = _T( "OriginY" );

/////////////////////////////////////////////////////////////////////////////
// CEGMDITabBtn

void CEGMDITabBtn::Copy( const CEGMDITabBtn & tab ) {
	m_hWnd = tab.m_hWnd;
	m_nWidth = tab.m_nWidth;
	m_nLeft = tab.m_nLeft;
	m_clrColor = tab.m_clrColor;
}

CEGMDITabBtn::CEGMDITabBtn( HWND hWnd ) {
	m_hWnd = hWnd;
	m_nWidth = 0;
	m_clrColor = themeData.GetNewColor();
}

CEGMDITabBtn::CEGMDITabBtn( const CEGMDITabBtn & tab ) {
	Copy( tab );
}

CEGMDITabBtn & CEGMDITabBtn::operator=( const CEGMDITabBtn & tab ) {
	Copy( tab );
	return *this;
}

CString CEGMDITabBtn::GetTitle() { 
	CString szTitle;
	GetWindowText( m_hWnd, szTitle.GetBuffer(100), 100 );
	szTitle.ReleaseBuffer();
	return szTitle; 
}

/////////////////////////////////////////////////////////////////////////////
// CEGMDIClient

static int CALLBACK EnumFontFamProc(ENUMLOGFONT FAR *lpelf,
                             NEWTEXTMETRIC FAR *lpntm,
                             int FontType,
                             LPARAM lParam)
{
    UNUSED_ALWAYS(lpelf);
    UNUSED_ALWAYS(lpntm);
    UNUSED_ALWAYS(FontType);
    UNUSED_ALWAYS(lParam);

    return 0;
}

CEGMDIClient::CEGMDIClient()
{   
	Reset();
	m_bAutoSaveRestore = FALSE;
	m_bShowTabs = FALSE;

  m_cxEdge = 6;
	m_cxControls = 45;
	m_nWidth = 0;

	m_bPriorEnabled = FALSE;
	m_bPriorHover = FALSE;
	m_bPriorPressed = FALSE;

	m_bNextEnabled = FALSE;
	m_bNextHover = FALSE;
	m_bNextPressed = FALSE;
		
	m_bCloseEnabled = TRUE;
	m_bCloseHover = FALSE;
	m_bClosePressed = FALSE;
	
	m_cxOffset = 0;
	m_cxBtnsAvailable = 0;
	m_cxBtnsTotal = 0;

	m_bTabDrag = FALSE;
}

CEGMDIClient::~CEGMDIClient()
{
}

void CEGMDIClient::PreSubclassWindow()
{
	CWnd::PreSubclassWindow();
	if ( m_bAutoSaveRestore == TRUE )
		RestoreState();

	m_oldWndProc = (WNDPROC)::GetWindowLongPtr( m_hWnd, GWLP_WNDPROC );
}

void CEGMDIClient::Reset()
{
	m_ptOrigin.x = m_ptOrigin.y = 0;
	m_sizeImage.cx = m_sizeImage.cy = 0;
	m_eDisplayMode = dispTile;
	m_strFileName.Empty();      
	SetBkColor( themeData.clrAppWorkSpace );
	m_bitmap.DeleteObject();
	if ( IsWindow( m_hWnd ) )
		Invalidate();
}

BOOL CEGMDIClient::SetBitmap( LPCTSTR lpszFileName, UINT uFlags )
{
	HANDLE handle = ::LoadImage( AfxGetInstanceHandle(),
		lpszFileName,
		IMAGE_BITMAP,
		0, 0,
		uFlags | LR_LOADFROMFILE );

	if ( !handle )    // There were some problems during loading the image
		return FALSE;

	m_bitmap.DeleteObject();
	m_bitmap.Attach( (HBITMAP)handle );
	if ( IsWindow( m_hWnd ) )
		Invalidate();
	m_strFileName = lpszFileName;

	BITMAP bi;
	m_bitmap.GetBitmap( &bi );
	m_sizeImage.cx = bi.bmWidth;
	m_sizeImage.cy = bi.bmHeight;

	return TRUE;
}

BOOL CEGMDIClient::SetBitmap( UINT nBitmapID, COLORMAP* pClrMap, int nCount )
{
	m_bitmap.DeleteObject();
	if ( pClrMap == NULL )  // Load normal
	{
		if ( m_bitmap.LoadBitmap( nBitmapID ) == FALSE )
			return FALSE;
	}
	else                    // Load mapped 
	{      
		if ( m_bitmap.LoadMappedBitmap( nBitmapID, 0, pClrMap, nCount ) == FALSE )
			return FALSE;
	}

	BITMAP bi;
	m_bitmap.GetBitmap( &bi );
	m_sizeImage.cx = bi.bmWidth;
	m_sizeImage.cy = bi.bmHeight;

	if ( IsWindow( m_hWnd ) )
		Invalidate();
	return TRUE;
}

void CEGMDIClient::SetBkColor( COLORREF clrValue )
{
	m_clrBackground = clrValue;
	m_brush.DeleteObject();
	m_brush.CreateSolidBrush( m_clrBackground );
	if ( IsWindow( m_hWnd ) )
		Invalidate();
}

void CEGMDIClient::SetDisplayMode( CEGMDIClient::DisplayModesEnum eDisplayMode )
{
	m_eDisplayMode = eDisplayMode;      
	if ( IsWindow( m_hWnd ) )
		Invalidate();
}

void CEGMDIClient::SaveState()
{
	AfxGetApp()->WriteProfileInt( szSection, szDisplayMode, GetDisplayMode() );
	AfxGetApp()->WriteProfileInt( szSection, szBkColor, GetBkColor() );
	AfxGetApp()->WriteProfileString( szSection, szFileName, GetFileName() );
	AfxGetApp()->WriteProfileInt( szSection, szOriginX, GetOrigin().x );
	AfxGetApp()->WriteProfileInt( szSection, szOriginY, GetOrigin().y );   
}

void CEGMDIClient::RestoreState()
{   
	m_eDisplayMode = (DisplayModesEnum)AfxGetApp()->GetProfileInt( szSection, szDisplayMode, dispTile );      
	m_ptOrigin.x = AfxGetApp()->GetProfileInt( szSection, szOriginX, 0 );
	m_ptOrigin.y = AfxGetApp()->GetProfileInt( szSection, szOriginY, 0 );
	SetBkColor( AfxGetApp()->GetProfileInt( szSection, szBkColor, themeData.clrAppWorkSpace ) );
	CString str = AfxGetApp()->GetProfileString( szSection, szFileName, _T( "" ) );
	if ( str.GetLength() )
		SetBitmap( str );
}

BEGIN_MESSAGE_MAP(CEGMDIClient, CWnd)
   ON_WM_DESTROY()
   ON_WM_PAINT()
   ON_WM_SIZE()
   ON_WM_ERASEBKGND()
	 ON_MESSAGE( WM_MDICREATE, OnMDICreate )
	 ON_MESSAGE( WM_MDIDESTROY, OnMDIDestroy )
	 ON_MESSAGE( WM_MDINEXT, OnMDINext )
	 ON_MESSAGE( WM_MDIACTIVATE, OnMDIActivate )
	 ON_MESSAGE( WM_RECALC_BUTTONS, OnRecalcButtons )

	 ON_WM_NCLBUTTONDOWN()
	 ON_WM_NCLBUTTONUP()
	 ON_WM_LBUTTONUP()
	 ON_WM_NCMOUSEMOVE()
	 ON_WM_CANCELMODE()
	 ON_WM_MOUSEMOVE()

	 ON_WM_STYLECHANGED( )
	 ON_WM_NCCALCSIZE()
	 ON_WM_NCPAINT( )
	 ON_WM_NCHITTEST()
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CEGMDIClient message handlers

void CEGMDIClient::OnPaint() 
{
	CPaintDC dc( this );
	CRect rc;
	GetClientRect( rc );

	if ( !(HBITMAP)m_bitmap )   // If no bitmap is selected
		dc.FillRect( rc, &m_brush );

	if ( (HBITMAP)m_bitmap )
	{
		CDC* pDC;
		CDC memDC;
		CBitmap bmp; 

		BOOL bDrawOnMemDC = ( GetDisplayMode() != dispTile ) ? TRUE : FALSE;
		if ( bDrawOnMemDC )
		{
			if ( GetDisplayMode() != dispStretch )
				bmp.CreateCompatibleBitmap( &dc, rc.right, rc.bottom );
			else
				bmp.CreateCompatibleBitmap( &dc, m_sizeImage.cx, m_sizeImage.cy );
			memDC.CreateCompatibleDC( &dc );
			memDC.SelectObject( &bmp );
			pDC = &memDC;
		}
		else
			pDC = &dc;      

		switch ( GetDisplayMode() )
		{
		case dispCustom:
			{
				pDC->FillRect( rc, &m_brush );               
				pDC->DrawState( m_ptOrigin, m_sizeImage, &m_bitmap, DST_BITMAP | DSS_NORMAL );
			}
			break;

		case dispCenter:
			{
				pDC->FillRect( rc, &m_brush );
				CPoint point( ( rc.Width() - m_sizeImage.cx ) / 2, 
					( rc.Height() - m_sizeImage.cy ) / 2 );
				pDC->DrawState( point, m_sizeImage, &m_bitmap, DST_BITMAP | DSS_NORMAL );
			}
			break;

		case dispTile:
			{
				CPoint point;
				for ( point.y = 0; point.y < rc.Height(); point.y += m_sizeImage.cy )
					for ( point.x = 0; point.x < rc.Width(); point.x += m_sizeImage.cx )
						pDC->DrawState( point, m_sizeImage, &m_bitmap, DST_BITMAP | DSS_NORMAL );
			}
			break;

		case dispStretch:
			{
				memDC.DrawState( CPoint(0,0), m_sizeImage, &m_bitmap, DST_BITMAP | DSS_NORMAL );
				dc.SetStretchBltMode( COLORONCOLOR );
				dc.StretchBlt( 0, 0, rc.right, rc.bottom, &memDC, 
					0, 0, m_sizeImage.cx, m_sizeImage.cy, SRCCOPY );
			}
			return;
		}

		if ( bDrawOnMemDC == TRUE )
			dc.BitBlt( 0, 0, rc.right, rc.bottom, pDC, 0, 0, SRCCOPY );
	}
}

BOOL CEGMDIClient::OnEraseBkgnd( CDC* /*pDC*/ ) 
{   
   return TRUE;    // Return TRUE so background is not erased   
}

void CEGMDIClient::OnSize( UINT nType, int cx, int cy )
{
	if ( nType != SIZE_MINIMIZED && GetDisplayMode() != dispTile )   // Force repainting if center mode is selected
		Invalidate();
	CWnd::OnSize( nType, cx, cy );
}

void CEGMDIClient::OnDestroy()
{   
	if ( m_bAutoSaveRestore == TRUE )
		SaveState();
	CWnd::OnDestroy();
}

LRESULT CEGMDIClient::OnMDICreate ( WPARAM wParam, LPARAM lParam ) {
	
	LRESULT res = m_oldWndProc( m_hWnd, WM_MDICREATE, wParam, lParam );

	if( res ) {
		m_lstTabBtns.push_back( CEGMDITabBtn( (HWND)res ) );
		m_hWndActive = (HWND)res;
		PostMessage( WM_RECALC_BUTTONS, 2 );
	}

	return res;
}

LRESULT CEGMDIClient::OnMDIDestroy ( WPARAM wParam, LPARAM lParam ) {
	LRESULT res = m_oldWndProc( m_hWnd, WM_MDIDESTROY, wParam, lParam );

	CEGMDITabBtnsIt itToDestroy = find_if( m_lstTabBtns.begin(), m_lstTabBtns.end(), MatchWndBtn( (HWND)wParam ) );

	if ( itToDestroy != m_lstTabBtns.end() )
		m_lstTabBtns.erase( itToDestroy );

	if ( m_bShowTabs ) {
		if ( NULL == ::GetWindow( m_hWnd, GW_CHILD ) ) {
			m_bShowTabs = FALSE;
			PostMessage( WM_RECALC_BUTTONS, 1 );
		} else {
			m_hWndActive = (HWND)::SendMessage( m_hWnd, WM_MDIGETACTIVE, 0, 0 );
			PostMessage( WM_RECALC_BUTTONS );
		}
	}

	return res;
}

LRESULT CEGMDIClient::OnMDINext ( WPARAM wParam, LPARAM lParam ) {
	//LRESULT res = m_oldWndProc( m_hWnd, WM_MDINEXT, wParam, lParam );
	if ( m_lstTabBtns.size() == 1 )
		return 0L;

	CEGMDITabBtnsIt itActive = find_if( m_lstTabBtns.begin(), m_lstTabBtns.end(), MatchWndBtn( (HWND)wParam ) );
	if ( itActive == m_lstTabBtns.end() )
		return 0L;

	if( lParam == 0 ) {
		// forward
		if( itActive->m_hWnd != m_lstTabBtns.back().m_hWnd ) {
			++itActive;
		} else {
			itActive = m_lstTabBtns.begin();
		}
	} else {
		// backward
		if( itActive->m_hWnd != m_lstTabBtns.front().m_hWnd ) {
			--itActive;
		} else {
			itActive = --m_lstTabBtns.end();
		}
	}

	if ( itActive->m_nLeft < 0 ) {
		m_cxOffset -= -itActive->m_nLeft;
	} else if ( m_cxBtnsAvailable < ( itActive->m_nLeft + itActive->m_nWidth ) ) {
		m_cxOffset += ( itActive->m_nLeft + itActive->m_nWidth ) - m_cxBtnsAvailable;
	}

	ActivateMDI( itActive->m_hWnd );

	m_hWndActive = itActive->m_hWnd;

	return 0L;
}

LRESULT CEGMDIClient::OnMDIActivate ( WPARAM wParam, LPARAM lParam ) {
	LRESULT res = m_oldWndProc( m_hWnd, WM_MDIACTIVATE, wParam, lParam );

	m_hWndActive = (HWND)wParam;

	OnRecalcButtons( 0, 0 );

	return res;
}

void CEGMDIClient::OnNcCalcSize(
   BOOL bCalcValidRects,
   NCCALCSIZE_PARAMS* lpncsp ) 
{
	CWnd::OnNcCalcSize( bCalcValidRects, lpncsp );
	if ( m_bShowTabs ) {
		lpncsp[0].rgrc->top += TABS_HEIGHT;
		lpncsp[0].rgrc->right -= 2;
		lpncsp[0].rgrc->left += 2;
		lpncsp[0].rgrc->bottom -= 2;

		CRect rc (*lpncsp[0].rgrc);
		rc.OffsetRect( -rc.TopLeft() );
		CalcButtons( &rc );
	}
}

void CEGMDIClient::OnStyleChanged( int nStyleType, LPSTYLESTRUCT lpStyleStruct ) {
	m_hWndActive = (HWND)::SendMessage( m_hWnd, WM_MDIGETACTIVE, 0, (LPARAM) &m_bShowTabs );
	m_bShowTabs = !m_bShowTabs;
}

void CEGMDIClient::OnNcPaint() {

	CWnd::OnNcPaint();

	if ( m_bShowTabs ) {
		// get window DC that is clipped to the non-client area
		CWindowDC dc(this);
		CRect rectClient;
		GetWindowRect(rectClient);
		rectClient.OffsetRect( -rectClient.TopLeft() );

		// Draw border
		BOOL bOldStyle = CEGMenu::GetMenuDrawMode() == CEGMenu::STYLE_ORIGINAL ||
			CEGMenu::GetMenuDrawMode() == CEGMenu::STYLE_ORIGINAL_NOBORDER;

//		if ( !bOldStyle ) {
		CPen pnBorder( PS_SOLID, 1, bOldStyle ? themeData.clrBtnFace : themeData.clr3DShadow );
		CPen * pOldPen = dc.SelectObject( &pnBorder );

		dc.MoveTo( 0 , 0 );
		dc.LineTo( rectClient.right - 1, 0  );
		dc.LineTo( rectClient.right - 1, rectClient.bottom - 1 );
		dc.LineTo( 0, rectClient.bottom - 1 );
		dc.LineTo( 0, 0 );

		CPen pnBorder2( PS_SOLID, 1, themeData.clrBtnFace );
		dc.SelectObject( &pnBorder2 );
		dc.MoveTo( rectClient.right - 2, 1  );
		dc.LineTo( rectClient.right - 2, rectClient.bottom - 2 );
		dc.LineTo( 1, rectClient.bottom - 2 );
		dc.LineTo( 1, 0 );

		dc.SelectObject( pOldPen );

		CRect rcTabs = rectClient;
		rcTabs.top = 1;
		rcTabs.bottom = rcTabs.top + TABS_HEIGHT - 1;

		CSurface surface;

		// tabs
		rcTabs.left = 2;
		rcTabs.right = rectClient.right - m_cxControls - m_cxEdge - 2;

		DrawTabs( surface.Lock( &dc, &rcTabs ), surface.GetBounds() );
		surface.Release();

		// controls
		rcTabs.left = rectClient.right - m_cxControls - m_cxEdge - 2;
		rcTabs.right = rectClient.right - 2;

		DrawControls( surface.Lock( &dc, &rcTabs ), surface.GetBounds() );
		surface.Release();
	}
}

void CEGMDIClient::DrawTabs( CDC * pDC, LPRECT lprcBounds ) {

	ASSERT( NULL != lprcBounds );

	if( m_lstTabBtns.empty() )
		return;

	CEGMDITabBtnsIt it, itFirst = m_lstTabBtns.begin(),
		itLast = m_lstTabBtns.end();

	COLORREF clrActive = themeData.clrBtnFace;
	for( it = itFirst; it != itLast; ++it ) {
		if ( it->m_hWnd == m_hWndActive ) {
			clrActive = it->m_clrColor;
			break;
		}
	}
	themeData.DrawTabCtrlBK( pDC, lprcBounds, ALIGN_TOP, TRUE, clrActive );


	// Draw buttons  
	CRect rcButton( *lprcBounds );
	rcButton.top+=2;

	int nOldBkMode = pDC->SetBkMode(TRANSPARENT);

	//	CFont* pOldFont = pDC->SelectObject( &m_fntThin );

	for( it = itFirst; it != itLast; ++it ) {

		CEGMDITabBtn btn = (*it);

		BOOL bSelected = ( btn.m_hWnd == m_hWndActive );

		int nWidth = btn.m_nWidth;
		rcButton.left = btn.m_nLeft;
		rcButton.right = rcButton.left + nWidth;

		themeData.DrawTab( pDC, &rcButton, NULL, (TCHAR*)(LPCTSTR)btn.GetTitle(), ALIGN_TOP, STYLE_COOL | ( bSelected ? STYLE_ACTIVE : 0 ), btn.m_clrColor );
	}

	// pDC->SelectObject( pOldFont );	
}

void CEGMDIClient::DrawControls( CDC * pDC, LPRECT lprcBounds ) {

	ASSERT( NULL != lprcBounds );

	CEGMDITabBtnsIt it, itFirst = m_lstTabBtns.begin(),
		itLast = m_lstTabBtns.end();

	COLORREF clrActive = themeData.clrBtnFace;
	for( it = itFirst; it != itLast; ++it ) {
		if ( it->m_hWnd == m_hWndActive ) {
			clrActive = it->m_clrColor;
			break;
		}
	}
	themeData.DrawTabCtrlBK( pDC, lprcBounds, ALIGN_TOP, TRUE, clrActive );

	CRect rc( *lprcBounds );

	CPen pnCross( PS_SOLID, 1, themeData.clr3DShadow );
	CPen * pOldPen = pDC->SelectObject( &pnCross );

	// Draw cross
	rc = m_rcClose;
	rc.OffsetRect( -( m_nWidth - ( lprcBounds->right - lprcBounds->left ) ), 0 );
	themeData.DrawX( pDC, &rc ); 
	rc.OffsetRect( -1, 0 );
	themeData.DrawX( pDC, &rc ); 

	if ( m_bCloseHover && m_bClosePressed ) {
		themeData.DrawPressedRect( pDC, &rc );
	} else if ( m_bCloseHover && !m_bClosePressed ) {
		themeData.DrawHoverRect( pDC, &rc );
	}

	// Draw arrows
	CBrush brEnabled, brDisabled, * pbrOld;
	brEnabled.CreateSolidBrush( themeData.clr3DShadow );
	brDisabled.CreateStockObject( NULL_BRUSH );

	rc = m_rcNext;
	rc.OffsetRect( -( m_nWidth - ( lprcBounds->right - lprcBounds->left ) ), 0 );

	POINT pts[3];

	pts[0].x = rc.left; pts[0].y = rc.top;
	pts[1].x = rc.left; pts[1].y = rc.bottom;
	pts[2].x = rc.left + 4; pts[2].y = rc.bottom - 4;

	if( m_bNextEnabled ) {
		pbrOld = pDC->SelectObject( &brEnabled );
	} else {
		pbrOld = pDC->SelectObject( &brDisabled );
	}
	pDC->Polygon( pts, 3);

	if ( m_bNextHover ) {
		rc.top = m_rcClose.top;
		rc.bottom = m_rcClose.bottom;
		rc.left -= 4;
		rc.right = rc.left + m_rcClose.Width();
		if ( m_bNextPressed ) {
			themeData.DrawPressedRect( pDC, &rc );
		} else {
			themeData.DrawHoverRect( pDC, &rc );
		}
	}

	rc = m_rcPrior;
	rc.OffsetRect( -( m_nWidth - ( lprcBounds->right - lprcBounds->left ) ), 0 );

	pts[0].x = rc.right; pts[0].y = rc.top;
	pts[1].x = rc.right; pts[1].y = rc.bottom;
	pts[2].x = rc.right - 4; pts[2].y = rc.bottom - 4;

	if( m_bPriorEnabled ) {
		pDC->SelectObject( &brEnabled );
	} else {
		pDC->SelectObject( &brDisabled );
	}
	pDC->Polygon( pts, 3);

	if ( m_bPriorHover ) {
		rc.top = m_rcClose.top;
		rc.bottom = m_rcClose.bottom;
		rc.left += 2;
		rc.right = rc.left + m_rcClose.Width();
		if ( m_bPriorPressed ) {
			themeData.DrawPressedRect( pDC, &rc );
		} else {
			themeData.DrawHoverRect( pDC, &rc );
		}
	}

	pDC->SelectObject( pbrOld );
	pDC->SelectObject( pOldPen );
}

void CEGMDIClient::CalcButtons( LPRECT lprcBounds ) {

	ASSERT( lprcBounds != NULL );

	// ���������� ������ ���������
	CRect rcButtons;
	rcButtons.left = m_cxEdge;
	CRect rcClient( *lprcBounds );
	m_nWidth = rcClient.Width();
	rcButtons.right = rcClient.Width() - m_cxEdge - m_cxControls;
	m_cxBtnsAvailable = rcButtons.Width();
	m_cxBtnsTotal = 0;

	CEGMDITabBtnsIt it, itFirst = m_lstTabBtns.begin(),
		itLast = m_lstTabBtns.end();
	
	CPaintDC dc( this );
	for( it = itFirst ; it != itLast; ++it ) {
	
		UINT nStyle = STYLE_COOL | ( it->m_hWnd == m_hWndActive ? STYLE_ACTIVE : 0 );

		it->m_nWidth = themeData.MeasureTab( &dc, FALSE, (TCHAR*)(LPCTSTR)it->GetTitle(), ALIGN_TOP, nStyle );
		it->m_nLeft = rcButtons.left;
		
		rcButtons.left += it->m_nWidth;
		m_cxBtnsTotal += it->m_nWidth;
	} 
	
	if ( m_cxOffset > 0 && ( m_cxBtnsTotal - m_cxOffset ) <= m_cxBtnsAvailable )
		m_cxOffset = m_cxBtnsTotal - m_cxBtnsAvailable;

	if ( m_cxOffset > 0 && m_cxBtnsTotal > m_cxBtnsAvailable ) {
		int nDelta = m_cxOffset;
		for( it = itFirst ; it != itLast; ++it )
			it->m_nLeft -= nDelta;
	}

	
	m_bNextEnabled = ( m_cxBtnsTotal - m_cxOffset > m_cxBtnsAvailable );
	m_bPriorEnabled = ( m_cxOffset > 0 );

	
	m_rcClose.SetRect( m_nWidth - 18, 3, m_nWidth - 4, 17 );
	m_rcNext.SetRect( m_nWidth - 30, 5, m_nWidth - 20, 13 );
	m_rcPrior.SetRect( m_nWidth - 50, 5, m_nWidth - 40, 13 );
}

LRESULT CEGMDIClient::OnRecalcButtons ( WPARAM wParam, LPARAM lParam ) {

	CRect rc;
	GetClientRect( &rc );
	CalcButtons( &rc );

	if ( 1 == wParam )
		::SetWindowPos( m_hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_DRAWFRAME | SWP_FRAMECHANGED );

	if( 2 == wParam && m_cxBtnsTotal > m_cxBtnsAvailable ) {
		m_cxOffset = m_cxBtnsTotal - m_cxBtnsAvailable;
		CalcButtons( &rc );
	}

	SendMessage( WM_NCPAINT );

	return 0L;
}

#define TEST_PRESSED( name, id ) \
	if ( m_b##name##Enabled && ( HTOBJECT + id == nHitTest ) ) {	\
		m_b##name##Pressed = TRUE;	\
		SetCapture();	\
		bNeedRepaint = TRUE;	\
	} else if( m_b##name##Pressed ) {	\
		m_b##name##Pressed = FALSE;	\
		bNeedRepaint = TRUE;	\
	}	\

#define ON_PRESSED( name, id, func ) \
	if ( m_b##name##Enabled && ( HTOBJECT + id == nHitTest ) )	\
		func##();	\

void CEGMDIClient::OnNcLButtonDown(UINT nHitTest, CPoint point) 
{

	ScreenToClient( &point );
	
	if ( HTOBJECT == nHitTest ) {
		// Searching the child tab at this point
		CEGMDITabBtnsIt it, itFirst = m_lstTabBtns.begin(),
				itLast = m_lstTabBtns.end();
		for( it = itFirst; it != itLast; ++it ) {
			if ( it->m_nLeft <= point.x && (it->m_nLeft + it->m_nWidth) >= point.x ) {
				if ( it->m_hWnd != m_hWndActive ) {
					if ( it->m_nLeft < 0 ) {
						if ( it->m_hWnd != itFirst->m_hWnd ) {
							m_cxOffset -= - it->m_nLeft + 30;
						} else {
							m_cxOffset = 0;
						}
					} else if ( it->m_nLeft + it->m_nWidth > m_cxBtnsAvailable ) {
						if ( it->m_hWnd != m_lstTabBtns.back().m_hWnd ) {
							m_cxOffset += it->m_nLeft + it->m_nWidth - m_cxBtnsAvailable + 30;
						} else {
							m_cxOffset += it->m_nLeft + it->m_nWidth - m_cxBtnsAvailable;
						}
					}
					ActivateMDI( it->m_hWnd );
				} 
				m_bTabDrag = TRUE;
				SetCapture();
				break;
			}
		}
	}

	BOOL bNeedRepaint = FALSE;

	TEST_PRESSED( Close, 1 );
	ON_PRESSED( Next, 2, ScrollNext );
	ON_PRESSED( Prior, 3, ScrollPrior );

	if(  bNeedRepaint )
		SendMessage( WM_NCPAINT );

	// Do not call CWnd::OnNcLButtonDown here! It will break mouse events handling
	// CWnd::OnNcLButtonDown( nHitTest, point );
}

#define ON_BUTTON_UP( name, id, func ) \
	if ( m_b##name##Pressed ) {	\
		m_b##name##Pressed = FALSE;	\
		if ( HTOBJECT + id == nHitTest ) {	\
			func##();	\
			return;	\
		} else {	\
			bNeedRepaint = TRUE;	\
		}	\
	}	\

void CEGMDIClient::OnNcLButtonUp(UINT nHitTest, CPoint point) 
{
	m_bTabDrag = FALSE;
	if ( ::GetCapture() == m_hWnd )
		ReleaseCapture();

	BOOL bNeedRepaint = FALSE;

	ON_BUTTON_UP( Close, 1, CloseActiveMDI ); 
	//ON_BUTTON_UP( Next, 2, ScrollNext ); 
	//ON_BUTTON_UP( Prior, 3, ScrollPrior ); 

	if( bNeedRepaint )
		SendMessage( WM_NCPAINT );

	CWnd::OnNcLButtonUp( nHitTest, point );
}

void CEGMDIClient::OnLButtonUp( UINT nFlags, CPoint point ) 
{
	if ( m_bClosePressed || m_bTabDrag ) {
		ClientToScreen( &point );
		OnNcLButtonUp( OnNcHitTest( point ), point );
	} else {
		CWnd::OnLButtonUp( nFlags, point );
	}
}

#if _MFC_VER < 0x0800  
  afx_msg UINT CEGMDIClient::OnNcHitTest(CPoint point)
  {
#else
  afx_msg LRESULT CEGMDIClient::OnNcHitTest(CPoint point)
  {
#endif
	UINT nRes = CWnd::OnNcHitTest( point );

	CPoint ptScreen( point );

	if ( m_bShowTabs && nRes == HTNOWHERE ) {
		ScreenToClient( &point );
		if ( point.x < (m_nWidth - m_cxEdge - m_cxControls ) && point.y < 0 && -point.y > 3 ) {
			CEGMDITabBtnsIt it = m_lstTabBtns.begin(),
					itLast = m_lstTabBtns.end();
			for( ; it != itLast; ++it ) {
				if ( it->m_nLeft <= point.x && (it->m_nLeft + it->m_nWidth) >= point.x ) {
					nRes = HTOBJECT;
					break;
				}
			}		
		} else if ( point.x > (m_nWidth - m_cxEdge - m_cxControls ) ) {
			
			point.y += TABS_HEIGHT;

			if ( m_rcClose.PtInRect( point ) ) {
				nRes = HTOBJECT + 1;
			} else if ( m_rcNext.PtInRect( point ) ) {
				nRes = HTOBJECT + 2;
			} else if ( m_rcPrior.PtInRect( point ) ) {
				nRes = HTOBJECT + 3;
			}
		}
	}

	if ( HTNOWHERE == nRes )
		OnNcMouseMove( HTNOWHERE, ptScreen );
	
	return nRes;
}

#define TEST_HOVER( name, id ) \
	bWasHover = m_b##name##Hover;	\
	m_b##name##Hover = m_b##name##Enabled && ( HTOBJECT + id == nHitTest );	\
	if ( m_b##name##Hover != bWasHover )	\
			bNeedRePaint = TRUE;	\

void CEGMDIClient::OnNcMouseMove( UINT nHitTest, CPoint point) {

	BOOL bNeedRePaint = FALSE;
	
	if ( m_bTabDrag ) {
		if( nHitTest == HTOBJECT	) {
			// ������ ����������� ��������
			CPoint ptClient( point );
			ScreenToClient( &ptClient );
			CEGMDITabBtnsIt itHot = find_if( m_lstTabBtns.begin(), m_lstTabBtns.end(), HotWndBtn( ptClient.x ) );
			if ( itHot != m_lstTabBtns.end() && itHot->m_hWnd != m_hWndActive ) {
				CEGMDITabBtnsIt itActive = find_if( m_lstTabBtns.begin(), m_lstTabBtns.end(), MatchWndBtn( m_hWndActive ) );
				if ( itActive->m_nLeft > itHot->m_nLeft ) {
					itActive->m_nLeft = itHot->m_nLeft;
					itHot->m_nLeft = itActive->m_nLeft + itActive->m_nWidth;
				} else {
					itHot->m_nLeft = itActive->m_nLeft;
					itActive->m_nLeft = itHot->m_nLeft + itHot->m_nWidth;
				}
				iter_swap( itHot, itActive );
				bNeedRePaint = TRUE;
			}
		}
	} else {
		BOOL bWasHover = FALSE;

		TEST_HOVER( Close, 1 )
		TEST_HOVER( Next, 2 )
		TEST_HOVER( Prior, 3 )
	}

	if( bNeedRePaint ) 
		SendMessage( WM_NCPAINT );

	CWnd::OnNcMouseMove( nHitTest, point );
}

void CEGMDIClient::OnMouseMove( UINT nFlags, CPoint point) {

	if ( m_bClosePressed || m_bTabDrag ) {
		ClientToScreen( &point );
		OnNcMouseMove( OnNcHitTest( point ), point );
	} else {
		CWnd::OnMouseMove( nFlags, point );
	}
}

void CEGMDIClient::OnCancelMode( ) {
	OnNcLButtonUp( HTNOWHERE, CPoint( 0, 0 ) );
}

void CEGMDIClient::ActivateMDI( HWND hWnd ) {
	SendMessage( WM_MDIACTIVATE, (LPARAM)hWnd, 0 );
}

void CEGMDIClient::CloseActiveMDI() {
	if( m_hWndActive )
		SendMessage( WM_MDIDESTROY, (LPARAM)m_hWndActive, 0 );
}

void CEGMDIClient::ScrollNext() {
	m_cxOffset = m_cxBtnsTotal - m_cxBtnsAvailable;
	m_bNextEnabled = FALSE;
	m_bNextHover = FALSE;
	OnRecalcButtons( 0, 0 );
}

void CEGMDIClient::ScrollPrior() {
	m_cxOffset = 0;
	m_bPriorEnabled = FALSE;
	m_bPriorHover = FALSE;
	OnRecalcButtons( 0, 0 );
}

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions