820 lines
22 KiB
C++
820 lines
22 KiB
C++
|
// TaskFrame.cpp : Implementation of CTaskUIApp and DLL registration.
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "TaskFrame.h"
|
||
|
#include "cbsc.h"
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Create and initialize an instance of the task frame.
|
||
|
//
|
||
|
HRESULT
|
||
|
CTaskFrame::CreateInstance( // [static]
|
||
|
IPropertyBag *pPropertyBag,
|
||
|
ITaskPageFactory *pPageFactory,
|
||
|
CComObject<CTaskFrame> **ppFrameOut
|
||
|
)
|
||
|
{
|
||
|
ASSERT(NULL != pPropertyBag);
|
||
|
ASSERT(NULL != pPageFactory);
|
||
|
ASSERT(!IsBadWritePtr(ppFrameOut, sizeof(*ppFrameOut)));
|
||
|
|
||
|
CComObject<CTaskFrame> *pFrame;
|
||
|
HRESULT hr = CComObject<CTaskFrame>::CreateInstance(&pFrame);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pFrame->_Init(pPropertyBag, pPageFactory);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
pFrame->AddRef();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
delete pFrame;
|
||
|
pFrame = NULL;
|
||
|
}
|
||
|
}
|
||
|
*ppFrameOut = pFrame;
|
||
|
|
||
|
ASSERT(SUCCEEDED(hr) || NULL == *ppFrameOut);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
CTaskFrame::CTaskFrame()
|
||
|
: m_pPropertyBag(NULL), m_pPageFactory(NULL), m_pUIParser(NULL),
|
||
|
m_hwndNavBar(NULL), m_hwndStatusBar(NULL),
|
||
|
m_himlNBDef(NULL), m_himlNBHot(NULL), m_pbmWatermark(NULL)
|
||
|
{
|
||
|
SetRectEmpty(&m_rcPage);
|
||
|
m_ptMinSize.x = m_ptMinSize.y = 0;
|
||
|
|
||
|
// DUI initialization
|
||
|
InitThread();
|
||
|
}
|
||
|
|
||
|
|
||
|
CTaskFrame::~CTaskFrame()
|
||
|
{
|
||
|
Close();
|
||
|
|
||
|
// m_dpaHistory is self-destructing
|
||
|
|
||
|
if (m_himlNBDef)
|
||
|
ImageList_Destroy(m_himlNBDef);
|
||
|
if (m_himlNBHot)
|
||
|
ImageList_Destroy(m_himlNBHot);
|
||
|
|
||
|
ATOMICRELEASE(m_pPropertyBag);
|
||
|
ATOMICRELEASE(m_pPageFactory);
|
||
|
|
||
|
delete m_pbmWatermark;
|
||
|
delete m_pUIParser;
|
||
|
|
||
|
// DUI shutdown
|
||
|
UnInitThread();
|
||
|
}
|
||
|
|
||
|
void CALLBACK TaskUIParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine)
|
||
|
{
|
||
|
//#if DBG
|
||
|
#if 1
|
||
|
WCHAR buf[201];
|
||
|
|
||
|
if (dLine != -1)
|
||
|
swprintf(buf, L"%s '%s' at line %d", pszError, pszToken, dLine);
|
||
|
else
|
||
|
swprintf(buf, L"%s '%s'", pszError, pszToken);
|
||
|
|
||
|
MessageBoxW(NULL, buf, L"Parser Message", MB_OK);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
HRESULT CTaskFrame::_Init(IPropertyBag* pBag, ITaskPageFactory* pPageFact)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (!pBag || !pPageFact)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
m_pPropertyBag = pBag;
|
||
|
m_pPropertyBag->AddRef();
|
||
|
|
||
|
m_pPageFactory = pPageFact;
|
||
|
m_pPageFactory->AddRef();
|
||
|
|
||
|
m_iCurrentPage = -1;
|
||
|
|
||
|
hr = Parser::Create(IDR_TASKUI_UI, _Module.GetResourceInstance(), TaskUIParseError, &m_pUIParser);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
if (m_pUIParser->WasParseError())
|
||
|
return E_FAIL;
|
||
|
|
||
|
CWndClassInfo& wci = GetWndClassInfo();
|
||
|
if (!wci.m_atom)
|
||
|
{
|
||
|
// Modify wndclass here if necessary
|
||
|
wci.m_wc.style &= ~(CS_HREDRAW | CS_VREDRAW);
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HWND CTaskFrame::CreateFrameWindow(HWND hwndOwner, UINT nID, LPVOID pParam)
|
||
|
{
|
||
|
if (NULL == m_pPropertyBag)
|
||
|
return NULL;
|
||
|
|
||
|
// Register the AtlAxHost window class, etc.
|
||
|
AtlAxWinInit();
|
||
|
|
||
|
// Default window styles & dimensions
|
||
|
DWORD dwWndStyle = GetWndStyle(0); // WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
|
||
|
DWORD dwWndExStyle = GetWndExStyle(0); // WS_EX_APPWINDOW | WS_EX_WINDOWEDGE
|
||
|
RECT rcFrame = CWindow::rcDefault; // { CW_USEDEFAULT, CW_USEDEFAULT, 0, 0 }
|
||
|
|
||
|
CComVariant var;
|
||
|
|
||
|
// Get the initial window dimensions from the property bag
|
||
|
if (SUCCEEDED(_ReadProp(TS_PROP_WIDTH, VT_I4, var)))
|
||
|
{
|
||
|
rcFrame.right = rcFrame.left + var.lVal;
|
||
|
}
|
||
|
if (SUCCEEDED(_ReadProp(TS_PROP_HEIGHT, VT_I4, var)))
|
||
|
{
|
||
|
rcFrame.bottom = rcFrame.top + var.lVal;
|
||
|
}
|
||
|
|
||
|
// See if we're resizable. Default is TRUE;
|
||
|
m_bResizable = TRUE;
|
||
|
if (SUCCEEDED(_ReadProp(TS_PROP_RESIZABLE, VT_BOOL, var)))
|
||
|
{
|
||
|
m_bResizable = (VARIANT_TRUE == var.boolVal);
|
||
|
}
|
||
|
if (m_bResizable)
|
||
|
{
|
||
|
// Resizable: get minimum dimensions if provided
|
||
|
if (SUCCEEDED(_ReadProp(TS_PROP_MINWIDTH, VT_I4, var)))
|
||
|
{
|
||
|
m_ptMinSize.x = var.lVal;
|
||
|
}
|
||
|
if (SUCCEEDED(_ReadProp(TS_PROP_MINHEIGHT, VT_I4, var)))
|
||
|
{
|
||
|
m_ptMinSize.y = var.lVal;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No resize: switch to a simple border style and don't allow maximize
|
||
|
dwWndStyle = (dwWndStyle & ~(WS_THICKFRAME | WS_MAXIMIZEBOX)) | WS_BORDER;
|
||
|
}
|
||
|
|
||
|
// See if we're modeless. Default is FALSE (modal).
|
||
|
BOOL bModeless = FALSE;
|
||
|
if (SUCCEEDED(_ReadProp(TS_PROP_MODELESS, VT_BOOL, var)))
|
||
|
{
|
||
|
bModeless = (VARIANT_TRUE == var.boolVal);
|
||
|
}
|
||
|
if (!bModeless)
|
||
|
{
|
||
|
// Modal
|
||
|
|
||
|
if (!m_bResizable)
|
||
|
dwWndExStyle |= WS_EX_DLGMODALFRAME;
|
||
|
|
||
|
// If not a top-level window, disallow minimize
|
||
|
if (hwndOwner)
|
||
|
dwWndStyle &= ~WS_MINIMIZEBOX;
|
||
|
}
|
||
|
|
||
|
// Get the application graphics
|
||
|
if (SUCCEEDED(_ReadProp(TS_PROP_WATERMARK, VT_BSTR, var)))
|
||
|
{
|
||
|
CComPtr<IStream> spStream;
|
||
|
HRESULT hr = BindToURL(var.bstrVal, &spStream);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Create GDI+ Bitmap from stream
|
||
|
delete m_pbmWatermark;
|
||
|
m_pbmWatermark = Bitmap::FromStream(spStream);
|
||
|
if (NULL != m_pbmWatermark && (Ok != m_pbmWatermark->GetLastStatus()))
|
||
|
{
|
||
|
delete m_pbmWatermark;
|
||
|
m_pbmWatermark = NULL;
|
||
|
}
|
||
|
// Later, when creating a page, set m_pbmWatermark as content of the
|
||
|
// "Picture" element
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Get the window title from the property bag
|
||
|
CComVariant varTitle;
|
||
|
if (FAILED(_ReadProp(TS_PROP_TITLE, VT_BSTR, varTitle)))
|
||
|
{
|
||
|
// Use NULL for no title
|
||
|
varTitle.bstrVal = NULL;
|
||
|
}
|
||
|
|
||
|
dwWndExStyle |= WS_EX_CONTROLPARENT;
|
||
|
|
||
|
return Create(hwndOwner, rcFrame, varTitle.bstrVal, dwWndStyle, dwWndExStyle, nID, pParam);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CTaskFrame::ShowPage(REFCLSID rclsidNewPage, BOOL bTrimHistory)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
int iPage;
|
||
|
TaskPage *pSavePage = NULL;
|
||
|
|
||
|
if (!m_dpaHistory.IsValid())
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
// m_iCurrentPage = -1 should only occur when Count = 0
|
||
|
ASSERT(-1 != m_iCurrentPage || 0 == m_dpaHistory.Count());
|
||
|
|
||
|
// If we don't have any pages, then we can't trim the history
|
||
|
if (-1 == m_iCurrentPage)
|
||
|
bTrimHistory = FALSE;
|
||
|
|
||
|
// First remove any forward pages from the history.
|
||
|
// Note that we never remove the first page (index 0).
|
||
|
for (iPage = m_dpaHistory.Count() - 1; iPage > 0 && iPage > m_iCurrentPage; iPage--)
|
||
|
{
|
||
|
TaskPage *pPage = m_dpaHistory[iPage];
|
||
|
ASSERT(NULL != pPage);
|
||
|
|
||
|
// Optimization: if we are navigating forward and the next page
|
||
|
// is the page we want, go directly there and reinitialize it.
|
||
|
if (!bTrimHistory && iPage == m_iCurrentPage+1 && rclsidNewPage == pPage->GetID())
|
||
|
{
|
||
|
hr = _ActivatePage(iPage, TRUE);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
_SetNavBarState();
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_dpaHistory.Remove(iPage);
|
||
|
|
||
|
// TODO OPTIMIZATION: cache the page
|
||
|
_DestroyPage(pPage);
|
||
|
}
|
||
|
|
||
|
// Either m_iCurrentPage = -1 and Count = 0, or
|
||
|
// m_iCurrentPage is the last page (Count-1) since
|
||
|
// we just truncated the history.
|
||
|
ASSERT(m_iCurrentPage + 1 == m_dpaHistory.Count());
|
||
|
|
||
|
iPage = m_iCurrentPage;
|
||
|
_DeactivateCurrentPage(); // sets m_iCurrentPage to -1
|
||
|
|
||
|
if (bTrimHistory)
|
||
|
{
|
||
|
// Can't delete this guy right right away since he's still
|
||
|
// processing messages (this is the page we just deactivated).
|
||
|
pSavePage = m_dpaHistory[iPage];
|
||
|
|
||
|
// Work backwards looking for rclsidNewPage, trimming as we go.
|
||
|
// Note that we never remove the first page (index 0).
|
||
|
while (0 < iPage)
|
||
|
{
|
||
|
TaskPage *pPage = m_dpaHistory[iPage];
|
||
|
ASSERT(NULL != pPage);
|
||
|
|
||
|
if (rclsidNewPage == pPage->GetID())
|
||
|
break;
|
||
|
|
||
|
m_dpaHistory.Remove(iPage);
|
||
|
if (pSavePage != pPage)
|
||
|
{
|
||
|
// TODO OPTIMIZATION: cache the page
|
||
|
_DestroyPage(pPage);
|
||
|
}
|
||
|
|
||
|
--iPage;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create a new page if necessary
|
||
|
TaskPage *pNewPage = NULL;
|
||
|
TaskPage *pCurrentPage = (-1 == iPage) ? NULL : m_dpaHistory[iPage];
|
||
|
if (NULL == pCurrentPage || rclsidNewPage != pCurrentPage->GetID())
|
||
|
{
|
||
|
hr = _CreatePage(rclsidNewPage, &pNewPage);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
iPage = m_dpaHistory.Append(pNewPage);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr) || -1 == iPage)
|
||
|
{
|
||
|
// Something bad happened, try to activate the home page
|
||
|
if (0 < m_dpaHistory.Count())
|
||
|
{
|
||
|
_ActivatePage(0);
|
||
|
}
|
||
|
if (NULL != pNewPage)
|
||
|
{
|
||
|
_DestroyPage(pNewPage);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Show the page
|
||
|
hr = _ActivatePage(iPage, NULL != pNewPage ? FALSE : TRUE);
|
||
|
}
|
||
|
|
||
|
_SetNavBarState();
|
||
|
|
||
|
if (pSavePage)
|
||
|
{
|
||
|
// TODO: need to free this guy later (currently leaked)
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CTaskFrame::Back(UINT cPages)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (-1 == m_iCurrentPage || 0 == m_dpaHistory.Count())
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
hr = S_FALSE;
|
||
|
|
||
|
if (0 < m_iCurrentPage)
|
||
|
{
|
||
|
int iNewPage;
|
||
|
|
||
|
ASSERT(m_iCurrentPage < m_dpaHistory.Count());
|
||
|
|
||
|
if (0 == cPages)
|
||
|
iNewPage = m_iCurrentPage - 1;
|
||
|
else if (cPages > (UINT)m_iCurrentPage)
|
||
|
iNewPage = 0;
|
||
|
else // cPages > 0 && cPages <= m_iCurrentPage
|
||
|
iNewPage = m_iCurrentPage - cPages;
|
||
|
|
||
|
hr = _ActivatePage(iNewPage);
|
||
|
}
|
||
|
|
||
|
_SetNavBarState();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CTaskFrame::Forward()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (-1 == m_iCurrentPage || 0 == m_dpaHistory.Count())
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
hr = S_FALSE;
|
||
|
|
||
|
int iNewPage = m_iCurrentPage + 1;
|
||
|
if (iNewPage < m_dpaHistory.Count())
|
||
|
{
|
||
|
hr = _ActivatePage(iNewPage);
|
||
|
}
|
||
|
|
||
|
_SetNavBarState();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CTaskFrame::Home()
|
||
|
{
|
||
|
if (-1 == m_iCurrentPage || 0 == m_dpaHistory.Count())
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
HRESULT hr = _ActivatePage(0);
|
||
|
|
||
|
_SetNavBarState();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CTaskFrame::SetStatusText(LPCWSTR pszText)
|
||
|
{
|
||
|
if (NULL == m_hwndStatusBar)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
::SendMessageW(m_hwndStatusBar, SB_SETTEXT, SB_SIMPLEID, (LPARAM)pszText);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CTaskFrame::_ReadProp(LPCWSTR pszProp, VARTYPE vt, CComVariant& var)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
ASSERT(NULL != m_pPropertyBag);
|
||
|
|
||
|
var.Clear();
|
||
|
hr = m_pPropertyBag->Read(pszProp, &var, NULL);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = var.ChangeType(vt);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
LRESULT CTaskFrame::_OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
|
||
|
{
|
||
|
BOOL bNavBar;
|
||
|
BOOL bStatusBar;
|
||
|
CComVariant var;
|
||
|
|
||
|
ASSERT(NULL != m_pPropertyBag);
|
||
|
|
||
|
// See if we're supposed to show the NavBar. Default is TRUE.
|
||
|
bNavBar = TRUE;
|
||
|
if (SUCCEEDED(_ReadProp(TS_PROP_NAVBAR, VT_BOOL, var)))
|
||
|
{
|
||
|
bNavBar = (VARIANT_TRUE == var.boolVal);
|
||
|
}
|
||
|
if (bNavBar)
|
||
|
{
|
||
|
_CreateNavBar();
|
||
|
}
|
||
|
|
||
|
// See if we're supposed to show a status bar. Default is FALSE.
|
||
|
bStatusBar = FALSE;
|
||
|
if (SUCCEEDED(_ReadProp(TS_PROP_STATUSBAR, VT_BOOL, var)))
|
||
|
{
|
||
|
bStatusBar = (VARIANT_TRUE == var.boolVal);
|
||
|
}
|
||
|
if (bStatusBar)
|
||
|
{
|
||
|
DWORD dwStyle = WS_CHILD | WS_VISIBLE | CCS_BOTTOM;
|
||
|
if (m_bResizable)
|
||
|
dwStyle |= SBARS_SIZEGRIP;
|
||
|
m_hwndStatusBar = CreateStatusWindowW(dwStyle, NULL, m_hWnd, IDC_STATUSBAR);
|
||
|
}
|
||
|
|
||
|
// Force m_rcPage to be calculated
|
||
|
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
|
||
|
_OnSize(WM_SIZE, SIZE_RESTORED, MAKELONG(LOWORD(pcs->cx),LOWORD(pcs->cy)), bHandled);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
LRESULT CTaskFrame::_OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
|
||
|
{
|
||
|
if (SIZE_RESTORED == wParam || SIZE_MAXIMIZED == wParam)
|
||
|
{
|
||
|
GetClientRect(&m_rcPage);
|
||
|
|
||
|
if (m_hwndNavBar)
|
||
|
{
|
||
|
RECT rc;
|
||
|
::SendMessageW(m_hwndNavBar, uMsg, wParam, lParam);
|
||
|
::GetWindowRect(m_hwndNavBar, &rc);
|
||
|
m_rcPage.top += (rc.bottom - rc.top);
|
||
|
}
|
||
|
|
||
|
if (m_hwndStatusBar)
|
||
|
{
|
||
|
RECT rc;
|
||
|
::SendMessageW(m_hwndStatusBar, uMsg, wParam, lParam);
|
||
|
::GetWindowRect(m_hwndStatusBar, &rc);
|
||
|
m_rcPage.bottom -= (rc.bottom - rc.top);
|
||
|
}
|
||
|
|
||
|
// At this point, m_rcPage represents the remaining usable client
|
||
|
// area between the toolbar and statusbar.
|
||
|
|
||
|
if (-1 != m_iCurrentPage)
|
||
|
{
|
||
|
// Resize the current page. Other pages will be resized
|
||
|
// as necessary when we show them.
|
||
|
_SyncPageRect(m_dpaHistory[m_iCurrentPage]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
LRESULT CTaskFrame::_OnTBGetInfoTip(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
|
||
|
{
|
||
|
LPNMTBGETINFOTIP pgit = (LPNMTBGETINFOTIP)pnmh;
|
||
|
::LoadStringW(_Module.GetResourceInstance(), pgit->iItem, pgit->pszText, pgit->cchTextMax);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
LRESULT CTaskFrame::_OnTBCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
|
||
|
{
|
||
|
LPNMCUSTOMDRAW pcd = (LPNMCUSTOMDRAW)pnmh;
|
||
|
switch (pcd->dwDrawStage)
|
||
|
{
|
||
|
case CDDS_PREPAINT:
|
||
|
return CDRF_NOTIFYITEMERASE;
|
||
|
|
||
|
case CDDS_PREERASE:
|
||
|
FillRect(pcd->hdc, &pcd->rc, GetSysColorBrush(COLOR_3DFACE));
|
||
|
break;
|
||
|
}
|
||
|
return CDRF_DODEFAULT;
|
||
|
}
|
||
|
|
||
|
LRESULT CTaskFrame::_OnAppCommand(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
|
||
|
{
|
||
|
switch (GET_APPCOMMAND_LPARAM(lParam))
|
||
|
{
|
||
|
case APPCOMMAND_BROWSER_BACKWARD:
|
||
|
Back(1);
|
||
|
break;
|
||
|
|
||
|
case APPCOMMAND_BROWSER_FORWARD:
|
||
|
Forward();
|
||
|
break;
|
||
|
|
||
|
case APPCOMMAND_BROWSER_HOME:
|
||
|
Home();
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
bHandled = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
LRESULT CTaskFrame::_OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
|
||
|
{
|
||
|
((LPMINMAXINFO)lParam)->ptMinTrackSize = m_ptMinSize;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
#define NAVBAR_CX 16
|
||
|
|
||
|
void CTaskFrame::_CreateNavBar()
|
||
|
{
|
||
|
HINSTANCE hInst = _Module.GetResourceInstance();
|
||
|
const DWORD dwStyle = WS_CHILD | WS_VISIBLE | CCS_TOP | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_CUSTOMERASE | TBSTYLE_TOOLTIPS;
|
||
|
|
||
|
// Create the NavBar toolbar control
|
||
|
m_hwndNavBar = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS /*| TBSTYLE_EX_DOUBLEBUFFER*/,
|
||
|
TOOLBARCLASSNAME,
|
||
|
NULL,
|
||
|
dwStyle,
|
||
|
0, 0, 0, 0,
|
||
|
m_hWnd,
|
||
|
(HMENU)IDC_NAVBAR,
|
||
|
hInst,
|
||
|
NULL);
|
||
|
if (m_hwndNavBar)
|
||
|
{
|
||
|
::SendMessageW(m_hwndNavBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
|
||
|
|
||
|
int idBmp = IDB_NAVBAR;
|
||
|
|
||
|
if (SHGetCurColorRes() > 8)
|
||
|
idBmp += (IDB_NAVBARHICOLOR - IDB_NAVBAR);
|
||
|
|
||
|
m_himlNBDef = ImageList_LoadImageW(hInst,
|
||
|
MAKEINTRESOURCE(idBmp),
|
||
|
NAVBAR_CX,
|
||
|
0,
|
||
|
CLR_DEFAULT,
|
||
|
IMAGE_BITMAP,
|
||
|
LR_CREATEDIBSECTION);
|
||
|
if (m_himlNBDef)
|
||
|
::SendMessageW(m_hwndNavBar, TB_SETIMAGELIST, 0, (LPARAM)m_himlNBDef);
|
||
|
|
||
|
m_himlNBHot = ImageList_LoadImageW(hInst,
|
||
|
MAKEINTRESOURCE(idBmp+1),
|
||
|
NAVBAR_CX,
|
||
|
0,
|
||
|
CLR_DEFAULT,
|
||
|
IMAGE_BITMAP,
|
||
|
LR_CREATEDIBSECTION);
|
||
|
if (m_himlNBHot)
|
||
|
::SendMessageW(m_hwndNavBar, TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlNBHot);
|
||
|
|
||
|
if (!m_himlNBDef && !m_himlNBHot)
|
||
|
{
|
||
|
// Must be serious low memory or other resource problems.
|
||
|
// There's no point having a toolbar without any images.
|
||
|
::DestroyWindow(m_hwndNavBar);
|
||
|
m_hwndNavBar = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TCHAR szBack[64];
|
||
|
TBBUTTON rgButtons[] =
|
||
|
{
|
||
|
{0, ID_BACK, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, {0}, 0, (INT_PTR)szBack},
|
||
|
{1, ID_FORWARD, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, 0},
|
||
|
{2, ID_HOME, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, 0},
|
||
|
};
|
||
|
|
||
|
::LoadStringW(hInst, ID_BACK, szBack, ARRAYSIZE(szBack));
|
||
|
::SendMessageW(m_hwndNavBar, TB_ADDBUTTONSW, ARRAYSIZE(rgButtons), (LPARAM)rgButtons);
|
||
|
|
||
|
// This happens in _OnSize
|
||
|
//::SendMessageW(m_hwndNavBar, TB_AUTOSIZE, 0, 0);
|
||
|
}
|
||
|
|
||
|
_SetNavBarState();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CTaskFrame::_SetNavBarState()
|
||
|
{
|
||
|
if (m_hwndNavBar)
|
||
|
{
|
||
|
::SendMessage(m_hwndNavBar, TB_ENABLEBUTTON, ID_BACK, MAKELONG((m_iCurrentPage > 0), 0));
|
||
|
::SendMessage(m_hwndNavBar, TB_ENABLEBUTTON, ID_HOME, MAKELONG((m_iCurrentPage > 0), 0));
|
||
|
::SendMessage(m_hwndNavBar, TB_ENABLEBUTTON, ID_FORWARD, MAKELONG((m_iCurrentPage < m_dpaHistory.Count() - 1), 0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CTaskFrame::_CreatePage(REFCLSID rclsidPage, TaskPage **ppPage)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
ASSERT(NULL != ppPage);
|
||
|
*ppPage = NULL;
|
||
|
|
||
|
if (NULL == m_pPageFactory || NULL == m_pUIParser)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
// Get this page's ITaskPage interface from the App
|
||
|
CComPtr<ITaskPage> spTaskPage;
|
||
|
hr = m_pPageFactory->CreatePage(rclsidPage, IID_ITaskPage, (void**)&spTaskPage.p);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Give the ITaskPage our ITaskFrame interface
|
||
|
CComQIPtr<ITaskFrame> spThis(this);
|
||
|
if (spThis)
|
||
|
spTaskPage->SetFrame(spThis);
|
||
|
|
||
|
// Create an HWNDElement to contain and layout the page content
|
||
|
TaskPage *pNewPage;
|
||
|
hr = TaskPage::Create(rclsidPage, m_hWnd, &pNewPage);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
Element* pe; // dummy
|
||
|
|
||
|
// Fill contents from markup using substitution
|
||
|
hr = m_pUIParser->CreateElement(L"main", pNewPage, &pe);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
Element::StartDefer();
|
||
|
|
||
|
_SyncPageRect(pNewPage);
|
||
|
|
||
|
// Some examples of ways to add graphics to the page
|
||
|
|
||
|
Element* pe = pNewPage->FindDescendent(StrToID(L"Picture"));
|
||
|
|
||
|
//pe->SetContentGraphic(L"C:\\windows\\ua_bkgnd.bmp", GRAPHIC_EntireAlpha, 64);
|
||
|
//pe->SetContentGraphic(L"C:\\windows\\ua_bkgnd.bmp", GRAPHIC_TransColorAuto);
|
||
|
|
||
|
//Value* pv = Value::CreateGraphic(MAKEINTRESOURCE(IDB_BACKGROUND), GRAPHIC_TransColorAuto, 0, 0, 0, _Module.GetResourceInstance());
|
||
|
//pe->SetValue(Element::ContentProp, PI_Local, pv);
|
||
|
//pv->Release();
|
||
|
|
||
|
#ifdef GADGET_ENABLE_GDIPLUS
|
||
|
if (NULL != m_pbmWatermark)
|
||
|
{
|
||
|
Value* pv = Value::CreateGraphic(m_pbmWatermark);
|
||
|
pe->SetValue(Element::ContentProp, PI_Local, pv);
|
||
|
pv->Release();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
hr = pNewPage->CreateContent(spTaskPage);
|
||
|
|
||
|
Element::EndDefer();
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
*ppPage = pNewPage;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_DestroyPage(pNewPage);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CTaskFrame::_ActivatePage(int iPage, BOOL bInit)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
ASSERT(m_dpaHistory.IsValid());
|
||
|
ASSERT(0 < m_dpaHistory.Count());
|
||
|
ASSERT(iPage >= 0 && iPage < m_dpaHistory.Count());
|
||
|
|
||
|
TaskPage *pPage = m_dpaHistory[iPage];
|
||
|
|
||
|
ASSERT(NULL != pPage);
|
||
|
|
||
|
if (bInit)
|
||
|
{
|
||
|
hr = pPage->Reinitialize();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
// Can't reinitialize? Create a new instance instead.
|
||
|
TaskPage *pNewPage = NULL;
|
||
|
hr = _CreatePage(pPage->GetID(), &pNewPage);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
m_dpaHistory.Set(iPage, pNewPage);
|
||
|
_DestroyPage(pPage);
|
||
|
pPage = pNewPage;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (m_iCurrentPage != iPage)
|
||
|
{
|
||
|
_DeactivateCurrentPage();
|
||
|
}
|
||
|
|
||
|
// In case we were resized since we last showed this page
|
||
|
_SyncPageRect(pPage);
|
||
|
|
||
|
m_iCurrentPage = iPage;
|
||
|
::ShowWindow(pPage->GetHWND(), SW_SHOW);
|
||
|
::SetFocus(pPage->GetHWND());
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CTaskFrame::_DeactivateCurrentPage()
|
||
|
{
|
||
|
if (-1 != m_iCurrentPage)
|
||
|
{
|
||
|
ASSERT(m_dpaHistory.IsValid());
|
||
|
ASSERT(m_iCurrentPage >= 0 && m_iCurrentPage < m_dpaHistory.Count());
|
||
|
|
||
|
TaskPage *pPage = m_dpaHistory[m_iCurrentPage];
|
||
|
|
||
|
ASSERT(NULL != pPage);
|
||
|
|
||
|
m_iCurrentPage = -1;
|
||
|
::ShowWindow(pPage->GetHWND(), SW_HIDE);
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
void CTaskFrame::_SyncPageRect(TaskPage* pPage)
|
||
|
{
|
||
|
if (NULL != pPage)
|
||
|
{
|
||
|
Element::StartDefer();
|
||
|
|
||
|
pPage->SetX(m_rcPage.left);
|
||
|
pPage->SetY(m_rcPage.top);
|
||
|
pPage->SetWidth(m_rcPage.right-m_rcPage.left);
|
||
|
pPage->SetHeight(m_rcPage.bottom-m_rcPage.top);
|
||
|
|
||
|
Element::EndDefer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CTaskFrame::_DestroyPage(TaskPage* pPage)
|
||
|
{
|
||
|
if (NULL != pPage)
|
||
|
{
|
||
|
HWND hwndPage = pPage->GetHWND();
|
||
|
|
||
|
if (NULL != hwndPage && ::IsWindow(hwndPage))
|
||
|
{
|
||
|
// This causes pPage to be deleted
|
||
|
::DestroyWindow(hwndPage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If the window exists, this would not destroy it, so only
|
||
|
// do this when there is no window.
|
||
|
delete pPage;
|
||
|
}
|
||
|
}
|
||
|
}
|