// Copyright � 2002 Oink!
// FILE NAME : DynWnd,h
// DESCRIPTION : Template for all Dynamic Windows and View
//
// PROGRAMMER DATE PATCH DESCRIPTION
// ============ =========== ======= ===============================================
#if !defined(AFX_DYNWND_H__C4176220_D285_11D0_93E9_004F4C01BE64__INCLUDED_)
#define AFX_DYNWND_H__C4176220_D285_11D0_93E9_004F4C01BE64__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#include "DynControl.h"
#include "DynDropTarget.h"
#include "resource.h"
#include "DynPropPage1.h"
#include "DynPropPage2.h"
#include "DynPropPage3.h"
#include "DynTracker.h"
#pragma warning (disable: 4146)
#import "msado15.dll" rename("EOF", "ADOEOF")
using namespace ADODB;
#pragma warning (default: 4146)
/////////////////////////////////////////////////////////////////////////////
// CDynWnd window
template <class BASECLASS> class CDynWnd : public BASECLASS
{
// Construction
public:
CDynWnd(int nIDD);
CDynWnd(int nIDD, CWnd* pParent);
CDynWnd();
// Attributes
private:
CPtrList m_ptrDynControls;
CDynTracker m_DynTracker;
CDynDropTarget m_DynDropTarget;
int m_nHighestID;
enum ControlType
{
CTLTYPE_LISTVIEW = 0x53,
CTLTYPE_BUTTON = 0x80,
CTLTYPE_EDIT = 0x81,
CTLTYPE_STATIC = 0x82,
CTLTYPE_LISTBOX = 0x83,
CTLTYPE_SCROLLBAR = 0x84,
CTLTYPE_COMBOBOX = 0x85
};
int m_nIDD;
LPBYTE m_pDlgRes;
CString m_strDialogFont;
WORD m_wpSize;
BOOL m_bInScreenDesignerMode;
int m_nGridX;
int m_nGridY;
CWnd* m_pChildInScreenDesigner;
BOOL m_bShowGrid;
// Operations
public:
void Initialise();
void ToggleScreenMode(BOOL bScreenDesignMode);
void ShowAllFields(BOOL bShowAll = TRUE);
void PreProcessResource(int nIDD);
void SaveScreen();
BOOL OnInitDialog();
void OnInitialUpdate();
void DynDoDataExchange(CDataExchange* pDX, BOOL bUsePointer = FALSE);
BOOL UpdateDynamicData(BOOL bSaveAndValidate, BOOL bUsePointer = FALSE);
void SetGridSize(int nX, int nY) { m_nGridX = nX; m_nGridY = nY; }
BOOL InScreenDesignerMode() { return m_bInScreenDesignerMode; }
void SetInScreenDesignerMode() { m_bInScreenDesignerMode = TRUE; ToggleScreenMode(TRUE); }
void SetChild(CWnd* pWnd) { TRACE("%d", m_nIDD); m_pChildInScreenDesigner = pWnd; }
CWnd* GetChild() { return m_pChildInScreenDesigner; }
private:
void MapRectDialog(CRect& rect, int &x, int &y, int &cx, int &cy)
{
// maps pixels to dialog units
CRect r = CRect(0,0,4,8);
::MapDialogRect(this->m_hWnd,r);
int pixelX = MulDiv( 201, r.right, 4 );
int dlgx = MulDiv(302,4,r.right);
x = MulDiv(rect.left,4,r.right);
cx = MulDiv(rect.right,4,r.right) - x; // this is the width
y = MulDiv(rect.top,8,r.bottom);
cy = MulDiv(rect.bottom,8,r.bottom) - y; // this is the height
}
int SkipOrdinalOrTextField(LPBYTE* pplDlgResource, CString* pstrTextValue = NULL)
{
// Skips a word or char in the resource file
ASSERT_VALID(this);
ASSERT(pplDlgResource);
int nCount = 0;
CString strText("");
// Ordinal number start with '0xFFFF'
if (0xFFFF == (WORD)**pplDlgResource)
{
*pplDlgResource += sizeof(WORD);
nCount = sizeof(WORD);
}
else
{
while (**pplDlgResource)
{
#if _MFC_VER < 0x0700
strText = strText + CString(**pplDlgResource);
#else
strText = strText + CString((WCHAR)**pplDlgResource);
#endif
*pplDlgResource += sizeof(WCHAR);
nCount += sizeof(WCHAR);
}
// Move past the null character
*pplDlgResource += sizeof(WCHAR);
nCount += sizeof(WCHAR);
}
if (pstrTextValue != NULL)
*pstrTextValue = strText;
return nCount;
}
// Overrides
#if _MFC_VER >= 0x0700
public:
#endif
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDynWnd)
afx_msg void OnPaint();
afx_msg long ScreenDesigner(WPARAM wParam, LPARAM lParam);
afx_msg long AddControl(WPARAM wParam, LPARAM lParam);
afx_msg long DeleteControl(WPARAM wParam, LPARAM lParam);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
// message handlers for controls
afx_msg void OnButtonedit();
afx_msg void OnButtonmledit();
afx_msg void OnButtonlabel();
afx_msg void OnButtoncombo();
afx_msg void OnButtongroup();
afx_msg void OnButtoncheck();
afx_msg void OnButtondate();
afx_msg void OnButtonradio();
// end of message handlers for controls
afx_msg void OnButtonLeftAlign();
afx_msg void OnButtonRightAlign();
afx_msg void OnButtonTopAlign();
afx_msg void OnButtonBottomAlign();
afx_msg void OnButtonMakeSameWidth();
afx_msg void OnButtonMakeSameHeight();
afx_msg void OnButtonMakeSameSize();
afx_msg void ShowGrid();
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
//}}AFX_VIRTUAL
virtual void OverrideVisible();
// Implementation
public:
virtual ~CDynWnd();
// Generated message map functions
protected:
//{{AFX_MSG(CDynWnd)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
static const AFX_MSGMAP* PASCAL GetBaseMessageMap();
static const AFX_MSGMAP_ENTRY _messageEntries[];
static const AFX_MSGMAP messageMap;
virtual const AFX_MSGMAP* GetMessageMap() const;
};
template <class BASECLASS> CDynWnd<BASECLASS>::CDynWnd(int nIDD) : BASECLASS(nIDD)
{
// constructor for baseclasses requiring a dialog
m_nIDD = nIDD;
Initialise();
}
template <class BASECLASS> CDynWnd<BASECLASS>::CDynWnd(int nIDD, CWnd* pParent) : BASECLASS(nIDD, pParent)
{
// constructor for baseclasses requiring a parent window and dialog ID
m_nIDD = nIDD;
Initialise();
}
template <class BASECLASS> CDynWnd<BASECLASS>::CDynWnd() : BASECLASS()
{
// constructor for baseclasses requiring nothing
Initialise();
}
template <class BASECLASS> CDynWnd<BASECLASS>::~CDynWnd()
{
// destructor
// delete all the controls created
CDynControl* pDynControl;
POSITION pos = m_ptrDynControls.GetHeadPosition();
while (pos)
{
pDynControl = (CDynControl*)m_ptrDynControls.GetNext(pos);
delete pDynControl;
}
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OverrideVisible()
{
// override to show/hide any specific controls, after the screen designer has
// shown or hidden them
}
template <class BASECLASS> void CDynWnd<BASECLASS>::Initialise()
{
// common code called in each constructor
m_nHighestID = 0;
PreProcessResource(m_nIDD);
m_bInScreenDesignerMode = FALSE;
m_pChildInScreenDesigner = NULL;
m_bShowGrid = TRUE;
// default grid size
m_nGridX = 5;
m_nGridY = 5;
}
template <class BASECLASS> const AFX_MSGMAP* PASCAL CDynWnd<BASECLASS>::GetBaseMessageMap()
{
// returns a pointer to the base class message map
return &BASECLASS::messageMap;
}
// The functions below are the actual expanded macro definitions of BEGIN_MESSAGEMAP
template <class BASECLASS> const AFX_MSGMAP* CDynWnd<BASECLASS>::GetMessageMap() const
{ return &CDynWnd<BASECLASS>::messageMap;}
template <class BASECLASS> AFX_DATADEF const AFX_MSGMAP CDynWnd<BASECLASS>::messageMap =
#if _MFC_VER < 0x0700
{ CDynWnd<BASECLASS>::GetBaseMessageMap, &CDynWnd<BASECLASS>::_messageEntries[0]};
#else
{ CDynWnd<BASECLASS>::GetThisMessageMap, &CDynWnd<BASECLASS>::_messageEntries[0]};
#endif
template <class BASECLASS> const AFX_MSGMAP_ENTRY CDynWnd<BASECLASS>::_messageEntries[] =
{
ON_WM_PAINT()
ON_WM_KEYDOWN()
ON_MESSAGE(WM_SCREENDESIGNER,ScreenDesigner)
ON_MESSAGE(WM_ADDCONTROL,AddControl)
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
ON_WM_SETCURSOR()
ON_WM_CREATE()
// command handlers for controls
ON_COMMAND(ID_DYNBUTTONEDIT, OnButtonedit)
ON_COMMAND(ID_DYNBUTTONEDITMULTI, OnButtonmledit)
ON_COMMAND(ID_DYNBUTTONLABEL, OnButtonlabel)
ON_COMMAND(ID_DYNBUTTONCOMBO, OnButtoncombo)
ON_COMMAND(ID_DYNBUTTONGROUP, OnButtongroup)
ON_COMMAND(ID_DYNBUTTONCHECK, OnButtoncheck)
ON_COMMAND(ID_DYNBUTTONRADIO, OnButtonradio)
ON_COMMAND(ID_DYNBUTTONDATE, OnButtondate)
// end of command handlers for controls
ON_COMMAND(ID_DYNBUTTONLEFTALIGN, OnButtonLeftAlign)
ON_COMMAND(ID_DYNBUTTONRIGHTALIGN, OnButtonRightAlign)
ON_COMMAND(ID_DYNBUTTONTOPALIGN, OnButtonTopAlign)
ON_COMMAND(ID_DYNBUTTONBOTTOMALIGN, OnButtonBottomAlign)
ON_COMMAND(ID_DYNBUTTONMAKESAMEWIDTH, OnButtonMakeSameWidth)
ON_COMMAND(ID_DYNBUTTONMAKESAMEHEIGHT, OnButtonMakeSameHeight)
ON_COMMAND(ID_DYNBUTTONMAKESAMESIZE, OnButtonMakeSameSize)
ON_COMMAND(ID_DYNBUTTONTOGGLEGRID, ShowGrid)
{0,0,0,0,AfxSig_end, (AFX_PMSG)0}
};
template <class BASECLASS> void CDynWnd<BASECLASS>::PreProcessResource(int nIDD)
{
// This function is called by the constructor of the window implementing a dynamic view
// to preprocess the resource
// get a handle to the resource for this window
// and open it
HRSRC hResource = ::FindResource(AfxGetResourceHandle(),MAKEINTRESOURCE(nIDD),RT_DIALOG);
HGLOBAL hData = ::LoadResource(AfxGetResourceHandle(),hResource);
if (hData != NULL)
{
DLGTEMPLATE dlgTemplate;
LPBYTE pDlgResItems;
LPBYTE pDlgResFirstByte;
CString strCtlText;
m_pDlgRes = (LPBYTE)::LockResource(hData);
pDlgResFirstByte = m_pDlgRes;
memcpy(&dlgTemplate,m_pDlgRes,sizeof(DLGTEMPLATE));
pDlgResItems = m_pDlgRes + sizeof(DLGTEMPLATE);
// move past the menu
SkipOrdinalOrTextField(&pDlgResItems);
// move past the class
SkipOrdinalOrTextField(&pDlgResItems);
// move past the caption
SkipOrdinalOrTextField(&pDlgResItems);
// the following will be present ONLY if "DS_SETFONT" style has been
// specified for the dialog box.
// 4 - Check if a unique font is specified for this dialog.
// 5 - Check if a FACE NAME is specified.
if (DS_SETFONT & dlgTemplate.style)
{
// get the point size
m_wpSize = (WORD)*pDlgResItems;
// move past the point size field
pDlgResItems += sizeof(WORD);
// "szFontName" contains "DOUBLE-NULL" terminated string. Se we
// need to advance the pointer TWO UNICODE characters. Since
// "SkipOrdinalOrText()" only advances past ONE null char, then
// we need to advance it past the second NULL char.
m_strDialogFont = "";
SkipOrdinalOrTextField(&pDlgResItems, &m_strDialogFont);
// move past the NULL char
pDlgResItems += sizeof(WCHAR);
}
// go through all the control in the resource
for (int nLoop = 0; nLoop < dlgTemplate.cdit; nLoop++)
{
DLGITEMTEMPLATE* pdlgItem;
DLGITEMTEMPLATE dlgItem;
BYTE byClassType;
CString strClassName;
WORD nExtraOffsetBytes;
nExtraOffsetBytes = (WORD)(4 - (((WORD)(DWORD)pDlgResItems) & 3)) % 4;
pDlgResItems += nExtraOffsetBytes;
pdlgItem = (DLGITEMTEMPLATE*)pDlgResItems;
memcpy(&dlgItem,pdlgItem,sizeof(DLGITEMTEMPLATE));
pDlgResItems = pDlgResItems + sizeof(DLGITEMTEMPLATE);
if (0xFFFF == *(WORD*)pDlgResItems)
{
pDlgResItems += sizeof(WORD);
switch(byClassType = (BYTE)*pDlgResItems)
{
case CTLTYPE_LISTVIEW : strClassName = _T("SysListView32") ; break;
case CTLTYPE_BUTTON : strClassName = _T("button") ; break;
case CTLTYPE_EDIT : strClassName = _T("edit") ; break;
case CTLTYPE_STATIC : strClassName = _T("static") ; break;
case CTLTYPE_LISTBOX : strClassName = _T("listbox") ; break;
case CTLTYPE_SCROLLBAR: strClassName = _T("scrollbar"); break;
case CTLTYPE_COMBOBOX : strClassName = _T("combobox") ; break;
#pragma warning (disable: 4244)
default : strClassName = *(WCHAR*)pDlgResItems;
#pragma warning (default: 4244)
byClassType = 0;
}
pDlgResItems += sizeof(WORD);
}
else
{
char pcOut[60];
WideCharToMultiByte(CP_ACP, 0, (WCHAR*)pDlgResItems, -1, pcOut, sizeof(pcOut), NULL, NULL);
strClassName = CString(pcOut);
pDlgResItems += strClassName.GetLength() * sizeof(WCHAR);
pDlgResItems += sizeof(WORD);
}
strCtlText = "";
if(0xFFFF != *(WORD*)pDlgResItems)
strCtlText = (WCHAR*)pDlgResItems;
// TRACE("%s %s %d\n", strClassName, strCtlText, pdlgItem->id);
// cope with the up-down controls
SkipOrdinalOrTextField(&pDlgResItems);
if (strCtlText == "msctls_updown32")
SkipOrdinalOrTextField(&pDlgResItems);
if (strClassName == "edit"
|| strClassName == "static"
|| strClassName == "combobox"
|| strClassName == "button"
|| strClassName == "SysDateTimePick32"
|| strClassName == "SysListView32")
// NOTE THERE ARE MANY OTHER types of controls
// you may have in your application that you need to trap
{
// see if the database contains a record of this control
// if it does then adjust this controls data
POSITION posDynControl = m_ptrDynControls.GetHeadPosition();
CDynControl* pDynControl;
BOOL bFound = FALSE;
while (posDynControl)
{
pDynControl = (CDynControl*)m_ptrDynControls.GetNext(posDynControl);
if (pDynControl->GetID() == pdlgItem->id)
{
bFound = TRUE;
// change info in the control
//TRACE("the pdlgitem %d %d %d %d",
//pdlgItem->x,pdlgItem->cx,pdlgItem->y,pdlgItem->cy);
// change the position information
pdlgItem->x = pDynControl->m_x;
pdlgItem->cx = pDynControl->m_cx;
pdlgItem->y = pDynControl->m_y;
pdlgItem->cy = pDynControl->m_cy;
break;
}
}
if (!bFound)
{
// create the control in the list of dynamic controls
// see note above about the different controls
int nType = 0;
if (strClassName == "edit") nType = ID_DYNBUTTONEDIT;
if (strClassName == "static") nType = ID_DYNBUTTONLABEL;
if (strClassName == "combobox") nType = ID_DYNBUTTONCOMBO;
if (nType == 0)
nType = ID_DYNBUTTONLABEL;
CDynControl* pDynControl = new CDynControl(this,nType,pdlgItem->id, FALSE);
pDynControl->SetText(strCtlText);
// keep a note of the controls original values
pDynControl->m_Originalx = pdlgItem->x;
pDynControl->m_Originaly = pdlgItem->y;
pDynControl->m_Originalcx = pdlgItem->cx;
pDynControl->m_Originalcy = pdlgItem->cy;
pDynControl->m_Originalvalue = strCtlText;
m_ptrDynControls.AddTail(pDynControl);
// keep a reminder of the highest id
if (pdlgItem->id > m_nHighestID)
m_nHighestID = pdlgItem->id;
}
}
// Move past the extra byte
pDlgResItems += sizeof(WORD);
}
UnlockResource(hData);
FreeResource(hData);
// next ID available
m_nHighestID++;
}
}
template <class BASECLASS> long CDynWnd<BASECLASS>::AddControl(WPARAM wParam, LPARAM lParam)
{
// Creates a new control on the screen, caught from the
// drop event from the toolbar control
int nType = wParam;
CPoint* ppoint;
ppoint = (CPoint*)lParam;
CDynControl* pDynControl = new CDynControl(this, nType, m_nHighestID, TRUE);
pDynControl->AddControl(ppoint);
m_ptrDynControls.AddTail(pDynControl);
m_nHighestID++;
if (m_bInScreenDesignerMode)
pDynControl->EnableWindow(FALSE);
return 0;
}
template <class BASECLASS> void CDynWnd<BASECLASS>::ShowGrid()
{
// toggles the grid
if (m_bShowGrid)
m_bShowGrid = FALSE;
else
m_bShowGrid = TRUE;
Invalidate();
}
template <class BASECLASS> long CDynWnd<BASECLASS>::ScreenDesigner(WPARAM wParam, LPARAM lParam)
{
// Message sent when screen is requested to toggle between screen designer and run mode
m_bInScreenDesignerMode = wParam;
m_DynTracker.RemoveAll();
// comming out of screen designer mode
if (!m_bInScreenDesignerMode)
{
SaveScreen();
if (m_pChildInScreenDesigner != NULL)
{
m_pChildInScreenDesigner->SendMessage(WM_SCREENDESIGNER,wParam,lParam);
m_pChildInScreenDesigner->PostMessage(WM_SYSCOMMAND,SC_CLOSE,0);
m_pChildInScreenDesigner = NULL;
}
}
ToggleScreenMode(m_bInScreenDesignerMode);
GetActiveWindow()->SetFocus();
Invalidate();
return 0;
}
template <class BASECLASS> void CDynWnd<BASECLASS>::ToggleScreenMode(BOOL bScreenDesignMode)
{
// Toggles screen between designer and run mode, normally used by ::ScreenDesigner
// go through all the controls on the screen
CDynControl* pDynControl;
POSITION pos = m_ptrDynControls.GetHeadPosition();
while (pos)
{
pDynControl = (CDynControl*)m_ptrDynControls.GetNext(pos);
if (bScreenDesignMode)
{
// show any windows which may of have been hidden
GetDlgItem(pDynControl->GetID())->ShowWindow(SW_NORMAL);
pDynControl->EnableWindow(FALSE);
}
else
{
pDynControl->EnableWindow(TRUE);
// see if the visible flag is enabled
if (pDynControl->GetVisible() == FALSE)
GetDlgItem(pDynControl->GetID())->ShowWindow(SW_HIDE);
}
}
// virtual function
// that allows base class to hide
// any controls that should not be
// seen
if (!bScreenDesignMode)
OverrideVisible();
}
template <class BASECLASS> void CDynWnd<BASECLASS>::ShowAllFields(BOOL bShowAll)
{
// Shows or hides all fields
// Add the visible style to all CDynEdit objects
CDynControl<CEdit>* pDynControl;
POSITION posDynControl = m_ptrDynamicControl.GetHeadPosition();
while (posDynControl)
{
pDynControl = (CDynControl<CEdit>*)m_ptrDynamicControl.GetNext(posDynControl);
if (pDynControl->m_structControlData.nID == 0)
{
// If it is should be visible
if (pDynControl->m_structControlData.bVisible)
{
if (bShowAll)
{
pDynControl->ShowWindow(SW_SHOW);
pDynControl->EnableWindow(TRUE);
}
else
pDynControl->ShowWindow(SW_HIDE);
}
// make sure it is hidden
else
pDynControl->ShowWindow(SW_HIDE);
}
else
{
if (pDynControl->m_structControlData.bVisible)
{
if (bShowAll)
{
GetDlgItem(pDynControl->m_structControlData.nID)->ShowWindow(SW_SHOW);
GetDlgItem(pDynControl->m_structControlData.nID)->EnableWindow(SW_SHOW);
}
else
GetDlgItem(pDynControl->m_structControlData.nID)->ShowWindow(SW_HIDE);
}
else
GetDlgItem(pDynControl->m_structControlData.nID)->ShowWindow(SW_HIDE);
}
}
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnPaint()
{
// paints the screen
// device context for painting
CPaintDC pDC(this);
// if in screen designer mode
if (m_bInScreenDesignerMode)
{
if (m_bShowGrid)
{
// Pen for grid
CPen dashPen(PS_DASH, 1, 1);
CPen* oldpen;
// calculate grid size
CRect rect(m_nGridX,m_nGridY,0,0);
::MapDialogRect(this->m_hWnd,&rect);
int nGridX = rect.left;
int nGridY = rect.top;
// Are gridlines turned on ?
oldpen = (CPen*)pDC.SelectObject(&dashPen);
// Get our screen area
RECT rectScrn;
GetClientRect(&rectScrn);
// We will draw as many grids as possible given the size
// of the grid variables and the size of the client area
div_t nX = div(rectScrn.right, m_nGridX);
div_t nY = div(rectScrn.bottom, m_nGridY);
for(int x = 1; x < nX.quot + 1; x++)
{
for(int y = 1; y < nY.quot + 1; y++)
{
pDC.SetPixel(x * nGridX, y * nGridY, 0);
}
}
pDC.SelectObject(oldpen);
}
}
m_DynTracker.Draw(&pDC);
}
template <class BASECLASS> BOOL CDynWnd<BASECLASS>::UpdateDynamicData(BOOL bSaveAndValidate, BOOL bUsePointer)
{
// swaps data between the screen and the controls and back again
CDataExchange dx(this, bSaveAndValidate);
// prevent control notifications from being dispatched during UpdateData
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
HWND hWndOldLockout = pThreadState->m_hLockoutNotifyWindow;
ASSERT(hWndOldLockout != m_hWnd); // must not recurse
pThreadState->m_hLockoutNotifyWindow = m_hWnd;
BOOL bOK = FALSE; // assume failure
try
{
DynDoDataExchange(&dx, bUsePointer);
bOK = TRUE; // it worked
}
catch(CUserException e)
{
// validation failed - user already alerted, fall through
ASSERT(bOK == FALSE);
// Note: DELETE_EXCEPTION_(e) not required
}
pThreadState->m_hLockoutNotifyWindow = hWndOldLockout;
return bOK;
}
template <class BASECLASS> void CDynWnd<BASECLASS>::DynDoDataExchange(CDataExchange* pDX, BOOL bUsePointer)
{
// do dynamic data exchange between the database and dynamic controls
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnLButtonDown(UINT nFlags, CPoint point)
{
// select a control
// Ask the multitrack if an object is already selected
// or a handle. If not, start the local tracker.
if (m_bInScreenDesignerMode)
{
if (m_DynTracker.HitTest(point) < 0)
{
// Reset the multitrack only if there
// is no CTRL key.
if (!(nFlags & MK_CONTROL))
m_DynTracker.RemoveAll();
CRect rcObject;
CDynControl* pObject;
// local tracker...
CRectTracker tracker;
if (tracker.TrackRubberBand(this, point, TRUE))
{
// see if rubber band intersects with the objects
CRect rectT;
tracker.m_rect.NormalizeRect();
POSITION pos = m_ptrDynControls.GetHeadPosition ();
while (pos != NULL)
{
// from the controls create rect tracker objects
pObject = (CDynControl*)(m_ptrDynControls.GetNext(pos));
rcObject = pObject->GetRect();
rectT.IntersectRect(tracker.m_rect, rcObject);
if (rectT == rcObject)
m_DynTracker.Add(pObject->GetRect(), this, pObject->GetID(), pObject); // add it to the multitrack, nd continue the loop
}
}
else
{
// No rubber band, see if the point selects an object.
POSITION pos = m_ptrDynControls.GetHeadPosition ();
while (pos != NULL) {
pObject = (CDynControl*)(m_ptrDynControls.GetNext(pos));
rcObject = pObject->GetRect();
if (rcObject.PtInRect(point))
{
m_DynTracker.Add(pObject->GetRect(), this, pObject->GetID(), pObject); // add just one object to the multitrack
break;
}
}
}
}
else
// Click on the multitrack, forward actions to it.
m_DynTracker.Track(this, point, FALSE);
// Update drawing.
Invalidate();
UpdateWindow();
}
BASECLASS::OnLButtonDown(nFlags, point);
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnRButtonDown(UINT nFlags, CPoint point)
{
// set the properties for the control
if (m_bInScreenDesignerMode && m_DynTracker.GetSize() == 1)
{
int nID = m_DynTracker.GetIDSelected();
// get the control
POSITION posDynControl = m_ptrDynControls.GetHeadPosition();
CDynControl* pDynControl;
BOOL bFound = FALSE;
while (posDynControl)
{
pDynControl = (CDynControl*)m_ptrDynControls.GetNext(posDynControl);
if (pDynControl->GetID() == nID)
{
bFound = TRUE;
break;
}
}
ASSERT(bFound);
CPropertySheet pSheet("Properties");
CDynPropPage1 p1;
CDynPropPage2 p2;
CDynPropPage3 p3;
p1.m_Visible = pDynControl->GetVisible();
p1.m_OrdinalValue = pDynControl->GetFieldID();
pSheet.AddPage(&p1);
BOOL bText = FALSE;
if (pDynControl->GetControlType() == ID_DYNBUTTONLABEL
|| pDynControl->GetControlType() == ID_DYNBUTTONRADIO
|| pDynControl->GetControlType() == ID_DYNBUTTONCHECK
|| pDynControl->GetControlType() == ID_DYNBUTTONGROUP)
{
bText = TRUE;
pSheet.AddPage(&p2);
p2.m_Text = pDynControl->GetText();
}
if (pDynControl->GetControlType() == ID_DYNBUTTONCOMBO)
{
pSheet.AddPage(&p3);
p3.m_strListItems = pDynControl->GetComboValues();
}
if (pSheet.DoModal())
{
// save away settings
pDynControl->SetVisible(p1.m_Visible);
pDynControl->SetFieldID(p1.m_OrdinalValue);
if (bText)
{
pDynControl->SetText(p2.m_Text);
// refrsh the control properties
GetDlgItem(pDynControl->GetID())->SetWindowText(pDynControl->GetText());
}
if (pDynControl->GetControlType() == ID_DYNBUTTONCOMBO)
pDynControl->SetComboValues(p3.m_strListItems);
}
UpdateData(FALSE);
}
}
template <class BASECLASS> BOOL CDynWnd<BASECLASS>::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// Called to determine what the cursor shape should be
if (pWnd == this && m_DynTracker.SetCursor(this, nHitTest))
return TRUE;
return BASECLASS::OnSetCursor(pWnd, nHitTest, message);
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnInitialUpdate()
{
// Used only for CView dervied classes
POSITION posDynControl = m_ptrDynControls.GetHeadPosition();
CDynControl* pDynControl;
while (posDynControl)
{
pDynControl = (CDynControl*)m_ptrDynControls.GetNext(posDynControl);
// if this is a dyamic control then create it
if (pDynControl->GetDynamic() == TRUE)
pDynControl->AddControl();
// initialisation of non dynamic controls labels, etc
if (::IsWindow(GetDlgItem(pDynControl->GetID())->GetSafeHwnd()))
{
if (pDynControl->GetControlType() == ID_DYNBUTTONLABEL
|| pDynControl->GetControlType() == ID_DYNBUTTONRADIO
|| pDynControl->GetControlType() == ID_DYNBUTTONCHECK
|| pDynControl->GetControlType() == ID_DYNBUTTONGROUP)
GetDlgItem(pDynControl->GetID())->SetWindowText(pDynControl->GetText());
}
}
// change the tab order
// First construct a reverse sorted listed
// of controls
CPtrList ptrDynamicControl;
posDynControl = m_ptrDynControls.GetHeadPosition();
CDynControl* pDynControl1;
CDynControl* pDynControl2;
int nCount = 0;
int nOLoop = 0;
int nILoop = 0;
void* pTemp;
while (posDynControl)
{
pDynControl = (CDynControl*)m_ptrDynControls.GetNext(posDynControl);
ptrDynamicControl.AddTail(pDynControl);
nCount++;
}
POSITION posVal1;
POSITION posVal2;
int nVal1;
int nVal2;
for (nOLoop = 0;nOLoop < nCount; nOLoop++)
{
for (nILoop = 0; nILoop < nCount - 1; nILoop++)
{
posVal1 = ptrDynamicControl.FindIndex(nILoop);
pDynControl1 = (CDynControl*)m_ptrDynControls.GetAt(posVal1);
nVal1 = pDynControl1->GetTabOrder();
posVal2 = ptrDynamicControl.FindIndex(nILoop + 1);
pDynControl2 = (CDynControl*)m_ptrDynControls.GetAt(posVal2);
nVal2 = pDynControl2->GetTabOrder();
if (nVal1 < nVal2)
{
pTemp = pDynControl1;
ptrDynamicControl.SetAt(posVal1,pDynControl2);
ptrDynamicControl.SetAt(posVal2,pTemp);
}
}
}
// now set the tab order in reverse order
// i.e. the last controls tab order set will be
// the first control to recieve the tab order
posDynControl = ptrDynamicControl.GetHeadPosition();
while (posDynControl)
{
pDynControl = (CDynControl*)ptrDynamicControl.GetNext(posDynControl);
int nTemp = pDynControl->GetTabOrder();
GetDlgItem(pDynControl->GetID())->SetWindowPos(NULL,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
}
BASECLASS::OnInitialUpdate();
ToggleScreenMode(m_bInScreenDesignerMode);
}
template <class BASECLASS> BOOL CDynWnd<BASECLASS>::OnInitDialog()
{
// On init overload
POSITION posDynControl = m_ptrDynControls.GetHeadPosition();
CDynControl* pDynControl;
while (posDynControl)
{
pDynControl = (CDynControl*)m_ptrDynControls.GetNext(posDynControl);
// if this is a dyamic control then create it
if (pDynControl->GetDynamic() == TRUE)
pDynControl->AddControl();
// initialisation of non dynamic controls labels, etc
if (::IsWindow(GetDlgItem(pDynControl->GetID())->GetSafeHwnd()))
{
if (pDynControl->GetControlType() == ID_DYNBUTTONLABEL
|| pDynControl->GetControlType() == ID_DYNBUTTONRADIO
|| pDynControl->GetControlType() == ID_DYNBUTTONCHECK
|| pDynControl->GetControlType() == ID_DYNBUTTONGROUP)
GetDlgItem(pDynControl->GetID())->SetWindowText(pDynControl->GetText());
}
}
// change the tab order
// First construct a reverse sorted listed
// of controls
CPtrList ptrDynamicControl;
posDynControl = m_ptrDynControls.GetHeadPosition();
CDynControl* pDynControl1;
CDynControl* pDynControl2;
int nCount = 0;
int nOLoop = 0;
int nILoop = 0;
void* pTemp;
while (posDynControl)
{
pDynControl = (CDynControl*)m_ptrDynControls.GetNext(posDynControl);
ptrDynamicControl.AddTail(pDynControl);
nCount++;
}
POSITION posVal1;
POSITION posVal2;
int nVal1;
int nVal2;
for (nOLoop = 0;nOLoop < nCount; nOLoop++)
{
for (nILoop = 0; nILoop < nCount - 1; nILoop++)
{
posVal1 = ptrDynamicControl.FindIndex(nILoop);
pDynControl1 = (CDynControl*)m_ptrDynControls.GetAt(posVal1);
nVal1 = pDynControl1->GetTabOrder();
posVal2 = ptrDynamicControl.FindIndex(nILoop + 1);
pDynControl2 = (CDynControl*)m_ptrDynControls.GetAt(posVal2);
nVal2 = pDynControl2->GetTabOrder();
if (nVal1 < nVal2)
{
pTemp = pDynControl1;
ptrDynamicControl.SetAt(posVal1,pDynControl2);
ptrDynamicControl.SetAt(posVal2,pTemp);
}
}
}
// now set the tab order in reverse order
// i.e. the last controls tab order set will be
// the first control to recieve the tab order
posDynControl = ptrDynamicControl.GetHeadPosition();
while (posDynControl)
{
pDynControl = (CDynControl*)ptrDynamicControl.GetNext(posDynControl);
int nTemp = pDynControl->GetTabOrder();
GetDlgItem(pDynControl->GetID())->SetWindowPos(NULL,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
}
BASECLASS::OnInitDialog();
ToggleScreenMode(m_bInScreenDesignerMode);
return TRUE;
}
template <class BASECLASS> void CDynWnd<BASECLASS>::SaveScreen()
{
// Writes back any screen changes made to the database
// or a data file
}
template <class BASECLASS> int CDynWnd<BASECLASS>::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// register window as drag drop target
if (BASECLASS::OnCreate(lpCreateStruct) == -1)
return -1;
m_DynDropTarget.Register(this);
m_DynDropTarget.m_nIDClipFormat = RegisterClipboardFormat("ScreenDesigner");
return 0;
}
// command handlers for buttons
// empty command handler to always have button enabled
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonedit() {}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonmledit() {}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonlabel() {}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtoncombo() {}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtongroup() {}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtoncheck() {}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtondate() {}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonradio() {}
// end of command handlers for buttons
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonLeftAlign()
{
// align the controls
m_DynTracker.AdjustLayout(1);
Invalidate();
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonRightAlign()
{
// align the controls
m_DynTracker.AdjustLayout(2);
Invalidate();
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonTopAlign()
{
// align the controls
m_DynTracker.AdjustLayout(3);
Invalidate();
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonBottomAlign()
{
// align the controls
m_DynTracker.AdjustLayout(4);
Invalidate();
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonMakeSameWidth()
{
// make same width
m_DynTracker.AdjustLayout(5);
Invalidate();
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonMakeSameHeight()
{
// make same height
m_DynTracker.AdjustLayout(6);
Invalidate();
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnButtonMakeSameSize()
{
// make same size
m_DynTracker.AdjustLayout(7);
Invalidate();
}
template <class BASECLASS> void CDynWnd<BASECLASS>::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// trap the delete key for deletion of a control
if (nChar == 46 /*delete*/ && m_bInScreenDesignerMode && m_DynTracker.GetSize() == 1)
{
int nID = m_DynTracker.GetIDSelected();
// get the control
POSITION posDynControl = m_ptrDynControls.GetHeadPosition();
CDynControl* pDynControl;
BOOL bFound = FALSE;
while (posDynControl)
{
POSITION posDynControlCurrent = posDynControl;
pDynControl = (CDynControl*)m_ptrDynControls.GetNext(posDynControl);
if (pDynControl->GetID() == nID)
{
bFound = TRUE;
GetDlgItem(pDynControl->GetID())->ShowWindow(SW_HIDE);
// redraw the original control
if (pDynControl->GetDynamic() == FALSE)
{
// refresh the properties
//if (m_pDynCurrentControl->m_structControlData.nType == 2
// || m_pDynCurrentControl->m_structControlData.nType == 4)
//{
GetDlgItem(pDynControl->GetID())->SetWindowText(pDynControl->m_Originalvalue);
CRect rectOriginal(pDynControl->m_Originalx,
pDynControl->m_Originaly,
pDynControl->m_Originalx + pDynControl->m_Originalcx,
pDynControl->m_Originaly + pDynControl->m_Originalcy);
::MapDialogRect(this->m_hWnd, rectOriginal);
ClientToScreen(rectOriginal);
CRect r;
GetDlgItem(pDynControl->GetID())->GetWindowRect(r);
ScreenToClient(rectOriginal);
GetDlgItem(pDynControl->GetID())->SetWindowPos
(NULL, rectOriginal.left,
rectOriginal.top,
rectOriginal.Width(),
rectOriginal.Height(), SWP_SHOWWINDOW | SWP_NOZORDER);
GetDlgItem(pDynControl->GetID())->ShowWindow(SW_NORMAL);
InvalidateRect(NULL);
// reset sane
pDynControl->ResetSane();
}
else
{
m_ptrDynControls.RemoveAt(posDynControlCurrent);
delete pDynControl;
}
m_DynTracker.RemoveAll();
break;
}
}
ASSERT(bFound);
Invalidate();
UpdateWindow();
}
else
BASECLASS::OnKeyDown(nChar, nRepCnt, nFlags);
}
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_DYNWND_H__C4176220_D285_11D0_93E9_004F4C01BE64__INCLUDED_)