//
// Asura_Dialog.h
//
// Created by Kevin Lea - 12/06/2001 11:11:48
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_DIALOG_H__
#define __ASURA_DIALOG_H__

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura_Callback.h"
#include "Core/Asura_Hash.h"
#include "Core/Asura_LinkList.h"
#include "Core/Asura_Maths.h"
#include "Core/Asura_String.h"
#include "Misc/list_tem.hpp"

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////

class Asura_Blueprint;
class Asura_Gadget;
class Asura_Key_Combination;
class Asura_Overlay;
class Asura_StringDisplay_Gadget;
class Asura_Dialog;
class Asura_Subwindow_Dialog;
class Asura_IncrementorFloat_Gadget;
class Asura_IncrementorFloat_Gadget;
class Asura_Float_Gadget;
template <class T> class Asura_Dialog_SharedValue;

// C L A S S E S /////////////////////////////////////////////////////////////

//Flags for reasons why a dialog may be hidden
//Some of them probably don't really need to be distinct values , but there isn't any shortage of space at the moment
#define ASURA_DIALOG_HIDEFLAG_ORIGINAL	0x00000001 //Corresponds to the original SetHidden() function
#define ASURA_DIALOG_HIDEFLAG_CALLBACK 	0x00000002 //Hidden by the callback function set via SetIsHiddenFunction()
#define ASURA_DIALOG_HIDEFLAG_TAB		0x00000004 //Hidden as a result of being in a hidden tab on a tab dialog
#define ASURA_DIALOG_HIDEFLAG_TABLE		0x00000008 //Hidden as a result of being part of a hidden table
#define ASURA_DIALOG_HIDEFLAG_PANEL		0x00000010 //Hidden as a result of being part of a hidden panel
#define ASURA_DIALOG_HIDEFLAG_MINIMISEDPANEL 0x00000020 //Hidden as a result of being part of a minimised panel
#define ASURA_DIALOG_HIDEFLAG_SUBWINDOW 0x00000040 //Hidden as a result of being part of a hidden subwindow

//flags for relative dialog placement
#define ASURA_DIALOG_RELATIVE_X_DIALOG		0x00000001//X pos should be relative to a dialog
#define ASURA_DIALOG_RELATIVE_X_OVERLAY		0x00000002//X pos should be relative to the edges of the overlay
#define ASURA_DIALOG_RELATIVE_X_RIGHT		0x00000004//X pos should be relative to the right of the overlay/dialog (default is left)
#define ASURA_DIALOG_RELATIVE_Y_DIALOG		0x00000008//Y pos should be relative to a dialog
#define ASURA_DIALOG_RELATIVE_Y_OVERLAY		0x00000010//Y pos should be relative to the edges of the overlay
#define ASURA_DIALOG_RELATIVE_Y_BOTTOM		0x00000020//Y pos should be relative to the bottom of the overlay/dialog (default is top)



//Iterator used by the overlay to step through all the dialogs , including ones that are
//held as children of other dialogs.
//Not done for table dialogs yet , since this isn't needed just at the moment.
class Asura_DialogIterator
{
public :
	//Initialises iterator at the first dialog
	Asura_DialogIterator(Asura_Dialog* pxFirstDialog);

	//Move to next dialog
	void Next();
	//Returns true if the iteration has finished
	bool Done() const {return m_iStackPos < 0;}

	//Get the current dialog in the iteration	
	Asura_Dialog* GetCurrent() const {Asura_Assert(m_iStackPos>=0,"");return m_iStackPos >= 0 ? m_apxDialog[m_iStackPos] : 0;}

	//Adds up all additional offsets from the parent dialogs for the current dialog
	Asura_Vector_2 GetParentOffset() const;

private :
	static const int s_iDIALOG_ITERATOR_STACK_SIZE = 8;

	Asura_Dialog* m_apxDialog[s_iDIALOG_ITERATOR_STACK_SIZE];
	int m_aiChildIndex[s_iDIALOG_ITERATOR_STACK_SIZE];
	int m_iStackPos;
};

#define ASURA_DIALOG_INVALIDPRIORITY (-1)

class Asura_Dialog
{
	public:

        // C O N S T R U C T O R S   /   D E S T R U C T O R S ///////////////

		Asura_Dialog( const char* szName, const Asura_Vector_2& xOffset, int iFocusPriority = 0);
		
		virtual ~Asura_Dialog( void );

        // M E T H O D S /////////////////////////////////////////////////////

		void AddGadget( Asura_Gadget* pxNewGadget );

        virtual const Asura_Vector_2& GetMaxCoords( void ) const { return m_xMaxCoord; }

        virtual unsigned GetColour( void ) const;

		virtual void Render( const Asura_Vector_2& xOrigin );

		virtual void Update( const Asura_Vector_2& xOrigin );

        // Another update function.This one is called regardless of whether the overlay is the active one.
        // If you override this in a derived class you MUST call the parent implementation from the
        // derived at some point.
		virtual void PerFrameUpdate();

		virtual void UpdateLabel(const char* text);//used to change the text on a control... not implemented for all controls yet

		virtual bool IsWindowsDialog( void ) const {return false;}
		virtual bool IsResizeDialog() const {return false;}

        virtual void SetEnabled( bool bEnabled );
	
		//Overridden by dialogs that can contain other dialogs
		virtual void AddDialog(Asura_Dialog* pxDialog){Asura_Assert(0,"This class doesn't support AddDialog()");}


		void SetHelpText(const char* pszText){m_xHelpText = pszText;}
		const char* GetHelpText() const {return m_xHelpText.GetString();}

        int  GetControlID() const { return m_iControlID; }
        void SetControlID( int iControlID ) { m_iControlID = iControlID; }

        const Asura_String& GetName() const { return m_xName; }
        void SetName( const char* szName ) { m_xName = szName; }
        void SetName( const Asura_String& xName ) { m_xName = xName; }

        // Note: may need to call CalculateOverlaySize() after setting a
        // dialog to be hidden.
        void SetHidden( bool bHidden ) { SetHideFlag(ASURA_DIALOG_HIDEFLAG_ORIGINAL, bHidden); }
		void SetHideFlag(u_int uFlag,bool bSet);
        bool IsHidden( void ) const { return m_uHideFlags != 0; }

		// Check to see whether this dialogue is enabled...
		bool	IsEnabled(void) const	{ return(m_bIsEnabled); }

		virtual bool IsPointInDialog(const Asura_Vector_2& xOrigin,const Asura_Vector_2& xPos) const;
		//determines whether the dialog's rect should be checked in addition to the gadgets
		virtual bool ShouldCheckDialogExtentsForIsPointInDialog() const {return false;}

		//set function to call to determine if the dialog should be shown as enabled
		void SetIsEnabledFunction(bool(*pfnIsEnabled)(void))						{SetIsEnabledFunction(Asura_Callback_Void<bool>(pfnIsEnabled));}
		void SetIsEnabledFunction(bool(*pfnIsEnabled)(int),int iUserData)			{SetIsEnabledFunction(Asura_Callback_UserData<bool,int>(pfnIsEnabled, iUserData));}
		void SetIsEnabledFunction(const Asura_Callback_Base<bool>& xIsEnabled)		{m_xIsEnabled.SetCallback(&xIsEnabled);}

		void SetIsHiddenFunction(bool(*pfnIsHidden)(int), int iUserData);

		//If iGroupID is non-zero then this causes the control to act as a radio button , grouped
		//with other buttons with the same ID. 
		//If bAtLeastOnePressed is true then at least one of the buttons must always be pressed.
		//This only works for tickboxes , and some similar controls
		//When clicking on such buttons ,the changed flag will only be set for the one clicked on.
		void SetRadioButtonGroup(int iGroupID,bool bAtLeastOnePressed);

		int GetFocusPriority() const { return m_iFocusPriority; }
		// Returns the priority of the next highest priority dialog in the list below the given one
		virtual int UpdateList(const Asura_Vector_2& xOrigin, int iPriority);
		// Returns the priority of the next lower priority dialog in the list below the given one
		// or ASURA_DIALOG_INVALIDPRIORITY if none
		virtual int RenderList(const Asura_Vector_2& xOrigin, int iPriority);


		static float SmallSpacing(){return 1.0f;}
		static float DefaultSpacing(){return 17.0f/14.0f;}
		static float LargeSpacing(){return 2.0f;}

		//Indicates that this control can have focus switched to it using Tab
		bool CanTakeTabFocus() const;
		//For taking input focus when control is tabbed to
		void TakeTabFocus();

		//moves dialog to new position
		void MoveDialog(const Asura_Vector_2& xNewOffset);

		//Sets the top left of this dialog to be relative to a specified
		//corner of another
		void SetRelativePosition(const Asura_Dialog* pxDialog,const Asura_Vector_2& xRelOffset,bool bRelBottom,bool bRelRight);
		void SetRelativePosition(const Asura_Dialog* pxDialog,bool bRelBottom,bool bRelRight);

		//Allows for x/y coordinates to be done separately relative to a dialog and the overlay edges.
		//Uses the ASURA_DIALOG_RELATIVE_ flags
		void SetRelativePositionFlags(const Asura_Dialog* pxDialog, const Asura_Vector_2& xRelOffset , u_int uRelativeFlags);

		//set relative position to a position defined by a derived class and identified by ID
		void SetRelativePosition(const Asura_Dialog* pxDialog,Asura_Hash_ID uRelativePositionID);
		virtual Asura_Vector_2 GetPositionFromID(Asura_Hash_ID uPositionID) const;

		//set position relative to sides of overlay
		void SetOverlayRelativePosition(const Asura_Vector_2& xRelOffset,bool bRelBottom,bool bRelRight);

		bool IsRelativeToOverlayRight() const {return (m_uRelativeFlags & ASURA_DIALOG_RELATIVE_X_OVERLAY) && (m_uRelativeFlags & ASURA_DIALOG_RELATIVE_X_RIGHT);}
		bool IsRelativeToOverlayBottom() const {return (m_uRelativeFlags & ASURA_DIALOG_RELATIVE_Y_OVERLAY) && (m_uRelativeFlags & ASURA_DIALOG_RELATIVE_Y_BOTTOM);}

