#include "StdAfx.h"
#include "CeWnd.h"
#include "CeDialog.h"
#include "CeMisc.h"
#include "CeString.h"
#ifdef IDC_STATIC
#undef IDC_STATIC
#endif
#define IDC_STATIC (65535) // all static controls
CeSet<HWND, HWND> CeDialog::m_setModeless;
///////////////////////////////////////////////////////////////////////////////
//
// CeDialog - Dialog implementation class
//
///////////////////////////////////////////////////////////////////////////////
bool CeDialog::IsDialogMsg(MSG* pMsg)
{
HWND hWnd;
for (POSITION pos = m_setModeless.GetStartPosition(); NULL != pos; )
{
m_setModeless.GetNextAssoc(pos, hWnd);
if (::IsDialogMessage(hWnd, pMsg))
return true;
}
return false;
}
/*static*/
BOOL CALLBACK CeDialog::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CeDialog* pDlg = (CeDialog*) ::GetWindowLong(hDlg, DWL_USER);
// TRACE(_T("pDlg = %x, hDlg = %x, uMsg = 0x%x, wParam = %x, lParam = %x\n"), pDlg, hDlg, uMsg, wParam, lParam);
if (NULL == pDlg)
{
if (WM_INITDIALOG == uMsg)
{
pDlg = (CeDialog*) lParam;
CHW_ASSERT(ISVALIDPTR(pDlg, sizeof *pDlg));
::SetWindowLong(hDlg, DWL_USER, (LONG) pDlg);
pDlg->OnFirstMessage(hDlg);
pDlg->m_hWnd = hDlg;
}
else
{
//
// we don't know ANYTHING about this window
// this normally happens for the WM_SETFONT and 0x210 messages
//
//TRACE0("WARNING: Received dialog message from UNKNOWN WINDOW\n");
return FALSE;
}
}
else
{
CHW_ASSERT(ISVALIDPTR(pDlg, sizeof *pDlg));
CHW_ASSERT(pDlg->m_hWnd == hDlg);
}
// keep message for default call
pDlg->m_cemsg.hwnd = hDlg;
pDlg->m_cemsg.uMsg = uMsg;
pDlg->m_cemsg.wParam = wParam;
pDlg->m_cemsg.lParam = lParam;
bool bHandled = false; // not handled by default
// LRESULT lResult = 0;
// encapsulate external calls in exception handlers, CE doesn't do a
// good job of showing exception conditions in the UI
__try
{
//
// dialog procs differ from windows procs in the result value
// returned, save the result of the message handling and set that value
// as the DWL_MSGRESULT, return wether it was handled or not
// winprocs just return the value instead
//
LRESULT lResult = pDlg->ProcessMessage(uMsg, wParam, lParam, bHandled);
if (bHandled)
{
//
// for these messages just return, no need to set the DWL_MSGRESULT
//
switch (uMsg)
{
case WM_COMPAREITEM:
case WM_VKEYTOITEM:
case WM_CHARTOITEM:
case WM_INITDIALOG:
case WM_QUERYDRAGICON:
case WM_CTLCOLORMSGBOX:
case WM_CTLCOLOREDIT:
case WM_CTLCOLORLISTBOX:
case WM_CTLCOLORBTN:
case WM_CTLCOLORDLG:
case WM_CTLCOLORSCROLLBAR:
case WM_CTLCOLORSTATIC:
return lResult;
}
// set this immeaditely before returning or we may get trounced by another call
pDlg->SetWindowLong(DWL_MSGRESULT, lResult);
}
else
{
//pDlg->Default();
//bHandled = true;
}
if (_LAST_WM_MESSAGE == uMsg)
{
// we received the LAST message we're going to to get
// unsubclass the window
if (NULL != pDlg->m_lpfnOldWndProc)
::SetWindowLong(pDlg->m_hWnd, DWL_DLGPROC, (LONG) pDlg->m_lpfnOldWndProc);
// reset the user data (this pointer)
::SetWindowLong(pDlg->m_hWnd, DWL_USER, 0);
// clear out window handle
pDlg->m_hWnd = NULL;
// allow derived classes to clean up after window is destroyed
pDlg->OnFinalMessage(hDlg);
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
::MessageBox(NULL,
_T("Window message termainated abnormally by an exception"),
_T("Fatal"), MB_OK | MB_ICONSTOP);
}
// good-bye
return bHandled;
}
CeDialog::CeDialog(LPCTSTR lpTemplateName)
{
m_lpTemplateName = lpTemplateName;
m_bModal = false;
}
CeDialog::CeDialog(UINT nDlgID)
{
m_lpTemplateName = MAKEINTRESOURCE(nDlgID);
m_bModal = false;
}
CeDialog::~CeDialog()
{
if (! m_bModal)
m_setModeless.RemoveKey(m_hWnd);
}
BOOL CeDialog::Create(LPCTSTR lpTemplateName, HWND hWndParent, HINSTANCE hInst)
{
CHW_ASSERT(NULL == m_hWnd); // don't create twice
CHW_ASSERT(hWndParent != NULL); // need a parent/owner for modeless/child dialogs
m_bModal = false;
if (NULL == lpTemplateName)
lpTemplateName = m_lpTemplateName;
if (hInst == NULL)
// use the applications instance if the user didn't specify
hInst = CeGetAppInstance();
CHW_ASSERT(NULL != hInst);
CHW_ASSERT(NULL != lpTemplateName);
HWND hDlg = ::CreateDialogParam(hInst,
lpTemplateName,
hWndParent,
(DLGPROCCAST) DlgProc,
(LPARAM) this);
m_setModeless.AddKey(m_hWnd);
return (hDlg != NULL && hDlg == m_hWnd);
}
int CeDialog::DoModal(LPCTSTR lpTemplateName, HWND hWndParent, HINSTANCE hInst)
{
CHW_ASSERT(NULL == m_hWnd);
m_bModal = true;
if (NULL == lpTemplateName)
lpTemplateName = m_lpTemplateName;
if (hInst == NULL)
// use the applications instance if the user didn't specify
hInst = CeGetAppInstance();
if (hWndParent == NULL)
// use the main/app window if not specified
hWndParent = CeGetAppWindow();
else if (::GetWindowLong(hWndParent, GWL_STYLE) & WS_CHILD)
hWndParent = GetTopLevelWindow();
CHW_ASSERT(NULL != hInst);
CHW_ASSERT(NULL != lpTemplateName);
CHW_ASSERT(NULL != hWndParent);
return ::DialogBoxParam(hInst,
lpTemplateName,
hWndParent,
(DLGPROCCAST) DlgProc,
(LPARAM) this);
}
///////////////////////////////////////////////////////////////////////////////
//
// Default - Calls either the default window procedure or the
// subclassed window procedure for the active message
//
///////////////////////////////////////////////////////////////////////////////
LRESULT CeDialog::Default()
{
if (m_lpfnOldWndProc)
{
// we subclassed somebody elses dialog proc
#ifdef STRICT
return ::CallWindowProc((WNDPROC) m_lpfnOldWndProc, m_cemsg.hwnd,
m_cemsg.uMsg, m_cemsg.wParam, m_cemsg.lParam);
#else
return ::CallWindowProc((FARPROC) m_lpfnOldWndProc, m_cemsg.hwnd,
m_cemsg.uMsg, m_cemsg.wParam, m_cemsg.lParam);
#endif
}
else
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
//
// CeDialog::ProcessMessage -
//
///////////////////////////////////////////////////////////////////////////////
LRESULT CeDialog::ProcessMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
LRESULT lRet = 0;
switch (uMsg)
{
case WM_INITDIALOG:
bHandled = true;
return OnInitDialog();
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
// In Windows CE (starting with 3.0) you no longer
// get a BN_CLICKED, instead you get the control ID
// and a 0x1000
case IDCANCEL:
//if (HIWORD(wParam) == BN_CLICKED)
OnCancel();
bHandled = true;
break;
case IDOK:
//if (HIWORD(wParam) == BN_CLICKED)
OnOK();
bHandled = true;
break;
case IDC_STATIC:
if (HIWORD(wParam) == STN_CLICKED)
{
HWND hStatic = (HWND) lParam;
HWND hNext = ::GetWindow(hStatic, GW_HWNDNEXT);
CeString str(hStatic), strNext(hNext);
TRACE(_T("%s / %s\n"), (LPCTSTR) str, (LPCTSTR) strNext);
if (hNext != NULL)
SendMessage(WM_NEXTDLGCTL, (WPARAM) hNext, MAKELPARAM(TRUE, 0));
}
bHandled = true;
break;
default:
lRet = OnCommand(wParam, lParam, bHandled);
}
return FALSE;
default:
lRet = CeMsgWnd::ProcessMessage(uMsg, wParam, lParam, bHandled);
break;
}
return lRet;
}
///////////////////////////////////////////////////////////////////////////////
//
// Dialog message virtual functions
//
///////////////////////////////////////////////////////////////////////////////
// special message, handled by default
BOOL CeDialog::OnInitDialog()
{
if (m_bModal)
CenterWindow();
return TRUE;
}
void CeDialog::OnCancel()
{
if (m_bModal)
EndDialog(IDCANCEL);
TRACE0("CeDialog: OnCancel()\n");
}
void CeDialog::OnOK()
{
if (m_bModal)
EndDialog(IDOK);
TRACE0("CeDialog: OnOK()\n");
}
///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
BOOL CeScrollDialog::OnInitDialog()
{
CeDialog::OnInitDialog();
CeRect rect;
GetClientRect(&rect);
m_cxOrig = rect.Width();
m_cyOrig = rect.Height();
m_bVertSBVisible = FALSE;
m_bHorzSBVisible = FALSE;
m_bInit = TRUE;
// adjust window size, if desired by caller
if (0 != m_nWidth || 0 != m_nHeight)
{
CeRect rect;
int nSBVWidth = ::GetSystemMetrics(SM_CXVSCROLL);
int nSBHHeight = ::GetSystemMetrics(SM_CYHSCROLL);
GetWindowRect(&rect);
int nWidth = (0 == m_nWidth ? rect.Width() + nSBVWidth : m_nWidth);
int nHeight = (0 == m_nHeight ? rect.Height() + nSBHHeight : m_nHeight);
MoveWindow(rect.TopLeft().x, rect.TopLeft().y, nWidth, nHeight);
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
LRESULT CeScrollDialog::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
switch (uMsg)
{
case WM_VSCROLL:
bHandled = true;
OnVScroll((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND) lParam);
break;
case WM_HSCROLL:
bHandled = true;
OnHScroll((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND) lParam);
break;
}
return 0;
}
int CeScrollDialog::SetScrollInfo(int fnBar, int nMin, int nMax, int nPage)
{
SCROLLINFO scrollinfo;
scrollinfo.cbSize = sizeof(scrollinfo);
scrollinfo.fMask = SIF_PAGE | SIF_RANGE;
scrollinfo.nMin = nMin;
scrollinfo.nMax = nMax;
scrollinfo.nPage = nPage;
return CeDialog::SetScrollInfo(fnBar, &scrollinfo);
}
///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
void CeScrollDialog::OnSize(UINT nType, int cx, int cy, bool& bHandled)
{
CeDialog::OnSize(nType, cx, cy, bHandled);
if (! m_bInit || SIZE_RESTORED != nType)
return;
bHandled = true;
if (cy < m_cyOrig)
{
// make scrollbar visible, if necessary
if (! m_bVertSBVisible)
{
/* THIS DOESN'T WORK; window does not stay widened
// widen the window
{
CeRect rect;
int nSBWidth = ::GetSystemMetrics(SM_CXVSCROLL);
GetWindowRect(&rect);
MoveWindow(rect.TopLeft().x, rect.TopLeft().y,
rect.Width()+nSBWidth, rect.Height());
}
*/
// ShowScrollBar(SB_VERT, TRUE);
m_bVertSBVisible = TRUE;
}
int nPos = GetScrollPos(SB_VERT);
// check for need to scroll window
if (nPos + cy > m_cyOrig)
{
ScrollWindowEx(0, (nPos + cy) - m_cyOrig, SW_ERASE|SW_INVALIDATE|SW_SCROLLCHILDREN);
nPos = m_cyOrig - cy;
}
// set the range
SetScrollInfo(SB_VERT, 0, m_cyOrig - 1, cy);
// adjust scroll position
SetScrollPos(SB_VERT, nPos);
}
else
{
// make scrollbar invisible, if necessary
if (m_bVertSBVisible)
{
ShowScrollBar(SB_VERT, FALSE);
m_bVertSBVisible = FALSE;
// set the range to empty
SetScrollInfo(SB_VERT, 0, m_cyOrig - 1, cy);
/* THIS DOESN'T WORK; window does not stay narrowed
// narrow the window
{
CeRect rect;
int nSBWidth = ::GetSystemMetrics(SM_CXVSCROLL);
GetWindowRect(&rect);
MoveWindow(rect.TopLeft().x, rect.TopLeft().y,
rect.Width()-nSBWidth, rect.Height());
}
*/
}
}
if (cx < m_cxOrig)
{
// make scrollbar visible, if necessary
if (!m_bHorzSBVisible)
{
ShowScrollBar(SB_HORZ, TRUE);
m_bHorzSBVisible = TRUE;
}
int nPos = GetScrollPos(SB_HORZ);
// check for need to scroll window
if (nPos + cx > m_cxOrig)
{
ScrollWindowEx((nPos + cx) - m_cxOrig, 0,
SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN );
nPos = m_cxOrig - cx;
}
// set scrollbar parameters
SetScrollInfo(SB_HORZ, 0, m_cxOrig-1, cx);
// adjust scroll position
SetScrollPos(SB_HORZ, nPos);
}
else
{
// make scrollbar invisible, if necessary
if (m_bHorzSBVisible)
{
// set scrollbar parameters - empty hides them
SetScrollInfo(SB_HORZ, 0, m_cxOrig-1, cx);
ShowScrollBar(SB_HORZ, FALSE);
m_bHorzSBVisible = FALSE;
}
}
}
// scroll amount that corresponds to a "line"
static const int LINE_AMOUNT=20;
///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
void CeScrollDialog::OnHScroll(UINT nSBCode, UINT nPos, HWND hScroll)
{
UNUSED_ALWAYS(hScroll);
if (! m_bHorzSBVisible)
// nothing; no scrollbar
return;
int nMin, nMax, nNew, nOrig = GetScrollPos(SB_HORZ);
CeRect rect;
GetClientRect(&rect);
GetScrollRange(SB_HORZ, &nMin, &nMax);
switch (nSBCode)
{
case SB_BOTTOM: nNew = nMax; break;
case SB_LINERIGHT: nNew = nOrig + LINE_AMOUNT; break;
case SB_LINELEFT: nNew = nOrig - LINE_AMOUNT; break;
case SB_PAGEDOWN: nNew = nOrig + rect.Width(); break;
case SB_PAGEUP: nNew = nOrig - rect.Width(); break;
case SB_TOP: nNew = 0; break;
//�Drag scroll box to specified position.
// The current position is provided in nPos.
case SB_THUMBTRACK: nNew = nPos; break;
default:
nNew = nOrig;
break;
}
if (nNew < 0)
nNew = 0;
else
{
int nLimit = nMax - rect.Width() + 1;
if (nNew > nLimit)
nNew = nLimit;
}
TRACE(_T("H: New: %d Orig: %d Min: %d Max: %d\n"),
nNew, nOrig, nMin, nMax);
if (nNew != nOrig)
{
ScrollWindowEx(nOrig-nNew, 0, SW_ERASE|SW_INVALIDATE|SW_SCROLLCHILDREN);
SetScrollPos(SB_HORZ, nNew);
}
}
///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
void CeScrollDialog::OnVScroll(UINT nSBCode, UINT nPos, HWND hScroll)
{
if (! m_bVertSBVisible)
// nothing; no scrollbar
return;
int nMin, nMax, nNew, nOrig = GetScrollPos(SB_VERT);
CeRect rect;
GetClientRect(&rect);
GetScrollRange(SB_VERT, &nMin, &nMax);
switch (nSBCode)
{
case SB_BOTTOM: nNew = nMax; break;
case SB_LINEDOWN: nNew = nOrig + LINE_AMOUNT; break;
case SB_LINEUP: nNew = nOrig - LINE_AMOUNT; break;
case SB_PAGEDOWN: nNew = nOrig + rect.Height(); break;
case SB_PAGEUP: nNew = nOrig - rect.Height(); break;
case SB_TOP: nNew = 0; break;
//�Drag scroll box to specified position.
// The current position is provided in nPos.
case SB_THUMBTRACK: nNew = nPos; break;
default:
nNew = nOrig;
break;
}
if (nNew < 0)
nNew = 0;
else
{
int nLimit = nMax - rect.Height() + 1;
if (nNew > nLimit)
nNew = nLimit;
}
TRACE(_T("V: New: %d Orig: %d Min: %d Max: %d\n"),
nNew, nOrig, nMin, nMax);
if (nNew != nOrig)
{
ScrollWindowEx(0, nOrig - nNew, SW_ERASE|SW_INVALIDATE|SW_SCROLLCHILDREN);
SetScrollPos(SB_VERT, nNew);
}
}