2024-06-23 17:36:53 +08:00

234 lines
6.8 KiB
C++

////////////////////////////////////////////////////////////////
// MSDN Magazine -- June 2005
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio .NET 2003 (V7.1) on Windows XP. Tab size=3.
//
#include "..\stdafx.h"
#include "InputDlg.h"
#include <atlconv.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//////////////////
// Note: Make sure nBufLen is big enough to hold your entire dialog template!
//
CDlgTemplateBuilder::CDlgTemplateBuilder(UINT nBufLen)
{
m_pBuffer = new WORD[nBufLen];
m_pNext = m_pBuffer;
m_pEndBuf = m_pNext + nBufLen;
}
CDlgTemplateBuilder::~CDlgTemplateBuilder()
{
delete [] m_pBuffer;
}
//////////////////
// Create template (DLGTEMPLATE)
//
DLGTEMPLATE* CDlgTemplateBuilder::Begin(DWORD dwStyle, const CRect& rc,
LPCTSTR text, DWORD dwStyleEx)
{
ASSERT(m_pBuffer==m_pNext); // call Begin first and only once!
DLGTEMPLATE* hdr = (DLGTEMPLATE*)m_pBuffer;
hdr->style = dwStyle; // copy style..
hdr->dwExtendedStyle = dwStyleEx; // ..and extended, too
hdr->cdit = 0; // number of items: zero
// Set dialog rectangle.
CRect rcDlg = rc;
hdr->x = (short)rcDlg.left;
hdr->y = (short)rcDlg.top;
hdr->cx = (short)rcDlg.Width();
hdr->cy = (short)rcDlg.Height();
// Append trailing items: menu, class, caption. I only use caption.
m_pNext = (WORD*)(hdr+1);
*m_pNext++ = 0; // menu (none)
*m_pNext++ = 0; // dialog class (use standard)
m_pNext = AddText(m_pNext, text); // append dialog caption
ASSERT(m_pNext < m_pEndBuf);
return hdr;
}
//////////////////
// Add dialog item (control).
//
void CDlgTemplateBuilder::AddItemTemplate(WORD wType, DWORD dwStyle,
const CRect& rc, WORD nID, DWORD dwStyleEx)
{
ASSERT(m_pNext < m_pEndBuf);
// initialize DLGITEMTEMPLATE
DLGITEMTEMPLATE& it = *((DLGITEMTEMPLATE*)AlignDWORD(m_pNext));
it.style = dwStyle;
it.dwExtendedStyle = dwStyleEx;
CRect rcDlg = rc;
it.x = (short)rcDlg.left;
it.y = (short)rcDlg.top;
it.cx = (short)rcDlg.Width();
it.cy = (short)rcDlg.Height();
it.id = nID;
// add class (none)
m_pNext = (WORD*)(&it+1);
*m_pNext++ = 0xFFFF; // next WORD is atom
*m_pNext++ = wType; // ..atom identifier
ASSERT(m_pNext < m_pEndBuf); // check not out of range
// increment control/item count
DLGTEMPLATE* hdr = (DLGTEMPLATE*)m_pBuffer;
hdr->cdit++;
}
//////////////////
// Add dialog item (control).
//
void CDlgTemplateBuilder::AddItem(WORD wType, DWORD dwStyle,
const CRect& rc, LPCTSTR text, WORD nID, DWORD dwStyleEx)
{
AddItemTemplate(wType, dwStyle, rc, nID, dwStyleEx);
m_pNext = AddText(m_pNext, text); // append title
*m_pNext++ = 0; // no creation data
ASSERT(m_pNext < m_pEndBuf);
}
//////////////////
// Add dialog item (control).
//
void CDlgTemplateBuilder::AddItem(WORD wType, DWORD dwStyle,
const CRect& rc, WORD wResID, WORD nID, DWORD dwStyleEx)
{
AddItemTemplate(wType, dwStyle, rc, nID, dwStyleEx);
*m_pNext++ = 0xFFFF; // next is resource id
*m_pNext++ = wResID; // ..here it is
*m_pNext++ = 0; // no extra stuff
ASSERT(m_pNext < m_pEndBuf);
}
//////////////////
// Append text to buffer. Convert to Unicode if necessary.
// Return pointer to next character after terminating NULL.
//
WORD* CDlgTemplateBuilder::AddText(WORD* buf, LPCTSTR text)
{
if (text) {
USES_CONVERSION;
wcscpy((WCHAR*)buf, T2W((LPTSTR)text));
buf += wcslen((WCHAR*)buf)+1;
} else {
*buf++ = 0;
}
return buf;
}
//////////////////
// Create string dialog. If no icon specified, use IDI_QUESTION. Note that
// the order in which the controls are added is the TAB order.
//
BOOL CInputDialog::Init(LPCTSTR caption, LPCTSTR prompt, CWnd* pParent, BOOL bIsOk, CString str, WORD nIDIcon)
{
m_str = str;
const CXDIALOG = 300; // dialog width
const DLGMARGIN = 7; // margins all around
const CYSTATIC = 8; // height of static text
const CYEDIT = 12; // height of edit control
const CYSPACE = 5; // vertical space between controls
const CXBUTTON = 40; // button width...
const CYBUTTON = 15; // ..and height
CDlgTemplateBuilder& dtb = m_dtb;
CRect rc(
CPoint(0,0),
CSize(CXDIALOG, CYSTATIC + CYEDIT + CYBUTTON + 2*DLGMARGIN + 2*CYSPACE));
// create dialog header
DLGTEMPLATE* pTempl = dtb.Begin(WS_POPUPWINDOW|DS_MODALFRAME|WS_DLGFRAME,rc,caption);
// shrink main rect by margins
rc.DeflateRect(CSize(DLGMARGIN,DLGMARGIN));
// create icon if needed
if (nIDIcon) {
if (nIDIcon >= (WORD)IDI_APPLICATION) {
// if using a system icon, I load it here and set it in OnInitDialog
// because can't specify system icon in template, only icons from
// application resource file.
m_hIcon = ::LoadIcon(NULL, MAKEINTRESOURCE(nIDIcon));
nIDIcon = 0;
} else {
m_hIcon = NULL;
}
// The size is calculated in pixels, but it seems to work OK--???
CSize sz(GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON));
CRect rcIcon(rc.TopLeft(), sz);
dtb.AddItem(CDlgTemplateBuilder::STATIC, // add icon
WS_VISIBLE|WS_CHILD|SS_LEFT|SS_ICON, rc, nIDIcon, IDICON);
rc.left += sz.cx; // shrink main rect by width of icon
}
// add prompt
rc.bottom = rc.top + CYSTATIC; // height = height of static
dtb.AddItem(CDlgTemplateBuilder::STATIC, // add it
WS_VISIBLE|WS_CHILD|SS_LEFT, rc, prompt);
// add edit control
rc += CPoint(0, rc.Height() + CYSPACE); // move below static
rc.bottom = rc.top + CYEDIT; // height = height of edit control
dtb.AddItem(CDlgTemplateBuilder::EDIT, // add it ES_AUTOHSCROLL must be add
WS_VISIBLE|WS_CHILD|WS_BORDER|WS_TABSTOP|ES_AUTOHSCROLL, rc, m_str, IDEDIT);
// add OK button
rc += CPoint(0, rc.Height() + CYSPACE); // move below edit control
rc.bottom = rc.top + CYBUTTON; // height = button height
rc.left = rc.right - CXBUTTON; // width = button width
rc -= CPoint(CXBUTTON + DLGMARGIN,0); // move left one button width
dtb.AddItem(CDlgTemplateBuilder::BUTTON, // add it
WS_VISIBLE|WS_CHILD|WS_TABSTOP|BS_DEFPUSHBUTTON, rc, _T("&OK"), IDOK);
// add Cancel button
rc += CPoint(CXBUTTON + DLGMARGIN,0); // move right again
dtb.AddItem(CDlgTemplateBuilder::BUTTON, // add Cancel button
WS_VISIBLE|WS_CHILD|WS_TABSTOP, rc, _T("&Cancel"), IDCANCEL);
m_bIsOk = bIsOk;
return InitModalIndirect(pTempl, pParent);
}
//////////////////
// Initialize dialog: if I loaded a system icon, set it in static control.
//
BOOL CInputDialog::OnInitDialog()
{
if (m_hIcon) {
CStatic* pStatic = (CStatic*)GetDlgItem(IDICON);
ASSERT(pStatic);
pStatic->SetIcon(m_hIcon);
}
return CDialog::OnInitDialog();
}
/////////////////
// User pressed OK: check for empty string if required flag is set.
//
void CInputDialog::OnOK()
{
UpdateData(TRUE);
if (m_bRequired && m_str.IsEmpty()) {
if(m_bIsOk)
{
MessageBeep(0);
return; // don't quit dialog!
}
}
CDialog::OnOK();
}