Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

The Ultimate Toolbox - Updates and User Contributions

, 12 Feb 2013
Updates and User Contributions for the Ultimate Toolbox Libraries
OutlookDemoUpdate.zip
Ultimate Grid
Demos
OutlookStyle
OutlookStyle.aps
OutlookStyle.dsp
OutlookStyle.dsw
OutlookStyle.suo
res
bitmap1.bmp
bmattach.bmp
bmp00001.bmp
bmp00002.bmp
bmp00003.bmp
Flags.bmp
OutlookStyle.ico
OutlookStyleDoc.ico
Toolbar.bmp
toolbar1.bmp
toolbar2.bmp
toolbarf.bmp
UltimateGrid72_Src_Update01.zip
CellTypes
Include
Source
UltimateGrid72_Src_Update02.zip
DataSources
ODBC
OleDB
EditControls
UltimateGrid72_Src_Update03.zip
UltimateGrid72_Src_Update04.zip
UltimateGrid73_src.zip
BuildDLL
Build DLL.dsp
Build DLL.dsw
res
BuildLib
ugmfclib.dsp
ugmfclib.dsw
Lib
Skel
UltimateTCP-IP42_Src_Update01.zip
Ultimate TCP-IP
Include
Security
Include
Source
source
UltimateTCP-IP42_Src_Update02.zip
Examples
Client
Mail
icon1.ico
icon2.ico
MailClientS.suo
test.dsp
test.dsw
UltimateTCP-IP42_Src_Update03.zip
ultimatetoolbox93_src_update01.zip
Ultimate Toolbox
include
source
UltimateToolbox93_Src_Update02.zip
lib
Build DLLs
Build Libs
UltimateToolbox93_Src_Update03.zip
UltimateToolbox93_Src_Update04.zip
UltimateToolbox93_Src_Update05.zip
// ========================================================================================
// 					Class Implementation : COXSizeControlBar
// ========================================================================================

// Source file : OXSizeCtrlBar.cpp

// Version: 9.3

// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
// Some portions Copyright (C)1994-5	Micro Focus Inc, 2465 East Bayshore Rd, Palo Alto, CA 94303.
                          
// //////////////////////////////////////////////////////////////////////////

#include "stdafx.h"

// v93 update 03 - 64-bit 
#include "UTB64Bit.h"

#include "OXSizeCtrlBar.h"

#include "OXMainRes.h"  // for some resource strings
#include "OXDragDockContext.h"
#include "OXFrameWndDock.h"
#include "OXMDIFloatWnd.h"
#include "OXSizeDockBar.h"  
#include "OXSzMiniDockFrmWnd.h"
#include "OXSkins.h"

#ifndef __OXMFCIMPL_H__
#if _MFC_VER >= 0x0700
#if _MFC_VER >= 1400
#include <afxtempl.h>
#endif
#include <..\src\mfc\afximpl.h>
#else
#include <..\src\afximpl.h>
#endif
#define __OXMFCIMPL_H__
#endif


#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// COXSizeControlBar

IMPLEMENT_DYNAMIC(COXSizeControlBar, CControlBar)

#define new DEBUG_NEW

/////////////////////////////////////////////////////////////////////////////
// Definition of static members
CObArray* COXSizeControlBar::m_parrAllocBars;

HHOOK COXSizeControlBar::m_hMouseHook = NULL;

HWND COXSizeControlBar::m_hwndPrevMouseMoveWnd = NULL;

// Data members -------------------------------------------------------------
// protected:

// private:
	
// Member functions ---------------------------------------------------------
// public:

COXSizeControlBar::COXSizeControlBar(int nStyle) :
	m_pDockbarSkin(NULL),
	m_bDragging(FALSE),
	m_bOkToDrag(FALSE),
	m_ptOffset(0, 0),
	m_bClientBorder(FALSE),
	m_iLastTabPosition(-1)
{
	m_Style=nStyle;						
    m_PrevSize=CSize(0xffff,0xffff);	// dummy values so WindowPosChanged will 
										// respond correctly
    m_bPrevFloating=3;					// neither TRUE not FALSE;
	
	m_FloatSize=CSize(0,0);				// size when floating
   	m_HorzDockSize=CSize(0,0);			// size when docked horizontal
	m_VertDockSize=CSize(0,0);			// size when docked vertical

   	m_SavedDockSize=CSize(0,0);			// size before maximizing

	m_FloatingPosition=CPoint(0,0);	
	m_dwAllowDockingState = 0;
	if (nStyle & SZBARF_AUTOTIDY)
	{
		if (m_parrAllocBars == NULL)
			m_parrAllocBars = new CObArray;
		
		m_parrAllocBars->Add(this);
	}

	m_rectGripper.SetRectEmpty();			// gripper rect
	m_rectCloseBtn.SetRectEmpty();			// close button rect
	m_rectResizeBtn.SetRectEmpty();		// restore button rect

	m_bDelayRecalcLayout=FALSE;

	m_pressedBtn=NONE;
	m_bMaximized=FALSE;
	m_bActive=FALSE;
}


COXSizeControlBar::~COXSizeControlBar()
{
	// if the bar was created with this flag, then ensure it is deleted with it also.
	if (m_Style & SZBARF_AUTOTIDY)
	{
		int i;
		for (i = PtrToInt(m_parrAllocBars->GetUpperBound()); i >= 0; i--)
			if ((*m_parrAllocBars)[i] == this)	
		{
			m_parrAllocBars->RemoveAt(i);
			break;
		}
		ASSERT(i >= 0);			// means we didn't delete this item from the list
	}
	
	// This loop of debug code checks that we don't have any other references in the array.
	// This happens if we changed the auto delete flag during the lifetime of the control bar.
#ifdef _DEBUG
	if (m_parrAllocBars != NULL)
	{
		for (int i = PtrToInt(m_parrAllocBars->GetUpperBound()); i >= 0; i--)
			ASSERT ((*m_parrAllocBars)[i] != this);	
	}
#endif

	if(m_pDockContext!=NULL)
	{
		// delete the dock context here - in an attempt to call the correct destructor
		delete (COXDragDockContext*)m_pDockContext;
		m_pDockContext = NULL;
	}

	// delete the classic skin
	if ( m_pDockbarSkin != NULL )
		delete m_pDockbarSkin;
}

void COXSizeControlBar::TidyUp(CFrameWnd* pTopLevelFrame)
{
	if(m_parrAllocBars!=NULL)
	{
		for (int i = PtrToInt(m_parrAllocBars->GetUpperBound()); i >= 0; i--)
		{
			ASSERT((*m_parrAllocBars)[i]->
				IsKindOf(RUNTIME_CLASS(COXSizeControlBar)));
			if(::IsWindow(((COXSizeControlBar*)(*m_parrAllocBars)[i])->GetSafeHwnd()) && 
				((COXSizeControlBar*)(*m_parrAllocBars)[i])->GetTopLevelFrame()==
				pTopLevelFrame)
			{

				((COXSizeControlBar*)(*m_parrAllocBars)[i])->DestroyWindow();
			}
			if(!::IsWindow(((COXSizeControlBar*)(*m_parrAllocBars)[i])->GetSafeHwnd()))
			{
				delete ((*m_parrAllocBars)[i]);
			}
		}
		if(m_parrAllocBars->GetSize()==0)
		{
			delete m_parrAllocBars;
			m_parrAllocBars=NULL;
		}
	}
}


BEGIN_MESSAGE_MAP(COXSizeControlBar, CControlBar)
//{{AFX_MSG_MAP(COXSizeControlBar)
	ON_WM_WINDOWPOSCHANGED()
	ON_WM_ERASEBKGND()
	ON_WM_CONTEXTMENU()
	ON_WM_SETCURSOR()
	ON_WM_NCCALCSIZE()
	ON_WM_NCPAINT()
	ON_WM_PAINT()
	ON_WM_NCHITTEST()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_SYSCOMMAND()
	//}}AFX_MSG_MAP
	ON_COMMAND(ID_OX_MRC_HIDE, OnHide)
	ON_COMMAND(ID_OX_MRC_ALLOWDOCKING, OnToggleAllowDocking)
	ON_COMMAND(ID_OX_MRC_MDIFLOAT,	OnFloatAsMDI)
	ON_MESSAGE(WM_ADDCONTEXTMENUITEMS, OnAddContextMenuItems)
	ON_MESSAGE(WM_OX_APP_AFTERFLOAT_MSG, OnAfterFloatMessage)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// COXSizeControlBar message handlers

CSize COXSizeControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
#ifdef _VERBOSE_TRACE
	CString strTitle;
	GetWindowText(strTitle);
	TRACE(_T("CalcFixedLayout: '%s' Horz(%d,%d)\n"), LPCTSTR(strTitle), 
		m_HorzDockSize.cx, m_HorzDockSize.cy);
#endif	
	CControlBar::CalcFixedLayout(bStretch, bHorz);
    if (IsFloating())
		return m_FloatSize;

    if (bHorz)
		return m_HorzDockSize;
	else
		return m_VertDockSize;
}

// need to supply this, or else we can't instantiate the class. Derived classes should
// subclass this if they need to update their gadgets using this interface
void COXSizeControlBar::OnUpdateCmdUI(CFrameWnd* pTarget, 
									  BOOL bDisableIfNoHndler)
{
	UNREFERENCED_PARAMETER(pTarget);
	UNREFERENCED_PARAMETER(bDisableIfNoHndler);
    CWnd* pFocusWnd=CWnd::GetFocus();
	BOOL bActive=FALSE;
    if(pFocusWnd!=NULL && (pFocusWnd==this || 
		AfxIsDescendant(GetSafeHwnd(),pFocusWnd->GetSafeHwnd())))
	{
		bActive=TRUE;
	}
	if(bActive!=IsActive())
	{
		SetActive(bActive);
	}
}


