Click here to Skip to main content
15,887,346 members
Articles / Desktop Programming / MFC

Screen Designer Classes

Rate me:
Please Sign up or sign in to vote.
4.93/5 (39 votes)
7 Mar 20045 min read 147.5K   3.9K   109  
Screen Designer Classes for MFC applications
// 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_)


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions