Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1671 lines
43 KiB

/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved.
//
// MODULE: navpane.cpp
//
// PURPOSE:
//
#include "pch.hxx"
#include "navpane.h"
#include "treeview.h"
#include "baui.h"
#include "browser.h"
#include "menuutil.h"
#include "inpobj.h"
/////////////////////////////////////////////////////////////////////////////
// Local Stuff
//
const TCHAR c_szNavPaneClass[] = _T("Outlook Express Navigation Pane");
const TCHAR c_szPaneFrameClass[] = _T("Outlook Express Pane Frame");
// Sizing consts
const int c_cxBorder = 1;
const int c_cyBorder = 1;
const int c_cxTextBorder = 4;
const int c_cyTextBorder = 2;
const int c_cyClose = 3;
const int c_cySplit = 4;
const int c_cxSplit = 3;
#define ID_PANE_CLOSE 2000
#define ID_PANE_PIN 2001
#define ID_PANE_TITLE 2002
#define IDT_PANETIMER 100
#define ELAPSE_MOUSEOVERCHECK 250
/////////////////////////////////////////////////////////////////////////////
// CNavPane Implementation
//
CNavPane::CNavPane()
{
m_cRef = 1;
m_fShow = FALSE;
m_fTreeVisible = FALSE;
m_fContactsVisible = FALSE;
m_hwnd = 0;
m_hwndParent = 0;
m_hwndTree = 0;
m_hwndContacts = 0;
m_pSite = NULL;
m_pTreeView = NULL;
m_pContacts = NULL;
m_pContactsFrame = NULL;
m_pContactsTarget = NULL;
m_cxWidth = 200;
m_fResizing = FALSE;
m_fSplitting = FALSE;
m_cySplitPct = 50;
ZeroMemory(&m_rcSplit, sizeof(RECT));
ZeroMemory(&m_rcSizeBorder, sizeof(RECT));
m_cyTitleBar = 32;
}
CNavPane::~CNavPane()
{
SafeRelease(m_pContactsFrame);
}
HRESULT CNavPane::Initialize(CTreeView *pTreeView)
{
// We've got to have this
if (!pTreeView)
return (E_INVALIDARG);
// Keep it
m_pTreeView = pTreeView;
m_pTreeView->AddRef();
// Load some settings
m_cxWidth = DwGetOption(OPT_NAVPANEWIDTH);
if (m_cxWidth < 0)
m_cxWidth = 200;
m_cySplitPct = DwGetOption(OPT_NAVPANESPLIT);
// Do some parameter checking
if (m_cySplitPct > 100 || m_cySplitPct < 2)
m_cySplitPct = 66;
return (S_OK);
}
//
// FUNCTION: CNavPane::QueryInterface()
//
// PURPOSE: Allows caller to retrieve the various interfaces supported by
// this class.
//
HRESULT CNavPane::QueryInterface(REFIID riid, LPVOID *ppvObj)
{
TraceCall("CNavPane::QueryInterface");
*ppvObj = NULL;
if (IsEqualIID(riid, IID_IUnknown))
*ppvObj = (LPVOID) (IDockingWindow *) this;
else if (IsEqualIID(riid, IID_IDockingWindow))
*ppvObj = (LPVOID) (IDockingWindow *) this;
else if (IsEqualIID(riid, IID_IObjectWithSite))
*ppvObj = (LPVOID) (IObjectWithSite *) this;
else if (IsEqualIID(riid, IID_IOleCommandTarget))
*ppvObj = (LPVOID) (IOleCommandTarget *) this;
else if (IsEqualIID(riid, IID_IInputObjectSite))
*ppvObj = (LPVOID) (IInputObjectSite *) this;
else if (IsEqualIID(riid, IID_IInputObject))
*ppvObj = (LPVOID) (IInputObject *) this;
if (*ppvObj)
{
AddRef();
return (S_OK);
}
return (E_NOINTERFACE);
}
//
// FUNCTION: CNavPane::AddRef()
//
// PURPOSE: Adds a reference count to this object.
//
ULONG CNavPane::AddRef(void)
{
TraceCall("CNavPane::AddRef");
return ((ULONG) InterlockedIncrement((LONG *) &m_cRef));
}
//
// FUNCTION: CNavPane::Release()
//
// PURPOSE: Releases a reference on this object.
//
ULONG CNavPane::Release(void)
{
TraceCall("CNavPane::Release");
if (0 == InterlockedDecrement((LONG *) &m_cRef))
{
delete this;
return 0;
}
return (m_cRef);
}
//
// FUNCTION: CNavPane::GetWindow()
//
// PURPOSE: Returns the handle of our outer window
//
// PARAMETERS:
// [out] pHwnd - return value
//
// RETURN VALUE:
// HRESULT
//
HRESULT CNavPane::GetWindow(HWND *pHwnd)
{
TraceCall("CNavPane::GetWindow");
if (!pHwnd)
return (E_INVALIDARG);
if (IsWindow(m_hwnd))
{
*pHwnd = m_hwnd;
return (S_OK);
}
return (E_FAIL);
}
//
// FUNCTION: CNavPane::ContextSensitiveHelp()
//
// PURPOSE: Does anyone _ever_ implement this?
//
HRESULT CNavPane::ContextSensitiveHelp(BOOL fEnterMode)
{
TraceCall("CNavPane::ContextSensitiveHelp");
return (E_NOTIMPL);
}
//
// FUNCTION: CNavPane::ShowDW()
//
// PURPOSE: Show's or hides the Nav pane. If the pane has not yet been
// created it does that too.
//
// PARAMETERS:
// [in] fShow - TRUE to show, FALSE to hide
//
// RETURN VALUE:
// HRESULT
//
HRESULT CNavPane::ShowDW(BOOL fShow)
{
HRESULT hr;
WNDCLASSEX wc;
TraceCall("CNavPane::ShowDW");
// Nothing works without a site pointer
if (!m_pSite)
return (E_UNEXPECTED);
// Check to see if we've been created yet
if (!m_hwnd)
{
// Register the window class if necessary
wc.cbSize = sizeof(WNDCLASSEX);
if (!GetClassInfoEx(g_hInst, c_szNavPaneClass, &wc))
{
wc.style = 0;
wc.lpfnWndProc = _WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hCursor = LoadCursor(0, IDC_SIZEWE);
wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = c_szNavPaneClass;
wc.hIcon = NULL;
wc.hIconSm = NULL;
RegisterClassEx(&wc);
}
// Get the parent window before we create ours
if (FAILED(m_pSite->GetWindow(&m_hwndParent)))
{
AssertSz(FALSE, "CNavPane::ShowDW() - Failed to get a parent window handle.");
}
// Create the window
m_hwnd = CreateWindowEx(WS_EX_CONTROLPARENT, c_szNavPaneClass, NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
0, 0, 10, 10, m_hwndParent, (HMENU) 0, g_hInst, this);
if (!m_hwnd)
{
AssertSz(FALSE, "CNavPane::ShowDW() - Failed to create main window.");
return (E_OUTOFMEMORY);
}
// Create any children
if (FAILED(hr = _CreateChildWindows()))
{
AssertSz(FALSE, "CNavPane::ShowDW() - Failed to create child windows.");
DestroyWindow(m_hwnd);
return (hr);
}
}
// Show or hide the window appropriately
m_fShow = (fShow && (m_fTreeVisible || m_fContactsVisible));
ResizeBorderDW(0, 0, FALSE);
ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE);
return (S_OK);
}
//
// FUNCTION: CNavPane::ResizeBorderDW()
//
// PURPOSE: Called when it's time for us to re-request space from our
// parent.
//
// PARAMETERS:
// [in] prcBorder - a RECT containing the outer rectangle the object can request space in
// [in] punkSite - pointer to the site that changed
// [in] fReserved - unused.
//
// RETURN VALUE:
// HRESULT
//
HRESULT CNavPane::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkSite, BOOL fReserved)
{
const DWORD c_cxResizeBorder = 3;
HRESULT hr = S_OK;
RECT rcRequest = { 0 };
RECT rcBorder;
TraceCall("CNavPane::ResizeBorderDW");
// If we don't have a site pointer, this ain't gonna work
if (!m_pSite)
return (E_UNEXPECTED);
// If we visible, then calculate our border requirements. If we're not
// visible, the our requirements are zero and we can use the default
// values in rcRequest.
Assert(IsWindow(m_hwnd));
// If the caller didn't provide us with a rect, get one ourselves
if (!prcBorder)
{
m_pSite->GetBorderDW((IDockingWindow *) this, &rcBorder);
prcBorder = &rcBorder;
}
// The space we need is the min of either what we want to be or the
// width of the parent minus some
if (m_fShow)
{
rcRequest.left = min(prcBorder->right - prcBorder->left - 32, m_cxWidth);
}
// Ask for the space we need
if (SUCCEEDED(m_pSite->RequestBorderSpaceDW((IDockingWindow *) this, &rcRequest)))
{
// Tell the site how be we're going to be
if (SUCCEEDED(m_pSite->SetBorderSpaceDW((IDockingWindow *) this, &rcRequest)))
{
// Now once that's all done, resize ourselves if we're visible
if (m_fShow)
{
SetWindowPos(m_hwnd, 0, prcBorder->left, prcBorder->top, rcRequest.left,
prcBorder->bottom - prcBorder->top, SWP_NOZORDER | SWP_NOACTIVATE);
}
}
}
return (S_OK);
}
//
// FUNCTION: CNavPane::CloseDW()
//
// PURPOSE: Called when the parent want's to destroy this window
//
// PARAMETERS:
// [in] dwReserved - unused
//
// RETURN VALUE:
// HRESULT
//
HRESULT CNavPane::CloseDW(DWORD dwReserved)
{
TraceCall("CNavPane::CloseDW");
// Save our settings
SetDwOption(OPT_NAVPANEWIDTH, m_cxWidth, NULL, 0);
SetDwOption(OPT_NAVPANESPLIT, m_cySplitPct, NULL, 0);
if (m_pTreeView)
m_pTreeView->DeInit();
if (m_hwnd)
{
DestroyWindow(m_hwnd);
m_hwnd = NULL;
}
// Destroy our children here
SafeRelease(m_pTreeView);
SafeRelease(m_pContactsTarget);
SafeRelease(m_pContacts);
return (S_OK);
}
//
// FUNCTION: CNavPane::GetSite()
//
// PURPOSE: Called to request an interface to our site
//
// PARAMETERS:
// [in] riid - Requested interface
// [out] ppvSite - Returned interface if available
//
// RETURN VALUE:
// HRESULT
//
HRESULT CNavPane::GetSite(REFIID riid, LPVOID *ppvSite)
{
HRESULT hr;
TraceCall("CNavPane::GetSite");
if (m_pSite)
{
// Ask our site for the requested interface
hr = m_pSite->QueryInterface(riid, ppvSite);
return (hr);
}
return (E_FAIL);
}
//
// FUNCTION: CNavPane::SetSite()
//
// PURPOSE: Called to tell us who our site will be.
//
// PARAMETERS:
// [in] pUnkSite - Pointer to the new site
//
// RETURN VALUE:
// HRESULT
//
HRESULT CNavPane::SetSite(IUnknown *pUnkSite)
{
HRESULT hr = S_OK;
TraceCall("CNavPane::SetSite");
// If we already have a site, release it
if (m_pSite)
{
m_pSite->Release();
m_pSite = 0;
}
// If we were given a new site, keep it
if (pUnkSite)
{
hr = pUnkSite->QueryInterface(IID_IDockingWindowSite, (LPVOID *) &m_pSite);
return (hr);
}
return (hr);
}
//
// FUNCTION: CNavPane::_WndProc()
//
// PURPOSE: External callback.
//
LRESULT CALLBACK CNavPane::_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CNavPane *pThis;
if (uMsg == WM_NCCREATE)
{
pThis = (CNavPane *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis);
}
else
pThis = (CNavPane *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (pThis)
return (pThis->_NavWndProc(hwnd, uMsg, wParam, lParam));
return (FALSE);
}
//
// FUNCTION: CNavPane::_NavWndProc()
//
// PURPOSE: Left as an exercise for the reader
//
LRESULT CALLBACK CNavPane::_NavWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hwnd, WM_SETCURSOR, _OnSetCursor);
HANDLE_MSG(hwnd, WM_SIZE, _OnSize);
HANDLE_MSG(hwnd, WM_MOUSEMOVE, _OnMouseMove);
HANDLE_MSG(hwnd, WM_LBUTTONDOWN, _OnLButtonDown);
HANDLE_MSG(hwnd, WM_LBUTTONUP, _OnLButtonUp);
case WM_SYSCOLORCHANGE:
case WM_WININICHANGE:
{
// Forward these to all our children
if (IsWindow(m_hwndTree))
SendMessage(m_hwndTree, uMsg, wParam, lParam);
if (IsWindow(m_hwndContacts))
SendMessage(m_hwndContacts, uMsg, wParam, lParam);
// Update any of our own sizes
m_cyTitleBar =(UINT) SendMessage(m_hwndTree, WM_GET_TITLE_BAR_HEIGHT, 0, 0);
return (0);
}
}
return (DefWindowProc(hwnd, uMsg, wParam, lParam));
}
//
// FUNCTION: CNavPane::_OnSize()
//
// PURPOSE: When our window get's resized, we need to resize our child
// windows too.
//
void CNavPane::_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
RECT rc;
DWORD cyTree;
DWORD cySplit = c_cySplit;
TraceCall("CNavPane::_OnSize");
// If only the tree is visible
if (m_fTreeVisible && !m_fContactsVisible)
cyTree = cy;
else if (m_fTreeVisible && m_fContactsVisible)
cyTree = (cy * m_cySplitPct) / 100;
else if (!m_fTreeVisible && m_fContactsVisible)
{
cyTree = 0;
cySplit = 0;
}
// Resize the TreeView to fit inside our window
if (m_hwndTree)
SetWindowPos(m_hwndTree, 0, 0, 0, cx - c_cxSplit, cyTree, SWP_NOZORDER | SWP_NOACTIVATE);
if (m_hwndContacts)
SetWindowPos(m_hwndContacts, 0, 0, cyTree + cySplit, cx - 3, cy - cyTree - cySplit, SWP_NOZORDER | SWP_NOACTIVATE);
// Figure out where a few things are, starting with the split bar
SetRect(&rc, c_cxBorder, cyTree, cx - c_cxSplit - c_cxBorder, cyTree + cySplit);
m_rcSplit = rc;
// Figure out where the right side is
SetRect(&rc, cx - c_cxSplit, 0, cx, cy);
m_rcSizeBorder = rc;
}
//
// FUNCTION: CNavPane::_OnLButtonDown()
//
// PURPOSE: When the user clicks down and we get this notification, it
// must be because they want to resize.
//
void CNavPane::_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
TraceCall("CNavPane::_OnLButtonDown");
if (!m_fResizing)
{
SetCapture(hwnd);
m_fResizing = TRUE;
POINT pt = {x, y};
if (PtInRect(&m_rcSplit, pt))
{
m_fSplitting = TRUE;
}
}
}
//
// FUNCTION: CNavPane::_OnMouseMove()
//
// PURPOSE: If we're resizing, update our position etc.
//
void CNavPane::_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
{
POINT pt = {x, y};
RECT rcClient;
TraceCall("CNavPane::_OnMouseMove");
if (m_fResizing)
{
if (m_fSplitting)
{
GetClientRect(m_hwnd, &rcClient);
m_cySplitPct = (int)(((float) pt.y / (float) rcClient.bottom) * 100);
// Make sure we have the min's and max's right
int cy = (rcClient.bottom * m_cySplitPct) / 100;
if (cy < m_cyTitleBar)
{
m_cySplitPct = (int)(((float) m_cyTitleBar / (float) rcClient.bottom) * 100);
}
else if (rcClient.bottom - cy < m_cyTitleBar)
{
m_cySplitPct = (int)(((float) (rcClient.bottom - m_cyTitleBar) / (float) rcClient.bottom) * 100);
}
_OnSize(hwnd, 0, rcClient.right, rcClient.bottom);
}
else
{
if (pt.x > 32)
{
GetClientRect(m_hwndParent, &rcClient);
m_cxWidth = max(0, min(pt.x, rcClient.right - 32));
ResizeBorderDW(0, 0, FALSE);
}
}
}
}
//
// FUNCTION: CNavPane::_OnLButtonUp()
//
// PURPOSE: If the user was resizing, then they're done now and we can
// clean up.
//
void CNavPane::_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
{
TraceCall("CNavPane::_OnLButtonUp");
if (m_fResizing)
{
ReleaseCapture();
m_fResizing = FALSE;
m_fSplitting = FALSE;
}
}
//
// FUNCTION: CNavPane::_OnSetCursor()
//
// PURPOSE: Do some jimmying with the cursor
//
BOOL CNavPane::_OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg)
{
POINT pt;
TraceCall("_OnSetCursor");
// Get the cursor position
GetCursorPos(&pt);
ScreenToClient(m_hwnd, &pt);
// If the cursor is within the split bar, update the cursor
if (PtInRect(&m_rcSplit, pt))
{
SetCursor(LoadCursor(NULL, IDC_SIZENS));
return (TRUE);
}
if (PtInRect(&m_rcSizeBorder, pt))
{
SetCursor(LoadCursor(NULL, IDC_SIZEWE));
return (TRUE);
}
return (FALSE);
}
//
// FUNCTION: CNavPane::_OnNCHitTest()
//
// PURPOSE: We monkey around with the non client area to get the correct
// cursors
//
// PARAMETERS:
// [in] hwnd - Window handle the mouse is in
// [in] x, y - Position of the mouse in screen coordinates
//
// RETURN VALUE:
// Our personal opinion of where the mouse is.
//
UINT CNavPane::_OnNCHitTest(HWND hwnd, int x, int y)
{
POINT pt = {x, y};
// If the cursor is in the split bar
if (PtInRect(&m_rcSplit, pt))
return (HTTOP);
if (PtInRect(&m_rcSizeBorder, pt))
return (HTRIGHT);
return (HTCLIENT);
}
//
// FUNCTION: CNavPane::_CreateChildWindows()
//
// PURPOSE: Creates the child windows that will be displayed.
//
// RETURN VALUE:
// HRESULT
//
HRESULT CNavPane::_CreateChildWindows(void)
{
IOleWindow *pWindow = NULL;
IInputObject *pInputObj = NULL;
HRESULT hr;
TraceCall("CNavPane::_CreateChildWindows");
// The treeview is always created by the browser. All we have to do
// is tell it to create it's UI.
m_hwndTree = m_pTreeView->Create(m_hwnd, (IInputObjectSite *) this, TRUE);
Assert(m_hwndTree);
// If the tree is supposed to be visible, show it
if (DwGetOption(OPT_SHOWTREE))
{
ShowWindow(m_hwndTree, SW_SHOW);
m_fTreeVisible = TRUE;
m_cyTitleBar = (UINT) SendMessage(m_hwndTree, WM_GET_TITLE_BAR_HEIGHT, 0, 0);
}
// If we're showing contacts, create it
if (DwGetOption(OPT_SHOWCONTACTS) && (!(g_dwAthenaMode & MODE_OUTLOOKNEWS)))
{
ShowContacts(TRUE);
}
return (S_OK);
}
//
// FUNCTION: CNavPane::ShowFolderList()
//
// PURPOSE: Shows and hides the folder list doodad
//
// PARAMETERS:
// BOOL fShow
//
BOOL CNavPane::ShowFolderList(BOOL fShow)
{
TraceCall("CNavPane::ShowFolderList");
// The folder list _always_ exists. We just toggle the state
ShowWindow(m_hwndTree, fShow ? SW_SHOW : SW_HIDE);
m_fTreeVisible = fShow;
_UpdateVisibleState();
RECT rc;
GetClientRect(m_hwnd, &rc);
_OnSize(m_hwnd, 0, rc.right, rc.bottom);
return (TRUE);
}
//
// FUNCTION: CNavPane::ShowContacts()
//
// PURPOSE:
//
// PARAMETERS:
// BOOL fShow
//
// RETURN VALUE:
// BOOL
//
BOOL CNavPane::ShowContacts(BOOL fShow)
{
CMsgrAb *pMsgrAb;
HWND hwnd;
IAthenaBrowser *pBrowser;
HRESULT hr;
RECT rc = {0};
if (!m_pContacts)
{
hr = CreateMsgrAbCtrl(&m_pContacts);
if (SUCCEEDED(hr))
{
// Initialize the control
m_pContactsFrame = new CPaneFrame();
if (!m_pContactsFrame)
return (0);
m_hwndContacts = m_pContactsFrame->Initialize(m_hwnd, this, idsABBandTitle, IDR_BA_TITLE_POPUP);
pMsgrAb = (CMsgrAb *) m_pContacts;
hwnd = pMsgrAb->CreateControlWindow(m_hwndContacts, rc);
if (hwnd)
{
if (SUCCEEDED(m_pSite->QueryInterface(IID_IAthenaBrowser, (LPVOID *) &pBrowser)))
{
m_pContactsFrame->SetChild(hwnd, DISPID_MSGVIEW_CONTACTS, pBrowser, pMsgrAb, pMsgrAb);
pBrowser->Release();
}
}
// Get the command target
m_pContacts->QueryInterface(IID_IOleCommandTarget, (LPVOID *) &m_pContactsTarget);
}
}
SetWindowPos(m_hwndContacts, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
ShowWindow(m_hwndContacts, fShow ? SW_SHOW : SW_HIDE);
m_fContactsVisible = fShow;
_UpdateVisibleState();
GetClientRect(m_hwnd, &rc);
_OnSize(m_hwnd, 0, rc.right, rc.bottom);
return (TRUE);
}
//
// FUNCTION: CNavPane::_UpdateVisibleState()
//
// PURPOSE: Checks to see if we need to show our hide ourselves
//
void CNavPane::_UpdateVisibleState(void)
{
// If this leaves us with nothing visible, then we hide ourselves
if (!m_fTreeVisible && !m_fContactsVisible)
{
ShowWindow(m_hwnd, SW_HIDE);
m_fShow = FALSE;
ResizeBorderDW(0, 0, 0);
}
else if (m_fShow == FALSE && (m_fTreeVisible || m_fContactsVisible))
{
// Show ourselves
m_fShow = TRUE;
ShowWindow(m_hwnd, SW_SHOW);
ResizeBorderDW(0, 0, 0);
}
}
HRESULT CNavPane::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[],
OLECMDTEXT *pCmdText)
{
if (m_pContactsTarget)
{
for (UINT i = 0; i < cCmds; i++)
{
if (prgCmds[i].cmdf == 0 && prgCmds[i].cmdID == ID_CONTACTS_MNEMONIC)
{
prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
}
}
}
if (m_pContactsTarget)
return (m_pContactsTarget->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText));
return (S_OK);
}
HRESULT CNavPane::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt,
VARIANTARG *pvaIn, VARIANTARG *pvaOut)
{
if (m_pContactsTarget && nCmdID == ID_CONTACTS_MNEMONIC)
{
m_pContactsFrame->ShowMenu();
return (S_OK);
}
if (m_pContactsTarget)
return (m_pContactsTarget->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut));
return (OLECMDERR_E_NOTSUPPORTED);
}
BOOL CNavPane::IsContactsFocus(void)
{
IInputObject *pInputObject = 0;
HRESULT hr = S_FALSE;
if (m_pContacts)
{
if (SUCCEEDED(m_pContacts->QueryInterface(IID_IInputObject, (LPVOID *) &pInputObject)))
{
hr = pInputObject->HasFocusIO();
pInputObject->Release();
return (S_OK == hr);
}
}
return (S_OK == hr);
}
HRESULT CNavPane::OnFocusChangeIS(IUnknown *punkSrc, BOOL fSetFocus)
{
// Simply call through to our host
UnkOnFocusChangeIS(m_pSite, (IInputObject*) this, fSetFocus);
return (S_OK);
}
HRESULT CNavPane::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
{
if (fActivate)
{
UnkOnFocusChangeIS(m_pSite, (IInputObject *) this, TRUE);
SetFocus(m_hwnd);
}
return (S_OK);
}
HRESULT CNavPane::HasFocusIO(void)
{
if (m_hwnd == 0)
return (S_FALSE);
HWND hwndFocus = GetFocus();
return (hwndFocus == m_hwnd || IsChild(m_hwnd, hwndFocus)) ? S_OK : S_FALSE;
}
HRESULT CNavPane::TranslateAcceleratorIO(LPMSG pMsg)
{
if (m_pTreeView && (m_pTreeView->HasFocusIO() == S_OK))
return m_pTreeView->TranslateAcceleratorIO(pMsg);
if (m_pContacts && (UnkHasFocusIO(m_pContacts) == S_OK))
return UnkTranslateAcceleratorIO(m_pContacts, pMsg);
return (S_FALSE);
}
/////////////////////////////////////////////////////////////////////////////
// CPaneFrame
//
CPaneFrame::CPaneFrame()
{
m_cRef = 1;
m_hwnd = 0;
m_hwndChild = 0;
m_hwndParent = 0;
m_szTitle[0] = 0;
m_hFont = 0;
m_hbr3DFace = 0;
m_cyTitleBar = 0;
m_fHighlightIndicator = FALSE;
m_fHighlightPressed = FALSE;
ZeroMemory(&m_rcTitleButton, sizeof(RECT));
m_hwndClose = 0;
m_cButtons = 1;
m_pBrowser = NULL;
m_dwDispId = 0;
m_pTarget = 0;
m_idMenu = 0;
m_fPin = FALSE;
}
CPaneFrame::~CPaneFrame()
{
if (m_hFont != 0)
DeleteObject(m_hFont);
if (m_hbr3DFace != 0)
DeleteObject(m_hbr3DFace);
}
//
// FUNCTION: CPaneFrame::Initialize()
//
// PURPOSE: Initializes the frame by telling the pane what it's title
// should be.
//
// PARAMETERS:
// [in] hwndParent
// [in] idsTitle
//
// RETURN VALUE:
// HWND
//
HWND CPaneFrame::Initialize(HWND hwndParent, IInputObjectSite *pSite, int idsTitle, int idMenu)
{
WNDCLASSEX wc;
TraceCall("CPaneFrame::Initialize");
// This should be NULL
Assert(NULL == m_hwnd);
// Save this for later
m_hwndParent = hwndParent;
m_idMenu = idMenu;
m_pSite = pSite;
// Load the title
AthLoadString(idsTitle, m_szTitle, ARRAYSIZE(m_szTitle));
// Register the window class if necessary
wc.cbSize = sizeof(WNDCLASSEX);
if (!GetClassInfoEx(g_hInst, c_szPaneFrameClass, &wc))
{
wc.style = 0;
wc.lpfnWndProc = _WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = c_szPaneFrameClass;
wc.hIcon = NULL;
wc.hIconSm = NULL;
RegisterClassEx(&wc);
}
// Create the window
m_hwnd = CreateWindowEx(WS_EX_CONTROLPARENT, c_szPaneFrameClass, m_szTitle,
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
0, 0, 0, 0, hwndParent, 0, g_hInst, this);
if (!m_hwnd)
{
AssertSz(m_hwnd, "CPaneFrame::Initialize() - Failed to create a frame");
return (0);
}
return (m_hwnd);
}
//
// FUNCTION: CPaneFrame::SetChild()
//
// PURPOSE: Allows the owner to tell us what the child window handle is.
//
BOOL CPaneFrame::SetChild(HWND hwndChild, DWORD dwDispId, IAthenaBrowser *pBrowser,
IObjectWithSite *pObject, IOleCommandTarget *pTarget)
{
TraceCall("CPaneFrame::SetChild");
if (IsWindow(hwndChild))
{
m_hwndChild = hwndChild;
if (pBrowser)
{
m_pBrowser = pBrowser;
m_dwDispId = dwDispId;
}
if (pObject)
{
pObject->SetSite((IInputObjectSite *) this);
}
if (pTarget)
{
m_pTarget = pTarget;
}
return (TRUE);
}
return (FALSE);
}
void CPaneFrame::ShowMenu(void)
{
if (m_idMenu)
{
_OnLButtonDown(m_hwnd, 0, m_rcTitleButton.left, m_rcTitleButton.top, 0);
}
}
//
// FUNCTION: CPaneFrame::QueryInterface()
//
// PURPOSE: Allows caller to retrieve the various interfaces supported by
// this class.
//
HRESULT CPaneFrame::QueryInterface(REFIID riid, LPVOID *ppvObj)
{
TraceCall("CPaneFrame::QueryInterface");
*ppvObj = NULL;
if (IsEqualIID(riid, IID_IUnknown))
*ppvObj = (LPVOID) (IInputObjectSite *) this;
else if (IsEqualIID(riid, IID_IInputObjectSite))
*ppvObj = (LPVOID) (IInputObjectSite *) this;
if (*ppvObj)
{
AddRef();
return (S_OK);
}
return (E_NOINTERFACE);
}
//
// FUNCTION: CPaneFrame::AddRef()
//
// PURPOSE: Adds a reference count to this object.
//
ULONG CPaneFrame::AddRef(void)
{
TraceCall("CPaneFrame::AddRef");
return ((ULONG) InterlockedIncrement((LONG *) &m_cRef));
}
//
// FUNCTION: CPaneFrame::Release()
//
// PURPOSE: Releases a reference on this object.
//
ULONG CPaneFrame::Release(void)
{
TraceCall("CPaneFrame::Release");
if (0 == InterlockedDecrement((LONG *) &m_cRef))
{
delete this;
return 0;
}
return (m_cRef);
}
HRESULT CPaneFrame::OnFocusChangeIS(IUnknown *punkSrc, BOOL fSetFocus)
{
// Simply call through to our host
UnkOnFocusChangeIS(m_pSite, (IInputObject*) this, fSetFocus);
return (S_OK);
}
//
// FUNCTION: CPaneFrame::_WndProc()
//
// PURPOSE: External callback.
//
LRESULT CALLBACK CPaneFrame::_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CPaneFrame *pThis;
if (uMsg == WM_NCCREATE)
{
pThis = (CPaneFrame *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis);
}
else
pThis = (CPaneFrame *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (pThis)
return (pThis->_FrameWndProc(hwnd, uMsg, wParam, lParam));
return (FALSE);
}
//
// FUNCTION: CPaneFrame::_FrameWndProc()
//
// PURPOSE: Left as an exercise for the reader
//
LRESULT CALLBACK CPaneFrame::_FrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hwnd, WM_CREATE, _OnCreate);
HANDLE_MSG(hwnd, WM_SIZE, _OnSize);
HANDLE_MSG(hwnd, WM_PAINT, _OnPaint);
HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand);
HANDLE_MSG(hwnd, WM_MOUSEMOVE, _OnMouseMove);
HANDLE_MSG(hwnd, WM_LBUTTONDOWN, _OnLButtonDown);
HANDLE_MSG(hwnd, WM_TIMER, _OnTimer);
case WM_TOGGLE_CLOSE_PIN:
_OnToggleClosePin(hwnd, (BOOL) lParam);
return (0);
case WM_GET_TITLE_BAR_HEIGHT:
return (m_cyTitleBar + (c_cyBorder * 2) + 1);
case WM_SYSCOLORCHANGE:
case WM_WININICHANGE:
{
// Forward these to all our children
if (IsWindow(m_hwndChild))
SendMessage(m_hwndChild, uMsg, wParam, lParam);
_UpdateDrawingInfo();
break;
}
case WM_SETFOCUS:
{
if (m_hwndChild && ((HWND)wParam) != m_hwndChild)
SetFocus(m_hwndChild);
break;
}
}
return (DefWindowProc(hwnd, uMsg, wParam, lParam));
}
//
// FUNCTION: CPaneFrame::_OnCreate()
//
// PURPOSE: Loads some info that will be handy later
//
BOOL CPaneFrame::_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
TraceCall("CPaneFrame::_OnCreate");
m_hwnd = hwnd;
_UpdateDrawingInfo();
_CreateCloseToolbar();
return (TRUE);
}
//
// FUNCTION: CPaneFrame::_OnSize()
//
// PURPOSE: Resizes our child to fit in the right place
//
void CPaneFrame::_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
TraceCall("CPaneFrame::_OnSize");
m_rcChild.left = c_cyBorder;
m_rcChild.top = m_cyTitleBar;
m_rcChild.right = cx - (2 * c_cyBorder);
m_rcChild.bottom = cy - m_cyTitleBar - c_cyBorder;
if (m_hwndChild)
SetWindowPos(m_hwndChild, 0, m_rcChild.left, m_rcChild.top, m_rcChild.right,
m_rcChild.bottom, SWP_NOZORDER | SWP_NOACTIVATE);
POINT pt = {cx, cy};
_PositionToolbar(&pt);
// Invalidate the title area
RECT rc = m_rcChild;
rc.top = 0;
rc.bottom = m_rcChild.top;
InvalidateRect(m_hwnd, &rc, FALSE);
rc.left = 0;
rc.right = c_cyBorder;
rc.bottom = cy;
InvalidateRect(m_hwnd, &rc, FALSE);
rc.left = cx - c_cyBorder;
rc.right = cx;
InvalidateRect(m_hwnd, &rc, FALSE);
}
//
// FUNCTION: CPaneFrame::_OnPaint()
//
// PURPOSE: Called when it's time to paint our borders and title area.
//
void CPaneFrame::_OnPaint(HWND hwnd)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rc;
RECT rcClient;
POINT pt[3];
HBRUSH hBrush,
hBrushOld;
HPEN hPen,
hPenOld;
// Get our window size
GetClientRect(m_hwnd, &rcClient);
rc = rcClient;
// Start painting
hdc = BeginPaint(hwnd, &ps);
// Draw a simple edge around or window
DrawEdge(hdc, &rc, BDR_SUNKENOUTER, BF_TOPRIGHT | BF_BOTTOMLEFT);
// Now draw a raised edge around our title bar area
InflateRect(&rc, -1, -1);
rc.bottom = m_cyTitleBar;
DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_TOPRIGHT | BF_BOTTOMLEFT);
// Paint the background
InflateRect(&rc, -c_cxBorder, -c_cyBorder);
FillRect(hdc, &rc, m_hbr3DFace);
// Now draw some groovy text
SelectFont(hdc, m_hFont);
SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
// Draw the text
InflateRect(&rc, -c_cxTextBorder, -c_cyTextBorder);
if (!m_fPin)
{
DrawText(hdc, m_szTitle, -1, &rc, DT_CALCRECT | DT_VCENTER | DT_LEFT);
DrawText(hdc, m_szTitle, -1, &rc, DT_VCENTER | DT_LEFT);
}
else
{
TCHAR sz[CCHMAX_STRINGRES];
AthLoadString(idsPushPinInfo, sz, ARRAYSIZE(sz));
IDrawText(hdc, sz, &rc, DT_VCENTER | DT_END_ELLIPSIS | DT_LEFT,
rc.bottom - rc.top);
DrawText(hdc, sz, -1, &rc, DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_LEFT);
}
// Drop-down indicator
if (m_idMenu)
{
COLORREF crFG = GetSysColor(COLOR_WINDOWTEXT);
pt[0].x = rc.right + 6;
pt[0].y = (m_cyTitleBar - 6) / 2 + 2;
pt[1].x = pt[0].x + 6;
pt[1].y = pt[0].y;
pt[2].x = pt[0].x + 3;
pt[2].y = pt[0].y + 3;
hPen = CreatePen(PS_SOLID, 1, crFG);
hBrush = CreateSolidBrush(crFG);
hPenOld = SelectPen(hdc, hPen);
hBrushOld = SelectBrush(hdc, hBrush);
Polygon(hdc, pt, 3);
SelectPen(hdc, hPenOld);
SelectBrush(hdc, hBrushOld);
DeleteObject(hPen);
DeleteObject(hBrush);
if (m_fHighlightIndicator)
{
rc = m_rcTitleButton;
DrawEdge(hdc, &rc, m_fHighlightPressed ? BDR_SUNKENOUTER : BDR_RAISEDINNER,
BF_TOPRIGHT | BF_BOTTOMLEFT);
}
}
EndPaint(hwnd, &ps);
}
//
// FUNCTION: _OnCommand()
//
// PURPOSE: We get the occasional command now and again
//
void CPaneFrame::_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch (id)
{
case ID_PANE_CLOSE:
{
if (m_pBrowser)
m_pBrowser->SetViewLayout(m_dwDispId, LAYOUT_POS_NA, FALSE, 0, 0);
return;
}
case ID_PANE_PIN:
{
SendMessage(m_hwndChild, WMR_CLICKOUTSIDE, CLK_OUT_DEACTIVATE, 0);
if (m_pBrowser)
m_pBrowser->SetViewLayout(m_dwDispId, LAYOUT_POS_NA, TRUE, 0, 0);
return;
}
}
return;
}
//
// FUNCTION: CPaneFrame::_OnToggleClosePin()
//
// PURPOSE: Sent to the frame when we should change the close button
// to a pin button.
//
// PARAMETERS:
// [in] fPin - TRUE to turn the Pin on, FALSE to turn it off.
//
void CPaneFrame::_OnToggleClosePin(HWND hwnd, BOOL fPin)
{
TraceCall("CPaneFrame::_OnToggleClosePin");
if (fPin)
{
static const TBBUTTON tb[] =
{
{ 2, ID_PANE_PIN, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}
};
SendMessage(m_hwndClose, TB_DELETEBUTTON, 0, 0);
SendMessage(m_hwndClose, TB_ADDBUTTONS, ARRAYSIZE(tb), (LPARAM) tb);
SendMessage(m_hwndClose, TB_SETHOTITEM, (WPARAM) -1, 0);
m_fPin = TRUE;
}
else
{
static const TBBUTTON tb[] =
{
{ 1, ID_PANE_CLOSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}
};
SendMessage(m_hwndClose, TB_DELETEBUTTON, 0, 0);
SendMessage(m_hwndClose, TB_ADDBUTTONS, ARRAYSIZE(tb), (LPARAM) tb);
SendMessage(m_hwndClose, TB_SETHOTITEM, (WPARAM) -1, 0);
m_fPin = FALSE;
}
}
//
// FUNCTION: CPaneFrame::_UpdateDrawingInfo()
//
// PURPOSE: When we get created or when the user changes their settings,
// we need to reload our fonts, colors, and sizes.
//
void CPaneFrame::_UpdateDrawingInfo(void)
{
LOGFONT lf;
TEXTMETRIC tm;
HDC hdc;
TraceCall("CPaneFrame::_UpdateDrawingInfo");
if (m_hFont)
DeleteObject(m_hFont);
// Figure out which font to use
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, FALSE);
// Create the font
m_hFont = CreateFontIndirect(&lf);
// Get the metrics of this font
hdc = GetDC(m_hwnd);
SelectFont(hdc, m_hFont);
GetTextMetrics(hdc, &tm);
// Calculate the height
m_cyTitleBar = tm.tmHeight + (2 * c_cyBorder) + (2 * c_cyTextBorder);
RECT rc = {2 * c_cxBorder, 2 * c_cyBorder, 0, m_cyTitleBar - c_cyBorder};
SIZE s;
GetTextExtentPoint32(hdc, m_szTitle, lstrlen(m_szTitle), &s);
m_rcTitleButton = rc;
m_rcTitleButton.right = 14 + (2 * c_cxTextBorder) + s.cx + (2 * c_cxBorder);
ReleaseDC(m_hwnd, hdc);
// Get the brush we need
if (m_hbr3DFace)
DeleteObject(m_hbr3DFace);
m_hbr3DFace = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
}
//
// FUNCTION: CPaneFrame::_CreateCloseToolbar()
//
// PURPOSE: Creates the toolbar that has our close button
//
void CPaneFrame::_CreateCloseToolbar()
{
CHAR szTitle[255];
TraceCall("CPaneFrame::_CreateCloseToolbar");
AthLoadString(idsHideFolders, szTitle, ARRAYSIZE(szTitle));
m_hwndClose = CreateWindowEx(0, TOOLBARCLASSNAME, szTitle,
WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT | TBSTYLE_CUSTOMERASE |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOMOVEY |
CCS_NOPARENTALIGN | CCS_NORESIZE,
0, c_cyClose, 30, 15, m_hwnd, 0, g_hInst, NULL);
if (m_hwndClose)
{
static const TBBUTTON tb[] =
{
{ 1, ID_PANE_CLOSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}
};
SendMessage(m_hwndClose, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
SendMessage(m_hwndClose, TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG(11, 9));
TBADDBITMAP tbab = { g_hLocRes, idbClosePin };
SendMessage(m_hwndClose, TB_ADDBITMAP, 4, (LPARAM) &tbab);
SendMessage(m_hwndClose, TB_ADDBUTTONS, ARRAYSIZE(tb), (LPARAM) tb);
SendMessage(m_hwndClose, TB_SETINDENT, 0, 0);
_SizeCloseToolbar();
}
}
//
// FUNCTION: CPaneFrame::_SizeCloseToolbar()
//
// PURPOSE: Set's the size of the toolbar appropriately.
//
void CPaneFrame::_SizeCloseToolbar(void)
{
TraceCall("CPaneFrame::_SizeCloseToolbar");
RECT rc;
LONG lButtonSize;
GetWindowRect(m_hwndClose, &rc);
lButtonSize = (LONG) SendMessage(m_hwndClose, TB_GETBUTTONSIZE, 0, 0L);
SetWindowPos(m_hwndClose, NULL, 0, 0, LOWORD(lButtonSize) * m_cButtons,
rc.bottom - rc.top, SWP_NOMOVE | SWP_NOACTIVATE);
_PositionToolbar(NULL);
}
//
// FUNCTION: CPaneFrame::_PositionToolbar()
//
// PURPOSE: Does the work of correctly positioning the close button
// toolbar.
//
// PARAMETERS:
// LPPOINT ppt
//
void CPaneFrame::_PositionToolbar(LPPOINT ppt)
{
TraceCall("CPaneFrame::_PositionToolbar");
if (m_hwndClose)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
if (ppt)
{
rc.left = 0;
rc.right = ppt->x;
}
RECT rcTB;
GetWindowRect(m_hwndClose, &rcTB);
rc.left = rc.right - (rcTB.right - rcTB.left) - 3;
DWORD top = max((int) ((m_cyTitleBar - (rcTB.bottom - rcTB.top)) / 2) + 1, 0);
SetWindowPos(m_hwndClose, HWND_TOP, rc.left, top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
}
}
void CPaneFrame::_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
POINT pt = {x, y};
UINT id;
if (m_idMenu && PtInRect(&m_rcTitleButton, pt))
{
m_fHighlightPressed = TRUE;
InvalidateRect(m_hwnd, &m_rcTitleButton, TRUE);
UpdateWindow(m_hwnd);
HMENU hMenu = LoadPopupMenu(m_idMenu);
MenuUtil_EnablePopupMenu(hMenu, m_pTarget);
if (m_idMenu == IDR_BA_TITLE_POPUP && ((g_dwHideMessenger == BL_HIDE) || (g_dwHideMessenger == BL_DISABLE)))
{
DeleteMenu(hMenu, ID_NEW_ONLINE_CONTACT, MF_BYCOMMAND);
DeleteMenu(hMenu, ID_SET_ONLINE_CONTACT, MF_BYCOMMAND);
DeleteMenu(hMenu, SEP_MESSENGER, MF_BYCOMMAND);
DeleteMenu(hMenu, ID_SORT_BY_NAME, MF_BYCOMMAND);
DeleteMenu(hMenu, ID_SORT_BY_STATUS, MF_BYCOMMAND);
}
pt.x = m_rcTitleButton.left;
pt.y = m_rcTitleButton.bottom;
ClientToScreen(m_hwnd, &pt);
id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
pt.x, pt.y, m_hwnd, NULL);
if (id)
{
m_pTarget->Exec(NULL, id, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
}
m_fHighlightPressed = m_fHighlightIndicator = FALSE;
KillTimer(m_hwnd, IDT_PANETIMER);
InvalidateRect(m_hwnd, &m_rcTitleButton, TRUE);
UpdateWindow(m_hwnd);
if(hMenu)
{
//Bug #101329 - (erici) Destroy leaked MENU.
BOOL bMenuDestroyed = DestroyMenu(hMenu);
Assert(bMenuDestroyed);
}
}
}
void CPaneFrame::_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
{
POINT pt = {x, y};
if (m_idMenu && (m_fHighlightIndicator != PtInRect(&m_rcTitleButton, pt)))
{
m_fHighlightIndicator = !m_fHighlightIndicator;
InvalidateRect(m_hwnd, &m_rcTitleButton, TRUE);
if (m_fHighlightIndicator)
SetTimer(m_hwnd, IDT_PANETIMER, ELAPSE_MOUSEOVERCHECK, NULL);
else
KillTimer(m_hwnd, IDT_PANETIMER);
}
}
void CPaneFrame::_OnTimer(HWND hwnd, UINT id)
{
RECT rcClient;
POINT pt;
DWORD dw;
dw = GetMessagePos();
pt.x = LOWORD(dw);
pt.y = HIWORD(dw);
ScreenToClient(m_hwnd, &pt);
if (id == IDT_PANETIMER)
{
GetClientRect(m_hwnd, &rcClient);
// No need to handle mouse in client area, OnMouseMove will catch this. We
// only need to catch the mouse moving out of the client area.
if (!PtInRect(&rcClient, pt) && !m_fHighlightPressed)
{
KillTimer(m_hwnd, IDT_PANETIMER);
m_fHighlightIndicator = FALSE;
InvalidateRect(m_hwnd, &m_rcTitleButton, TRUE);
}
}
}