// CWnd-style create - need ability to specific window class in order to prevent 
// flicker during resizing. 
BOOL COXSizeControlBar::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
							   DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, 
							   UINT nID, CCreateContext* pContext)
{
    ASSERT(pParentWnd != NULL);
	
    // have to set the style here
#if _MFC_VER <= 0x0421
    m_dwStyle = dwStyle;
#else
    m_dwStyle = dwStyle&CBRS_ALL;
#endif
	
    CRect Rectx;
    Rectx = rect;
	
    // calculate a sensible default rectangle if that's what the user wanted...
    if (memcmp(&rect, &CFrameWnd::rectDefault, sizeof(RECT)) == 0)
	{
        pParentWnd->GetClientRect(&Rectx);
        CSize def;
        def.cx = Rectx.right / 2;
        def.cy = Rectx.bottom  / 4;
        Rectx.left = Rectx.right - def.cx;
        Rectx.top  = Rectx.bottom - def.cy;
	}
	
   	// the rectangle specifies the default floating size.
   	m_FloatSize = Rectx.Size();
	
	// set default values for the docked sizes, based on this size.
	m_HorzDockSize.cx = m_FloatSize.cx;
	m_HorzDockSize.cy = m_FloatSize.cy;	
	
	m_VertDockSize.cx = m_HorzDockSize.cy;
	m_VertDockSize.cy = m_HorzDockSize.cx;

	// prevents flashing
	dwStyle|=WS_CLIPCHILDREN; 
	
    return CControlBar::Create(lpszClassName, lpszWindowName, dwStyle, 
		Rectx, pParentWnd, nID, pContext);
}

BOOL COXSizeControlBar::Create(CWnd* pParentWnd, LPCTSTR lpszWindowName, UINT nID,
								DWORD dwStyle, const RECT& rect)
{
	return Create(NULL, lpszWindowName, dwStyle, rect, pParentWnd, nID);
}

void COXSizeControlBar::SetSizeDockStyle(DWORD dwStyle)
{
	m_Style=dwStyle;
	if(::IsWindow(GetSafeHwnd()))
	{
		SetWindowPos(NULL,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_DRAWFRAME);
	}
}


// Largely a copy of CControlBar::EnableDocking() - but uses a different class for the
// m_pDockContext, to give us different (hopefully you'll think better) dragging 
// behaviour.
void COXSizeControlBar::EnableDocking(DWORD dwDockStyle)
{
	// must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only
    ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY | CBRS_FLOAT_MULTI)) == 0);
	
    m_dwDockStyle = dwDockStyle;
    if (m_pDockContext == NULL)
		m_pDockContext = new COXDragDockContext(this);
	
    // permanently wire the bar's owner to its current parent
	if (m_hWndOwner == NULL)
		m_hWndOwner = ::GetParent(m_hWnd);
}

// message handler. Force the parent of the control bar to update it's style
// after floating, otherwise we'll wait till an WM_NCHITTEST.
// v9.3 - update 03 - 64-bit - changed these to LRESULT, WPARAM, LPARAM from LONG, UINT, LONG
LRESULT COXSizeControlBar::OnAfterFloatMessage(WPARAM /* wParam */, LPARAM /* lParam */)
{
	CWnd* pFrame = GetParentFrame();
	if(pFrame != NULL && pFrame->IsKindOf(RUNTIME_CLASS(COXSizableMiniDockFrameWnd)))
	{
		((COXSizableMiniDockFrameWnd*)pFrame)->GetContainedBarType();
	}
	
	return TRUE;			// message handled.
}

// paint the background of the window - probably want a style flag to turn this
// off as for many control bars it won't be required.
BOOL COXSizeControlBar::OnEraseBkgnd(CDC* pDC)
{
	CRect rect;
	pDC->GetClipBox(&rect);
	pDC->FillSolidRect(&rect,::GetSysColor(COLOR_BTNFACE)); 
    return TRUE;
}


// change the cursor 
BOOL COXSizeControlBar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
	UNREFERENCED_PARAMETER(nHitTest);
	UNREFERENCED_PARAMETER(message);

	if(pWnd==this)
	{
		HCURSOR hCursor;     // Load the predefined Windows standard cursor.
		hCursor=AfxGetApp()->LoadStandardCursor(IDC_ARROW);
		ASSERT(hCursor);
		::SetCursor(hCursor);
		return TRUE;
	}

	return FALSE;
}

// Normally a CControlBar would just pass most of these messages through to
// the parent. We want to handle them properly though - again may be this should
// be a behaviour flag
LRESULT COXSizeControlBar::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
	AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif

    ASSERT_VALID(this);
	
    // We need to ensure WM_COMMAND and other messages get through to the derived class.
    // Primarily done so we receive notifications from child windows. The default CControlBar
    // code routes messsages through to the parent. This means WM_COMMANDs, etc make their
    // way to a FrameWnd eventually. This is needed for toolbar's, dialog bars, etc, but isn't
    // very useful if we want to put controls on a COXSizeControlBar and process them 
	// locally
	
    // In case any of these messages are actually needed by the owner window, we check to see
    // if CWnd would handle them first. If not, then we pass them through to the owner window,
    // as CControlBar would.
	
    switch (nMsg)
	{
	case WM_COMMAND:
		{
			if (OnCommand(wParam, lParam))          // post normal commands....
			{
				return 1L; // command handled
			}
			break;
		}

	case WM_DESTROY:
		{
			CFrameWnd* pParentFrameWnd=GetParentFrame();
			ASSERT(pParentFrameWnd!=NULL);
			if(IsFloating())
			{
				pParentFrameWnd=pParentFrameWnd->GetTopLevelFrame();
				ASSERT(pParentFrameWnd!=NULL);
			}

			// notify main frame window that the current active control bar
			// window has changed
			COXMDIFrameWndSizeDock* pMDIFrameWnd=
				DYNAMIC_DOWNCAST(COXMDIFrameWndSizeDock,pParentFrameWnd);
			if(pMDIFrameWnd!=NULL && pMDIFrameWnd->m_pLastActiveCtrlBar==this)
			{
				pMDIFrameWnd->m_pLastActiveCtrlBar=NULL;
			}
			break;
		}
	}

	return CControlBar::WindowProc(nMsg, wParam, lParam);
}