		bool IsUsingRelativePosition() const {return m_uRelativeFlags != 0;}

		//Deletes a single gadget from the dialog
		void DeleteSingleGadget(Asura_Gadget* pxGadget);

		// Deletes the child gadgets from this dialog
		virtual void DeleteChildDialogs(void)	{}

		//Called when a single dialog is being deleted (as opposed to the entire overlay being closed).
		virtual void RemoveReferencesToDialog(const Asura_Dialog* pxDialog) {}

		void SetParentSubwindow(Asura_Subwindow_Dialog* pxDialog){m_pxParentSubwindow = pxDialog;}
		Asura_Subwindow_Dialog* GetParentSubwindow() const {return m_pxParentSubwindow;}

		//Used by the overlay to recalculate the sizes of all the controls
		virtual void UpdateSizeInit(){}
		virtual void UpdateSize();

		
		//This gets called by Asura_Resize_Dialog to setup the dialog that is going to be resized
		void SetAllowResize(bool bSet, Asura_Vector_2* pxUserSetSize);
		
		//Allows control to prepare for the overlay being resized
		virtual void StartResize(u_int uResizeFlags){}
		//Handles user resizing the overlay. xDelta is the cumulative delta from the start of the operation
		virtual void UpdateResize(u_int uResizeFlags, const Asura_Vector_2& xDelta) {};
		//Gets the direction(s) in which this dialog can be resized
		virtual u_int GetAllowedResizeFlags() const {return 0;}



		//Gets offset modified by any additional offset	from the parent subwindow if required
		Asura_Vector_2 GetModifiedOffset() const;

		//gets additional offset to use for text position
		virtual Asura_Vector_2 GetTextOffset() const {return Asura_Maths::ZeroVector2;}

		virtual bool CanRenderOutsideOfParentSubwindow() const {return false;}

		//Used internally to deal with radio button style tickboxes
		void RadioButtonPressed(const class Asura_Gadget* pxPressedGadget);

		//Function used by the dialog iterator for accessing dialogs that don't appear in the overlay's list
		//If the index is greater than the number of child lists then it should return 0
		virtual Asura_Dialog* GetHeadOfChildDialogList(int iListIndex) {return 0;}

		float GetWidth() const {return m_xMaxCoord.x - m_xOffset.x;}
		float GetHeight() const {return m_xMaxCoord.y - m_xOffset.y;}


        // S T A T E /////////////////////////////////////////////////////////

		Asura_Dialog* m_pxNextDialog;
		mutable Asura_Vector_2 m_xMaxCoord;
		
		Asura_String m_xName;
		Asura_Vector_2 m_xOffset;
		Asura_Gadget* m_pxGadgetList;
		Asura_Overlay* m_pxOverlay;
		int m_iControlID;

    protected:
		void UpdateRelativePosition();

		virtual void ShowHelpText();
		
		//Called when the dialog becomes hidden or unhidden. RAR 23/04/2007
		virtual void OnHiddenStateChange(){};

        // S T A T E /////////////////////////////////////////////////////////

        bool m_bIsEnabled;
       	u_int m_uHideFlags;
		int m_iFocusPriority;

		const Asura_Dialog* m_pxRelativeDialog;
		//bool m_bRelativeToOverlay;
		Asura_Vector_2 m_xRelativeOffset;
		//bool m_bRelativeBottom;
		//bool m_bRelativeRight;
		u_int m_uRelativeFlags;
		Asura_Hash_ID m_uRelativePositionID;

		bool m_bAllowResize;
		Asura_Vector_2*	m_pxUserSetSize;


	private:
		Asura_String m_xHelpText;
		Asura_Callback_Wrapper<bool> m_xIsEnabled;

		bool(*m_pfnIsHidden)(int);
		int m_iIsHiddenUserData;


		Asura_Subwindow_Dialog* m_pxParentSubwindow;//set if contained within a subwindow control

		
        
};

class Asura_Numerical_Dialog : public Asura_Dialog
{
	public:

		Asura_Numerical_Dialog(const char* name, const Asura_Vector_2& offset, float* value, float min, float max,float delta, const char* printFormat, bool* flag = 0);
		Asura_Numerical_Dialog(const char* name, const Asura_Vector_2& offset, int* value, int min, int max,int delta, const char* printFormat, bool* flag = 0);
		Asura_Numerical_Dialog(const char* name, const Asura_Vector_2& offset, u_int* value, u_int min, u_int max,int delta, const char* printFormat, bool* flag = 0);
		Asura_Numerical_Dialog(const char* szName, const Asura_Vector_2& xOffset, u_char* pucValue, u_char ucMin, u_char ucMax, int iDelta, const char* szPrintFormat, bool* pbFlag = 0);

		Asura_Numerical_Dialog(const char* name, const Asura_Vector_2& offset, Asura_Dialog_SharedValue<float>* pxSharedValue, float min, float max,float delta, const char* printFormat);
		Asura_Numerical_Dialog(const char* name, const Asura_Vector_2& offset, Asura_Dialog_SharedValue<int>* pxSharedValue, int min, int max,int delta, const char* printFormat);
		Asura_Numerical_Dialog(const char* name, const Asura_Vector_2& offset, Asura_Dialog_SharedValue<u_int>* pxSharedValue, u_int min, u_int max,int delta, const char* printFormat);


		void SetReadOnly(bool bReadOnly);

		virtual Asura_Vector_2 GetTextOffset() const {return m_xTextOffset;}

		//Causes this control to take input focus during the first frame.
		void SetDefaultFocus(bool bSet);

		//Forces the numerical dialog to have space for the specified number of characters , regardless
		//of the print format.
		void SetBoxLength(int iNumChars);

		// Set the float Delta (step value) for the increment and decrement gadgets.
		// If the gadgets don't support floats an assert will trigger
		void SetDelta(float fDelta);

		// Set the int Delta (step value) for the increment and decrement gadgets.
		// If the gadgets don't support ints an assert will trigger
		void SetDelta(int iDelta);

	private :
		Asura_Vector_2 m_xTextOffset;

		class Asura_BaseText_Gadget* m_pxTextGadget;
		class Asura_Gadget* m_pxIncGadget;
		class Asura_Gadget* m_pxDecGadget;


};


//Numerical dialog in which the values are multiplied by a scale value for UI purposes.
//The min , max , delta and print format should be for the scaled up (or down) values.
class Asura_ScaledNumerical_Dialog : public Asura_Dialog
{
	public:
		Asura_ScaledNumerical_Dialog(const char* szName, const Asura_Vector_2& xOffset, float fScale,float* pfValue, float fScaledMin, float fScaledMax,float fScaledDelta, char* szPrintFormat, bool* pFlag = 0);
		virtual void PerFrameUpdate();
		void SetScale( const float fScale,  const float fScaledMin,  const float fScaledMax );
		void SetDelta( const float fDelta );
		void SetPrintFormat( const char* const szPrintFormat );

	private :
		float m_fScale;
		float* m_pfValue;
		float m_fValueBackup;//copy of the value stored above ,to check for outside changes
		bool* m_pbFlag;
		float m_fScaledValue;
		float m_fScaledMin;
		float m_fScaledMax;
		float m_fScaledMinBackup;
		float m_fScaledMaxBackup;
		bool m_bChanged;
		Asura_IncrementorFloat_Gadget* m_pxDecGadget;
		Asura_Float_Gadget* m_pxValGadget;
		Asura_IncrementorFloat_Gadget* m_pxIncGadget;
};



//dialog that takes an angle in radians , but does the editing in degrees
//(min/max , and printing format are in degrees)
class Asura_AngleNumerical_Dialog : public  Asura_ScaledNumerical_Dialog
{
	public:
		Asura_AngleNumerical_Dialog(const char* name, const Asura_Vector_2& offset, Asura_Angle* AngleRadians, float min, float max,float delta, char* printFormat, bool* flag = 0)
		:Asura_ScaledNumerical_Dialog(name,offset,Asura_Maths::RadToDegConstant,AngleRadians,min,max,delta,printFormat,flag)
		{}
};

//And similarly for colour values. Edits a float in the range 0 to 1 , but shows as a 
//value from 0 to 255
class Asura_ColourNumerical_Dialog : public  Asura_Dialog
{
	public:
		Asura_ColourNumerical_Dialog(const char* pszName, const Asura_Vector_2& xOffset, float* pfValue, char* pszPrintFormat, bool* pbFlag = 0);
		virtual void PerFrameUpdate();
		void	UpdateColour(float fNewValue);

	private :
		float* m_pfValue;
		float m_fValueBackup;	//copy of the value stored above ,to check for outside changes
		bool* m_pbFlag;
		int m_iColour;
		bool m_bChanged;

};


class Asura_NumberSlider_Dialog : public Asura_Dialog
{
	public:

		Asura_NumberSlider_Dialog( const Asura_Vector_2& offset, float* value, float* minPtr, float* maxPtr,float slideWidth, char* printFormat, bool* flag = 0);
		void SetPrintFormat(const char* pszPrintFormat);

	private :
		class Asura_NumberSlider_Gadget* m_pxSliderGadget;
};


class Asura_String_Dialog : public Asura_Dialog
{
	public:
		Asura_String_Dialog(const char* name, const Asura_Vector_2& offset, class Asura_String* value, int maxLength, bool* flag = 0,bool defaultFocus = false);

		//sets maximum length without resizing the box
		void SetMaxStringLength(int iMaxLength);

		//Causes this control to take input focus during the first frame.
		void SetDefaultFocus(bool bSet);

		//Read only dialogs show the string but can not be edit
		void SetReadOnly(bool bSet); 

		//Sets a callback that gets called when the text in the dialog changes
		void SetTextChangeCallback (const Asura_Callback_Base<void>& xCallback);

		class Asura_String_Gadget* GetStringGadget () const { return m_pxStringGadget; }

		//Causes the string to be updated immediately as the user types , instead of waiting for return to be pressed
		void SetUpdateImmediatelyWhileTyping(bool bSet);

	private :
		class Asura_String_Gadget* m_pxStringGadget;
};

