2025-11-27 16:46:48 +09:00

1217 lines
31 KiB
C++

// ========================================================================================
// 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"
#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.
LONG COXSizeControlBar::OnAfterFloatMessage(UINT /* wParam */, LONG /* 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));
}
LONG 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;
}