// This handler is used to notify sizeable bars if their size has
// changed, or if they are docked/undocked.
void COXSizeControlBar::OnWindowPosChanged(WINDOWPOS* lpwndpos)
{
    CControlBar::OnWindowPosChanged(lpwndpos);
    CSize NewSize(lpwndpos->cx, lpwndpos->cy);

	// This is meant to return "floating" if we're not docked yet...
    BOOL bFloating = IsProbablyFloating();
	
    int Flags = (NewSize == m_PrevSize ? 0 : 1);
    Flags |= (bFloating == m_bPrevFloating ? 0 : 2);
    if (Flags != 0)
	{
		m_PrevSize = NewSize;
        m_bPrevFloating = bFloating;
        OnSizedOrDocked(NewSize.cx, NewSize.cy, bFloating, Flags);
		RedrawWindow();
	}

	RecalcLayout();

	if(m_bMaximized)
	{
		SetMaximized(FALSE);
	}
}


// override this function to respond to a redraw as a result of a
// resize or docked/undocked notification
void COXSizeControlBar::OnSizedOrDocked(int /* cx */, int /* cy */, 
										BOOL /* bFloating */, int /* flags */)
{
}


BOOL COXSizeControlBar::IsProbablyFloating()
{ 
	// used to check the dock bar status, but this has problems when we 
	// docking/undocking - so check the actual bar style instead
	return (m_pDockBar == NULL || (GetBarStyle() & CBRS_FLOATING));
}


// v9.3 - update 03 - 64-bit - changed return value to LRESULT from LONG
LRESULT COXSizeControlBar::OnAddContextMenuItems(WPARAM /* wParam */, LPARAM lParam)
{
	HMENU hMenu = (HMENU)lParam;		// handle of menu.
	CMenu Menu;
	Menu.Attach(hMenu);
	
	DWORD dwDockStyle = m_dwDockStyle & CBRS_ALIGN_ANY;
	DWORD style;
	CString strMenu;
	
	BOOL bMDIFloating = FALSE;
	CFrameWnd* pParentFrame = GetParentFrame();
	if (IsFloating())
	{
		if (pParentFrame != NULL && 
			pParentFrame->IsKindOf(RUNTIME_CLASS(COXMDIFloatWnd)))
		{
			bMDIFloating = TRUE;
		}
	}
	style = (bMDIFloating ? MF_STRING | MF_CHECKED : MF_STRING);
	
	// if allowed - add the float as MDI floating window
	if ((m_Style&SZBARF_ALLOW_MDI_FLOAT)!=0 && m_pDockContext!=NULL)
	{	
		VERIFY(strMenu.LoadString(ID_OX_MRC_MDIFLOAT));
		Menu.AppendMenu(style, ID_OX_MRC_MDIFLOAT, strMenu);
	}
	
	if (!bMDIFloating && (dwDockStyle != 0 || m_dwAllowDockingState != 0))	// ie docking is actually allowed ...
	{
		DWORD style = (dwDockStyle != 0 ? MF_STRING | MF_CHECKED : MF_STRING);
		VERIFY(strMenu.LoadString(ID_OX_MRC_ALLOWDOCKING));
		Menu.AppendMenu(style, ID_OX_MRC_ALLOWDOCKING, strMenu);
	}
	VERIFY(strMenu.LoadString(ID_OX_MRC_HIDE));
	Menu.AppendMenu(MF_STRING, ID_OX_MRC_HIDE, strMenu);
	
	Menu.Detach();	// detatch MFC object
	return TRUE;
}


void COXSizeControlBar::OnHide()
{
	CFrameWnd* pParentFrameWnd = GetParentFrame();
	BOOL bMDIFloating = (IsFloating() && pParentFrameWnd != NULL && 
		pParentFrameWnd->IsKindOf(RUNTIME_CLASS(COXMDIFloatWnd)));
	if (bMDIFloating)
		// Have to activate another MDIChildFrame Wnd
	{
		((COXMDIFloatWnd*)pParentFrameWnd)->ShowControlBar(this, FALSE, FALSE);
		CFrameWnd* pTopParentFrameWnd = pParentFrameWnd->GetTopLevelFrame();
		if (pTopParentFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)))
		{
			((CMDIFrameWnd*)pTopParentFrameWnd)->MDINext();
		}
	}
	else
		pParentFrameWnd->ShowControlBar(this, FALSE, FALSE);
}


void COXSizeControlBar::OnToggleAllowDocking()
{
	if ((m_dwDockStyle & CBRS_ALIGN_ANY) != 0)
	{											   // docking currently allowed - disable it
		m_dwAllowDockingState = m_dwDockStyle & CBRS_ALIGN_ANY;	// save previous state
		if (!IsFloating())
		{					// if docked, then force it to be floating...
			ASSERT(m_pDockContext != NULL);
			m_pDockContext->ToggleDocking();
		}
		EnableDocking(0);				// disable docking
	}
	else
	{
		EnableDocking (m_dwAllowDockingState);	// re-enable docking...
	}
}