class Asura_Tickbox_Dialog : public Asura_Dialog
{
public:
	Asura_Tickbox_Dialog(const char* name, const Asura_Vector_2& offset, bool* value, bool* flag = 0);
	void UpdateLabel(const char* text);
	void SetValue(bool* pbValue);
	
	//set callback function to be called whenever tickbox is clicked
	void SetClickedFunction(void(*pfnOnClicked)(void)) {SetClickedFunction(Asura_Callback_Void<void>(pfnOnClicked));}
    void SetClickedFunction(void(*pfnOnClicked)(int), int iUserData) {SetClickedFunction(Asura_Callback_UserData<void,int>(pfnOnClicked, iUserData));}
	void SetClickedFunction(const Asura_Callback_Base<void>& xCallback);

	void SetUseSharedDialogColour(bool bShared);

private:
	class Asura_BoolTickbox_Gadget* m_pxTickbox;
};

//tickbox for working on bits of a flags entry
class Asura_FlagTickbox_Dialog : public Asura_Dialog
{
	public:
		Asura_FlagTickbox_Dialog(const char* name, const Asura_Vector_2& offset, int* flagsField , int flagBit, bool* flag = 0);
		Asura_FlagTickbox_Dialog(const char* name, const Asura_Vector_2& offset, unsigned int* flagsField , int flagBit, bool* flag = 0);
		Asura_FlagTickbox_Dialog(const char* szName, const Asura_Vector_2& xOffset, char* pcFlagsField , char cFlagBit, bool* pbFlag = 0);
		Asura_FlagTickbox_Dialog(const char* szName, const Asura_Vector_2& xOffset, u_char* pucFlagsField , u_char ucFlagBit, bool* pbFlag = 0);
		void UpdateLabel(const char* text);
	
		//set callback function to be called whenever tickbox is clicked
		void SetClickedFunction(void(*pfnOnClicked)(void));

	private:
		void CreateGadgets(const char* szName, const Asura_Vector_2& xOffset, int* piFlagsField , int iFlagBit, bool* pbFlag);
		void CreateGadgets(const char* szName, const Asura_Vector_2& xOffset, char* pcFlagsField, char cFlagBit, bool* pbFlag);
		void AdjustDimensions(const char* szName);

		class Asura_FlagTickbox_Gadget* m_pxTickbox;
};

//tickbox that has a value that is is shared between multiple selected objects.
//may be at an intermediate state if it doesn't have the same value for all
class Asura_SharedTickbox_Dialog : public Asura_Dialog
{
	public:
		Asura_SharedTickbox_Dialog(const char* pszName, const Asura_Vector_2& xOffset, Asura_Dialog_SharedValue<bool>* pxSharedValue);
		void UpdateLabel(const char* pszText);

};

//tickbox whose tickiness is controlled by callback functions
class Asura_FunctionTickbox_Dialog : public Asura_Dialog
{
	public:
		Asura_FunctionTickbox_Dialog(const char* szName, const Asura_Vector_2& xOffset, bool(*pfnIsChecked)(), void(*pfnSetChecked)(bool bSet));
		Asura_FunctionTickbox_Dialog(const char* szName, const Asura_Vector_2& xOffset, void* pData, bool(*pfnIsChecked)(void* pData), void(*pfnSetChecked)(bool bSet,void* pData));
		Asura_FunctionTickbox_Dialog(const char* szName, const Asura_Vector_2& xOffset, int iData, bool(*pfnIsChecked)(int iData), void(*pfnSetChecked)(bool bSet,int iData));
};



class Asura_Windows_Dialog : public Asura_Dialog
{
	public:
		Asura_Windows_Dialog(const char* name, const Asura_Vector_2& xOffset, float width, bool* shouldClose, u_int* puMinimisedState);
		virtual void Render( const Asura_Vector_2& xOrigin );
		virtual void Update( const Asura_Vector_2& xOrigin );
		virtual bool IsWindowsDialog( void ) const {return true;}


	private:
		u_int *m_puMinimisedState;
};

class Asura_Function_Dialog : public Asura_Dialog
{
	public:
		Asura_Function_Dialog( const char* szName,
                               const Asura_Vector_2& xOffset,
                               void(*pfnCallback)(void),
                               bool* pbFlag = NULL,
                               bool(*pfnIsEnabled)(void) = NULL,
                               bool bLineUpWithTickboxes = false );

		//variation that will pass back some user data to the callback function
		Asura_Function_Dialog( const char* szName,
                               const Asura_Vector_2& xOffset,
                               void(*pfnCallback)(int),
                               int iUserData,
                               bool* pbFlag = NULL,
                               bool(*pfnIsEnabled)(void) = NULL,
                               bool bLineUpWithTickboxes = false );
		//variation using the callback class for the function
		Asura_Function_Dialog( const char* szName,
                               const Asura_Vector_2& xOffset,
							   const Asura_Callback_Base<void>& xCallback,
                               bool* pbFlag = NULL,
                               bool bLineUpWithTickboxes = false );


		//and variations of the above that are for use with function controls
		//that will affect multiple objects (and also may need to show that
		//the values aren't the same for all
		Asura_Function_Dialog( const char* pszNamePrefix,
                               Asura_Dialog_SharedValue<Asura_String>* pxSharedName,
                               const Asura_Vector_2& xOffset,
                               void(*pfnCallback)(void),
                               bool* pbFlag = NULL,
                               bool(*pfnIsEnabled)(void) = NULL,
                               bool bLineUpWithTickboxes = false );

		Asura_Function_Dialog( const char* pszNamePrefix,
		                       Asura_Dialog_SharedValue<Asura_String>* pxSharedName,
                               const Asura_Vector_2& xOffset,
                               void(*pfnCallback)(int),
                               int iUserData,
                               bool* pbFlag = NULL,
                               bool(*pfnIsEnabled)(void) = NULL,
                               bool bLineUpWithTickboxes = false );

		Asura_Function_Dialog( const char* pszNamePrefix,
		                       Asura_Dialog_SharedValue<Asura_String>* pxSharedName,
                               const Asura_Vector_2& xOffset,
							   const Asura_Callback_Base<void>& xCallback,
                               bool* pbFlag = NULL,
                               bool bLineUpWithTickboxes = false );




		void UpdateLabel(const char* text);
		unsigned GetColour() const;

		//tells the function dialog to colour the square box blue to indicate a gadget
		//that will affect all selected objects. (done automatically if using the 
		//SharedValue constructors).
		void SetUseSharedDialogColour(bool bShared);

		//Allows the callback to be changed after creation
		void SetCallback(void(*pfnIntCallback)(int),int iUserData) {SetCallback(Asura_Callback_UserData<void,int>(pfnIntCallback, iUserData));}
		void SetCallback(const Asura_Callback_Base<void>& xCallback);


	protected :
		virtual void PerFrameUpdate();
		void SetMixedSharedValue(bool bSet) {m_bMixedSharedValue = bSet;}


	private:
		void CreateGadgets( const Asura_Vector_2& xOffset,
							const Asura_Callback_Base<void>& xCallback,
							bool* pbFlag,
							bool(*pfnIsEnabled)(void),
							bool bLineUpWithTickboxes);

		Asura_String m_xNamePrefix;
		Asura_Dialog_SharedValue<Asura_String>* m_pxSharedName;
		bool m_bMixedSharedValue;
		bool *IsMinimised;
};

//Asura_Resize_Dialog creates a small icon that can be dragged on for resizing another dialog.
//By default it is placed in the bottom right corner of the overlay.
//It can be set to be relative to something else as normal using SetRelativePosition()
class Asura_Resize_Dialog : public Asura_Dialog
{
	public :
		//pxUserSetSize is an (optional) pointer to a vector for storing the size of the control being resized , and for initialising the size
		//when the overlay is created
		//If the vector pointed to by pxUserSetSize is zero , then it is taken as being unset, and the existing
		//size of the resized dialog is kept.
		Asura_Resize_Dialog(Asura_Dialog* pxDialogToResize, Asura_Vector_2* pxUserSetSize);
		
		//adds additional dialogs to be resized at the same time
		//this is only likely to be useful in cases where the additional dialogs are on different tabs.
		void AddResizableDialog(Asura_Dialog* pxDialogToResize, Asura_Vector_2* pxUserSetSize);

		virtual void StartResize(u_int uResizeFlags);
		virtual void UpdateResize(u_int uResizeFlags, const Asura_Vector_2& xDelta);
		virtual u_int GetAllowedResizeFlags() const;

		virtual bool IsResizeDialog() const {return true;}

		virtual void RemoveReferencesToDialog(const Asura_Dialog* pxDialog);


	private :
		Asura_LinkList<Asura_Dialog*> m_xResizeList;
};

class Asura_FunctionWithKeybinding_Dialog : public Asura_Dialog
{

	public:

		Asura_FunctionWithKeybinding_Dialog( const char* szName,
                                             const Asura_Vector_2& xOffset,
                                             void(*pfnCallback)(void),
                                             const Asura_Key_Combination& xBinding,
                                             bool* pbFlag = NULL,
                                             bool bLineUpWithTickboxes = false );

		Asura_FunctionWithKeybinding_Dialog( const char* szName,
                                             const Asura_Vector_2& xOffset,
                                             void(*pfnCallback)(int),
											 int iUserData,
                                             const Asura_Key_Combination& xBinding,
                                             bool* pbFlag = NULL,
                                             bool bLineUpWithTickboxes = false );

		void UpdateLabel(const char* text);

};

class Asura_List_Dialog : public Asura_Dialog
{
	public:
		Asura_List_Dialog(const Asura_Vector_2& offset, const char* const* list, int* listOffset, int* selection, int numberOfLines, int numberInList, void(*function)(void));

		//alternative constructor for list box that will maintain the list offset and selection values internally , and just fill in a
		//single index value for the current selection
		Asura_List_Dialog(const Asura_Vector_2& xOffset, const char* const* ppszList, int* piSelectionIndex, int iNumberOfLines, int iNumberInList, void(*pFunction)(void),bool* pbChangedFlag = 0, const bool bOnlySelectOnClick = false );

