//
//	Copyright © 2006 Nemetschek North America 
//	All Rights Reserved.
//
// Created by Vladislav Stanev

#include "StdHeaders.h"

#include "Dialog.h"
#include "DialogEventArgs.h"

#include "Control.h"
#include "CheckButtonCtrl.h"
#include "GroupBoxCtrl.h"
#include "ListBoxCtrl.h"
#include "ListBrowserCtrl.h"
#include "MarkerPopupCtrl.h"
#include "PictureCtrl.h"
#include "PullDownMenuCtrl.h"
#include "PushButtonCtrl.h"
#include "RadioButtonCtrl.h"
#include "RadioGroupBoxCtrl.h"
#include "StaticTextCtrl.h"
#include "TabPaneCtrl.h"
#include "TabCtrl.h"
#include "ThumbnailPopupCtrl.h"
#include "CheckButtonCtrl.h"
#include "CheckGroupBoxCtrl.h"
#include "ColorButtonCtrl.h"
#include "EditIntegerCtrl.h"
#include "EditRealCtrl.h"
#include "EditTextCtrl.h"
#include "SliderCtrl.h"
#include "ColorPopupCtrl.h"
#include "PatternPopupCtrl.h"
#include "LineAttributePopupCtrl.h"
#include "LineStylePopupCtrl.h"
#include "LineWeightPopupCtrl.h"
#include "CustomCtrl.h"
#include "DialogData.h"


// memory managment macros
#define		NEW_OBJECT(T)				new ( malloc( sizeof(T) ) ) T
#define		DELETE_OBJECT(T, p)			if ( p ) { p->~T(); free( p ); } p = NULL;

using namespace VectorWorks::VWUI;

EVENT_DISPATCH_MAP_BEGIN( VWDialog );
EVENT_DISPATCH_MAP_END;

VWDialog::VWDialog()
: VWControlsContainer( 0 )
{
	fbIsSetup				= false;
	fpItemHit				= NULL;

	// allocate arrays
	fpArrControls			= NEW_OBJECT( TControlsArray );
	fpArrTabPanes			= NEW_OBJECT( TTabPanesArray );
	fpArrDDXData			= NEW_OBJECT( TDDXDataArray );
	farrSavedSettingsItems	= NEW_OBJECT( TSavedSettingsItemsArray );
	
	this->InitExtendedEventSupport();
}

VWDialog::~VWDialog()
{
	this->DeinitExtendedEventSupport();

	TControlsArray*				pArrControls	= (TControlsArray*) fpArrControls;
	TTabPanesArray*				pArrPanes		= (TTabPanesArray*) fpArrTabPanes;
	TDDXDataArray*				pArrDDX			= (TDDXDataArray*) fpArrDDXData;
	TSavedSettingsItemsArray*	pArrSSData		= (TSavedSettingsItemsArray*) farrSavedSettingsItems;

	if ( pArrControls ) {
		size_t				len				= pArrControls->size();
		for(size_t i=0; i<len; i++) {
			SChildControls&	child	= (*pArrControls)[ i ];
			if ( child.bFake ) {
				DELETE_OBJECT( VWControl, child.pControl );
			}
		}
		pArrControls->clear();
	}

	// free
	DELETE_OBJECT( TControlsArray, pArrControls );
	DELETE_OBJECT( TTabPanesArray, pArrPanes );
	DELETE_OBJECT( TDDXDataArray, pArrDDX );
	DELETE_OBJECT( TSavedSettingsItemsArray, pArrSSData );

	fpArrControls		= NULL;
	fpArrTabPanes		= NULL;
	fpArrDDXData		= NULL;
	pArrSSData			= NULL;
}

bool VWDialog::CreateDilaog(const TXString& dlgTitle, const TXString& defaultBtn, const TXString& cancelBtn, bool hasHelp/*=true*/, bool bResizableWidth/*=false*/, bool bResizableHeight/*=false*/)
{
	if ( bResizableWidth || bResizableHeight ) {
		fControlID = ::GS_CreateResizableLayout( gCBP, dlgTitle, hasHelp, defaultBtn, cancelBtn, bResizableWidth, bResizableHeight );
	}
	else {
		fControlID = ::GS_CreateLayout( gCBP, dlgTitle, hasHelp, defaultBtn, cancelBtn );
	}
	return ::GS_VerifyLayout( gCBP, fControlID ) ? true : false;
}

bool VWDialog::CreateDilaog(short strListID, short dlgTitleIndex, short defaultBtnIndex, short cancelBtnIndex, bool hasHelp/*=true*/, bool bResizableWidth/*=false*/, bool bResizableHeight/*=false*/)
{
	Str255 theString;
	::GS_GetResourceString( gCBP, strListID, dlgTitleIndex, theString );
	TXString		dlgTitle( theString );
	::GS_GetResourceString( gCBP, strListID, defaultBtnIndex, theString );
	TXString		defaultBtn( theString );
	::GS_GetResourceString( gCBP, strListID, cancelBtnIndex, theString );
	TXString		cancelBtn( theString );


	if ( bResizableWidth || bResizableHeight ) {
		fControlID = ::GS_CreateResizableLayout( gCBP, dlgTitle, hasHelp, defaultBtn, cancelBtn, bResizableWidth, bResizableHeight );
	}
	else {
		fControlID = ::GS_CreateLayout( gCBP, dlgTitle, hasHelp, defaultBtn, cancelBtn);
	}
	return ::GS_VerifyLayout( gCBP, fControlID ) ? true : false;
}

bool VWDialog::CreateDialogLayoutFromRsrc(short TEXTResourceID)
{
	fControlID = ::GS_GetLayoutFromRsrc( gCBP, TEXTResourceID );
	return ::GS_VerifyLayout( gCBP, fControlID ) ? true : false;
}

TXString VWDialog::GetContextualHelpID() const
{
	return TXString();
}

TControlID VWDialog::GetDialogID() const
{
	return fControlID;
}

void VWDialog::SetDefaultButtonHelpString(const TXString& helpText)
{
	::GS_SetHelpText( gCBP, fControlID, 1, helpText );
}

void VWDialog::SetDefaultButtonHelpString(short strListID, short strHelpIndex)
{
	this->SetDefaultButtonHelpString( TXString( strListID, strHelpIndex ) );
}

void VWDialog::SetCancelButtonHelpString(const TXString& helpText)
{
	::GS_SetHelpText( gCBP, fControlID, 2, helpText );
}

void VWDialog::SetCancelButtonHelpString(short strListID, short strHelpIndex)
{
	this->SetCancelButtonHelpString( TXString( strListID, strHelpIndex ) );
}


ViewRect VWDialog::GetDialogDimension() const
{
	short	left, top, right, bottom;
	Boolean	ok	= ::GS_GetLayoutDialogPosition( gCBP, this->GetDialogID(), left, top, right, bottom );
	VERIFYN( kVStanev, ok );

	ViewRect	dlgDim;
	if ( ok ) {
		dlgDim.left			= left;
		dlgDim.top			= top;
		dlgDim.right		= right;
		dlgDim.bottom		= bottom;
	}

	return dlgDim;
}

ViewPt VWDialog::GetDialogPosition() const
{
	short	left, top, right, bottom;
	Boolean	ok	= ::GS_GetLayoutDialogPosition( gCBP, this->GetDialogID(), left, top, right, bottom );
	VERIFYN( kVStanev, ok );

	ViewPt	dlgPos;
	if ( ok ) {
		dlgPos.x			= left;
		dlgPos.y			= top;
	}

	return dlgPos;
}

void VWDialog::SetDialogPosition(ViewCoord left, ViewCoord top)
{
	VERIFYN( kVStanev, ::GS_SetLayoutDialogPosition( gCBP, this->GetDialogID(), left, top ) );
}

void VWDialog::GetDialogSize(ViewCoord& outWidth, ViewCoord& outHeight) const
{
	short		width, height;
	::GS_GetLayoutDialogSize( gCBP, this->GetDialogID(), width, height);

	outWidth		= width;
	outHeight		= height;
}

