You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

557 lines
12 KiB
C++

// XTPMiniToolBar.cpp : implementation of the CXTPMiniToolBar class.
//
// This file is a part of the XTREME COMMANDBARS MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPHookManager.h"
#include "Common/XTPColorManager.h"
#include "XTPCommandBarsDefines.h"
#include "XTPCommandBar.h"
#include "XTPPopupBar.h"
#include "XTPPaintManager.h"
#include "XTPMouseManager.h"
#include "XTPMiniToolBar.h"
#include "XTPControls.h"
#include "XTPControl.h"
#include "XTPControlButton.h"
#include "XTPControlCustom.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifndef LWA_ALPHA
#define LWA_ALPHA 0x00000002
#endif
#ifndef WS_EX_LAYERED
#define WS_EX_LAYERED 0x00080000
#endif
/////////////////////////////////////////////////////////////////////////////
// CXTPMiniToolBar
IMPLEMENT_XTP_COMMANDBAR(CXTPMiniToolBar, CXTPPopupToolBar);
CXTPMiniToolBar::CXTPMiniToolBar()
{
m_pfnSetLayeredWindowAttributes = NULL;
m_pfnUpdateLayeredWindow = NULL;
HMODULE hLib = GetModuleHandle(_T("USER32"));
if (hLib)
{
m_pfnSetLayeredWindowAttributes = (PFNSETLAYEREDWINDOWATTRIBUTES) ::GetProcAddress(hLib, "SetLayeredWindowAttributes");
m_pfnUpdateLayeredWindow = (LPFNUPDATELAYEREDWINDOW) GetProcAddress(hLib, "UpdateLayeredWindow");
}
m_bActivated = FALSE;
m_bTracking = FALSE;
m_nOpacity = 0;
m_pContextMenu = FALSE;
m_bTrackOnHover = FALSE;
m_bCustomControlKeyboardInteraction = FALSE;
m_rcBorders = CRect(2, 2, 2, 2);
m_szButtonSpacing = CSize(0, 3);
}
CXTPMiniToolBar::~CXTPMiniToolBar()
{
}
void CXTPMiniToolBar::UpdateOpacity()
{
CXTPWindowRect rc(this);
CPoint pt;
GetCursorPos(&pt);
int x = pt.x < rc.left ? rc.left - pt.x : pt.x > rc.right ? pt.x - rc.right : 0;
int y = pt.y < rc.top ? rc.top - pt.y : pt.y > rc.bottom ? pt.y - rc.bottom : 0;
int nLen = max(x, y);
int nOpacity = 0;
if (m_nPopuped != -1 || m_pContextMenu || IsTrackingMode() || nLen == 0)
{
nLen = 0;
nOpacity = 255;
}
else if (!m_bActivated)
{
if (nLen < 17) nOpacity = 17 + (16 - nLen) * 14;
}
else
{
if (nLen < 90) nOpacity = MulDiv(255, 90 - nLen, 90);
}
if ((m_nOpacity != nOpacity))
{
m_nOpacity = nOpacity;
if (m_pfnSetLayeredWindowAttributes)
{
m_pfnSetLayeredWindowAttributes(m_hWnd, 0x00, (BYTE)nOpacity, LWA_ALPHA);
}
else
{
SetWindowPos(0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | (nOpacity > 20 ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
}
CXTPShadowManager* pShadowManager = GetPaintManager()->GetShadowManager();
POSITION pos = pShadowManager->GetHeadPosition(this);
while (pos)
{
CWnd* pShadow = pShadowManager->GetNext(pos);
if (m_pfnUpdateLayeredWindow)
{
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = (BYTE)nOpacity;
bf.AlphaFormat = 0x01;
m_pfnUpdateLayeredWindow(pShadow->GetSafeHwnd(), (HDC)0, 0, 0, 0, 0, 0, &bf, 0x02);
}
else
{
pShadow->SetWindowPos(0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | (nOpacity > 20 ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
}
}
}
if (m_nOpacity == 255)
{
m_bActivated = TRUE;
}
if (nLen > (m_bActivated ? 180 : 110))
{
m_bTracking = FALSE;
}
}
void CXTPMiniToolBar::Animate()
{
GetPaintManager()->SetCommandBarRegion(this);
if (m_pfnSetLayeredWindowAttributes != 0)
{
ModifyStyleEx(0, WS_EX_LAYERED);
}
}
BOOL CXTPMiniToolBar::TrackMiniBar(UINT nFlags, int x, int y)
{
CXTPMouseManager* pMouseManager = XTPMouseManager();
m_bActivated = FALSE;
m_bTracking = TRUE;
m_popupFlags = xtpPopupUp;
m_nOpacity = 0;
CWnd* pWnd = GetSite();
if (pWnd && pWnd->GetExStyle() & (WS_EX_LAYOUTRTL | WS_EX_RIGHT))
nFlags |= TPM_RIGHTALIGN;
m_bExecOnRButton = nFlags & TPM_RIGHTBUTTON;
m_popupFlags = (nFlags & TPM_RIGHTALIGN) ? xtpPopupLeft | xtpPopupUp : xtpPopupUp;
pMouseManager->SendTrackLost();
ReleaseCapture();
if (!Popup(x, y, CRect(0, 0, 0, 0)))
{
return FALSE;
}
InternalAddRef();
SetTrackingMode(FALSE);
UpdateOpacity();
PumpMessage();
DestroyWindow();
InternalRelease();
return TRUE;
}
BOOL CXTPMiniToolBar::TrackPopupMenu(CXTPPopupBar* pPopup, UINT nFlags, int x, int y)
{
ASSERT(pPopup);
if (!pPopup)
{
return FALSE;
}
m_bActivated = TRUE;
m_bTracking = TRUE;
m_nOpacity = 0;
m_popupFlags = xtpPopupUp;
const UINT uMenuAndToolbarIdent = 15; // px
CWnd* pWnd = GetSite();
if (pWnd && pWnd->GetExStyle() & (WS_EX_LAYOUTRTL | WS_EX_RIGHT))
nFlags |= TPM_RIGHTALIGN;
UINT nReturn = TRUE;
pPopup->m_pReturnCmd = NULL;
if (nFlags & TPM_RETURNCMD)
{
pPopup->m_pReturnCmd = &nReturn;
nReturn = 0;
}
m_bExecOnRButton = nFlags & TPM_RIGHTBUTTON;
pPopup->m_bIgnoreUpdateHandler = nFlags & TPM_NONOTIFY;
pPopup->m_bExecOnRButton = nFlags & TPM_RIGHTBUTTON;
if (nFlags & TPM_RIGHTALIGN)
{
SetPopupFlags(xtpPopupLeft | xtpPopupUp);
pPopup->SetPopupFlags(xtpPopupLeft | xtpPopupDown);
}
else
{
SetPopupFlags(xtpPopupUp);
pPopup->SetPopupFlags(xtpPopupDown);
}
CXTPMouseManager* pMouseManager = XTPMouseManager();
pMouseManager->SendTrackLost();
ReleaseCapture();
pMouseManager->IgnoreLButtonUp();
if (!Create())
return FALSE;
if (!pPopup->Create())
return FALSE;
int nPopupWidth = pPopup->GetWidth();
int nMiniBarWidth = GetWidth();
CSize szMiniBar = CalcDynamicLayout(0, 0);
CSize szPopupBar = pPopup->CalcDynamicLayout(0, 0);
CPoint ptPopup(x, y);
CRect rc = pPopup->CalculatePopupRect(ptPopup, szPopupBar);
int nWidth = max(szMiniBar.cx, szPopupBar.cx);
int nTop = rc.top - uMenuAndToolbarIdent; // default minibar position
pPopup->SetWidth(nWidth);
SetWidth(nWidth);
CRect rcWorkArea = XTPMultiMonitor()->GetWorkArea(ptPopup);
if (nTop < rcWorkArea.top) // ?
{
nTop = rc.bottom + uMenuAndToolbarIdent;
m_popupFlags &= ~xtpPopupUp;
}
else if ( (y+szPopupBar.cy) >= rcWorkArea.bottom) // the menu popup goes up, we're in the bottom of the screen
{
nTop = rc.bottom + uMenuAndToolbarIdent + szMiniBar.cy; // minibar will be below popup
if (nTop >= rcWorkArea.bottom) // the minibar is too tall to fit below, we need to place it above
{
nTop = y - szPopupBar.cy - uMenuAndToolbarIdent;
}
}
else if ( (nTop-szMiniBar.cy) <= rcWorkArea.top ) // the minibar is too tall to fit above, we need to place it below
{
nTop = rc.bottom + uMenuAndToolbarIdent + szMiniBar.cy; // minibar goes below popup
}
if (!Popup(x, nTop, CRect(0, 0, 0, 0)))
{
return FALSE;
}
m_pContextMenu = pPopup;
UpdateOpacity();
UpdateWindow();
if (!pPopup->Popup(x, y, CRect(0, 0, 0, 0)))
{
m_pContextMenu = NULL;
return FALSE;
}
InternalAddRef();
PumpMessage();
SetWidth(nMiniBarWidth);
pPopup->SetWidth(nPopupWidth);
m_pContextMenu = NULL;
DestroyWindow();
InternalRelease();
return nReturn;
}
BOOL CXTPMiniToolBar::OnHookKeyDown(UINT nChar, LPARAM lParam)
{
if (m_pContextMenu)
return FALSE;
return CXTPPopupToolBar::OnHookKeyDown(nChar, lParam);
}
BOOL CXTPMiniToolBar::SetTrackingMode(int bMode, BOOL bSelectFirst, BOOL bKeyboard)
{
return CXTPCommandBar::SetTrackingMode(bMode, bSelectFirst, bKeyboard);
}
void CXTPMiniToolBar::SetCustomControlKeyboardInteraction(BOOL bInteract /*= TRUE*/)
{
m_bCustomControlKeyboardInteraction = bInteract;
}
BOOL CXTPMiniToolBar::IsCustomControlKeyboardInteraction() const
{
return m_bCustomControlKeyboardInteraction;
}
BOOL CXTPMiniToolBar::CursorInWindow() const
{
CPoint pt;
GetCursorPos(&pt);
if (CXTPWindowRect(this).PtInRect(pt))
return TRUE;
CXTPCommandBar* pCommandBar = XTPMouseManager()->HitTest(pt);
if (!pCommandBar)
return FALSE;
return pCommandBar->GetRootParent() == (CXTPCommandBar*)this;
}
int CXTPMiniToolBar::OnHookMessage(HWND hWnd, UINT nMessage, WPARAM& wParam, LPARAM& lParam, LRESULT& lResult)
{
if (m_bTracking)
{
if (nMessage == WM_ENABLE || nMessage == WM_ACTIVATEAPP)
{
ShowWindow(SW_HIDE);
m_bTracking = FALSE;
}
}
return CXTPPopupToolBar::OnHookMessage(hWnd, nMessage, wParam, lParam, lResult);
}
void CXTPMiniToolBar::PumpMessage()
{
HWND hwndSite = GetSite()->m_hWnd;
CWinThread* pThread = XTPGetThread();
XTPHookManager()->SetHook(hwndSite, this);
HWND hWndTopLevelParent = hwndSite;
while (GetWindowLong(hWndTopLevelParent, GWL_STYLE) & WS_CHILD)
hWndTopLevelParent = ::GetParent(hWndTopLevelParent);
if (hwndSite != hWndTopLevelParent)
XTPHookManager()->SetHook(hWndTopLevelParent, this);
while (m_bTracking)
{
MSG msg;
if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!m_bTracking)
break;
if (!m_pContextMenu)
{
if (msg.message == WM_MOUSEMOVE)
{
UpdateOpacity();
}
if ((msg.message == WM_KEYDOWN || msg.message == WM_CHAR
|| msg.message == WM_SYSKEYDOWN || msg.message == WM_MOUSEWHEEL) && !IsTrackingMode())
{
BOOL bDisableTrackingMode = TRUE;
if (IsCustomControlKeyboardInteraction())
{
// custom controls does not have appropriate keyboard hooks, so
// we need to disable setting tracking mode to FALSE on them
// thus keyboard interaction with a custom control will not close it
int i=0, c = GetControlCount();
for (i = 0; i<c; i++)
{
CXTPControlCustom *pCustom = DYNAMIC_DOWNCAST(CXTPControlCustom , GetControl(i) );
if (pCustom && pCustom->GetControl()->GetSafeHwnd() == msg.hwnd)
{
bDisableTrackingMode = FALSE;
break;
}
}
}
if (bDisableTrackingMode)
m_bTracking = FALSE;
}
if (msg.message == WM_CLOSE || msg.message == WM_SYSCOMMAND)
{
m_bTracking = FALSE;
}
if ((msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN ||
msg.message == WM_NCLBUTTONDOWN || msg.message == WM_NCRBUTTONDOWN) && !CursorInWindow())
{
m_bTracking = FALSE;
}
}
else
{
if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN ||
msg.message == WM_NCLBUTTONDOWN || msg.message == WM_NCRBUTTONDOWN)
{
if (!CursorInWindow())
{
CPoint point;
GetCursorPos(&point);
if (XTPMouseManager()->HitTest(point) == 0)
m_bTracking = FALSE;
}
else
{
m_pContextMenu->SetTrackingMode(FALSE);
m_pContextMenu = NULL;
SetTrackingMode(FALSE);
}
}
}
if (msg.message == WM_ACTIVATE || msg.message == WM_ACTIVATEAPP || msg.message == WM_CAPTURECHANGED)
{
m_bTracking = FALSE;
}
if (m_pContextMenu && !m_pContextMenu->IsTrackingMode())
{
ShowWindow(SW_HIDE);
m_bTracking = FALSE;
}
if (!m_bTracking)
break;
if (!::GetMessage(&msg, NULL, 0, 0))
break;
if (m_pContextMenu && !m_pContextMenu->IsTrackingMode())
{
m_bTracking = FALSE;
}
if (!m_bTracking)
{
::PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam);
break;
}
if (msg.message != WM_KICKIDLE && !pThread->PreTranslateMessage(&msg))
{
// process this message
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
pThread->OnIdle(-1);
OnIdleUpdateCmdUI(TRUE, 0L);
}
else
{
WaitMessage();
}
}
if (hwndSite != hWndTopLevelParent)
XTPHookManager()->RemoveHook(hWndTopLevelParent, this);
XTPHookManager()->RemoveHook(hwndSite, this);
}
CXTPMiniToolBar* CXTPMiniToolBar::CreateMiniToolBar(CXTPCommandBars* pCommandBars)
{
CXTPMiniToolBar* pMiniToolBar = new CXTPMiniToolBar();
pMiniToolBar->SetCommandBars(pCommandBars);
return pMiniToolBar;
}
INT_PTR CXTPMiniToolBar::OnToolHitTest(CPoint /*point*/, TOOLINFO* /*pTI*/) const
{
return -1; // No Tips.
}
BEGIN_MESSAGE_MAP(CXTPMiniToolBar, CXTPPopupToolBar)
//{{AFX_MSG_MAP(CXTPMiniToolBar)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CXTPMiniToolBar message handlers