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
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);
|
|
}
|
|
}
|
|
}
|