void VWDialog::SetDialogSize(ViewCoord width, ViewCoord height) const
{
	::GS_SetLayoutDialogSize( gCBP, this->GetDialogID(), width, height );
}

EDialogButton VWDialog::RunDialogLayout()
{
	// first create the layout
	if ( ! this->CreateDialogLayout() )
		return kDialogButton_None;

	TControlID	result	= 0;
	// check if the dialog was created with CreateDilaogLayout
	ASSERTN( kVStanev, fControlID != 0 );
	if ( fControlID == 0 )
		return kDialogButton_None;

	// set off the setup of the dialog
	// we dont want to dispatch messages untill the dialog is setup
	fbIsSetup			= false;

	bool	isLayoutOK	= ::GS_VerifyLayout( gCBP, fControlID );
	ASSERTN( kVStanev, isLayoutOK );
	// Verify that all items were created on the dialog.
	if ( isLayoutOK ) {
		// Display the dialog. Will call the Event handling routine specified.  
		// Returns the id of the button used to close the dialog: 1 for default button, 2 for cancel button.
		result = ::GS_RunLayoutDialog( gCBP, fControlID, VWDialog::DialogEventHandler, this );
	}

	return (EDialogButton) result;
}

void VWDialog::DialogEventHandler(long dlogID, long& itemHit, void* data, void* env)
{
	VWDialog*		pEnv	= static_cast<VWDialog*>( env );
	ASSERTN( kVStanev, pEnv );
	if ( pEnv )
	{
		// assert that this event belongs to the environment dialog that has to be called
		ASSERTN( kVStanev, pEnv->fControlID == dlogID );
		pEnv->LocalDialogEventHandler( itemHit, data );
	}
}

void VWDialog::LocalDialogEventHandler(long& itemHit, void* pData)
{
	ASSERTN( kVStanev, fpArrControls );
	ASSERTN( kVStanev, fpArrTabPanes );
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrControls == NULL || fpArrTabPanes == NULL || fpArrDDXData == NULL )
		return;
	TTabPanesArray&		arrPanes		= * ((TTabPanesArray*) fpArrTabPanes);

	bool		bUpdateUI		= false;

	switch( itemHit )
	{
	case kSetupMessage: {
			this->OnSetUpEvent();

			bUpdateUI		= true;
			fbIsSetup		= true;
		} break;
	case kSetdownMessage: {
			this->OnSetDownEvent();

			size_t	len		= arrPanes.size();
			for(size_t i=0; i<len; i++) {
				VWTabPaneCtrl*	pPane	= arrPanes[ i ];
				pPane->OnSetDownEvent();
			}
			fbIsSetup		= false;
		} break;
	case kDefaultButtonID:
		// update the variables
		this->UpdateData( false );

		// let itemHit be 0 which means that the dialog wont close
		// by 'fpItemHit' VWDialog function for default button handling can set itemHit not null and cause dialog to close
		fpItemHit		= & itemHit;
		itemHit			= 0;
		this->OnDefaultButtonEvent();
		fpItemHit		= NULL;
		break;
	case kCancelButtonID:
		// let itemHit be 0 which means that the dialog wont close
		// by 'fpItemHit' VWDialog function for cancel button handling can set itemHit not null and cause dialog to close
		fpItemHit		= & itemHit;
		itemHit			= 0;
		this->OnCancelButtonEvent();
		fpItemHit		= NULL;
		break;
#ifndef _VWFC_FOR_VW125x
	case kDialogDisplayContextualHelp: {
			TXString	contextualHelpID	= this->GetContextualHelpID();
			if ( ! contextualHelpID.IsEmpty() ) {
				if ( ::GS_DisplayContextualHelp( gCBP, contextualHelpID ) ) {
					itemHit = kDialogHasContextualHelp;
				}
			}
		} break;
#endif
	default: {
			// dont dispatch if the dialog has not need setup
			// there were the times when VW called event for the tab control
			// even before the setup event -- prevet this!!!
			if ( fbIsSetup ) {
				// update the variables
				this->UpdateData( false );

				bUpdateUI		= true;

				// control IDs are always positive values
				// negative value for 'itemHit' is used to
				// specify special event for the control with Abs(itemHit) ID
				// we let the VWDialogEventArgs class handle this specific event
				// and work with absolute control ID value
				long		controlID	= itemHit >= 0 ? itemHit : - itemHit;
				VWControl*	pControl	= this->GetControl( controlID );
				if ( pControl )
					this->OnControlEvent( pControl );

				fpItemHit		= & itemHit;

				VWDialogEventArgs	eventArg( this->GetControlID(), itemHit, pData );
				this->OnBeforeDispatchEvent( controlID, eventArg );

				// dispatch the event into the dialogs' event dispatching map
				this->DispatchEvent( controlID, eventArg );

				if ( itemHit > 2 ) {
					size_t	len		= arrPanes.size();
					for(size_t i=0; i<len; i++) {
						VWTabPaneCtrl*	pPane	= arrPanes[ i ];
						pPane->DispatchEvent( itemHit, eventArg );
					}
				}

				fpItemHit		= NULL;
			}
		} break;
	}


	if ( bUpdateUI ) {
		this->OnUpdateUI();

		size_t	len		= arrPanes.size();
		if ( len > 0 ) {
			bool	bEnableOK	= true;
			for(size_t i=0; i<len; i++) {
				VWTabPaneCtrl*	pPane	= arrPanes[ i ];
				pPane->OnUpdateUI();
				bEnableOK	= bEnableOK && pPane->CanEnableOK();
			}
			this->EnableDefaultButton( bEnableOK );
		}
	}
}

void VWDialog::OnSetUpEvent()
{
	fSavedDialogPosition.MakeEmpty();

	// before all, read saved settings for this dialog if available
	this->UpdateSavedSettings( true );

	if ( ! fSavedDialogPosition.IsEmpty() ) {
		// set the saved settings dialog dimensions
		this->SetDialogPosition( fSavedDialogPosition.left, fSavedDialogPosition.top );
		this->SetDialogSize( fSavedDialogPosition.Width(), fSavedDialogPosition.Height() );
	}

	ASSERTN( kVStanev, fpArrTabPanes );
	if ( fpArrTabPanes == NULL )
		return;
	TTabPanesArray&		arrPanes		= * ((TTabPanesArray*) fpArrTabPanes);

	// set up event to the panes
	size_t	panesCnt		= arrPanes.size();
	for(size_t i=0; i<panesCnt; i++) {
		VWTabPaneCtrl*	pPane	= arrPanes[ i ];
		pPane->OnSetUpEvent();
	}

	// initialize content before attaching DDX
	this->OnInizializeContent();

	// initialize DDX
	this->OnDDXInitialize();
	for(size_t i=0; i<panesCnt; i++) {
		VWTabPaneCtrl*	pPane	= arrPanes[ i ];
		pPane->OnDDXInitialize();
	}
	
	// update UI
	this->UpdateData( true );
}

void VWDialog::OnSetDownEvent()
{
	// get dialog dimensions
	ViewCoord	width	= 0;
	ViewCoord	height	= 0;
	ViewPt		dlgPos	= this->GetDialogPosition();
	this->GetDialogSize( width, height );

	// ... and prepare it as saved settings
	fSavedDialogPosition.left	= dlgPos.x;
	fSavedDialogPosition.top	= dlgPos.y;
	fSavedDialogPosition.left	= dlgPos.x + width;
	fSavedDialogPosition.top	= dlgPos.y + height;

	// save saved settings for this dialog if available
	this->UpdateSavedSettings( false );
}

void VWDialog::OnDefaultButtonEvent()
{
	if ( fpItemHit )
		*fpItemHit	= 1;
}

void VWDialog::OnCancelButtonEvent()
{
	if ( fpItemHit )
		*fpItemHit	= 2;
}

void VWDialog::OnControlEvent(VWControl* /*pParentControl*/)
{
}

void VWDialog::OnBeforeDispatchEvent(TControlID /*controlID*/, VWDialogEventArgs& /*eventArg*/)
{
}

void VWDialog::OnInizializeContent()
{
}

void VWDialog::OnUpdateUI()
{
}

TXString VWDialog::GetDialogTitle() const
{
	GSStr255	title;
	::GS_GetItemText( gCBP, this->GetDialogID(), this->GetDialogID(), title );
	return title;
}

void VWDialog::SetDialogTitle( const TXString &inTitle )
{
	GSStr255	title;
	
	inTitle.CopyInto( title );
	::GS_SetItemText( gCBP, this->GetDialogID(), this->GetDialogID(), title );
}

void VWDialog::EnableDefaultButton(bool bEnable)
{
	::GS_EnableItem( gCBP, fControlID, 1, bEnable );
}

void VWDialog::EnableCancelButton(bool bEnable)
{
	::GS_EnableItem( gCBP, fControlID, 2, bEnable );
}

void VWDialog::EnableControl(TControlID id, bool bEnable)
{
	::GS_EnableItem( gCBP, fControlID, id, bEnable );
}

void VWDialog::ShowControl(TControlID id, bool bVisible)
{
	::GS_ShowItem( gCBP, fControlID, id, bVisible );
}

void VWDialog::SetControlHelpText(TControlID id, const TXString& helpText)
{
	::GS_SetHelpText( gCBP, fControlID, id, helpText );
}

void VWDialog::AddFirstGroupControl(VWControl* pControl)
{
	VERIFYN( kVStanev, ::GS_SetFirstLayoutItem( gCBP, fControlID, pControl->GetControlID() ) );
	this->AddControl( pControl );
}

void VWDialog::AddBelowControl(VWControl* pExistingControl, VWControl* pNewControl, short indent /*=0*/, short lineSpacing /*=0*/)
{
	VERIFYN( kVStanev, ::GS_SetBelowItem( gCBP, fControlID, pExistingControl->GetControlID(), pNewControl->GetControlID(), indent, lineSpacing ) );			
	this->AddControl( pNewControl );
}

void VWDialog::AddRightControl(VWControl* pExistingControl, VWControl* pNewControl, short indent /*=0*/, short lineSpacing /*=0*/)
{
	VERIFYN( kVStanev, ::GS_SetRightItem( gCBP, fControlID, pExistingControl->GetControlID(), pNewControl->GetControlID(), indent, lineSpacing ) );
	this->AddControl( pNewControl );
}

VWCheckButtonCtrl* VWDialog::GetCheckButtonCtrByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWCheckButtonCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWCheckButtonCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWCheckButtonCtrl*) pControl;
}

VWGroupBoxCtrl* VWDialog::GetGroupBoxCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWGroupBoxCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWGroupBoxCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWGroupBoxCtrl*) pControl;
}

VWListBoxCtrl* VWDialog::GetListBoxCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWListBoxCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWListBoxCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWListBoxCtrl*) pControl;
}

VWMarkerPopupCtrl* VWDialog::GetMarkerPopupCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWMarkerPopupCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWMarkerPopupCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWMarkerPopupCtrl*) pControl;
}

VWPictureCtrl* VWDialog::GetPictureCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWPictureCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWPictureCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWPictureCtrl*) pControl;
}

VWPullDownMenuCtrl* VWDialog::GetPullDownMenuCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWPullDownMenuCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWPullDownMenuCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWPullDownMenuCtrl*) pControl;
}

VWPushButtonCtrl* VWDialog::GetPushButtonCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWPushButtonCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWPushButtonCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWPushButtonCtrl*) pControl;
}

VWRadioButtonCtrl* VWDialog::GetRadioButtonCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWRadioButtonCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWRadioButtonCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWRadioButtonCtrl*) pControl;
}

VWRadioGroupBoxCtrl* VWDialog::GetRadioGroupBoxCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWRadioGroupBoxCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWRadioGroupBoxCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWRadioGroupBoxCtrl*) pControl;
}

VWStaticTextCtrl* VWDialog::GetStaticTextCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWStaticTextCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWStaticTextCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWStaticTextCtrl*) pControl;
}

VWTabPaneCtrl* VWDialog::GetTabPaneCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWTabPaneCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWTabPaneCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWTabPaneCtrl*) pControl;
}

VWTabCtrl* VWDialog::GetTabCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWTabCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWTabCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWTabCtrl*) pControl;
}

VWSwapPaneCtrl* VWDialog::GetSwapPaneCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWSwapPaneCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWSwapPaneCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWSwapPaneCtrl*) pControl;
}

VWSwapCtrl* VWDialog::GetSwapCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWSwapCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWSwapCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWSwapCtrl*) pControl;
}


VWThumbnailPopupCtrl* VWDialog::GetThumbnailPopupCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWThumbnailPopupCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWThumbnailPopupCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWThumbnailPopupCtrl*) pControl;
}

VWCheckButtonCtrl* VWDialog::GetCheckButtonCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWCheckButtonCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWCheckButtonCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWCheckButtonCtrl*) pControl;
}

VWCheckGroupBoxCtrl* VWDialog::GetCheckGroupBoxCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWCheckGroupBoxCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWCheckGroupBoxCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWCheckGroupBoxCtrl*) pControl;
}

VWColorButtonCtrl* VWDialog::GetColorButtonCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWColorButtonCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWColorButtonCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWColorButtonCtrl*) pControl;
}

VWEditIntegerCtrl* VWDialog::GetEditIntegerCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWEditIntegerCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWEditIntegerCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWEditIntegerCtrl*) pControl;
}

VWEditRealCtrl* VWDialog::GetEditRealCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWEditRealCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWEditRealCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWEditRealCtrl*) pControl;
}

VWEditTextCtrl* VWDialog::GetEditTextCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWEditTextCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWEditTextCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWEditTextCtrl*) pControl;
}

VWSliderCtrl* VWDialog::GetSliderCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWSliderCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWSliderCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWSliderCtrl*) pControl;
}

VWColorPopupCtrl* VWDialog::GetColorPopupCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWColorPopupCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWColorPopupCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWColorPopupCtrl*) pControl;
}


VWColorPopupCustomCtrl* VWDialog::GetColorPopupCustomCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWColorPopupCustomCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWColorPopupCustomCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWColorPopupCustomCtrl*) pControl;
}

VWPatternPopupCtrl* VWDialog::GetPatternPopupCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWPatternPopupCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWPatternPopupCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWPatternPopupCtrl*) pControl;
}

VWLineAttributePopupCtrl* VWDialog::GetLineAttributePopupCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWLineAttributePopupCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWLineAttributePopupCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWLineAttributePopupCtrl*) pControl;
}

VWLineStylePopupCtrl* VWDialog::GetLineStylePopupCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWLineStylePopupCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWLineStylePopupCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWLineStylePopupCtrl*) pControl;
}

VWLineWeightPopupCtrl* VWDialog::GetLineWeightPopupCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWLineWeightPopupCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWLineWeightPopupCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWLineWeightPopupCtrl*) pControl;
}

VWListBrowserCtrl* VWDialog::GetListBrowserCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWListBrowserCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWListBrowserCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWListBrowserCtrl*) pControl;
}

VWTreeCtrl* VWDialog::GetTreeCtrlByID(TControlID id)
{
	VWControl*	pControl	= this->GetControl( id );
	if ( pControl )
		return dynamic_cast<VWTreeCtrl*>( pControl );
	pControl				= NEW_OBJECT(VWTreeCtrl)( id );
	pControl->fpParentDlg	= this;
	this->AddControl( pControl, true );
	return (VWTreeCtrl*) pControl;
}

VWControl* VWDialog::GetControl(TControlID id)
{
	ASSERTN( kVStanev, fpArrControls );
	if ( fpArrControls == NULL )
		return NULL;
	TControlsArray&		arrControls		= * ((TControlsArray*) fpArrControls);

	size_t		len		= arrControls.size();
	for(size_t i=0; i<len; i++) {
		SChildControls&	child	= arrControls[ i ];
		if ( child.pControl->GetControlID() == id )
			return child.pControl;
	}
	return NULL;
}

void VWDialog::AddControl(VWControl* pControl, bool fake /*=false*/)
{
	ASSERTN( kVStanev, fpArrControls );
	if ( fpArrControls == NULL )
		return;
	TControlsArray&		arrControls		= * ((TControlsArray*) fpArrControls);

	ASSERTN( kVStanev, pControl );
	if ( pControl == NULL )
		return;

	VWControl*			pCtrl	= this->GetControl( pControl->GetControlID() );
	// ups we have a control with this ID
	ASSERTN( kVStanev, pCtrl == NULL );
	if ( pCtrl != NULL )
		return;

	SChildControls		child;
	child.bFake				= fake;
	child.pControl			= pControl;
	arrControls.push_back( child );
}

// tab pane managment
void VWDialog::AddTabPaneControl(VWTabPaneCtrl* pTabPane)
{
	ASSERTN( kVStanev, fpArrTabPanes );
	if ( fpArrTabPanes == NULL )
		return;
	TTabPanesArray&		arrPanes		= * ((TTabPanesArray*) fpArrTabPanes);

	pTabPane->fpParentDlg	= this;
	this->AddControl( pTabPane );
	arrPanes.push_back( pTabPane );
}

void VWDialog::UpdateData(bool bSafeToUI/*=false*/)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	size_t	len	= arrDDX.size();
	for(size_t i=0; i<len; i++) {
		SDDXData&	data	= arrDDX[ i ];
		switch( data.type ) {
			case kDDXTypeStaticText: {
					VWStaticTextCtrl*		pCtrl	= this->GetStaticTextCtrlByID( data.controlID );
					TXString*				pData	= (TXString*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetControlText( *pData );
				} break;
			case kDDXTypeCheckButton: {
					VWCheckButtonCtrl*		pCtrl	= this->GetCheckButtonCtrByID( data.controlID );
					bool*					pData	= (bool*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetState( *pData );
					if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetState();
				} break;
				
			case kDDXTypeCheckButtonBoolean: {
					VWCheckButtonCtrl*		pCtrl	= this->GetCheckButtonCtrByID( data.controlID );
					Boolean*				pData	= (Boolean*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetState( *pData );
					if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetState();
				} break;

			case kDDXTypeCheckGroupBox: {
					VWCheckGroupBoxCtrl*	pCtrl	= this->GetCheckGroupBoxCtrlByID( data.controlID );
					bool*					pData	= (bool*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetState( *pData );
					if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetState();
				} break;
			case kDDXTypeColorButton: {					
					VWColorButtonCtrl*		pCtrl	= this->GetColorButtonCtrlByID( data.controlID );
					RGBColor*				pData	= (RGBColor*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetColor( *pData );
					if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetColor();
				} break;
			case kDDXTypeEditInteger: {					
					VWEditIntegerCtrl*		pCtrl	= this->GetEditIntegerCtrlByID( data.controlID );
					long*					pData	= (long*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetEditInteger( *pData );
					if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetEditInteger();
				} break;
			case kDDXTypeEditReal: {					
					VWEditRealCtrl*			pCtrl	= this->GetEditRealCtrlByID( data.controlID );
					double*					pData	= (double*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetEditReal( *pData, (VWEditRealCtrl::EEditControlType) data.lData );
					if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetEditReal( (VWEditRealCtrl::EEditControlType) data.lData );
				} break;
			case kDDXTypeEditText: {					
					VWEditTextCtrl*			pCtrl	= this->GetEditTextCtrlByID( data.controlID );
					TXString*				pData	= (TXString*) data.pData;
					if ( pCtrl && pData && bSafeToUI ) {
						if ( data.lData )	pCtrl->SetMultilineText( *pData );
						else				pCtrl->SetText255( *pData );
					}
					if ( pCtrl && pData && ! bSafeToUI ) {
						if ( data.lData )	pCtrl->GetMultilineText( *pData );
						else				pCtrl->GetText255( *pData );
					}
				} break;
			case kDDXTypeSlider: {
					VWSliderCtrl*			pCtrl	= this->GetSliderCtrlByID( data.controlID );
					long*					pData	= (long*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetSliderValue( *pData );
					if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetSliderValue();
				} break;
			case kDDXTypeRadioButton: {					
					VWRadioButtonCtrl*		pCtrl	= this->GetRadioButtonCtrlByID( data.controlID );
					bool*					pData	= (bool*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetState( *pData );
					if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetState();
				} break;

			case kDDXTypeRadioButtonBoolean: {					
					VWRadioButtonCtrl*		pCtrl	= this->GetRadioButtonCtrlByID( data.controlID );
					Boolean*				pData	= (Boolean*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetState( *pData );
					if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetState();
				} break;

			case kDDXTypeRadioGroupBox: {					
					VWRadioGroupBoxCtrl*	pCtrl	= this->GetRadioGroupBoxCtrlByID( data.controlID );
					bool*					pData	= (bool*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetState( *pData );
					else if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetState();
				} break;
			case kDDXTypePulldownMenu: {
					VWPullDownMenuCtrl*	pCtrl	= this->GetPullDownMenuCtrlByID( data.controlID );
					short*				pData	= (short*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SelectIndex( *pData );
					else if ( pCtrl && pData && ! bSafeToUI )
						*pData	= pCtrl->GetSelectedIndex();
				} break;

			case kDDXTypeListBox: {
					VWListBoxCtrl*		pCtrl	= this->GetListBoxCtrlByID( data.controlID );
					short*				pData	= (short*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SelectIndex( *pData );
					else if ( pCtrl && pData && ! bSafeToUI )
						*pData	= pCtrl->GetSelectedIndex();
				} break;

			case kDDXTypeColorPopup: {
				const RGBColor		kRGBWhite	= { 0xFFFF, 0xFFFF, 0xFFFF };
				const RGBColor		kRGBBlack	= { 0x0000, 0x0000, 0x0000 };
				bool		bReverseBlackAndWhite	= false;
				if ( data.lData != 0 ) {
					::GS_GetProgramVariable( gCBP, varBlackBackground, & bReverseBlackAndWhite );
				}
				
				VWColorPopupCtrl*	pCtrl		= this->GetColorPopupCtrlByID( data.controlID );
				RGBColor*			pData		= (RGBColor*) data.pData;
				if ( pCtrl && pData && bSafeToUI ) {
					RGBColor	color					= *pData;
					if ( bReverseBlackAndWhite ) {
						if ( color.red == kRGBBlack.red && color.green == kRGBBlack.green && color.blue == kRGBBlack.blue )
							color		= kRGBWhite;
						else if ( color.red == kRGBWhite.red && color.green == kRGBWhite.green && color.blue == kRGBWhite.blue )
							color		= kRGBBlack;
					}
					
					pCtrl->SetSelectedColor( color );
				}
				else if ( pCtrl && pData && ! bSafeToUI ) {
					*pData		= pCtrl->GetSelectedColor();
					
					if ( bReverseBlackAndWhite ) {
						if ( (*pData).red == kRGBBlack.red && (*pData).green == kRGBBlack.green && (*pData).blue == kRGBBlack.blue )
							*pData		= kRGBWhite;
						else if ( (*pData).red == kRGBWhite.red && (*pData).green == kRGBWhite.green && (*pData).blue == kRGBWhite.blue )
							*pData		= kRGBBlack;
					}
				}
			} break;
				
			case kDDXTypeColorPopupCustom: {
					VWColorPopupCustomCtrl*	pCtrl	= this->GetColorPopupCustomCtrlByID( data.controlID );
					ColorRef*				pData	= (ColorRef*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetSelectedColor( *pData );
					else if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetSelectedColor();
			} break;

			case kDDXTypePatternPopup: {
					VWPatternPopupCtrl*	pCtrl	= this->GetPatternPopupCtrlByID( data.controlID );
					short*				pData	= (short*) data.pData;
					RGBColor*			pData1	= (RGBColor*) data.pData1; 
					RGBColor*			pData2	= (RGBColor*) data.pData2;	
					if ( pCtrl && pData && pData1 && pData2 && bSafeToUI )
						pCtrl->SetSelectedPattern( *pData, *pData1, *pData2 );
					else if ( pCtrl && pData && pData1 && pData2 && ! bSafeToUI )
						pCtrl->GetSelectedPattern( *pData, *pData1, *pData2 );
				} break;

			case kDDXTypeLineAttribPopup: {
					VWLineAttributePopupCtrl*	pCtrl	= this->GetLineAttributePopupCtrlByID( data.controlID );
					short*						pData	= (short*) data.pData;
					short*						pData1	= (short*) data.pData1;
					if ( pCtrl && pData && pData1 && bSafeToUI )
						pCtrl->SetSelectedAttribute( *pData, *pData1 );
					else if ( pCtrl && pData && pData1 && ! bSafeToUI )
						pCtrl->GetSelectedAttribute( *pData, *pData1 );
				} break;

			case kDDXTypeLineStylePopup: {
					VWLineStylePopupCtrl*	pCtrl	= this->GetLineStylePopupCtrlByID( data.controlID );
					short*					pData	= (short*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetSelectedLineStyle( *pData );
					else if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetSelectedLineStyle();
				} break;

			case kDDXTypeLineWeightPopup: {
					VWLineWeightPopupCtrl*	pCtrl	= this->GetLineWeightPopupCtrlByID( data.controlID );
					short*					pData	= (short*) data.pData;
					if ( pCtrl && pData && bSafeToUI )
						pCtrl->SetSelectedLineWeight( *pData );
					else if ( pCtrl && pData && ! bSafeToUI )
						*pData		= pCtrl->GetSelectedLineWeight();
				} break;
			case kDDXTypeMarkerPopup:{
					VWMarkerPopupCtrl*		pCtrl	= this->GetMarkerPopupCtrlByID( data.controlID );
					SMarkerStyle*			pValue	= (SMarkerStyle*) data.pData;
					if ( pCtrl && pValue && bSafeToUI ) {
						pCtrl->SetSelectedItem( *pValue );
					}
					else if ( pCtrl && pValue && ! bSafeToUI ) {
						pCtrl->GetSelectedItem( *pValue );
					}
				} break;
		}
	}
}

void VWDialog::AddDDX_StaticText(TControlID controlID, TXString* pValue)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pValue );
	SDDXData		data;
	data.type				= kDDXTypeStaticText;
	data.controlID			= controlID;
	data.pData				= (void*) pValue;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_CheckButton(TControlID controlID, bool* pCheckState)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pCheckState );
	SDDXData		data;
	data.type				= kDDXTypeCheckButton;
	data.controlID			= controlID;
	data.pData				= (void*) pCheckState;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_CheckButton(TControlID controlID, Boolean* pCheckState)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pCheckState );
	SDDXData		data;
	data.type				= kDDXTypeCheckButtonBoolean;
	data.controlID			= controlID;
	data.pData				= (void*) pCheckState;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_CheckGroupBox(TControlID controlID, bool* pCheckState)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pCheckState );
	SDDXData		data;
	data.type				= kDDXTypeCheckGroupBox;
	data.controlID			= controlID;
	data.pData				= (void*) pCheckState;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_ColorButton(TControlID controlID, RGBColor* pSelectedColor)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pSelectedColor );
	SDDXData		data;
	data.type				= kDDXTypeColorButton;
	data.controlID			= controlID;
	data.pData				= (void*) pSelectedColor;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_EditInteger(TControlID controlID, long* pValue)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pValue );
	SDDXData		data;
	data.type				= kDDXTypeEditInteger;
	data.controlID			= controlID;
	data.pData				= (void*) pValue;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_EditReal(TControlID controlID, double* pValue, VWEditRealCtrl::EEditControlType editType)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pValue );
	SDDXData		data;
	data.type				= kDDXTypeEditReal;
	data.controlID			= controlID;
	data.pData				= (void*) pValue;
	data.lData				= (long) editType;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_EditText(TControlID controlID, TXString* pValue, bool bMultiline /*=false*/)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pValue );
	SDDXData		data;
	data.type				= kDDXTypeEditText;
	data.controlID			= controlID;
	data.pData				= (void*) pValue;
	data.lData				= bMultiline ? 1 : 0;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_Slider(TControlID controlID, long* pPosition)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pPosition );
	SDDXData		data;
	data.type				= kDDXTypeSlider;
	data.controlID			= controlID;
	data.pData				= (void*) pPosition;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_RadioButton(TControlID controlID, bool* pCheckState)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pCheckState );
	SDDXData		data;
	data.type				= kDDXTypeRadioButton;
	data.controlID			= controlID;
	data.pData				= (void*) pCheckState;
	arrDDX.push_back( data );
}


void VWDialog::AddDDX_RadioButton(TControlID controlID, Boolean* pCheckState)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pCheckState );
	SDDXData		data;
	data.type				= kDDXTypeRadioButtonBoolean;
	data.controlID			= controlID;
	data.pData				= (void*) pCheckState;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_RadioGroupBox(TControlID controlID, bool* pCheckState)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pCheckState );
	SDDXData		data;
	data.type				= kDDXTypeRadioGroupBox;
	data.controlID			= controlID;
	data.pData				= (void*) pCheckState;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_PulldownMenu(TControlID controlID, short* pSelected)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pSelected );
	SDDXData		data;
	data.type				= kDDXTypePulldownMenu;
	data.controlID			= controlID;
	data.pData				= (void*) pSelected;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_ListBox(TControlID controlID, short* pSelected)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pSelected );
	SDDXData		data;
	data.type				= kDDXTypeListBox;
	data.controlID			= controlID;
	data.pData				= (void*) pSelected;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_ColorPopup(TControlID controlID, RGBColor* pSelectedColor, bool bMatchBlackBkgr /*=true*/)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pSelectedColor );
	SDDXData		data;
	data.type				= kDDXTypeColorPopup;
	data.controlID			= controlID;
	data.pData				= (void*) pSelectedColor;
	data.lData				= bMatchBlackBkgr ? 1 : 0;
	arrDDX.push_back( data );
}



void VWDialog::AddDDX_ColorPopupCustom(TControlID controlID, ColorRef* pSelectedColor)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pSelectedColor );
	SDDXData		data;
	data.type				= kDDXTypeColorPopupCustom;
	data.controlID			= controlID;
	data.pData				= (void*) pSelectedColor;
	arrDDX.push_back( data );
}


void VWDialog::AddDDX_PatternPopup(TControlID controlID, short* pPatternIndex, RGBColor* pForeColor, RGBColor* pBackColor)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pPatternIndex );
	ASSERTN( kVStanev, pForeColor );
	ASSERTN( kVStanev, pBackColor );
	SDDXData		data;
	data.type				= kDDXTypePatternPopup;
	data.controlID			= controlID;
	data.pData				= (void*) pPatternIndex;
	data.pData1				= (void*) pForeColor;
	data.pData2				= (void*) pBackColor;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_LineAttribsPopup(TControlID controlID, short* pLineStyle, short* pLineWeight)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pLineStyle );
	ASSERTN( kVStanev, pLineWeight );
	SDDXData		data;
	data.type				= kDDXTypeLineAttribPopup;
	data.controlID			= controlID;
	data.pData				= (void*) pLineStyle;
	data.pData1				= (void*) pLineWeight;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_LineStylePopup(TControlID controlID, short* pLineStyle)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pLineStyle );
	SDDXData		data;
	data.type				= kDDXTypeLineStylePopup;
	data.controlID			= controlID;
	data.pData				= (void*) pLineStyle;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_LineWeightPopup(TControlID controlID, short* pLineWeight)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pLineWeight );
	SDDXData		data;
	data.type				= kDDXTypeLineWeightPopup;
	data.controlID			= controlID;
	data.pData				= (void*) pLineWeight;
	arrDDX.push_back( data );
}

void VWDialog::AddDDX_MarkerPopup(TControlID controlID, SMarkerStyle* pValue)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return;
	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	ASSERTN( kVStanev, pValue );
	SDDXData		data;
	data.type				= kDDXTypeMarkerPopup;
	data.controlID			= controlID;
	data.pData				= (void*) pValue;
	arrDDX.push_back( data );
}

bool VWDialog::GetDDXControlValue(TControlID controlID, TXString& outValue)
{
	ASSERTN( kVStanev, fpArrDDXData );
	if ( fpArrDDXData == NULL )
		return false;

	TDDXDataArray&		arrDDX			= * ((TDDXDataArray*) fpArrDDXData);

	bool	ok	= false;
	size_t	len	= arrDDX.size();
	for(size_t i=0; i<len; i++) {
		SDDXData&	data	= arrDDX[ i ];
		if ( data.controlID == controlID ) {
			switch( data.type ) {

				case kDDXTypeEditInteger: {					
						long*		pData	= (long*) data.pData;
						outValue.Format( "%d", *pData );
						ok					= true;
					} break;
				case kDDXTypeEditReal: {					
						double*		pData	= (double*) data.pData;
						outValue.Format( "%f", *pData );
						ok					= true;
					} break;
				case kDDXTypeEditText: {					
						TXString*	pData	= (TXString*) data.pData;
						outValue			= *pData;
						ok					= true;
					} break;

/*				case kDDXTypePulldownMenu: {
						VWPullDownMenuCtrl*	pCtrl	= this->GetPullDownMenuCtrlByID( data.controlID );
						short*				pData	= (short*) data.pData;
						if ( pCtrl && pData && bSafeToUI )
							pCtrl->SelectIndex( *pData );
						else if ( pCtrl && pData && ! bSafeToUI )
							*pData	= pCtrl->GetSelectedIndex();
					} break;*/

				default:
					break;
			}
		}

		if ( ok ) {
			break;
		}
	}

	return ok;
}

// ---------------------------------------------------------------------------------------------------
// tools

// Displays an alert dialog that informs the user of a serious problem
// that requires intervention or correction before work can continue.
/*static*/ void VWDialog::AlertCritical(const TXString& text, const TXString& advice)
{
	::GS_AlertCritical( gCBP, text, advice );
}

// Displays a dialog which informs the user about the result of a command.
// Offers no user choices; the user acknowledges the message by clicking the OK button.
/*static*/ void VWDialog::AlertInform(const TXString& text, const TXString& advice, bool bMinorAlert)
{
	::GS_AlertInform( gCBP, text, advice, bMinorAlert );
}

// Displays a dialog that alerts the user to a condition
// or situation that requires the user's decision and input before preceeding,
// such as an impending action with potentially destructive or irreversible consequencies. 
/*static*/ EDialogButton VWDialog::AlertQuestion(	const TXString& question,
													const TXString& advice,
													EDialogButton defaultButton,
													const TXString& strOkText,
													const TXString& strCancelText,
													const TXString& strCustomButtonAText,
													const TXString& strCustomButtonBText )
{
	// Specifies which button is to be made the default 
	//		0: the negative button is the default
	//		1: the positive button is the default
	//		2: custom button A is the default
	//		3: custom button B is the default
	short			defButton	= 0;
	switch( defaultButton ) {
		case kDialogButton_Cancel:		defButton = 0;	break;
		case kDialogButton_Ok:			defButton = 1;	break;
		case kDialogButton_CustomA:		defButton = 2;	break;
		case kDialogButton_CustomB:		defButton = 3;	break;
		default:
			break;
	}

	short			res		= ::GS_AlertQuestion( gCBP, question, advice, defButton, strOkText, strCancelText, strCustomButtonAText, strCustomButtonBText );
	EDialogButton	result	= kDialogButton_None;
	switch( res ) {
		case 0:	result = kDialogButton_Cancel;	break;
		case 1:	result = kDialogButton_Ok;		break;
		case 2:	result = kDialogButton_CustomA;	break;
		case 3:	result = kDialogButton_CustomB;	break;
		default:
			break;
	}
	return result;
}

void VWDialog::SetDialogClose(bool bCloseWithOK)
{
	if ( fpItemHit ) {
		*fpItemHit	= bCloseWithOK ? kDialogButton_Ok : kDialogButton_Cancel;
	}
}

// enables saved settings for this dialog
// if no dialog name is specified, the dialog title is used
void VWDialog::SetSavedSettingsTag(const TXString& category)
{
	fstrDialogCategory		= category;
	fstrDialogName.Clear();
}

void VWDialog::SetSavedSettingsTag(const TXString& category, const TXString& dialogName)
{
	fstrDialogCategory		= category;
	fstrDialogName			= dialogName;
}

// allows additional data to be stored in saved settings for this dialog
void VWDialog::SetSavedValue(const TXString& name, const TXString& value)
{
	TSavedSettingsItemsArray*	pArrSSData		= (TSavedSettingsItemsArray*) farrSavedSettingsItems;
	if ( pArrSSData ) {
		bool	bItemFound	= false;
		size_t	itemsCnt	= pArrSSData->size();
		for(size_t i=0; i<itemsCnt; i++) {
			SSavedSettingsItem&	item	= (*pArrSSData)[ i ];
			if ( item.name == name ) {
				item.value		= value;
				bItemFound		= true;
				break;
			}
		}

		if ( ! bItemFound ) {
			SSavedSettingsItem	item;
			item.name		= name;
			item.value		= value;
			pArrSSData->push_back( item );
		}
	}
}

bool VWDialog::GetSavedValue(const TXString& name, TXString& outValue) const
{
	bool	bItemFound	= false;

	TSavedSettingsItemsArray*	pArrSSData		= (TSavedSettingsItemsArray*) farrSavedSettingsItems;
	if ( pArrSSData ) {
		size_t	itemsCnt	= pArrSSData->size();
		for(size_t i=0; i<itemsCnt; i++) {
			const SSavedSettingsItem&	item	= (*pArrSSData)[ i ];
			if ( item.name == name ) {
				outValue		= item.value;
				bItemFound		= true;
				break;
			}
		}
	}

	return bItemFound;
}

void VWDialog::UpdateSavedSettings(bool bRead)
{
	const TXString			kX			= "x";
	const TXString			kY			= "y";
	const TXString			kWidth		= "width";
	const TXString			kHeight		= "height";

	TSavedSettingsItemsArray*	pArrSSData		= (TSavedSettingsItemsArray*) farrSavedSettingsItems;
	if ( ! fstrDialogCategory.IsEmpty() && pArrSSData ) {
		if ( fstrDialogName.IsEmpty() ) {
			fstrDialogName	= this->GetDialogTitle();
		}

		// prepare full string category for this dialog
		TXString		theDlgCategory	= fstrDialogCategory + "/" + fstrDialogName;

		// ensure the category name doesn't contain illegal caracters
		// nothing but chars or numbers goes in
		TXString	dlgCategory;
		int			charsCnt		= theDlgCategory.GetLength();
		for(int i=0; i<charsCnt; i++) {
			char	c		= theDlgCategory.GetAt( i );
			if ( c != '/' ) {
				bool	isDigit	= ( (((c) >= '0') && ((c) <= '9')) );
				bool	isAlpha	= ( (((c) >= 'a') && ((c) <= 'z')) ) || ( (((c) >= 'A') && ((c) <= 'Z')) );
				bool	isOk	= isAlpha || (i > 0 && isDigit);
				if ( isOk ) {
					dlgCategory	+= c;
				}
			}
			else {
				dlgCategory	+= c;
			}
		}

		if ( bRead ) {
			// read dialog position
			Str255		strX, strY, strWidth, strHeight;
			if ( ::GS_GetSavedSetting( gCBP, dlgCategory, kX, strX ) &&
				 ::GS_GetSavedSetting( gCBP, dlgCategory, kY, strY ) &&
				 ::GS_GetSavedSetting( gCBP, dlgCategory, kWidth, strWidth ) &&
				 ::GS_GetSavedSetting( gCBP, dlgCategory, kHeight, strHeight ) )
			{
				fSavedDialogPosition.left	= TXString(strX).atoi();
				fSavedDialogPosition.top	= TXString(strY).atoi();
				fSavedDialogPosition.right	= fSavedDialogPosition.left + TXString(strWidth).atoi();
				fSavedDialogPosition.bottom	= fSavedDialogPosition.top + TXString(strHeight).atoi();
			}

			// read user defined items
			size_t	itemsCnt	= pArrSSData->size();
			for(size_t i=0; i<itemsCnt; i++) {
				SSavedSettingsItem&	item	= (*pArrSSData)[ i ];

				Str255	value;
				if ( ::GS_GetSavedSetting( gCBP, dlgCategory, item.name, value ) ) {
					item.value	= value;
				}
			}
		}
		else {
			// save dialog position
			ViewPt		dlgPos	= this->GetDialogPosition();
			
			ViewCoord	dialogWidth;
			ViewCoord	dialogHeight;			
			this->GetDialogSize( dialogWidth, dialogHeight );
			
			TXString	strX;		strX.Format( "%d", dlgPos.x );
			TXString	strY;		strY.Format( "%d", dlgPos.y );
			TXString	strWidth;	strWidth.Format( "%d", dialogWidth );
			TXString	strHeight;	strHeight.Format( "%d", dialogHeight );

			::GS_SetSavedSetting( gCBP, dlgCategory, kX, strX );
			::GS_SetSavedSetting( gCBP, dlgCategory, kY, strY );
			::GS_SetSavedSetting( gCBP, dlgCategory, kWidth, strWidth );
			::GS_SetSavedSetting( gCBP, dlgCategory, kHeight, strHeight );

			// save user defined items
			size_t	itemsCnt	= pArrSSData->size();
			for(size_t i=0; i<itemsCnt; i++) {
				const SSavedSettingsItem&	item	= (*pArrSSData)[ i ];
				::GS_SetSavedSetting( gCBP, dlgCategory, item.name, item.value );
			}
		}
	}
}

// extended eventing support for custom controls
void VWDialog::InitExtendedEventSupport()
{
#ifndef _WINDOWS
	fEventHandlerRef		= NULL;
	fEventHandlerUPP		= NULL;
#endif
}

void VWDialog::DeinitExtendedEventSupport()
{
#ifndef _WINDOWS
	if ( fEventHandlerUPP ) {
		DisposeEventHandlerUPP( fEventHandlerUPP );
	}

	if ( fEventHandlerRef ) {
		RemoveEventHandler( fEventHandlerRef );
	}
#endif
}

void VWDialog::InstallExtendedEventSupport(VWControl* pControl)
{
#ifndef _WINDOWS
	VWCustomCtrl*	pCustomCtrl	= dynamic_cast<VWCustomCtrl*>( pControl );
	if ( pCustomCtrl ) {
		WindowRef	windowRef	= (WindowRef)  pCustomCtrl->GetOSParentHandle();
		
		// Install the window event handler
		EventTypeSpec    kEvents[] =
		{
 	    	{ kEventClassMouse, kEventMouseWheelMoved },
 	    	{ kEventClassMouse, kEventMouseDown },
			{ kEventClassMouse, kEventMouseUp },
			{ kEventClassMouse, kEventMouseMoved },
			{ kEventClassMouse, kEventMouseDragged },
		};    	

		fEventHandlerUPP		= NewEventHandlerUPP( VWDialog::_WindowMouseEventHandler );
		InstallEventHandler(	GetWindowEventTarget( windowRef ),
								fEventHandlerUPP,
								GetEventTypeCount( kEvents ),
								kEvents,
								this,
								& fEventHandlerRef );
	}
#endif
}

#ifndef _WINDOWS
VWCustomCtrl* VWDialog::GetCustomCtrlAtPoint(const ViewPt& pt)
{
	VWCustomCtrl*	pFoundCtrl	= NULL;

	ASSERTN( kVStanev, fpArrControls );
	if ( fpArrControls ) {
		TControlsArray&		arrControls		= * ((TControlsArray*) fpArrControls);

		size_t	ctrlsCnt	= arrControls.size();
		for(size_t i=0; i<ctrlsCnt; i++) {
			SChildControls&		controlDef	= arrControls[ i ];

			VWCustomCtrl*	pCustomCtrl	= dynamic_cast<VWCustomCtrl*>( controlDef.pControl );
			if ( pCustomCtrl ) {
				ViewRect	ctrlRect	= pCustomCtrl->GetControlRect();
				if ( pCustomCtrl->IsVisible() && ctrlRect.PtInRect( ViewPt(pt) ) ) {
					pFoundCtrl	= pCustomCtrl;
					// found! BREAK!
					break;
				}
			}
		}
	}
	
	return pFoundCtrl;
}

// Mac: recognize the event of interest
/*static*/ OSStatus VWDialog::_WindowMouseEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void* inUserData)
{
	const signed long msg_MouseWheel		= 851;	// SMouseEvent*
	const signed long msg_MouseDown			= 852;	// SMouseEvent*
	const signed long msg_MouseUp			= 853;	// SMouseEvent*
	const signed long msg_MouseClick		= 854;	// SMouseEvent*
	const signed long msg_MouseDblClick		= 855;	// SMouseEvent*

	const signed long msg_MouseRDown		= 856;	// SMouseEvent*
	const signed long msg_MouseRUp			= 857;	// SMouseEvent*
	const signed long msg_MouseRClick		= 858;	// SMouseEvent*
	const signed long msg_MouseRDblClick	= 859;	// SMouseEvent*

	const signed long msg_MouseMDown		= 860;	// SMouseEvent*
	const signed long msg_MouseMUp			= 861;	// SMouseEvent*
	const signed long msg_MouseMClick		= 862;	// SMouseEvent*
	const signed long msg_MouseMDblClick	= 863;	// SMouseEvent*

	const signed long msg_MouseMoved		= 864;	// SMouseEvent*

	typedef struct {
		Point		wherePort;
		Point		whereLocal;
		EventRecord	macEvent;
		Boolean		delaySelect;
	} SMouseEvent;
	

	VWDialog*		pDialog	= (VWDialog*) inUserData;
	ASSERTN( kVStanev, pDialog );
	if ( pDialog )  {
		Uint32				eventClass		= ::GetEventClass( inEvent );
	    Uint32				eventKind		= ::GetEventKind( inEvent );

		if ( eventClass == kEventClassMouse && eventKind == kEventMouseDown ) {
			WindowRef			windowRef;
			HIPoint  			pt;
			EventMouseButton	mouseButton		= 0;
			UInt32				keyModifiers	= 0;
			UInt32				clickCnt		= 0;
			GetEventParameter( inEvent, kEventParamWindowRef, typeWindowRef, NULL,  sizeof(WindowRef), NULL, & windowRef );
			GetEventParameter( inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HICommand), NULL, & pt );
			GetEventParameter( inEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, & mouseButton );
			GetEventParameter( inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, & keyModifiers );
			GetEventParameter( inEvent, kEventParamClickCount, typeUInt32, NULL, sizeof(UInt32), NULL, & clickCnt );

			Rect windowRect;
			GetWindowBounds( windowRef, kWindowContentRgn, & windowRect );

			// translate the pt into window client rect coords	
			ViewPt		viewPt;
			viewPt.x		= pt.x - windowRect.left;
			viewPt.y		= pt.y - windowRect.top;

			// fint the custom control to sent it the event
			VWCustomCtrl* 	pCustomCtrl	= pDialog->GetCustomCtrlAtPoint( viewPt );
			if ( pCustomCtrl && pCustomCtrl->IsVisible() ) {
				ViewRect	ctrlRect		= pCustomCtrl->GetControlRect();

				SMouseEvent	event;
				event.wherePort.h			= viewPt.x;
				event.wherePort.v			= viewPt.y;
				event.whereLocal.h			= viewPt.x - ctrlRect.left;
				event.whereLocal.v			= viewPt.y - ctrlRect.top;
				event.macEvent.modifiers	= keyModifiers;
				event.macEvent.message		= 0;
				event.macEvent.when			= 0;
				event.delaySelect			= false;

				// send out mouse down
				long		message			= msg_MouseDown;
				if ( mouseButton == kEventMouseButtonSecondary ) 		message	= msg_MouseRDown;
				else if ( mouseButton == kEventMouseButtonTertiary )	message	= msg_MouseMDown;
				pCustomCtrl->CustomMacHandler( message, & event, NULL, pDialog->fControlID, pCustomCtrl->GetControlID() );
			}				
		}
		else if ( eventClass == kEventClassMouse && eventKind == kEventMouseUp ) {
			WindowRef			windowRef;
			HIPoint  			pt;
			EventMouseButton	mouseButton		= 0;
			UInt32				keyModifiers	= 0;
			UInt32				clickCnt		= 0;
			GetEventParameter( inEvent, kEventParamWindowRef, typeWindowRef, NULL,  sizeof(WindowRef), NULL, & windowRef );
			GetEventParameter( inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HICommand), NULL, & pt );
			GetEventParameter( inEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, & mouseButton );
			GetEventParameter( inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, & keyModifiers );
			GetEventParameter( inEvent, kEventParamClickCount, typeUInt32, NULL, sizeof(UInt32), NULL, & clickCnt );

			Rect windowRect;
			GetWindowBounds( windowRef, kWindowContentRgn, & windowRect );

			// translate the pt into window client rect coords	
			ViewPt		viewPt;
			viewPt.x		= pt.x - windowRect.left;
			viewPt.y		= pt.y - windowRect.top;

			// fint the custom control to sent it the event
			VWCustomCtrl* 	pCustomCtrl	= pDialog->GetCustomCtrlAtPoint( viewPt );
			if ( pCustomCtrl && pCustomCtrl->IsVisible() ) {
				ViewRect	ctrlRect		= pCustomCtrl->GetControlRect();

				SMouseEvent	event;
				event.wherePort.h			= viewPt.x;
				event.wherePort.v			= viewPt.y;
				event.whereLocal.h			= viewPt.x - ctrlRect.left;
				event.whereLocal.v			= viewPt.y - ctrlRect.top;
				event.macEvent.modifiers	= keyModifiers;
				event.macEvent.message		= 0;
				event.macEvent.when			= 0;
				event.delaySelect			= false;

				// send out mouse up
				long		message			= msg_MouseUp;
				if ( mouseButton == kEventMouseButtonSecondary )		message	= msg_MouseRUp;
				else if ( mouseButton == kEventMouseButtonTertiary )	message	= msg_MouseMUp;
				pCustomCtrl->CustomMacHandler( msg_MouseUp, & event, NULL, pDialog->fControlID, pCustomCtrl->GetControlID() );
				
				// now send click event or double click
				message						= (clickCnt <= 1) ? msg_MouseClick : msg_MouseDblClick;
				if ( mouseButton == kEventMouseButtonSecondary )		message	= (clickCnt <= 1) ? msg_MouseRClick : msg_MouseRDblClick;
				else if ( mouseButton == kEventMouseButtonTertiary )	message	= (clickCnt <= 1) ? msg_MouseMClick : msg_MouseMDblClick;
				pCustomCtrl->CustomMacHandler( message, & event, NULL, pDialog->fControlID, pCustomCtrl->GetControlID() );
			}				
		}
		else if ( eventClass == kEventClassMouse && ( eventKind == kEventMouseMoved || eventKind == kEventMouseDragged ) ) {
			WindowRef			windowRef;
			HIPoint  			pt;
			EventMouseButton	mouseButton		= 0;
			UInt32				keyModifiers	= 0;
			GetEventParameter( inEvent, kEventParamWindowRef, typeWindowRef, NULL,  sizeof(WindowRef), NULL, & windowRef );
			GetEventParameter( inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HICommand), NULL, & pt );
			GetEventParameter( inEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, & mouseButton );
			GetEventParameter( inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, & keyModifiers );

			Rect windowRect;
			GetWindowBounds( windowRef, kWindowContentRgn, & windowRect );

			// translate the pt into window client rect coords	
			ViewPt		viewPt;
			viewPt.x		= pt.x - windowRect.left;
			viewPt.y		= pt.y - windowRect.top;			
			
			// fint the custom control to sent it the event
			VWCustomCtrl* 	pCustomCtrl	= pDialog->GetCustomCtrlAtPoint( viewPt );
			if ( pCustomCtrl && pCustomCtrl->IsVisible() ) {
				ViewRect	ctrlRect		= pCustomCtrl->GetControlRect();

				SMouseEvent	event;
				event.wherePort.h			= viewPt.x;
				event.wherePort.v			= viewPt.y;
				event.whereLocal.h			= viewPt.x - ctrlRect.left;
				event.whereLocal.v			= viewPt.y - ctrlRect.top;
				event.macEvent.modifiers	= keyModifiers;
				event.macEvent.message		= 0;
				event.macEvent.when			= 0;
				event.delaySelect			= false;

				pCustomCtrl->CustomMacHandler( msg_MouseMoved, & event, NULL, pDialog->fControlID, pCustomCtrl->GetControlID() );
			}
		}
		else if ( eventClass == kEventClassMouse && eventKind == kEventMouseWheelMoved ) {
			WindowRef			windowRef;
			HIPoint  			pt;
			EventMouseWheelAxis	wheelAxis		= 0;
			SInt32				wheelDelta		= 0;
			EventMouseButton	mouseButton		= 0;
			UInt32				keyModifiers	= 0;
			GetEventParameter( inEvent, kEventParamWindowRef, typeWindowRef, NULL,  sizeof(WindowRef), NULL, & windowRef );
			GetEventParameter( inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HICommand), NULL, & pt );
			GetEventParameter( inEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(EventMouseWheelAxis), NULL, & wheelAxis );
			GetEventParameter( inEvent, kEventParamMouseWheelDelta, typeSInt32, NULL, sizeof(SInt32), NULL, & wheelDelta );
			GetEventParameter( inEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, & mouseButton );
			GetEventParameter( inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, & keyModifiers );

			Rect windowRect;
			GetWindowBounds( windowRef, kWindowContentRgn, & windowRect );

			// translate the pt into window client rect coords	
			ViewPt		viewPt;
			viewPt.x		= pt.x - windowRect.left;
			viewPt.y		= pt.y - windowRect.top;

			// fint the custom control to sent it the event
			VWCustomCtrl* 	pCustomCtrl	= pDialog->GetCustomCtrlAtPoint( viewPt );
			if ( pCustomCtrl && pCustomCtrl->IsVisible() ) {
				ViewRect	ctrlRect		= pCustomCtrl->GetControlRect();

				SMouseEvent	event;
				event.wherePort.h			= viewPt.x;
				event.wherePort.v			= viewPt.y;
				event.whereLocal.h			= viewPt.x - ctrlRect.left;
				event.whereLocal.v			= viewPt.y - ctrlRect.top;
				event.macEvent.modifiers	= keyModifiers;
				event.macEvent.message		= wheelAxis == kEventMouseWheelAxisX ? 0 : 1;
				event.macEvent.when			= (UInt32) wheelDelta;
				event.delaySelect			= false;

				pCustomCtrl->CustomMacHandler( msg_MouseWheel, & event, NULL, pDialog->fControlID, pCustomCtrl->GetControlID() );
			}
		}
	}
	
	return eventNotHandledErr;
}
#endif