void COXSizeControlBar::OnFloatAsMDI()
{
	ASSERT(m_Style & SZBARF_ALLOW_MDI_FLOAT);		// must have specified this
	
	COXMDIFrameWndSizeDock* pFrame = (COXMDIFrameWndSizeDock*)AfxGetMainWnd();
	ASSERT(pFrame != NULL);
	ASSERT(pFrame->IsKindOf(RUNTIME_CLASS(COXMDIFrameWndSizeDock)));
	ASSERT(m_pDockContext!=NULL);
	
	CFrameWnd* pParentFrame = GetParentFrame();
	BOOL bMDIFloating = (IsFloating() && pParentFrame != NULL && 
		pParentFrame->IsKindOf(RUNTIME_CLASS(COXMDIFloatWnd)));
	
	if (bMDIFloating)
	{
		pFrame->UnFloatInMDIChild(this, m_pDockContext->m_ptMRUFloatPos);
	}
	else
	{
		pFrame->FloatControlBarInMDIChild(this, m_pDockContext->m_ptMRUFloatPos);
	}		
}


// Now run off WM_CONTEXTMENU: if user wants standard handling, then let him have it
void COXSizeControlBar::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	if (m_Style & SZBARF_STDMOUSECLICKS)
	{
		CMenu menu;
		if (menu.CreatePopupMenu())
		{
			OnAddContextMenuItems(0,(LPARAM)menu.m_hMenu);
			menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
		}
	} 
	else
	{
		CControlBar::OnContextMenu(pWnd, point);
	}
}

void COXSizeControlBar::OnNcCalcSize(BOOL bCalcValidRects, 
									 NCCALCSIZE_PARAMS* lpncsp)
{
	CControlBar::OnNcCalcSize(bCalcValidRects, lpncsp);
	GetDockbarSkin()->OnNcCalcSize(bCalcValidRects, lpncsp, this);
}


void COXSizeControlBar::OnNcPaint() 
{
	EraseNonClient();
}

void COXSizeControlBar::OnPaint() 
{
    // overridden to skip border painting based on clientrect
    CPaintDC dc(this);
}

void COXSizeControlBar::EraseNonClient()
{
    // get window DC that is clipped to the non-client area
    CWindowDC dc(this);
    CRect rectClient;
    GetClientRect(rectClient);
    CRect rectWindow;
    GetWindowRect(rectWindow);
    ScreenToClient(rectWindow);
	CSize sizeOffset(-rectWindow.left, -rectWindow.top);
	rectClient+=sizeOffset;

    rectWindow+=sizeOffset;

    // erase parts not drawn
	dc.ExcludeClipRect(rectClient);
	dc.IntersectClipRect(rectWindow);
	CRect rect;
	dc.GetClipBox(&rect);

	GetDockbarSkin()->DrawNonClientArea(&dc, rectWindow, this);

	RecalcLayout();

	if(IsGripper())
	{
		DrawGripper(&dc);
	}
	if(IsCloseBtn())
	{
		DrawCloseBtn(&dc);
	}
	if(IsResizeBtn())
	{
		DrawResizeBtn(&dc);
	}

	// Draw the border
	if (m_bClientBorder)
	{
		CBrush brBorder;
		brBorder.CreateSolidBrush(GetDockbarSkin()->GetClientBorderColor());
		rectClient.InflateRect(1, 1);
		dc.FrameRect(rectClient, &brBorder);
	}
}

void COXSizeControlBar::DrawGripper(CDC* pDC)
{
	GetDockbarSkin()->DrawGripper(pDC, this);
}

void COXSizeControlBar::DrawCloseBtn(CDC* pDC)
{
	GetDockbarSkin()->DrawCloseButton(pDC, this);
}

void COXSizeControlBar::DrawResizeBtn(CDC* pDC)
{
	GetDockbarSkin()->DrawResizeButton(pDC, this);
}

void COXSizeControlBar::RecalcLayout()
{
	GetDockbarSkin()->RecalcLayout(this);
}

#if _MSC_VER >= 1400
LRESULT COXSizeControlBar::OnNcHitTest(CPoint point)
#else
UINT COXSizeControlBar::OnNcHitTest(CPoint point)
#endif
{
    if((m_dwStyle & CBRS_FLOATING))
	{
        return CControlBar::OnNcHitTest(point);
	}

    CRect rectWindow;
    GetWindowRect(rectWindow);
    if (rectWindow.PtInRect(point))
	{
        return HTCLIENT;
	}
    else
	{
        return CControlBar::OnNcHitTest(point);
	}
}


void COXSizeControlBar::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if(!IsFloating())
	{
		CPoint ptTest=point;
		// handle mouse click over close, restore buttons
		//
		m_pressedBtn=NONE;

		if(m_rectCloseBtn.PtInRect(ptTest))
		{
			SetCapture();
			m_pressedBtn=CLOSEBTN;
			RedrawCloseBtn();
			return;
		}
		else if(m_rectResizeBtn.PtInRect(ptTest))
		{
			if(CanResize())
			{
				SetCapture();
				m_pressedBtn=RESIZEBTN;
				RedrawResizeBtn();
			}
			return;
		}
		else if (AfxGetMainWnd()->SendMessage(WM_QUERYSNAPPING))
		{
			m_ptLButtonDown = point;
			m_bOkToDrag = TRUE;
			return;
		}
	}

	CControlBar::OnLButtonDown(nFlags, point);
}


void COXSizeControlBar::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default

	if (m_bDragging)
	{
		ReleaseCapture();
		m_bDragging = FALSE;
		return;
	}

	SIZEBARBTN pressedBtn=m_pressedBtn;
	m_pressedBtn=NONE;
	if(pressedBtn==CLOSEBTN)
		RedrawCloseBtn();
	else if(pressedBtn==RESIZEBTN)
		RedrawResizeBtn();

	if(::GetCapture()!=GetSafeHwnd())
	{
		CControlBar::OnLButtonUp(nFlags,point);
		return;
	}

	::ReleaseCapture();

	CPoint ptTest=point;
	
	if(pressedBtn==CLOSEBTN && m_rectCloseBtn.PtInRect(ptTest))
	{
		// close the bar
		ShowBar(FALSE);
	}
	else if(m_pDockBar!=NULL && pressedBtn==RESIZEBTN && 
		m_rectResizeBtn.PtInRect(ptTest))
	{
		// restore the bar
		ASSERT(m_pDockBar->IsKindOf(RUNTIME_CLASS(COXSizeDockBar)));
		((COXSizeDockBar*)m_pDockBar)->ResizeBar(this,!m_bMaximized);
	}
}

void COXSizeControlBar::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	if(::GetCapture()==GetSafeHwnd())
	{
		SIZEBARBTN pressedBtn=NONE;
		if(m_rectCloseBtn.PtInRect(point))
		{
			pressedBtn=CLOSEBTN;
		}
		else if(m_rectResizeBtn.PtInRect(point) && CanResize())
		{
			pressedBtn=RESIZEBTN;
		}

		if(m_pressedBtn!=pressedBtn)
			m_pressedBtn=pressedBtn;
	}

	RedrawButtons();

	// In order to start dragging the left button must be down and the current point
	// must be at least 3 pixels away from the point where the button was pressed
	if (!m_bDragging && m_bOkToDrag && (nFlags & MK_LBUTTON) && 
		(abs(point.x - m_ptLButtonDown.x) > 3 || abs(point.y - m_ptLButtonDown.y) > 3))
	{
		m_bOkToDrag = FALSE; // reset the flag

		// Start dragging
		SaveMouseOffset(point);
		m_bDragging = TRUE;
		SetCapture();
		::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
		return;
	}

	// If we are already dragging
	if (m_bDragging)
	{
		CPoint ptScreen = point;
		ClientToScreen(&point);

		// Get the appropriate dock bar. If one is not found then float.
		CFrameWnd* pFrameWnd = DYNAMIC_DOWNCAST(CFrameWnd, ::AfxGetMainWnd());
		if (pFrameWnd == NULL)
		{
			ReleaseCapture();
			m_bDragging = FALSE;
			return;
		}

		// Handle pending WM_PAINT messages
		MSG msg;
		while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
		{
			if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
			{
				ReleaseCapture();
				m_bDragging = FALSE;
				return;
			}
			DispatchMessage(&msg);
		}

		if (m_pDockContext == NULL)
			pFrameWnd->FloatControlBar(this, point);
		else
		{
			COXSizeDockBar* pDockBar = COXSizeDockBar::GetAppropriateDockBar(point, this);
			if (pDockBar == NULL || nFlags & MK_CONTROL)
			{
				if (m_pDockBar != NULL)
				{
					COXSizeDockBar* pSizeDockBar = DYNAMIC_DOWNCAST(COXSizeDockBar, m_pDockBar);
					if (pSizeDockBar != NULL)
						pSizeDockBar->m_wndDockTabCtrl.RemoveTab(this);
				}
				pFrameWnd->FloatControlBar(this, point - m_ptOffset);
			}
			else
			{
				// Determine the docking rectangle
				CRect rectWindow;
				GetWindowRect(rectWindow);
				CRect rectDock;
				rectDock.SetRect(point.x, point.y, point.x + rectWindow.Width(), point.y + rectWindow.Height());

				pDockBar->DockControlBar(this, rectDock);
			}
		}
	}
	else
		CControlBar::OnMouseMove(nFlags, point);
}


void COXSizeControlBar::RedrawCloseBtn()
{
	CRect rect=m_rectCloseBtn;
	RedrawWindow(rect,NULL,RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE);
}


void COXSizeControlBar::RedrawResizeBtn()
{
	CRect rect=m_rectResizeBtn;
	RedrawWindow(rect,NULL,RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE);
}


BOOL COXSizeControlBar::CanResize() const
{
	BOOL bCanResize=FALSE;
	if(m_pDockBar!=NULL && m_pDockBar->IsKindOf(RUNTIME_CLASS(COXSizeDockBar)))
	{

		if (((COXSizeDockBar*)m_pDockBar)->m_wndDockTabCtrl.GetItemCount() > 0)
			return FALSE;

		CRect rect;
		GetWindowRect(rect);
		if(((COXSizeDockBar*)m_pDockBar)->
			BarsOnThisRow((CControlBar*)this,rect)>0)
		{
			bCanResize=TRUE;
		}
	}

	return bCanResize;
}


void COXSizeControlBar::SetActive(BOOL bActive, BOOL bResetAllCtrlBars/*=FALSE*/)
{
	ASSERT(::IsWindow(GetSafeHwnd()));

	m_bActive=bActive;

	CFrameWnd* pParentFrameWnd=GetParentFrame();
	ASSERT(pParentFrameWnd!=NULL);
	if(IsFloating())
	{
		pParentFrameWnd=pParentFrameWnd->GetTopLevelFrame();
		ASSERT(pParentFrameWnd!=NULL);
	}

	if(m_bActive)
	{
		CWnd* pFocusWnd=CWnd::GetFocus();
		if(pFocusWnd!=this && !IsChild(pFocusWnd))
		{
			// try to set focus to first child window
			CWnd* pChildWnd=this;
			while(pChildWnd!=NULL)
			{
				pChildWnd->SetFocus();
				pFocusWnd=GetFocus();
				if(pFocusWnd!=NULL && (pFocusWnd==pChildWnd || IsChild(pFocusWnd)))
				{
					break;
				}
				else
				{
					pChildWnd=pChildWnd->GetWindow(GW_CHILD);
				}
			}
		}

		if(bResetAllCtrlBars)
		{
			POSITION pos=pParentFrameWnd->m_listControlBars.GetHeadPosition();
			while(pos!=NULL)
			{
				COXSizeControlBar* pBar=DYNAMIC_DOWNCAST(COXSizeControlBar,
					(CControlBar*)pParentFrameWnd->m_listControlBars.GetNext(pos));
				if(pBar!=NULL && pBar!=this && pBar->IsActive() && 
					!pBar->IsKindOf(RUNTIME_CLASS(COXSizeViewBar)))
				{
					pBar->SetActive(FALSE);
				}
			}
		}
	}	

	// notify main frame window that the current active control bar
	// window has changed
	COXMDIFrameWndSizeDock* pMDIFrameWnd=
		DYNAMIC_DOWNCAST(COXMDIFrameWndSizeDock,pParentFrameWnd);
	if(pMDIFrameWnd!=NULL)
	{
		if(m_bActive)
		{
			pMDIFrameWnd->m_pLastActiveCtrlBar=this;
		}
		else
		{
			if(pMDIFrameWnd->m_pLastActiveCtrlBar==this)
			{
				CMDIChildWnd* pMDIChildWnd=pMDIFrameWnd->MDIGetActive();
				if(pMDIChildWnd!=NULL)
				{
					CWnd* pFocusWnd=GetFocus();
					if(pFocusWnd!=NULL && 
						(pMDIChildWnd->IsChild(pFocusWnd) || pMDIChildWnd==pFocusWnd))
					{
						//pMDIFrameWnd->m_pLastActiveCtrlBar=NULL;
					}
				}
			}
		}
	}	

	RedrawWindow(m_rectGripper,NULL,RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE);
}

COXDockbarSkin* COXSizeControlBar::GetDockbarSkin()
{
	// Check if the app is derived from COXSkinnedApp
	COXSkinnedApp* pSkinnedApp = DYNAMIC_DOWNCAST(COXSkinnedApp, AfxGetApp());
	if (pSkinnedApp != NULL && pSkinnedApp->GetCurrentSkin() != NULL)
		return pSkinnedApp->GetCurrentSkin()->GetDockbarSkin();
	else
	{
		// Create a classic skin for this class if not created already
		if (m_pDockbarSkin == NULL)
			m_pDockbarSkin = new COXDockbarSkinClassic();

		return m_pDockbarSkin;
	}
}

// Update the buttons of dockbar when the mouse leaves
LRESULT CALLBACK COXSizeControlBar::MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if (nCode < 0)
		return ::CallNextHookEx(m_hMouseHook, nCode, wParam, lParam);

	if (nCode == HC_ACTION && (wParam == WM_MOUSEMOVE || wParam == WM_NCMOUSEMOVE))
	{

		MOUSEHOOKSTRUCT* pMH = (MOUSEHOOKSTRUCT*) lParam;

		// If the previous message was for COXSizableMiniDockFrameWnd and the current is not
		// we need to update the caption buttons
		COXSizeControlBar* pPrev = DYNAMIC_DOWNCAST(COXSizeControlBar,
			CWnd::FromHandlePermanent(m_hwndPrevMouseMoveWnd));
		COXSizeControlBar* pCurrent = DYNAMIC_DOWNCAST(COXSizeControlBar,
			CWnd::FromHandlePermanent(pMH->hwnd));

		if (pPrev != NULL && pCurrent != pPrev)
		{
			// The mouse just left the window
			pPrev->RedrawButtons();
		}
		m_hwndPrevMouseMoveWnd = pMH->hwnd;
	}

	return CallNextHookEx(m_hMouseHook, nCode, wParam, lParam);
}

int COXSizeControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CControlBar::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// Hook the mouse
	if (m_hMouseHook == NULL)
		m_hMouseHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, 0, AfxGetApp()->m_nThreadID);
	
	return 0;
}

void COXSizeControlBar::OnDestroy() 
{
	// Unhook the mouse
	if (m_hMouseHook)
	{
		::UnhookWindowsHookEx(m_hMouseHook);
		m_hMouseHook = NULL;
	}

	CControlBar::OnDestroy();
}

