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.

952 lines
24 KiB
C++

// XTPDockingPaneKeyboardHook.cpp : implementation of the CXTPDockingPaneKeyboardHook class.
//
// This file is a part of the XTREME DOCKINGPANE 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/XTPResourceManager.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/Resource.h"
#include "Common/XTPColorManager.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPImageManager.h"
#include "Resource.h"
#include "TabManager/XTPTabManager.h"
#include "TabManager/XTPTabPaintManager.h"
#include "XTPDockingPaneDefines.h"
#include "XTPDockingPaneBase.h"
#include "XTPDockingPaneKeyboardHook.h"
#include "XTPDockingPane.h"
#include "XTPDockingPanePaintManager.h"
#include "XTPDockingPaneManager.h"
#include "XTPDockingPaneMiniWnd.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CXTPDockingPaneWindowSelect
IMPLEMENT_DYNCREATE(CXTPDockingPaneWindowSelect, CMiniFrameWnd)
CXTPDockingPaneWindowSelect::CXTPDockingPaneWindowSelect()
{
LOGFONT lfIcon;
VERIFY(CXTPDrawHelpers::GetIconLogFont(&lfIcon));
lfIcon.lfWeight = FW_NORMAL;
m_fnt.CreateFontIndirect(&lfIcon);
lfIcon.lfWeight = FW_BOLD;
m_fntBold.CreateFontIndirect(&lfIcon);
XTPResourceManager()->LoadString(&m_strActiveTools, XTP_IDS_DOCKINGPANE_SELECTWINDOW_ACTIVETOOLS);
XTPResourceManager()->LoadString(&m_strActiveFiles, XTP_IDS_DOCKINGPANE_SELECTWINDOW_ACTIVEFILES);
m_pSelected = NULL;
m_pManager = NULL;
m_bActivatePanes = FALSE;
m_nPaneCount = 0;
m_nFirstFile = 0;
m_hHandCursor = AfxGetApp()->LoadStandardCursor(MAKEINTRESOURCE(32649));
if (m_hHandCursor == 0)
m_hHandCursor = XTPResourceManager()->LoadCursor(XTP_IDC_HAND);
m_hArrowCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
}
CXTPDockingPaneWindowSelect::~CXTPDockingPaneWindowSelect()
{
for (int i = 0; i < (int)m_arrItems.GetSize(); i++)
{
delete m_arrItems[i];
}
m_arrItems.RemoveAll();
}
int CXTPDockingPaneWindowSelect::CalcItemHeight(CDC* pDC)
{
CXTPFontDC font(pDC, &m_fnt);
CSize szFont = pDC->GetTextExtent(_T(" "), 1);
CSize szIcon = m_pManager->GetPaintManager()->GetTabPaintManager()->m_szIcon;
return max(szIcon.cy + 4, szFont.cy + 4);
}
CXTPDockingPaneWindowSelect::CItem* CXTPDockingPaneWindowSelect::HitTest(CPoint point) const
{
for (int i = 0; i < (int)m_arrItems.GetSize(); i++)
{
CItem* pItem = m_arrItems[i];
if (pItem->rc.PtInRect(point))
{
return pItem;
}
}
return 0;
}
CString CXTPDockingPaneWindowSelect::GetItemCaption(CItem* pItem) const
{
if (pItem->type == itemPane)
{
return pItem->pPane->GetTitle();
}
else
{
CString strCaption;
CFrameWnd* pChild = DYNAMIC_DOWNCAST(CFrameWnd, CWnd::FromHandle(pItem->hWndFrame));
if (pChild && pChild->GetActiveDocument())
{
strCaption = pChild->GetActiveDocument()->GetTitle();
}
else
{
CXTPDrawHelpers::GetWindowCaption(pItem->hWndFrame, strCaption);
}
return strCaption;
}
}
CString CXTPDockingPaneWindowSelect::GetItemDescription(CItem* pItem) const
{
if (pItem->type == itemPane)
return _T("");
CFrameWnd* pChild = DYNAMIC_DOWNCAST(CFrameWnd, CWnd::FromHandle(pItem->hWndFrame));
if (!pChild)
return _T("");
CDocument* pDocument = pChild->GetActiveDocument();
if (!pDocument)
return _T("");
CString strTypeName;
if (pDocument->GetDocTemplate() != NULL) pDocument->GetDocTemplate()->GetDocString(strTypeName, CDocTemplate::regFileTypeName);
return strTypeName;
}
CString CXTPDockingPaneWindowSelect::GetItemPath(CItem* pItem) const
{
if (pItem->type == itemPane)
return _T("");
CFrameWnd* pChild = DYNAMIC_DOWNCAST(CFrameWnd, CWnd::FromHandle(pItem->hWndFrame));
if (!pChild)
return _T("");
CDocument* pDocument = pChild->GetActiveDocument();
if (!pDocument)
return _T("");
return pDocument->GetPathName();
}
HWND CXTPDockingPaneWindowSelect::GetMDIClient() const
{
CMDIFrameWnd* pFrame = DYNAMIC_DOWNCAST(CMDIFrameWnd, m_pManager->GetSite());
HWND hWndClient = pFrame ? pFrame->m_hWndMDIClient : NULL;
return hWndClient;
}
BOOL CXTPDockingPaneWindowSelect::Reposition()
{
CClientDC dc(this);
int nItemHeight = CalcItemHeight(&dc);
int nItemWidth = 163;
int y = nItemHeight + 13;
int x = 9;
int nRow = 0;
int nColumn = 0;
m_pSelected = 0;
int nTotalRow = 0;
int nFirstColumn = 0;
CXTPDockingPaneInfoList& paneList = m_pManager->GetPaneList();
POSITION pos = paneList.GetHeadPosition();
while (pos)
{
CXTPDockingPane* pPane = paneList.GetNext(pos);
if ((pPane->GetEnabled() & xtpPaneEnableClient) == 0)
continue;
if (nColumn == 0 && m_pManager->IsClientHidden() && nRow > paneList.GetCount() / 2)
{
CColumn colNext;
colNext.nFirst = 0;
colNext.nLast = (int)m_arrItems.GetSize() - 1;
m_arrColumns.Add(colNext);
nTotalRow = max(nRow, nTotalRow);
nFirstColumn = (int)m_arrItems.GetSize();
nRow = 0;
nColumn++;
y = nItemHeight + 13;
x += nItemWidth + 12;
}
CItem* pItem = new CItem;
pItem->pPane = pPane;
pItem->type = itemPane;
pItem->rc = CRect(x, y, x + nItemWidth, y + nItemHeight);
y += nItemHeight + 1;
pItem->nIndex = (int)m_arrItems.Add(pItem);
pItem->nColumn = nColumn;
pItem->nRow = nRow;
if (m_pManager->GetActivePane() == pPane)
m_pSelected = pItem;
nRow++;
}
m_nPaneCount = (int)m_arrItems.GetSize();
if (m_bActivatePanes && m_nPaneCount > 0)
{
if (m_pSelected == 0)
{
m_pSelected = m_arrItems[GetKeyState(VK_SHIFT) >= 0 ? 0 : nRow - 1];
}
else
{
if (GetKeyState(VK_SHIFT) >= 0)
{
m_pSelected = m_arrItems[m_pSelected->nIndex >= nRow - 1 ? 0 : m_pSelected->nIndex + 1];
}
else
{
m_pSelected = m_arrItems[m_pSelected->nIndex > 0 ? m_pSelected->nIndex - 1 : nRow - 1];
}
}
}
nTotalRow = max(nRow, nTotalRow);
if (m_nPaneCount > 0)
{
CColumn col;
col.nFirst = nFirstColumn;
col.nLast = (int)m_arrItems.GetSize() - 1;
m_arrColumns.Add(col);
}
else
{
m_bActivatePanes = FALSE;
}
m_nFirstFile = (int)m_arrItems.GetSize();
nFirstColumn = m_nFirstFile;
nRow = 0;
if (m_nPaneCount > 0 && !m_pManager->IsClientHidden())
{
nColumn++;
x += nItemWidth + 12;
y = nItemHeight + 13;
}
HWND hWndClient = GetMDIClient();
HWND hWndActive = hWndClient ? (HWND)::SendMessage(hWndClient, WM_MDIGETACTIVE, 0, 0) : 0;
if (m_pManager->IsClientHidden())
{
}
else if (hWndActive)
{
HWND hWndFrame = hWndActive;
while (hWndFrame)
{
DWORD dwStyle = GetWindowLong(hWndFrame, GWL_STYLE);
if (((dwStyle & WS_VISIBLE) != 0) && ((dwStyle & WS_DISABLED) == 0))
{
if (nRow > 14)
{
CColumn colNext;
colNext.nFirst = nFirstColumn;
colNext.nLast = (int)m_arrItems.GetSize() - 1;
m_arrColumns.Add(colNext);
nTotalRow = max(nRow, nTotalRow);
nFirstColumn = (int)m_arrItems.GetSize();
nRow = 0;
nColumn++;
y = nItemHeight + 13;
x += nItemWidth + 12;
}
CItem* pItem = new CItem;
pItem->hWndFrame = hWndFrame;
pItem->type = itemMDIFrame;
pItem->rc = CRect(x, y, x + nItemWidth, y + nItemHeight);
y += nItemHeight + 1;
pItem->nIndex = (int)m_arrItems.Add(pItem);
pItem->nColumn = nColumn;
pItem->nRow = nRow;
if (hWndActive == hWndFrame && !m_bActivatePanes)
m_pSelected = pItem;
nRow++;
}
hWndFrame = ::GetWindow(hWndFrame, GW_HWNDNEXT);
}
}
else if (!hWndClient)
{
CItem* pItem = new CItem;
pItem->hWndFrame = m_pManager->GetSite()->GetSafeHwnd();
pItem->type = itemSDIFrame;
pItem->rc = CRect(x, y, x + nItemWidth, y + nItemHeight);
pItem->nIndex = (int)m_arrItems.Add(pItem);
pItem->nColumn = nColumn;
pItem->nRow = nRow;
if (m_pSelected == NULL)
m_pSelected = pItem;
m_nFirstFile++;
}
if (nFirstColumn < m_arrItems.GetSize())
{
CColumn colNext;
colNext.nFirst = nFirstColumn;
colNext.nLast = (int)m_arrItems.GetSize() - 1;
m_arrColumns.Add(colNext);
}
if (m_nFirstFile < m_arrItems.GetSize() - 1 && !m_bActivatePanes)
{
if (GetKeyState(VK_SHIFT) >= 0)
m_pSelected = m_arrItems[m_nFirstFile + 1];
else
m_pSelected = m_arrItems[ m_arrItems.GetSize() - 1];
}
nTotalRow = max(nRow, nTotalRow);
int nTotalColumns = max(2, (int)m_arrColumns.GetSize());
CSize sz(4 + (nItemWidth + 12) * nTotalColumns,
nItemHeight + 13 + nTotalRow * (nItemHeight + 1) + 110);
CXTPWindowRect rcWindow(m_pManager->GetSite());
CPoint ptCenter = rcWindow.CenterPoint();
CRect rect(CPoint(ptCenter.x - sz.cx / 2, ptCenter.y - sz.cy /2), sz);
SetWindowPos(&CWnd::wndTopMost, rect.left, rect.top, rect.Width(), rect.Height(),
SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
return TRUE;
}
BEGIN_MESSAGE_MAP(CXTPDockingPaneWindowSelect, CMiniFrameWnd)
//{{AFX_MSG_MAP(CXTPDockingPaneWindowSelect)
ON_WM_KILLFOCUS()
ON_WM_CAPTURECHANGED()
ON_WM_PAINT()
ON_WM_KEYDOWN()
ON_WM_SYSKEYDOWN()
ON_WM_KEYUP()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_CHAR()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#define CS_DROPSHADOW 0x00020000
/////////////////////////////////////////////////////////////////////////////
// CXTPDockingPaneWindowSelect message handlers
BOOL CXTPDockingPaneWindowSelect::DoModal()
{
CWnd* pSite = m_pManager->GetSite();
HWND hWndParent = pSite->GetSafeHwnd();
HWND hwndFocus = ::GetFocus();
BOOL bLayoutRTL = m_pManager->IsLayoutRTL();
UINT nClassStyle = bLayoutRTL ? 0 : CS_SAVEBITS | CS_OWNDC;
if (XTPSystemVersion()->IsWinXPOrGreater()) // Windows XP only
{
nClassStyle |= CS_DROPSHADOW;
}
if (!CreateEx(WS_EX_TOOLWINDOW | (bLayoutRTL ? WS_EX_LAYOUTRTL : 0),
AfxRegisterWndClass(nClassStyle, m_hArrowCursor), 0,
WS_POPUP | MFS_SYNCACTIVE, CRect(0, 0, 0, 0), pSite, 0))
return FALSE;
if (!Reposition())
{
DestroyWindow();
return FALSE;
}
SetFocus();
SetCapture();
BOOL bEnableParent = FALSE;
if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
{
CWnd::ModifyStyle(hWndParent, 0, WS_DISABLED, 0);
bEnableParent = TRUE;
}
m_nFlags |= WF_CONTINUEMODAL;
if (m_nFlags & WF_CONTINUEMODAL)
{
// enter modal loop
DWORD dwFlags = MLF_SHOWONIDLE;
VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
}
// hide the window before enabling the parent, etc.
if (m_hWnd != NULL)
SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
if (bEnableParent)
CWnd::ModifyStyle(hWndParent, WS_DISABLED, 0, 0);
if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
::SetActiveWindow(hWndParent);
if (m_nModalResult == IDOK && m_pSelected)
{
if (m_pSelected->type == itemPane)
{
m_pManager->ShowPane(m_pSelected->pPane);
}
else if (m_pSelected->type == itemMDIFrame)
{
HWND hWndClient = GetMDIClient();
::SendMessage(hWndClient, WM_MDIACTIVATE, (WPARAM)m_pSelected->hWndFrame, 0);
CWnd* pWnd = CWnd::FromHandle(m_pSelected->hWndFrame);
CWnd* pFocus = GetFocus();
BOOL bHasFocus = pFocus->GetSafeHwnd() &&
(pFocus == pWnd || pWnd->IsChild(pFocus) || (pFocus->GetOwner()->GetSafeHwnd() && pWnd->IsChild(pFocus->GetOwner())));
if (!bHasFocus)
pWnd->SetFocus();
}
}
else
{
::SetFocus(hwndFocus);
}
DestroyWindow();
return TRUE;
}
void CXTPDockingPaneWindowSelect::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
if (m_nFlags & WF_CONTINUEMODAL) EndModalLoop(IDCANCEL);
}
void CXTPDockingPaneWindowSelect::OnCaptureChanged(CWnd *pWnd)
{
if (m_nFlags & WF_CONTINUEMODAL) EndModalLoop(IDCANCEL);
CWnd::OnCaptureChanged(pWnd);
}
void CXTPDockingPaneWindowSelect::OnPaint()
{
CPaintDC dcPaint(this); // device context for painting
CXTPClientRect rc(this);
CXTPBufferDC dc(dcPaint);
dc.FillSolidRect(rc, GetSysColor(COLOR_3DFACE));
dc.Draw3dRect(rc, GetXtremeColor(XPCOLOR_HIGHLIGHT_BORDER), GetXtremeColor(XPCOLOR_HIGHLIGHT_BORDER));
int nItemHeight = CalcItemHeight(&dc);
CXTPFontDC font(&dc, &m_fntBold);
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(GetXtremeColor(COLOR_BTNTEXT));
if (m_nPaneCount > 0)
{
CRect rcActiveTools(9, 0, 9 + 163, nItemHeight + 12);
dc.DrawText(m_strActiveTools, rcActiveTools, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);
if (!m_pManager->IsClientHidden())
{
CRect rcActiveFiles( 9 + 13 + 163, 0, 9 + 13 + 2 * 163, nItemHeight + 12);
dc.DrawText(m_strActiveFiles, rcActiveFiles, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);
}
}
else
{
CRect rcActiveFiles( 9, 0, 9 + 2 * 163, nItemHeight + 12);
dc.DrawText(m_strActiveFiles, rcActiveFiles, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);
}
font.SetFont(&m_fnt);
CSize szIcon = m_pManager->GetPaintManager()->GetTabPaintManager()->m_szIcon;
for (int i = 0; i < (int)m_arrItems.GetSize(); i++)
{
CItem* pItem = m_arrItems[i];
if (m_pSelected == pItem)
{
dc.FillSolidRect(pItem->rc, GetXtremeColor(XPCOLOR_HIGHLIGHT));
dc.Draw3dRect(pItem->rc, GetXtremeColor(XPCOLOR_HIGHLIGHT_BORDER), GetXtremeColor(XPCOLOR_HIGHLIGHT_BORDER));
}
if (pItem->type == itemPane)
{
CPoint ptIcon(pItem->rc.left + 2, pItem->rc.CenterPoint().y - szIcon.cy/2);
CXTPImageManagerIcon* pImage = pItem->pPane->GetIcon(szIcon.cx);
if (pImage) pImage->Draw(&dc, ptIcon, szIcon);
}
else
{
CPoint ptIcon(pItem->rc.left + 2, pItem->rc.CenterPoint().y - szIcon.cy/2);
HICON hIcon = (HICON)::SendMessage(pItem->hWndFrame, WM_GETICON, ICON_SMALL, 0);
if (hIcon == NULL) hIcon = (HICON)::SendMessage(pItem->hWndFrame, WM_GETICON, ICON_BIG, 0);
if (hIcon == NULL) hIcon = (HICON)(ULONG_PTR)::GetClassLongPtr(pItem->hWndFrame, GCLP_HICONSM);
if (hIcon)
{
if (GetExStyle() & WS_EX_LAYOUTRTL)
::DrawIconEx(dc, ptIcon.x + szIcon.cx, ptIcon.y, hIcon, -szIcon.cx, szIcon.cy, 0, 0, DI_NORMAL);
else
::DrawIconEx(dc, ptIcon.x, ptIcon.y, hIcon, szIcon.cx, szIcon.cy, 0, 0, DI_NORMAL);
}
}
CRect rcText(pItem->rc);
rcText.left += 5 + szIcon.cx;
dc.DrawText(GetItemCaption(pItem), rcText, DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
}
CRect rcInfoPane(11, rc.bottom - 100, rc.right - 11, rc.bottom - 10);
dc.Draw3dRect(rcInfoPane, GetXtremeColor(XPCOLOR_HIGHLIGHT_BORDER), GetXtremeColor(XPCOLOR_HIGHLIGHT_BORDER));
if (!m_pSelected)
return;
rcInfoPane.DeflateRect(15, 13, 15, 13);
font.SetFont(&m_fntBold);
CRect rcCaption(rcInfoPane.left, rcInfoPane.top, rcInfoPane.right, rcInfoPane.top + rcInfoPane.Height() / 3);
dc.DrawText(GetItemCaption(m_pSelected), rcCaption, DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
font.SetFont(&m_fnt);
CRect rcTypeName(rcInfoPane.left, rcCaption.bottom, rcInfoPane.right, rcCaption.bottom + rcInfoPane.Height() / 3);
dc.DrawText(GetItemDescription(m_pSelected), rcTypeName, DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
CRect rcPathName(rcInfoPane.left, rcTypeName.bottom, rcInfoPane.right, rcInfoPane.bottom);
dc.DrawText(GetItemPath(m_pSelected), rcPathName, DT_SINGLELINE | DT_VCENTER | DT_PATH_ELLIPSIS | DT_NOPREFIX);
}
void CXTPDockingPaneWindowSelect::Select(int nItem)
{
Select(nItem >= 0 && nItem < m_arrItems.GetSize() ? m_arrItems[nItem] : NULL);
}
void CXTPDockingPaneWindowSelect::Select(CItem* pItem)
{
if (m_pSelected != pItem)
{
m_pSelected = pItem;
Invalidate(FALSE);
}
}
void CXTPDockingPaneWindowSelect::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CMiniFrameWnd::OnChar(nChar, nRepCnt, nFlags);
}
void CXTPDockingPaneWindowSelect::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
OnKeyDown(nChar, nRepCnt, nFlags);
}
void CXTPDockingPaneWindowSelect::OnKeyDown(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
{
XTPDrawHelpers()->KeyToLayout(this, nChar);
if (nChar == VK_TAB)
{
if (GetKeyState(VK_SHIFT) >= 0)
{
int nSelected = m_pSelected ? m_pSelected->nIndex + 1: 0;
if (nSelected >= m_arrItems.GetSize())
nSelected = m_nFirstFile == m_arrItems.GetSize() ? 0 : m_nFirstFile;
else if (nSelected == m_nFirstFile)
nSelected = 0;
Select(nSelected);
}
else
{
int nSelected = m_pSelected ? m_pSelected->nIndex - 1: (int)m_arrItems.GetSize() - 1;
if (nSelected < 0)
nSelected = m_nFirstFile == 0 ? (int)m_arrItems.GetSize() - 1 : m_nFirstFile - 1;
else if (nSelected == m_nFirstFile - 1)
nSelected = (int)m_arrItems.GetSize() - 1;
Select(nSelected);
}
}
else if (nChar == VK_LEFT)
{
if (m_arrColumns.GetSize() > 1 && m_pSelected)
{
int nColumn = m_pSelected->nColumn;
int nRow = m_pSelected->nRow;
CColumn& col = m_arrColumns[nColumn > 0 ? nColumn - 1 : m_arrColumns.GetSize() - 1];
int nItem = col.nFirst + nRow > col.nLast ? col.nLast : col.nFirst + nRow;
Select(nItem);
}
}
else if (nChar == VK_RIGHT)
{
if (m_arrColumns.GetSize() > 1 && m_pSelected)
{
int nColumn = m_pSelected->nColumn;
int nRow = m_pSelected->nRow;
CColumn& col = m_arrColumns[nColumn < m_arrColumns.GetSize() - 1 ? nColumn + 1 : 0];
int nItem = col.nFirst + nRow > col.nLast ? col.nLast : col.nFirst + nRow;
Select(nItem);
}
}
else if (nChar == VK_DOWN)
{
int nSelected = m_pSelected ? m_pSelected->nIndex + 1 : 0;
Select(nSelected < m_arrItems.GetSize() ? nSelected : 0);
}
else if (nChar == VK_UP)
{
int nSelected = m_pSelected ? m_pSelected->nIndex - 1 : -1;
Select(nSelected >= 0 ? nSelected : (int)m_arrItems.GetSize() - 1);
}
else if (nChar == VK_SHIFT)
{
}
else
{
EndModalLoop(IDOK);
}
}
void CXTPDockingPaneWindowSelect::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (::GetKeyState(VK_CONTROL) >= 0)
{
EndModalLoop(IDOK);
}
CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}
void CXTPDockingPaneWindowSelect::OnLButtonDown(UINT nFlags, CPoint point)
{
CXTPClientRect rc(this);
if (!rc.PtInRect(point))
EndModalLoop(IDCANCEL);
CItem* pItem = HitTest(point);
if (pItem)
{
Select(pItem);
}
CWnd::OnLButtonDown(nFlags, point);
}
void CXTPDockingPaneWindowSelect::OnLButtonUp(UINT nFlags, CPoint point)
{
CItem* pItem = HitTest(point);
if (pItem)
{
m_pSelected = pItem;
EndModalLoop(IDOK);
}
CWnd::OnLButtonUp(nFlags, point);
}
void CXTPDockingPaneWindowSelect::OnMouseMove(UINT /*nFlags*/, CPoint point)
{
CItem* pItem = HitTest(point);
::SetCursor(pItem ? m_hHandCursor : m_hArrowCursor);
}
void CXTPDockingPaneWindowSelect::PostNcDestroy()
{
}
//////////////////////////////////////////////////////////////////////////
// CXTPDockingPaneKeyboardHook
CThreadLocal<CXTPDockingPaneKeyboardHook> CXTPDockingPaneKeyboardHook::_xtpKeyboardThreadState;
CXTPDockingPaneKeyboardHook::CXTPDockingPaneKeyboardHook()
{
m_pWindowSelect = 0;
m_hHookKeyboard = 0;
#ifdef _AFXDLL
m_pModuleState = 0;
#endif
}
CXTPDockingPaneKeyboardHook::~CXTPDockingPaneKeyboardHook()
{
ASSERT(m_mapSites.IsEmpty());
ASSERT(m_hHookKeyboard == 0);
}
CXTPDockingPaneManager* CXTPDockingPaneKeyboardHook::FindFocusedManager()
{
HWND hWnd = GetFocus();
while (hWnd)
{
CXTPDockingPaneManager* pManager = Lookup(hWnd);
if (pManager)
{
if (!pManager->GetSite()->IsWindowEnabled())
return FALSE;
return pManager;
}
LONG dwStyle = ::GetWindowLong(hWnd, GWL_STYLE);
if (dwStyle & WS_CHILD)
{
hWnd = ::GetParent(hWnd);
}
else if (::GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
{
CXTPDockingPaneMiniWnd* pMinWnd = DYNAMIC_DOWNCAST(CXTPDockingPaneMiniWnd,
CWnd::FromHandle(hWnd));
if (pMinWnd != NULL)
return pMinWnd->GetDockingPaneManager();
return NULL;
}
else return NULL;
}
return NULL;
}
LRESULT CALLBACK CXTPDockingPaneKeyboardHook::KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
CXTPDockingPaneKeyboardHook* pKeyboardManager = GetThreadState();
if (code != HC_ACTION)
return CallNextHookEx(pKeyboardManager->m_hHookKeyboard, code, wParam, lParam);
if ((!(HIWORD(lParam) & KF_UP)))
{
if (wParam == VK_TAB && GetKeyState(VK_CONTROL) < 0 && !(HIWORD(lParam) & KF_ALTDOWN))
{
SAFE_MANAGE_STATE(pKeyboardManager->m_pModuleState);
CXTPDockingPaneWindowSelect*& pWindowSelect = pKeyboardManager->m_pWindowSelect;
if (pWindowSelect)
{
pWindowSelect->OnKeyDown(VK_TAB, 0, 0);
return TRUE;
}
CXTPDockingPaneManager* pManager = pKeyboardManager->FindFocusedManager();
if (pManager && (pManager->IsKeyboardNavigateEnabled() & xtpPaneKeyboardUseCtrlTab))
{
pWindowSelect = (CXTPDockingPaneWindowSelect*)pManager->GetKeyboardWindowSelectClass()->CreateObject();
pWindowSelect->m_pManager = pManager;
pWindowSelect->m_bActivatePanes = FALSE;
BOOL bResult = pWindowSelect->DoModal();
delete pWindowSelect;
pWindowSelect = 0;
if (bResult)
return TRUE;
}
}
if ((HIWORD(lParam) & KF_ALTDOWN) && (wParam == VK_F7) && GetKeyState(VK_CONTROL) >= 0)
{
SAFE_MANAGE_STATE(pKeyboardManager->m_pModuleState);
CXTPDockingPaneWindowSelect*& pWindowSelect = pKeyboardManager->m_pWindowSelect;
if (pWindowSelect)
{
pWindowSelect->OnKeyDown(VK_TAB, 0, 0);
return TRUE;
}
CXTPDockingPaneManager* pManager = pKeyboardManager->FindFocusedManager();
if (pManager && (pManager->IsKeyboardNavigateEnabled() & xtpPaneKeyboardUseAltF7))
{
pWindowSelect = (CXTPDockingPaneWindowSelect*)pManager->GetKeyboardWindowSelectClass()->CreateObject();
pWindowSelect->m_pManager = pManager;
pWindowSelect->m_bActivatePanes = TRUE;
BOOL bResult = pWindowSelect->DoModal();
delete pWindowSelect;
pWindowSelect = 0;
if (bResult)
return TRUE;
}
}
if ((HIWORD(lParam) & KF_ALTDOWN) && (wParam == VK_F6) && GetKeyState(VK_CONTROL) >= 0) // Alt + F6
{
SAFE_MANAGE_STATE(pKeyboardManager->m_pModuleState);
CXTPDockingPaneManager* pManager = pKeyboardManager->FindFocusedManager();
if (pManager && (pManager->IsKeyboardNavigateEnabled() & xtpPaneKeyboardUseAltF6))
{
pManager->PostMessage(WM_SYSCOMMAND,
(UINT)(GetKeyState(VK_SHIFT) >= 0 ? SC_NEXTWINDOW : SC_PREVWINDOW), 0);
return TRUE;
}
}
if ((HIWORD(lParam) & KF_ALTDOWN) && ((wParam == 0xBD || wParam == VK_SUBTRACT)) &&
GetKeyState(VK_CONTROL) >= 0 && GetKeyState(VK_SHIFT) >= 0) // Alt + '-'
{
SAFE_MANAGE_STATE(pKeyboardManager->m_pModuleState);
CXTPDockingPaneManager* pManager = pKeyboardManager->FindFocusedManager();
if (pManager && (pManager->IsKeyboardNavigateEnabled() & xtpPaneKeyboardUseAltMinus))
{
CXTPDockingPane* pPane = pManager->GetActivePane();
if (pPane)
{
if (!pPane->IsClosed() && !pPane->IsHidden())
pManager->PostMessage(WM_SYSCOMMAND, SC_KEYMENU, MAKELONG(TEXT('-'), 0));
return TRUE;
}
}
}
}
return CallNextHookEx(pKeyboardManager->m_hHookKeyboard, code, wParam, lParam);
}
CXTPDockingPaneManager* CXTPDockingPaneKeyboardHook::Lookup(HWND hSite) const
{
CXTPDockingPaneManager* pManager = NULL;
if (m_mapSites.Lookup(hSite, pManager))
return pManager;
return NULL;
}
void CXTPDockingPaneKeyboardHook::SetupKeyboardHook(CXTPDockingPaneManager* pManager, BOOL bSetup)
{
if (!pManager->GetSite())
return;
if (bSetup)
{
if (Lookup(pManager->GetSite()->GetSafeHwnd()))
return;
if (m_hHookKeyboard == 0)
{
m_hHookKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, AfxGetInstanceHandle(), GetCurrentThreadId());
}
#ifdef _AFXDLL
m_pModuleState = AfxGetModuleState();
#endif
m_mapSites.SetAt(pManager->GetSite()->GetSafeHwnd(), pManager);
}
else
{
if (Lookup(pManager->GetSite()->GetSafeHwnd()))
{
m_mapSites.RemoveKey(pManager->GetSite()->GetSafeHwnd());
}
if (m_hHookKeyboard && m_mapSites.IsEmpty())
{
UnhookWindowsHookEx(m_hHookKeyboard);
m_hHookKeyboard = 0;
}
}
}