		//creates a list dialog with check boxes for each of the entries
		Asura_List_Dialog(const Asura_Vector_2& xOffset, const char* const* ppszList, int* piSelectionIndex, int iNumberOfLines, int iNumberInList, bool(*pfnIsChecked)(int iIndex,int iUserData),void(*pfnToggleCheck)(int iIndex,int iUserData),int iUserData,bool* pbChangedFlag = 0, const bool bOnlySelectOnClick = false);

		~Asura_List_Dialog();
		
		//set help strings for each item in the list
		void SetListHelpStrings(const char* const * ppszHelpText);

		//Alternative method of showing the help/tooltips via a callback.
		//The callback should set the help text via Asura_Overlay_System::SetHelpText()
		//iIndex is the index of the item the mouse is over.
		//szText is the string for that item.
		void SetTooltipCallback( void (*pfnDisplayTooltipCallback)(int iIndex,const char* szText));


		virtual void Render( const Asura_Vector_2& xOrigin );
		virtual void Update( const Asura_Vector_2& xOrigin );

		virtual void PerFrameUpdate();

		//helper function for adjusting selection/offset values to ensure that they are in range RAR 04/04/03
		static void AdjustListSelectionAndOffset(int* piListOffset,int* piListSelection,int iNumberOfLines,int iNumberInList);

		//set the index of the current selection
		void SetSelection(int iIndex, bool bAffectMultipleSelection = true);

		//Changes the list of strings being displayed by this dialog.
		//This won't create/destroy the up/down arrows or scroll bar however
		void ReplaceStrings(int iNumberInList,const char* const* ppszList);

		//Forces scrollbar to be hidden/shown
		void ShowScrollBar(bool bShow);

		//Enable/disable multiple selection. Note that if multiple selection is used then the selection index pointer passed
		//into the constructor is to a certain extent redundant , and only get used for determining the visible
		//part of the list.
		//If the callback functions are set , then the selection is stored externally via those , rather than being stored in the list dialog.
		//Also note that replacing the strings will cause the selection list to be cleared (unless the callback functions are used)
		void EnableMultipleSelection(bool bEnable,bool (*pfnIsSelected)(int iIndex) = 0,void (*pfnSetSelected)(int iIndex,bool bSet) = 0);

		//Get the current selection (multiple selection only , and only if the callbacks aren't being used).
		int GetNumSelected() const;
		int GetSelection(int iIndex) const;

		//Sets a callback to call when a list entry is double clicked
		void SetDoubleClickFunction(void (*pfnDoubleClick)(int iUserData),int iUserData) {SetDoubleClickFunction(Asura_Callback_UserData<void,int>(pfnDoubleClick, iUserData));}
		void SetDoubleClickFunction(const Asura_Callback_Base<void>& xDoubleClickCallback);
		//Sets a callback to call when a list entry is single clicked
		void SetSingleClickFunction(void (*pfnSingleClick)(int iUserData),int iUserData) {SetSingleClickFunction(Asura_Callback_UserData<void,int>(pfnSingleClick, iUserData));}
		void SetSingleClickFunction(const Asura_Callback_Base<void>& xSingleClickCallback);

		//Enable/disable rendering of the list box border
		//(default is true)
		void SetBorder(bool bEnabled);

		//If set to true then the space used by the text is expanded to the right side of the overlay
		//(default is true)
		void SetExpandWidthToFillOverlay(bool bSet);

		//sets the minimum width to use for the listbox
//		void SetExpandToFillOverlay(bool bSet);
		//(default is 0)
		void SetMinWidth(float fMinWidth);


		//Allows control to prepare for the overlay being resized
		virtual void StartResize(u_int uResizeFlags){m_iNumberOfLinesBeforeResize = m_iNumberOfLines;}
		//Handles user resizing the overlay. xDelta is the cumulative delta from the start of the operation
		virtual void UpdateResize(u_int uResizeFlags, const Asura_Vector_2& xDelta);
		//Gets the direction(s) in which this dialog can be resized
		virtual u_int GetAllowedResizeFlags() const;

	protected:
		void CreateGadgets(const Asura_Vector_2& xOffset, const char* const* ppszList, int* piListOffset, int* piListOffsetScroll, int* piSelection, int iNumberOfLines, int iNumberInList, void(*pFunction)(void));

		bool HasTickboxes(){return m_pfnIsChecked && m_pfnToggleChecked;}
		bool IsChecked(int iIndex);
		void ToggleChecked(int iIndex);

		//updates the gadget and dialog width based on m_fTextWidth and m_fMinWidth
		void SetWidths();

		//values for use when using list box that just has single pointer to an index value
		int* m_piSelectionIndex;
		int m_iListOffset;
		int m_iListOffsetScroll;
		int m_iListSelection;
		bool* m_pbChangedFlag;
		const bool m_bOnlySelectOnClick;

		int m_iUserData;
		bool (* m_pfnIsChecked)(int iIndex,int iUserData);
		void (* m_pfnToggleChecked)(int iIndex,int iUserData);

		class Asura_List_Dialog_SelectionHandler* m_pxMultipleSelectionHandler;

		int m_iNumberOfLines;
		int m_iNumberInList;
		class Asura_TextSelect_Gadget* m_pxFirstTextGadget;//first text gadget in linked list (which will be the last one created)
		class Asura_ListTickbox_Gadget* m_pxFirstTickboxGadget;//similarly for the tickboxes

		class Asura_UpDown_Gadget* m_pxUpGadget;
		class Asura_UpDown_Gadget* m_pxDownGadget;
		class Asura_VerticalScroll_Gadget* m_pxScrollGadget;


		friend class Asura_ListTickbox_Gadget;


		bool  m_bHasOutline;
		bool m_bExpandWidthToFillOverlay;
		float m_fMinWidth;//minimum width to use for text gadgets
		float m_fTextWidth;//width of text gadgets required by the current list of strings

		int m_iNumberOfLinesBeforeResize;

};

//class for dealing with multiple selection in the list dialog
class Asura_List_Dialog_SelectionHandler
{
public :
	Asura_List_Dialog_SelectionHandler(int iNumberInList,bool* pbChangedFlag,bool (*pfnIsSelected)(int iIndex),void (*pfnSetSelected)(int iIndex,bool bSet));
	~Asura_List_Dialog_SelectionHandler();
	
	void ClearSelection();
	void SetSize(int iNumberInList);

	int GetNumSelected() const;
	int GetSelection(int iIndex) const;
	void SetSelected(int iIndex,bool bSet);

	bool IsSelected(int iIndex) const;
	bool IsInDragSelection(int iIndex) const;

	void Update(int iIndex,bool bClickable);

	void PreGadgetUpdate();
	void PostGadgetUpdate();

private :

	List<int>* m_pxList;
	bool* m_pbChangedFlag;

	bool (*m_pfnIsSelected)(int iIndex);
	void (*m_pfnSetSelected)(int iIndex,bool bSet);

	int m_iNumberInList;//number of text strings , not number in selection list.
	int m_iAnchorIndex;//index to start block selection from if shift is held
	int m_iDragStartIndex;//start of drag selection
	int m_iMouseIndex;//index of list entry that the mouse has most recently been over
	bool m_bUpdatedThisFrame;

};

class Asura_Button_Dialog : public Asura_Dialog
{
	public :
		Asura_Button_Dialog( const Asura_Vector_2& offset,int textureIndex,int textureSize,Asura_Vector_2 buttonPixelPos,Asura_Vector_2 buttonPixelSize,void(*clickedFunction)(void) = 0);
		Asura_Button_Dialog( const Asura_Vector_2& offset,int textureIndex,int textureSize,Asura_Vector_2 buttonPixelPos,Asura_Vector_2 buttonPixelSize,void(*clickedFunction)(void*),void* pContext);
};


class Asura_DynamicList_Dialog : public Asura_Dialog
{
	public:
		Asura_DynamicList_Dialog(const Asura_Vector_2& xOffset, char** ppcList, int* piListOffset, int* piSelection, int iNumberOfLines, int* piNumberInList, void(*pxFunction)(void));

		virtual void Render( const Asura_Vector_2& xOrigin );
		virtual void Update( const Asura_Vector_2& xOrigin );
		const char* GetItemName(int iItem) { return m_ppcList[iItem]; };

	private:
		int m_iNumberOfLines;
		int* m_piNumberInList;
		int* m_piListOffset;
		char** m_ppcList;
		int* m_piSelection;
		void(*m_pxFunction)(void);
		Asura_Vector_2 m_xOffset;
		
};

class Asura_StringDisplay_Dialog : public Asura_Dialog
{

    public:

        // C O N S T R U C T O R S   /   D E S T R U C T O R S ///////////////

        Asura_StringDisplay_Dialog( const char* szString, const Asura_Vector_2& xOffset ) : Asura_Dialog( szString, xOffset ) { m_uColour = 0x0; }

		//virtual unsigned GetColour(void) const { return (m_uColour == 0x0) ? Asura_Dialog::GetColour() : m_uColour; }
		virtual unsigned GetColour(void) const;
		void SetColour(unsigned int uColour) { m_uColour = uColour; }

	private:

		unsigned int m_uColour;

};

class Asura_CtrlTabList_Dialog : public Asura_Dialog
{

    public:
    
        // C O N S T R U C T O R S   /   D E S T R U C T O R S ///////////////

        Asura_CtrlTabList_Dialog( u_int uMaxDisplayedEntries );
        virtual ~Asura_CtrlTabList_Dialog( void );

        // M E T H O D S /////////////////////////////////////////////////////

        virtual void Render( const Asura_Vector_2& xOrigin );
        virtual void Update( const Asura_Vector_2& xOrigin );

        virtual void ForgetOverlayList( void );
        virtual void SetOverlayList( Asura_Overlay** ppxOverlayList, u_int uOverlayListLen );
        virtual void SetSelectedEntry( u_int uEntry );

    protected:

        // C O N S T A N T S /////////////////////////////////////////////////
        
        enum { MAX_ENTRY_NAME_LEN = 32 };

        // S T A T E /////////////////////////////////////////////////////////

        Asura_StringDisplay_Gadget** m_ppxDisplayedListEntries;
        const u_int                  m_uMaxDisplayedEntries;
        u_int                        m_uNumDisplayedEntries;
        
        Asura_Overlay**              m_ppxOverlayList;
        u_int                        m_uOverlayListLen;

};

/// Richard May - 05/11/2002 09:42:09 - Used to display a string that can be dynamically altered
/// elsewhere
class Asura_Dynamic_Dialog : public Asura_Dialog
{
	public:
		/* Constructor/Destructor */
		Asura_Dynamic_Dialog(Asura_String* pszName, Asura_Vector_2 xOffset);
		virtual ~Asura_Dynamic_Dialog(void) {};

		virtual void PerFrameUpdate(void);
		virtual const Asura_Vector_2& GetMaxCoords(void) const;

		void SetNameValue( const Asura_String& xValue )  { if( m_pszName ) *m_pszName = xValue; }

	protected:

		Asura_String* m_pszName;
};


class Asura_Icon_Dialog : public Asura_Dialog
{
	public :
		Asura_Icon_Dialog(const Asura_Vector_2& xOffset,int iTextureIndex,int iIconIndex);

		//sets function to be called when icon is clicked
		void SetClickedFunction(void(*pfnClickedFunction)(void))	{SetClickedFunction(Asura_Callback_Void<void>(pfnClickedFunction));}
		//similarly , but with an optional parameter
		void SetClickedFunction(void(*pfnClickedFunction)(int),int iUserData)	{SetClickedFunction(Asura_Callback_UserData<void,int>(pfnClickedFunction, iUserData));}

		void SetClickedFunction(const Asura_Callback_Base<void>& xCallback);

		//sets bool that should be set to true when icon is clicked
		void SetClickedFlag(bool* pbClickedFlag);

		//Turns icon into a checkbox style gadget. Icon will be shown as down/up
		//according to the value of the bool passed
		void SetCheckboxBool(bool* pbValue);

		//Similarly , but using a bit from a flags field
		void SetCheckboxFlag(u_int* puFlagsField,u_int uFlagBit);
		void SetCheckboxFlag(int* piFlagsField,u_int uFlagBit);

		//And another alternative for a checkbox with values controlled by callbacks
		void SetCheckboxFunction(const Asura_Callback_Base<bool>& xIsChecked, const Asura_Callback_Base_1Arg<void,bool>& xSetChecked);

};

class Asura_ClickableString_Dialog : public Asura_Dialog
{
public:
	// Constructor
	Asura_ClickableString_Dialog(const char* szName, const Asura_Vector_2& xOffset);

	//Sets a callback to call when a list entry is single clicked
	void SetClickFunction(void (*pfnClick)(int iUserData),int iUserData);

	void SetString(const char* szName);

protected :

private:
	static void OnClick(int iArg);
	class Asura_StringDisplay_Gadget*		m_pxTextGadget;
	void (*m_pfnClick)(int iUserData);
	int m_iUserData;
};

class Asura_DropDown_List_Dialog : public Asura_Dialog
{
	public:
		// Standard constructor.
		Asura_DropDown_List_Dialog( const Asura_Vector_2& xOffset,
									const char* const* pszList,
									int* piListOffset, int* piListSelection,
									int iNumberOfLines, int iNumberInList,
									void( *pfFunction )( void ),
									const char* szName = NULL,
									const bool bOnlySelectOnClick = false );

		// Alternative constructor for list box that will maintain the list offset and selection values internally , and just fill in a
		// single index value for the current selection.
		Asura_DropDown_List_Dialog( const Asura_Vector_2& xOffset,
									const char* const* ppszList,
									int* piSelectionIndex,
									int iNumberOfLines, int iNumberInList,
									void( *pfFunction )( void ),
									bool* pbChangedFlag = 0,
									const char* szName = NULL,
									const bool bOnlySelectOnClick = false );

		// Alternative constructor for list box that will maintain the list offset and selection values internally , and just fill in a
		// single u_int index value for the current selection.
		Asura_DropDown_List_Dialog( const Asura_Vector_2& xOffset,
									const char* const* ppszList,
									u_int* puSelectionIndex,
									int iNumberOfLines, int iNumberInList,
									void( *pfFunction )( void ),
									bool* pbChangedFlag = 0,
									const char* szName = NULL,
									const bool bOnlySelectOnClick = false );

		// Shared value constructor.
		Asura_DropDown_List_Dialog( const Asura_Vector_2& xOffset,
									const char* const* ppszList,
									Asura_Dialog_SharedValue< int >* pxSharedSelectionIndex,
									int iNumberOfLines, int iNumberInList,
									void( *pfFunction )( void ),
									bool* pbChangedFlag = 0,
									const char* szName = NULL,
									const bool bOnlySelectOnClick = false );

		~Asura_DropDown_List_Dialog();

		//set help strings for each item in the list
		void SetListHelpStrings(const char* const * ppszHelpText);

		void Render(const Asura_Vector_2& xOrigin);
		void Update(const Asura_Vector_2& xOrigin);
		void PerFrameUpdate();

		void SetMaximumWidth(const float fMaxWidth);

		// Changes contents of drop down list. Does handle scroll bar adding/removing, unlike Asura_List_Dialog equivalent
		void ReplaceStrings(int iNumberInList, const char* const* ppszList);
		// Selects the given entry, scrolling to position if necessary
		// iSelection is based on the index into the original unsorted list
		void SelectEntry(int iSelection, bool bUpdateExternalIndex = true);

		//for setting the callback functions			
		void SetOnSelectCallback(void(*pfnOnSelect)(void));
		void SetOnSelectCallback(void(*pfnOnSelect)(int),int iUserData);

		//If set then the value in piSelectionIndex will only get updated and the changed flag set , when the
		//dropdown list is closed by clicking on it.
		//This doesn't work if using the version that takes a separate list offset and list selection
		void SetOnlyUpdateSelectionIndexOnClick(bool bSet) {m_bOnlyUpdateSelectionIndexOnClick = bSet;}

		//set the minimum width for the control in print coords, to help with lining up with other drop down lists
		void SetMinimumWidth(float fWidth);

		//Causes the list to be sorted alphabetically.
		//The selection index is still considered to be based on the unsorted list ,and is translated internally.
		//This won't work in a useful manner if using the first (and largely obsolete) constructor that takes
		//a separate list offset and selection instead of a single selection index
		//Use the uStartSortOffset to prevent elements at the start of the array from being sorted.
		//This is especially useful if the first item is a default setting that needs to 
		//remain at the start of the list.
		//To sort the entire list uStartSortOffset needs to be 0
		void SetSortStrings(bool bSort,u_int uStartSortOffset = 0);

		//gets width in print coords required for string
		static float GetWidthForString(const char* szString);

		// in case we want to adjust the position of the line
		static float s_fDropListSpacing;
		static float s_fDropListLineOffsetY;
		static float s_fDropListLineAdjustX1;
		static float s_fDropListLineAdjustX2;
		static Asura_Vector_2 s_xDropListScrollBarOffset;
		static float s_fCaptionSpacing;

	protected :
		//constructor for derived classes ,to be followed by initialise
		Asura_DropDown_List_Dialog(const Asura_Vector_2& xOffset, const bool bOnlySelectOnClick = false );
		void Initialise(const Asura_Vector_2& xOffset,const char* const* ppszList, int* piSelectionIndex, int iNumberOfLines, int iNumberInList, void(*pfFunction)(void),bool* pbChangedFlag = 0, const char* szName = NULL);

		bool IsDroppedDown() const {return m_bIsDroppedDown;}

		virtual bool CanRenderOutsideOfParentSubwindow() const {return IsDroppedDown();}


		//Derived class can return true if the drop down list should be using the shared value colour
		virtual bool IsSharedValue() const {return m_pxSharedSelectionIndex != 0;}
		//Derived class can return true if the drop down list is using a shared value which is different over the selected objects
		virtual bool IsMixedValue() const;

	private:
		// Brings up/removes the list
		void ToggleDropDown();
		// Sets up correct gadget hidden settings
		void SetGadgetsHidden();

		//create gadgets , split off from the constructor so it can be shared
		void CreateGadgets( const Asura_Vector_2& xOffset, const char* const* ppszList, int* piListOffset, int* piListOffsetScroll, int* piSelection, int iNumberOfLines, int iNumberInList );

		//GetExternalIndex() gets the index into the unsorted list
		//Get the current index from m_piSelectionIndex or m_pxSharedSelectionIndex
		int GetExternalIndex() const;
		//set the externally stored index value
		void SetExternalIndex(int iIndex);
		//true if there is a single stored index value , instead of being a list offset/list selection
		bool HasExternalIndex() const {return m_piSelectionIndex || m_puSelectionIndex || m_pxSharedSelectionIndex;}
		//update the external index, if we have one
		void UpdateExternalIndex( void );
		//get the internal index  (scroll offset + index)
		int GetInternalIndex_Sorted( void ) const;
		//get the internal index and converts to the unsorted list
		int GetInternalIndex_Unsorted( void ) const;

		int ToSortedIndex(int iIndex) const;
		int FromSortedIndex(int iIndex) const;

		static int SortStringCallback(const void* pEntry1, const void* pEntry2);
		void UpdateSortedStringList();

		//deals with key presses while dropped down
		void HandleKeyboard();

		bool GetCroppedString(char* pszDest, const char* pszSource, const u_int uDestSize);

		// Members
		// Current number of lines 
		int									m_iNumberOfLines;
		// Number of lines specified in constructor
		int									m_iMaxNumberOfLines;
		// Dummy variable used for the down arrow on the right
		int									m_iDropDown;
		// Whether the list of entries is visible or not
		bool								m_bIsDroppedDown;
		// Whether we have more entries than lines
		bool								m_bNeedsScrollBar;
		// Length of string list
		int									m_iNumberInList;
		// List of entries
		const char* const*					m_pszUnsortedStringList;
		// Position in list
		int*								m_piListOffset;
		int*								m_piListSelection;
		// Sorry, fed up with working around the default dialog name functionality...
		const char*							m_szName;
		// first text gadget in linked list (which will be the last one created)
		class Asura_TextSelect_Gadget*		m_pxFirstTextGadget;
		// Scroll bar top
		class Asura_UpDown_Gadget*			m_pxUpGadget;
		// Scroll bar bottom
		class Asura_UpDown_Gadget*			m_pxDownGadget;
		// Scroll bar
		class Asura_VerticalScroll_Gadget*	m_pxScrollGadget;
		// Text display of selection
		class Asura_StringDisplay_Gadget*	m_pxSelectedGadget;
		// Down arrow
		class Asura_UpDown_Gadget*			m_pxDropDownGadget;

		//For automatically sorted dropdown llists
		int*								m_piToSortedIndex;
		int*								m_piFromSortedIndex;
		bool								m_bSortStrings;

		//Only sort items in the string list at or after this offset.
		//Allows elements at the start of the list to remain in place even when then
		//list is sorted.
		//To sort the entire list m_uStartSortOffset needs to be 0
		u_int								m_uStartSortOffset;

		float m_fMinWidth;

		//For jumping to middle of list by typing start of a word
		char m_szInput[ 64 ];			// PAZ - working with quite long prefixes for some DVS variables, so made this buffer a bit bigger

		float m_fMaxWidth;	// Force the maximum width of the closed control
		float m_fFullWidth;	// This is only used if m_fMaxWidth has been set.  This is the original width (used for the opened combo box)

		//values for use when using list box that just has single pointer to an index value
		int* m_piSelectionIndex;
		u_int* m_puSelectionIndex;
		Asura_Dialog_SharedValue<int>* m_pxSharedSelectionIndex;
		int m_iSelectionIndexBackup;	//for tracking external changes to the selection
		int m_iListOffset;
		int m_iListOffsetScroll;
		int m_iListSelection;
		bool* m_pbChangedFlag;
		void(*m_pfOnSelectCallbackVoid)(void);
		void(*m_pfOnSelectCallbackInt)(int);
		int m_iOnSelectCallbackUserData;

		bool m_bOnlyUpdateSelectionIndexOnClick;
		// PAZ - this is different to OnlyUpdateSelectionIndexOnClick
		const bool m_bOnlySelectOnClick;				
};

//Base class for a specialised drop down list for setting hash values , and that maintains
//the list of strings internally.
//The hash values must be the hash values generated from the strings in the dialog
class Asura_Hash_DropDownList_Dialog : public Asura_DropDown_List_Dialog
{
public :
	Asura_Hash_DropDownList_Dialog(const Asura_Vector_2& xOffset);
	~Asura_Hash_DropDownList_Dialog();


protected :
	//overrides from parent c;ass
	virtual bool IsSharedValue() const {return m_pxSharedSelected!=0;}
	virtual bool IsMixedValue() const;

	virtual void PerFrameUpdate();

	//For iterating over the list of names when populating the drop down list.
	//By default these will make use of GetNumberOfHashValues() and GetNameByIndex() , so
	//either these need to be overridden or the other two functions
	virtual void Iteration_Start() {m_uIterationPos = 0; m_uIterationLength = GetNumberOfHashValues();}
	virtual void Iteration_Next() {m_uIterationPos++;}
	virtual bool Iteration_Done() const {return m_uIterationPos >= m_uIterationLength;}
	//Get the current name in the iteration. If a null pointer is returned , then it will be ignored
	virtual const char* Iteration_GetCurrent() const {return GetNameByIndex(m_uIterationPos);}

	//Used for iterating over the names when populating the drop down list
	//These need to be overridden if using the default Iteration_ functions above

	//Get the number of hash values (not including ASURA_HASH_ID_UNSET)
	virtual u_int GetNumberOfHashValues() const {return 0;}
	//Get the name for the iIndex'th hash value
	virtual const char* GetNameByIndex(int iIndex) const {return 0;}

	
	//Get the text to use for a hash value of zero
	virtual const char* GetZeroHashText() const {return "*None*";}
	virtual const char* GetUnknownHashText() const {return "*Unknown*";}

	//Gets a value to see whether the list is out of date. The index can be incremented whenever
	//all dialogs of the same class need to be updated.
	virtual int GetListValidID() const {return 0;}


	void Initialise(const Asura_Vector_2& xOffset,int iNumberOfLines,Asura_Hash_ID* puSelected,bool* pbChangedFlag,const char* szName);
	void Initialise(const Asura_Vector_2& xOffset,int iNumberOfLines,Asura_Dialog_SharedValue<Asura_Hash_ID>* pxSharedSelected,bool* pbChangedFlag,const char* szName);

	// AJK 29-07-08
	// The dialog adds a *NONE* entry by default; Override this function to remove the entry.
	virtual bool GetAllowNoneEntry() const { return true; }

private :
	//Get the current hash ID from m_puSelected or m_pxSharedSelected
	Asura_Hash_ID GetExternalHash() const;
	//set the externally stored hash value
	void SetExternalHash(Asura_Hash_ID uHash);

	void Update(const Asura_Vector_2& xOrigin);

	void UpdateStringList(bool bUpdateDialog = true);
	void DeleteStringList();

	bool UpdateSelectedIndex();

	int m_iSelectedIndex;
	bool m_bChanged;

	Asura_Hash_ID m_uSelectedCopy;//copy of selection for detecting external changes

	Asura_Hash_ID* m_puSelected;	
	Asura_Dialog_SharedValue<Asura_Hash_ID>* m_pxSharedSelected;
	bool* m_pbChangedFlag;

	class Asura_StringTree* m_pxStringTree;
	const char** m_ppszStrings;

	int m_iListValidID;

	u_int m_uIterationPos;
	u_int m_uIterationLength;
};

class Asura_StringValuePair_DropDownList_Dialog : public Asura_Dialog
{

public:

	typedef Asura_Dialog PARENT;

	struct SelectionItem
	{
		Asura_String	xString;
		Asura_String	xHelpString;
		int				iData;
		bool			bSelectedInitially;
	};

	Asura_StringValuePair_DropDownList_Dialog( Asura_Vector_2& xOffset, const char* szName, int* iSelectionValue, bool* bChanged );
	~Asura_StringValuePair_DropDownList_Dialog();


	void AddItem( const char* szString, int iData = 0, bool bIsSelectedInitially = false, const char* szHelpString = NULL, bool bDontAddIfDuplicateString = false );

	void InitialiseData( void );

	const char* GetEmptyListString( void ) const;

	void Render(const Asura_Vector_2& xOrigin);
	void Update(const Asura_Vector_2& xOrigin);
	void PerFrameUpdate();

	//create gadgets , split off from the constructor so it can be shared
	void CreateGadgets( Asura_Vector_2& xOffset, const int iNumLines = 0 );

private:

	static float s_fDropListSpacing;
	static float s_fDropListLineOffsetY;
	static float s_fDropListLineAdjustX1;
	static float s_fDropListLineAdjustX2;
	static Asura_Vector_2 s_xDropListScrollBarOffset;

	// Brings up/removes the list
	void ToggleDropDown();
	// Sets up correct gadget hidden settings
	void SetGadgetsHidden();

	void SelectEntry( int iSelection );

	List<SelectionItem*>				m_xItems;
	const char**						m_ppcStrings;
	const char**						m_ppcHelpStrings;
	int*								m_piIndexConv;
	int*								m_iSelectedValue;
	int*								m_piListOffsetScroll;
	int									m_iNumItems;
	
	int									m_iSelection;
	int									m_iLastSelection;
	int									m_iNumInList;
	int									m_iNumLines;
	bool								m_bNeedsScrollBar;
	float								m_fMinWidth;

	bool								m_bIsDroppedDown;
	bool*								m_bChanged;

	class Asura_TextSelect_Gadget*		m_pxFirstTextGadget;
	// Scroll bar top
	class Asura_UpDown_Gadget*			m_pxUpGadget;
	// Scroll bar bottom
	class Asura_UpDown_Gadget*			m_pxDownGadget;
	// Scroll bar
	class Asura_VerticalScroll_Gadget*	m_pxScrollGadget;
	// Text display of selection
	class Asura_StringDisplay_Gadget*	m_pxSelectedGadget;
	// Down arrow
	class Asura_UpDown_Gadget*			m_pxDropDownGadget;
	// Dummy variable used for the down arrow on the right
	int									m_iDropDown;
	// Sorry, fed up with working around the default dialog name functionality...
	const char*							m_szName;


};



class Asura_Image_Dialog : public Asura_Dialog
{
public:
	/* Constructor & Destructor */
	Asura_Image_Dialog( const Asura_Vector_2& xOffset, int iTextureIndex, float fWidth, float fHeight );
	Asura_Image_Dialog( const Asura_Vector_2& xOffset, Asura_Hash_ID uTileHash, float fWidth, float fHeight );
	virtual ~Asura_Image_Dialog();

	void SetTexture(int iTextureIndex);
	void SetTranslucent(bool bTrans){m_bTranslucent = bTrans;}
	//override the texture operation used. If set to ASURA_TEXTUROP_INVALID then the default will be used
	void SetTextureOp(int iTextureOp){m_iTextureOp = iTextureOp;}

	// set uv rectangle for texture to be displayed. Values are ignored if tile hash id is set 
	void SetTextureUV( const Asura_Bounding_Rectangle& xUV ) { m_xTextureUV = xUV; }
	void SetTextureUV( const float fU1,const float fV1,const float fU2, const float fV2 ) { m_xTextureUV.Set( fU1,fV1,fU2,fV2 ); }

	//adds a border around the image
	void SetBorder(u_int uColour, u_int uBorderPixels)
	{
		m_uBorderColour = uColour;
		m_uBorderPixels = uBorderPixels;
	}

	//Sets the background colour to use (if non-zero)
	void SetBackground(u_int uColour)
	{
		m_uBackgroundColour = uColour;
	}

	//Sets both the background and border at the same time
	void SetBackground(u_int uColour, u_int uBorderPixels)
	{
		m_uBackgroundColour = uColour;
		m_uBorderColour = uColour;
		m_uBorderPixels = uBorderPixels;
	}





public:
	/* Public Interface Functions */
	virtual void Render(const Asura_Vector_2& xOrigin);
	virtual bool ShouldCheckDialogExtentsForIsPointInDialog() const {return true;}

private:
	/* Data */
	int m_iTextureIndex;
	Asura_Hash_ID m_uTileHash;
	Asura_Vector_2 m_xSize;
	Asura_Bounding_Rectangle m_xTextureUV;
	bool m_bTranslucent;
	int m_iTextureOp;

	u_int m_uBackgroundColour;
	u_int m_uBorderColour;
	u_int m_uBorderPixels;
};


class Asura_Tabs_Dialog : public Asura_Dialog
{
public:
	// Constructor & Destructor
	Asura_Tabs_Dialog(const Asura_Vector_2& xOffset, const char* const* pxTabNames, u_int uNumberOfTabs, int iMaxWidth = 0);
	Asura_Tabs_Dialog(const Asura_Vector_2& xOffset, int iMaxWidth = 0);
	~Asura_Tabs_Dialog();

	// Interface functions
	void SelectTab(int iTab);
	// This function will select the tab with the given name if it exists and return true. If it doesn't exist it
	// select the first tab and return false
	bool SelectTabByName(const Asura_String& xName, bool bDefaultToFirstTab = true);
	virtual void AddDialog(Asura_Dialog* pxDialog);
	u_int GetSelected() const { return m_uSelectedTab; }
	const char* GetSelectedTabName() const;
	//Used for setting a pointer that can be used for getting/setting the selected tab
	//(should be done after all of the controls have been added to be of much use)
	void SetSelectedTabPointer(u_int* puSelectedTab);
	// Same as the above but grabs the tab with the given name rather then index
	void SetSelectedTabPointerByName(Asura_String* pxSelectedTabname);

	u_int GetNumTabs() const { return m_uNumberOfTabs; }

	//Adds a new tab to the end of the list , and selects it
	void AddTab(const char* szTabName);
	
	//Deletes the specified tab  , along with all of its child controls
	void DeleteTab(u_int uTab);
	void DeleteTabByName( const Asura_String& xName );

	//Renames a tab
	//If bChangeIDName is false then the old name is kept for the purpose of identifying it when
	//selecting by name
	void RenameTab(u_int uTab,const char* szTabName, bool bChangeIDName = true);

	// Clears a specified tab...
	void ClearTab(u_int uTab);

	//gets a suitable position for creating a child dialog
	Asura_Vector_2 GetTopDialogPosition() const;


	virtual void Render(const Asura_Vector_2& xOrigin);
	virtual void Update(const Asura_Vector_2& xOrigin);
	virtual void PerFrameUpdate();

	virtual const Asura_Vector_2& GetMaxCoords() const;
    virtual Asura_Vector_2        GetMaxCoordsForTab( const u_int uTab );

	virtual void OnHiddenStateChange();

	virtual void DeleteChildDialogs(void);
	virtual void RemoveReferencesToDialog(const Asura_Dialog* pxDialog);

	//Allows control to prepare for the overlay being resized
	virtual void StartResize(u_int uResizeFlags);
	//Handles user resizing the overlay. xDelta is the cumulative delta from the start of the operation
	virtual void UpdateResize(u_int uResizeFlags, const Asura_Vector_2& xDelta);
	//Gets the direction(s) in which this dialog can be resized
	virtual u_int GetAllowedResizeFlags() const;

	//gets the width used by the tab gadgets
	float GetTabWidth();

    virtual Asura_Vector_2 GetPositionFromID(Asura_Hash_ID uPositionID) const;
	//ID for positioning controls relative to top left of the main area
	static const Asura_Hash_ID s_uTopLeftPositionID = 0x1250B032; //Asura_GetHashID("Tab_TopLeft")
private:
	float GetMaxXForRow(u_int uRow) const;
	void RepositionTabGadgets();
	// Data
	class Asura_Tab_Gadget**			m_ppxTabGadgets;
	u_int								m_uNumberOfTabs;
	u_int								m_uNumberOfRows;
	u_int								m_uSelectedTab;
	u_int*								m_puSelectedTab;
	mutable Asura_Vector_2				m_xMaxCoordIncludingChildren;
	int									m_iMaxWidth;
	Asura_String*						m_pxSelectedTabName;
	float								m_fPreResizeWidth;
	float								m_fPreResizeHeight;
};




class Asura_Scrollbar_Dialog : public Asura_Dialog
{
public :
	Asura_Scrollbar_Dialog(const Asura_Vector_2& xOffset,float* pfValue,float fMin,float fMax,bool bHorizontal,float fLength,const char* szPrintFormat,bool* pbChanged, void(*pfnChanged)(void) = 0 );
	
private :
	virtual void ShowHelpText();

	class Asura_Scrollbar_Gadget* m_pxScrollbar;
	const char* m_szPrintFormat;
	float* m_pfValue;
};


/*
Asura_Subwindow_Dialog is a dialog control for containing other controls that might be too large to fit on screen.
If the child controls are too large to fit into the space allocated for this , then scrollbars will be added
to allow the subwindow to be scrolled.

This hasn't been tested when combined with tab controls or subwindow controls yet , and so may need a few tweaks to allow
this.
RAR 25/07/2006
*/

class Asura_Subwindow_Dialog : public Asura_Dialog
{
public :
	
	//fMaxWidth and fMaxHeight are the maximum width and height allowed for the control in overlay/print coordinates
	//If bShrinkToFit is true then the control will be made smaller if not all the space is needed by the child controls.
	Asura_Subwindow_Dialog(const Asura_Vector_2& xOffset,float fMaxWidth,float fMaxHeight,bool bShrinkToFit);

	//Adds a control as a child to the subwindow dialog. Note that the Offsets on any such controls are taken as being
	//relative to the subwindow control , rather than relative to the overlay.
	virtual void AddDialog(Asura_Dialog* pxDialog);

	//Get additonal offset that needs to be applied to the child dialogs
	Asura_Vector_2 GetChildOffset() const;

	//gets max y of all child controls
	float GetChildMaxY();

	//scrolls to bottom of subwindow
	void ScrollToBottom();
	

	//used by rendering
	void EnableClipping();
	static void DisableClipping();

	//rerturns true if the child dialog is at least partially in the visible area
	bool IsDialogInVisibleArea(Asura_Dialog* pxDialog) const;

	//returns true if the mouse cursor is over the area available for child controls
	bool IsCursorWithinChildRect() const;

	//returns true if the point (in screen relative print coords) is over the area available for child controls
	bool IsPointWithinChildRect(float fX,float fY) const;

	//used when calculating the size of the overlay
	virtual void UpdateSizeInit();
	virtual void UpdateSize();
	void UpdateSize(const Asura_Dialog* pxChildDialog);

	//Enables mousewheel support ,and determines how fast the control should be scrolled
	//(in print coordinates per mouse wheel click)
	//RAR 06/08/2008 Now defaults to being on , but can be turned off if needed by setting to 0 , or set to
	//a different speed if required.
	void SetMouseWheelScrollRate(float fRate){m_fMouseWheelScrollRate = fRate;} 


	//Allows control to prepare for the overlay being resized
	virtual void StartResize(u_int uResizeFlags);
	//Handles user resizing the overlay. xDelta is the cumulative delta from the start of the operation
	virtual void UpdateResize(u_int uResizeFlags, const Asura_Vector_2& xDelta);
	//Gets the direction(s) in which this dialog can be resized
	virtual u_int GetAllowedResizeFlags() const;

	// Deletes the child gadgets from this dialog
	virtual void DeleteChildDialogs(void);
	//Called when a single dialog is being deleted (as opposed to the entire overlay being closed).
	virtual void RemoveReferencesToDialog(const Asura_Dialog* pxDialog);


	bool IsOutlineHidden() const { return m_bOutlineHidden; }
	void SetOutlineHidden( bool bHidden ) { m_bOutlineHidden = bHidden; }

protected :
	virtual void Update( const Asura_Vector_2& xOrigin );
	virtual void Render( const Asura_Vector_2& xOrigin );

	//Called when the dialog becomes hidden or unhidden. RAR 23/04/2007
	virtual void OnHiddenStateChange();


private :

	void UpdateChildRect();

	class Asura_Scrollbar_Gadget* m_pxHorizontalBar;
	class Asura_Scrollbar_Gadget* m_pxVerticalBar;
	
    bool m_bShrinkToFit;
	bool m_bOutlineHidden;	
	bool m_bSizeValid;
	//current width/height of the dialog
	float m_fWidth;
	float m_fHeight;
	
	//max allowed width/height
	float m_fMaxWidth;
	float m_fMaxHeight;

	//width and height required by the child controls
	float m_fChildWidth;
	float m_fChildHeight;

	//width and height usable by the child controls (after subtracting space for the scrollbars)
	float m_fUsableWidth;
	float m_fUsableHeight;

	//Area for child controls in print coordinates ,relative to the overlay
	Asura_Vector_2 m_xChildRectMin;
	Asura_Vector_2 m_xChildRectMax;

	Asura_Vector_2 m_xChildOffset;

	//vertical scroll speed for mouse wheel
	float m_fMouseWheelScrollRate;

	float m_fPreResizeWidth;
	float m_fPreResizeHeight;

	Asura_LinkList<Asura_Dialog*> m_xDialogList;


	static Asura_Subwindow_Dialog* s_pxClippingWindow;
};


template <class T> class Asura_Dialog_SharedValue
{
public :
	virtual ~Asura_Dialog_SharedValue(){}

	//Gets the value , and other info if pointers are non-null
	//pbMixed indicates whether the value is different over several objects
	virtual void GetValue(T* pxValue,bool* pbMixed) const = 0;
	virtual void SetValue(const T& xValue) = 0;
};


/*
Asura_Panel_Dialog is a dialog control for drawing coloured panels behind existing controls.
There are two methods of using it, firstly you can add existing dialogs to the panel and it
will size itself so as to contain them. Secondly you can specify a size.

JEB DF 08/11/2006
*/
class Asura_Panel_Dialog : public Asura_Dialog
{
public:
	// Public functions...
	Asura_Panel_Dialog( const unsigned int uColour);
	Asura_Panel_Dialog( const Asura_Vector_2& xOffset, const Asura_Vector_2& xSize, const unsigned int uColour);
	virtual ~Asura_Panel_Dialog();

	void AddDialogToPanel( Asura_Dialog* pxDialog );
	void RemoveDialogFromPanel(Asura_Dialog* pxDialog);
    const Asura_Dialog* FindDialogOnPanel( const int iControlID ) const;
    Asura_Dialog* FindDialogOnPanel( const int iControlID );

    // 23/07/2007 - NJD - Temporary fix to stop crashes. 
    // Dialogs added to table dialogs, and dialogs added to table cell panel dialogs do not get registered with their overlay properly, and don't
    // hold a pointer to their overlay properly either. This fixes the second problem. Rich Rice to investigate the first.
    void SetOverlayPointer( Asura_Overlay* pxOverlay );

	// Overridden functions...
	virtual int UpdateList(const Asura_Vector_2& xOrigin, int iPriority);
	virtual int RenderList(const Asura_Vector_2& xOrigin, int iPriority);
	virtual void Update( const Asura_Vector_2& xOrigin );
    virtual void PerFrameUpdate();
	virtual void Render(const Asura_Vector_2& xOrigin);
	virtual void UpdateSize(void);
	virtual void UpdateLabel(const char* text);//used to change the text on a control... not implemented for all controls yet
//	virtual int RenderList(const Asura_Vector_2& xOrigin, int iPriority);
	virtual void OnHiddenStateChange();
	virtual bool IsPointInDialog(const Asura_Vector_2& xOrigin,const Asura_Vector_2& xPos) const;
	virtual Asura_Vector_2 GetTextOffset() const {return m_bMinimiseEnabled ? Asura_Vector_2(2.0f,0.0f) : Asura_Maths::ZeroVector2;}

	virtual u_int GetPanelBorderColour() { return 0xffffff; }

	virtual bool CanRenderOutsideOfParentSubwindow() const;

	const Asura_Vector_2& GetDialogSize() const	{ return m_xDialogSize; }
	const Asura_Vector_2& GetLabelSize() const { return m_xLabelSize; }
	const Asura_Vector_2& GetMinSize() const { return m_xMinSize; }
	void SetMinSize(const Asura_Vector_2& xMinSize) { m_xMinSize = xMinSize; }

	//gets the highest priority for this and any children
	int GetHighestPriority() const;

	void SetPanelColour(u_int uColour) {m_uColour = uColour;}

	//If used then the panel can be minimised by clicking on a minimise gadget.
	//If pbMinimisedFlag is provided then it is used as input/output for the current state
	void EnableMinimise(bool* pbMinimisedFlag = NULL);
	bool IsMinimised() const { return m_bMinimised; }
	void SetMinimised( bool bMinimised );
	// Set a callback that will get called when the minimised state changes.
	void SetOnMinimisedToggleCallback( void(*pfnOnToggle)(void) ) { m_pfnOnMinimisedToggle = pfnOnToggle; }

	//Enables rendering of a line border around the panel
	void SetRenderBorder(bool bSet){m_bRenderBorder = bSet;}

	//Used by the table dialog to ensure all the child dialogs get rendered ,since it
	//isn't setup to render using RenderList()
	void RenderThisAndChildDialogs(const Asura_Vector_2& xOrigin);

	virtual Asura_Dialog* GetHeadOfChildDialogList(int iListIndex) {return iListIndex==0 ? m_pxDialogList : 0;}

protected:
	bool m_bUpdateSize;

private:
	void ToggleMinimised();

	// Private typedefs...
	typedef Asura_Dialog PARENT;

	// Private variables...
	Asura_Vector_2	m_xMinSize;		// The minimum size of this panel.
	Asura_Vector_2	m_xLabelSize;	// The size of the label for this panel.
	Asura_Vector_2	m_xDialogSize;	// The size calculated from the current dialogs on the panel.
	Asura_Dialog*	m_pxDialogList;	// A pointer to the first of a list of dialogs.
	u_int			m_uColour;		// The colour to render the panel as.
	bool			bRender;		// Flag to say whether we wish to render this panel.
	bool			m_bRenderBorder;// Indicates whether a line border should be rendered around the panel

	bool			m_bMinimiseEnabled; //Determines whether the panel can be minimised by the user
	bool			m_bMinimised;		//Whether the panel is currently minimised
	bool*			m_pbMinimisedFlag;	//External store of the minimised flag
	u_int			m_uMinimisedForGadget;//The value controller by the minimise gadget

	void(*m_pfnOnMinimisedToggle)(void);
};


class Asura_Divider_Dialog : public Asura_Dialog
{
public:
	enum
	{
		VERTICAL        = 1, // Renders a vertical line instead of horizontal
		EXTEND_NEGATIVE = 2, // Extends from position up or left, instead of full overlay size
		EXTEND_POSITIVE = 4, // Extends from position down or right
	};

	Asura_Divider_Dialog( const Asura_Vector_2& xOffset, const u_int uColour=0xffffff,
		const u_int uFlags=0 );

	virtual void Render( const Asura_Vector_2& xOrigin );
	u_int m_uColour;
	u_int m_uFlags;
};


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Blueprint picker dialog 
//
// Fairly straight-forward: create a new dialog of this type, passing in a pointer to the hash ID you want
// to set and a function pointer that returns true if the supplied blueprint matches certain criteria. Valid blueprints
// are then added to the blueprint list which is then sorted alphabetically. NULL is a valid value for pfnIsValid: in 
// that case, all blueprints in the given types will be added to the list.
// 
// There are two constructors: one takes a single blueprint type and the other an ASURA_HASH_ID_UNSET-terminated 
// array of the types you wish to include in the test.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Asura_BlueprintPicker_Dialog : public Asura_Hash_DropDownList_Dialog
{
private:
	typedef Asura_Hash_DropDownList_Dialog PARENT;

public:
	// constructors
	Asura_BlueprintPicker_Dialog( const char* szName, Asura_Vector_2& xOffset, int iNumLines, Asura_Hash_ID* puOutputValue,
		bool(*pfnIsValid)(const Asura_Blueprint* pxBlueprint,Asura_Hash_ID uBPType), const Asura_Hash_ID* puBPTypeListbool, bool* pbChanged=NULL );
	Asura_BlueprintPicker_Dialog( const char* szName, Asura_Vector_2& xOffset, int iNumLines, Asura_Hash_ID* puOutputValue,
		bool(*pfnIsValid)(const Asura_Blueprint* pxBlueprint,Asura_Hash_ID uBPType), Asura_Hash_ID uBPTypebool, bool* pbChanged=NULL );
	Asura_BlueprintPicker_Dialog( const char* szName, Asura_Vector_2& xOffset, int iNumLines,
		Asura_Dialog_SharedValue<Asura_Hash_ID>* pxSharedSelected,
		bool(*pfnIsValid)(const Asura_Blueprint* pxBlueprint,Asura_Hash_ID uBPType), const Asura_Hash_ID* puBPTypeListbool, bool* pbChanged=NULL );
	Asura_BlueprintPicker_Dialog( const char* szName, Asura_Vector_2& xOffset, int iNumLines,
		Asura_Dialog_SharedValue<Asura_Hash_ID>* pxSharedSelected,
		bool(*pfnIsValid)(const Asura_Blueprint* pxBlueprint,Asura_Hash_ID uBPType), Asura_Hash_ID uBPTypebool, bool* pbChanged=NULL );

	//virtual ~Asura_BlueprintPicker_Dialog() {};

protected:
	// virtual overrides
	virtual u_int GetNumberOfHashValues( void ) const	   { return m_xBPItems.size(); }
	virtual const char* GetNameByIndex( int iIndex ) const { return m_xBPItems.get_entry(iIndex)->GetString(); }

	// helper functions
	void InitialiseBPList( const Asura_Hash_ID* puBPTypeList, bool(*pfnIsValid)(const Asura_Blueprint* pxBlueprint,Asura_Hash_ID uBPType), int& iNumItems );

private:
	// data
	List<const Asura_String*> m_xBPItems;
};

// Creates a pair of numerical dialogs which represent the minimum and maximum of a value. Ensures that *pxValueMin <= *pxValueMax
template<typename T>
class Asura_MinMax_Dialog : public Asura_Dialog
{
private:
	typedef Asura_Dialog PARENT;
public:
	Asura_MinMax_Dialog( const char* szName, const Asura_Vector_2& xOffset, T* pxValueMin, T* pxValueMax, const T xMin, const T xMax, const T xDelta, const char* szPrintFormat, Asura_Overlay* pxOverlay, bool* pbModifed = NULL)
	: Asura_Dialog(szName, xOffset)
	, m_pxValueMin(NULL)
	, m_pxValueMax(NULL)
	, m_bMinModified(false)
	, m_bMaxModified(false)
	, m_pbModified(NULL)
	{
		const Asura_Vector_2 xMinOffset(m_xMaxCoord.x + 1.f, xOffset.y);
		Asura_Dialog* pxMinDialog = new Asura_Numerical_Dialog("Min", xMinOffset, pxValueMin, xMin, xMax, xDelta, szPrintFormat, &m_bMinModified);
		pxOverlay->AddDialog(pxMinDialog);

		const Asura_Vector_2 xMaxOffset(pxMinDialog->m_xMaxCoord.x + 1.f, xOffset.y);
		Asura_Dialog* pxMaxDialog = new Asura_Numerical_Dialog("Max", xMaxOffset, pxValueMax, xMin, xMax, xDelta, szPrintFormat, &m_bMaxModified);
		pxOverlay->AddDialog(pxMaxDialog);

		m_pxValueMin = pxValueMin;
		m_pxValueMax = pxValueMax;
		m_pbModified = pbModifed;
	}

protected :
	virtual void Update( const Asura_Vector_2& xOrigin )
	{
		PARENT::Update(xOrigin);
		if(m_bMinModified)
		{
			*m_pxValueMin = Asura_Maths::Min(*m_pxValueMin, *m_pxValueMax);
			if(m_pbModified)
			{
				*m_pbModified = true;
			}
			m_bMinModified = false;
		}
		if(m_bMaxModified)
		{
			*m_pxValueMax = Asura_Maths::Max(*m_pxValueMin, *m_pxValueMax);
			if(m_pbModified)
			{
				*m_pbModified = true;
			}
			m_bMaxModified = false;
		}
	}

	T* m_pxValueMin;
	T* m_pxValueMax;
	bool m_bMinModified;
	bool m_bMaxModified;
	bool* m_pbModified;
};
#endif//__ASURA_DIALOG_H__