void COXSizeControlBar::RedrawButtons()
{
	CWindowDC dc(this);
	DrawCloseBtn(&dc);//GetDockbarSkin()->DrawCloseButton(&dc, this);
	DrawResizeBtn(&dc);//GetDockbarSkin()->DrawResizeButton(&dc, this);
}

void COXSizeControlBar::SaveMouseOffset(CPoint point)
{
	// Calculate and save the offset
	CRect rectWindow;
	GetWindowRect(rectWindow);
	ScreenToClient(&rectWindow);

	// Since the offset will be used only for floating windows we need
	// to scale it accordingly
	if (m_dwStyle & CBRS_ORIENT_HORZ && !IsFloating())
	{
		m_ptOffset.x = rectWindow.bottom - point.y;
		m_ptOffset.y = point.x - rectWindow.left;

		m_ptOffset.x = (long) (m_ptOffset.x * 
			((double) m_FloatSize.cx / (double) rectWindow.Height()));
	}
	else
	{
		m_ptOffset = point - rectWindow.TopLeft();
		m_ptOffset.x = (long) (m_ptOffset.x * 
			((double) m_FloatSize.cx / (double) rectWindow.Width()));
	}

	if (m_ptOffset.x < 5)
		m_ptOffset.x = 5;
	if (m_ptOffset.x > m_FloatSize.cx - 20)
		m_ptOffset.x = m_FloatSize.cx - 20;

	if (!IsFloating())
		m_ptOffset.y = 10; // always use 10
}

void COXSizeControlBar::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// only toggle docking if clicked in "void" space
	if (m_pDockBar != NULL && OnToolHitTest(point, NULL) == -1)
	{
		COXSizeDockBar* pSzDockBar = DYNAMIC_DOWNCAST(COXSizeDockBar, m_pDockBar);
		if (pSzDockBar != NULL && AfxGetMainWnd()->SendMessage(WM_QUERYSNAPPING))
		{
			// If this was tabbed we need to untab it and select something else
			int iOldIndex = pSzDockBar->m_wndDockTabCtrl.FindTab(this);
			if (iOldIndex != -1)
				pSzDockBar->m_wndDockTabCtrl.RemoveTab(this);			
		}

		// start the drag
		ASSERT(m_pDockContext != NULL);
		m_pDockContext->ToggleDocking();	
	}
	else
	{
		CWnd::OnLButtonDblClk(nFlags, point);
	}
}

void COXSizeControlBar::ShowBar(BOOL bShow)
{
	if (IsWindowVisible() == bShow)
		return; // already shown or already hidden
	

	CFrameWnd* pParentFrame = GetParentFrame();
	ASSERT(pParentFrame != NULL); // this bar must have a parent frame

	// If foating or there are no tabbed controls simply call CFrameWnd::ShowControlBar()
	COXSizeDockBar* pDockBar = (COXSizeDockBar*) m_pDockBar;
	
	if (bShow)
	{
		// If the control bar is tabbed we need to just select it
		COXDockTabCtrl* pDockTabCtrl = GetDockTabCtrl();
		if (pDockTabCtrl != NULL)
		{
			pDockTabCtrl->SetCurSel(pDockTabCtrl->FindTab(this));
			pDockTabCtrl->ShowSelectedTab();
			return;
		}

		pParentFrame->ShowControlBar(this, bShow, TRUE);
		
		// Figure out if we need to tab the control bar
		if (!IsFloating() && pDockBar != NULL &&
			m_iLastTabPosition != -1 &&
			pDockBar->GetVisibleSizeControlBarCount(this) > 1)
		{
			int iTabIndex = pDockBar->m_wndDockTabCtrl.FindTab(this);
			if (iTabIndex == -1)
			{
				// Tab is not there, so insert it
				pDockBar->m_wndDockTabCtrl.InsertTab(this, m_iLastTabPosition, TRUE);
			}
			else
			{
				// Just select it
				pDockBar->m_wndDockTabCtrl.SetCurSel(iTabIndex);
				pDockBar->m_wndDockTabCtrl.ShowSelectedTab();
			}
		}
	}
	else // hide
	{
		pParentFrame->ShowControlBar(this, bShow, TRUE);

		if (!IsFloating() && pDockBar != NULL &&
			pDockBar->m_wndDockTabCtrl.GetItemCount() != 0)
		{
			// Save the last tab position
			m_iLastTabPosition = pDockBar->m_wndDockTabCtrl.FindTab(this);
			
			// Remove the tab
			pDockBar->m_wndDockTabCtrl.RemoveTab(this);
		}
	}
}

COXDockTabCtrl* COXSizeControlBar::GetDockTabCtrl()
{
	COXSizeDockBar* pDockBar = DYNAMIC_DOWNCAST(COXSizeDockBar, m_pDockBar);
	if (pDockBar == NULL)
		return NULL;

	if (pDockBar->m_wndDockTabCtrl.FindTab(this) == -1)
		return NULL;
	else
		return &pDockBar->m_wndDockTabCtrl;
}

BOOL COXSizeControlBar::IsShown()
{
	if (IsVisible())
		return TRUE;
	else
		return FALSE;
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

The Ultimate Toolbox
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.
 
Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
Group type: Organisation

381 members


| Advertise | Privacy | Mobile
Web04 | 2.8.140827.1 | Last Updated 13 Feb 2013
Article Copyright 2008 by The Ultimate Toolbox
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid