//
// Tools_GUIMenu_Root.cpp
//
// Created by Richard Rice - 30/11/2006
// 
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header
#include "GUIMenu/Tools_GUIMenu_Root.h"

#ifdef ASURA_USE_GUI_MENU_SYSTEM
// Asura
#include "Core/Asura_HashTree.h"
#include "Core/Asura_Timers.h"
#include "Core/Asura_UserInput.h"
#include "GUIMenu/Asura_GUIMenu_Animator.h"
#include "GUIMenu/Asura_GUIMenu_Menu_Page.h"
#include "GUIMenu/Asura_GUIMenu_Modifier.h"
#include "GUIMenu/Asura_GUIMenu_Root.h"
#include "GUIMenu/Asura_GUIMenu_System.h"
#include "Interface/Asura_CommandConsole.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Overlay_System.h"
#include "Rendering/Asura_Render.h"

// Tools
#include "Tools_Overlays.h"
#include "GUIMenu/Tools_GUIMenu_AnimEdit.h"
#include "GUIMenu/Tools_Mode_GUIMenu.h"
#include "GUIMenu/Tools_GUIMenu_PreviewOverlay.h"
#include "GUIMenu/Tools_GUIMenu_System.h"
#include "Interface/Tools_ColourPicker.h"
#include "Load&Save/LevelExport/Tools_Level_Export.h"
#include "Misc/Tools_Modal_Overlay.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Misc/Tools_MessageLog.h"

#include "PC/Core/Asura_Windows.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct MenuFlagNameAndValue
{
	const char* m_szName;
	const char* m_szHelpText;
	u_int m_uValue;
};

static MenuFlagNameAndValue g_axFlags[] =
{
	{"Visible in default state", "The menu item is visible if any of these visibility conditions are met.",ASURA_GUIMENU_ACTION_FLAG_IS_DEFAULT},
	{"Visible when disabled", "The menu item is visible if any of these visibility conditions are met.", ASURA_GUIMENU_ACTION_FLAG_IS_DISABLED},
	{"Visible when clicked", "The menu item is visible if any of these visibility conditions are met.", ASURA_GUIMENU_ACTION_FLAG_IS_CLICKED},
	{"Visible on roll on", "The menu item is visible if any of these visibility conditions are met.", ASURA_GUIMENU_ACTION_FLAG_IS_ROLL_ON},
	{"Visible on roll off", "The menu item is visible if any of these visibility conditions are met.", ASURA_GUIMENU_ACTION_FLAG_IS_ROLL_OFF},
	{"Visible when hilighted", "The menu item is visible if any of these visibility conditions are met.", ASURA_GUIMENU_ACTION_FLAG_IS_HILIGHTED},
	{"Visible on Edit Mode", "The menu item is visible if any of these visibility conditions are met.", ASURA_GUIMENU_ACTION_FLAG_IS_EDITING},
	{"Notify changes on exit", "Any changes to the data are applied when exiting the menu", ASURA_GUIMENU_ACTION_FLAG_NOTIFY_DATA_CHANGE_ON_EXIT},
	{"Notify changes immediately", "Any changes to the data are applied immediately.",ASURA_GUIMENU_ACTION_FLAG_NOTIFY_DATA_CHANGE_IMMEDIATE},
};

static const u_int g_uNumMenuFlags = sizeof(g_axFlags) / sizeof(MenuFlagNameAndValue);

static MenuFlagNameAndValue g_axStates[] =
{
	{"In default state", 0,ASURA_GUIMENU_ACTION_FLAG_IS_DEFAULT},
	{"When disabled", 0, ASURA_GUIMENU_ACTION_FLAG_IS_DISABLED},
	{"When clicked", 0, ASURA_GUIMENU_ACTION_FLAG_IS_CLICKED},
	{"On roll on", 0, ASURA_GUIMENU_ACTION_FLAG_IS_ROLL_ON},
	{"On roll off", 0, ASURA_GUIMENU_ACTION_FLAG_IS_ROLL_OFF},
	{"When hilighted", 0, ASURA_GUIMENU_ACTION_FLAG_IS_HILIGHTED},
	{"On edit mode", 0, ASURA_GUIMENU_ACTION_FLAG_IS_EDITING},

	{"On menu fade in", 0, ASURA_GUIMENU_ACTION_FLAG_IS_MENU_FADE_IN},
	{"On menu fade out", 0, ASURA_GUIMENU_ACTION_FLAG_IS_MENU_FADE_OUT},
	{"On menu fade active", 0, ASURA_GUIMENU_ACTION_FLAG_IS_MENU_ACTIVE},
};

static const u_int g_uNumModifierStates = sizeof(g_axStates) / sizeof(MenuFlagNameAndValue);

struct TranslucencyNameAndValue
{
	const char* m_szName;
	ASURA_TRANSLUCENCY_MODE m_eMode;
};

static TranslucencyNameAndValue g_axTranslucencyModes[] =
{
	{"Off", ASURA_TRANSLUCENCY_OFF},
	{"Normal Blend", ASURA_TRANSLUCENCY_NORMAL},
	{"Inverse Colour Blend", ASURA_TRANSLUCENCY_INVCOLOUR},
	{"Colour Blend", ASURA_TRANSLUCENCY_COLOUR},
	{"Double Colour Blend", ASURA_TRANSLUCENCY_DOUBLECOLOUR},
	{"Glowing Blend", ASURA_TRANSLUCENCY_GLOWING},
	{"Darken Colour Blend", ASURA_TRANSLUCENCY_DARKENINGCOLOUR},
//	{"Additive Blend", ASURA_TRANSLUCENCY_ADD}	// SK 21.11.07 - removed because it's not supported.
};

static const Asura_Char* g_apcTranslucencyNames[] = 
{
	g_axTranslucencyModes[0].m_szName,
	g_axTranslucencyModes[1].m_szName,
	g_axTranslucencyModes[2].m_szName,
	g_axTranslucencyModes[3].m_szName,
	g_axTranslucencyModes[4].m_szName,
	g_axTranslucencyModes[5].m_szName,
	g_axTranslucencyModes[6].m_szName,
//	g_axTranslucencyModes[7].m_szName
};

static const u_int g_uNumTranslucencyModes = sizeof(g_axTranslucencyModes) / sizeof(TranslucencyNameAndValue);

struct DisplayConditionNameAndValue
{
	const char* m_szName;
	Asura_GUIMenu_Display_Condition m_eMode;
};

static DisplayConditionNameAndValue g_axDisplayCondModes[] =
{
	{" None ", ASURA_GUIMENU_CONDITION_NONE},
	{"  =   ", ASURA_GUIMENU_CONDITION_EQUAL},
	{"  >   ", ASURA_GUIMENU_CONDITION_GREATER},
	{"  >=  ", ASURA_GUIMENU_CONDITION_GREATER_EQUAL},
	{"  <   ", ASURA_GUIMENU_CONDITION_LESS},
	{"  <=  ", ASURA_GUIMENU_CONDITION_LESS_EQUAL},
	{"  !=  ", ASURA_GUIMENU_CONDITION_NOT_EQUAL}
};

static const Asura_Char* g_apcDisplayCondNames[] = 
{
	g_axDisplayCondModes[0].m_szName,
	g_axDisplayCondModes[1].m_szName,
	g_axDisplayCondModes[2].m_szName,
	g_axDisplayCondModes[3].m_szName,
	g_axDisplayCondModes[4].m_szName,
	g_axDisplayCondModes[5].m_szName,
	g_axDisplayCondModes[6].m_szName
};

static const u_int g_uNumDisplayCondModes = sizeof(g_axDisplayCondModes) / sizeof(DisplayConditionNameAndValue);

static const char* g_aszLogicOperators[ASURA_GUIMENU_LOGIC_NUMTYPES] = 
{
	"And",
	"Or",
	"Xor",
};

static const u_int uTOOLS_GUIMENU_MAX_COMMENT_STRING_LENGTH = 256;

static const char* const g_aszHorzPosModeNames[Asura_GUIMenu_Root::NUM_POS_MODES] = 
{
	"Left - Absolute (default)",
	"Centre - Absolute",
	"Right - Absolute",
	"Width - Proportional",
	"Height - Proportional (alt)",
};

static const char* const g_aszVertPosModeNames[Asura_GUIMenu_Root::NUM_POS_MODES] = 
{
	"Top - Absolute (default)",
	"Centre - Absolute",
	"Bottom - Absolute",
	"Height - Proportional",
	"Width - Proportional (alt)",
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*----------------------------------**
** Tools_GUIMenu_PickItem_AddToGroup **
**-----------------------------------*/

class Tools_GUIMenu_PickItem_AddToGroup : public Tools_GUIMenu_PickItem
{
public :
	Tools_GUIMenu_PickItem_AddToGroup(Tools_GUIMenu_Root* pxItemToAdd)
	{
		m_pxItemToAdd = pxItemToAdd;
	}

	virtual const char* GetPrompt(){return "Select group widget";}

	virtual bool IsValidSelection(Tools_GUIMenu_Root* pxItem)
	{
		if(pxItem)
		{
			if(pxItem == m_pxItemToAdd) return false;
			return pxItem->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_GROUP;
		}
		return false;
	}

	virtual void OnFinish(Tools_GUIMenu_Root* pxItem)
	{
		if(pxItem)
		{
			m_pxItemToAdd->AddToGroup(pxItem);
		}
	}

private :
	Tools_GUIMenu_Root* m_pxItemToAdd;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------**
** Tools_GUIMenu_Root **
**--------------------*/
List<Tools_GUIMenu_Root*> Tools_GUIMenu_Root::s_xList;
Asura_TemplateHashTree<Tools_GUIMenu_Root*> Tools_GUIMenu_Root::s_xHashTree;

Asura_Vector_2 Tools_GUIMenu_Root::s_xOverlayPosition(15.0f,3.0f);
u_int Tools_GUIMenu_Root::s_uOverlayMinimised = 0;
bool Tools_GUIMenu_Root::s_bIsRenaming;

Asura_List_Dialog* Tools_GUIMenu_Root::s_pxModifierListDialog;
Asura_Tabs_Dialog* Tools_GUIMenu_Root::s_pxTabsDialog = 0;
Asura_Subwindow_Dialog* Tools_GUIMenu_Root::s_pxDispCondSubwindowDialog = 0;
Asura_Vector_2 Tools_GUIMenu_Root::s_xModifierDialogOffset(0.0f,0.0f);
Asura_Vector_2 Tools_GUIMenu_Root::s_xAnimatorDialogOffset(0.0f,0.0f);
List<Asura_Dialog*> Tools_GUIMenu_Root::s_xModifierDialogList;
List<Asura_Dialog*> Tools_GUIMenu_Root::s_xAnimatorDialogList;
int Tools_GUIMenu_Root::s_iStyleTab = -1;
int Tools_GUIMenu_Root::s_iModifierTab = -1;
int Tools_GUIMenu_Root::s_iAnimatorTab = -1;
int Tools_GUIMenu_Root::s_iDisplayConditionTab = -1;
int Tools_GUIMenu_Root::s_iPlatformTab = -1;

Asura_List_Dialog* Tools_GUIMenu_Root::s_pxAnimatorListDialog;

Tools_GUIMenu_Root* Tools_GUIMenu_Root::s_pxCurrentSelectedRoot(NULL);


Tools_GUIMenu_Root::Tools_GUIMenu_Root(Asura_GUIMenu_Root* pxRoot,Tools_GUIMenu_Root* pxToolsParent,const char* szName)
: m_iModifierListSize(0)
, m_iModifierIndex(0)
, m_bModifierIndexChanged(false)
, m_pszModifierStrings(0)
, m_uModifierStates(0)
, m_bModifierChanged(0)
, m_xModifierData_Colour(0,0)
, m_xModifierData_Vector2(0.0f, 0.0f)
, m_iModifierData(0)
, m_uModifierData(0)
, m_fModifierData(0)
, m_iAnimatorListSize(0)
, m_iAnimatorIndex(0)
, m_bAnimatorIndexChanged(false)
, m_bAnimatorConditionChanged(false)
, m_pszAnimatorStrings(0)
, m_fAnimatorSpeed(0.0f)
, m_fAnimatorDelay(0.0f)
, m_bAnimatorChanged(0)
, m_bAnimatorShouldStartActive(true)
, m_bAnimatorInitialiseToEnd(false)
, m_xTabsStart(0.0f,0.0f)
, m_xTabsEnd(0.0f,0.0f)
, m_bSelected(false)
, m_bHidden(false)
, m_xPixelOrigin(0.0f, 0.0f)
, m_bPosOriginChanged(false)
, m_bScaleFlagChanged(false)
, m_iCompVal1(0)
, m_iCompCond1(0)

, m_iCompVal2(0)
, m_iCompCond2(0)

, m_bInHashTree(false)
, m_uID(0)
, m_pxTreeItem(0)
, m_bOverlayCreated(false)
{
	s_xList.add_entry(this);

	m_pxAsuraRoot = pxRoot;
	m_pxToolsParent = pxToolsParent;

	if(pxRoot)
	{
		Asura_Assert(!szName,"");
		m_xName = pxRoot->GetNameAsChar();
		m_uID = m_pxAsuraRoot->GetID();
		AddToHashTree();

	}
	else
	{
		Asura_Assert(szName,"");
		m_xName = szName;
	}

	//add to the parent's list
	if(m_pxToolsParent)
	{
		m_pxToolsParent->m_xChildren.add_entry(this);
	}

	//add to tree view
	Tools_Mode_GUIMenu::GetInstance()->AddToTree(this);

	if(m_pxAsuraRoot)
	{
		m_uFlags = m_pxAsuraRoot->GetFlags();
		m_xColour = m_pxAsuraRoot->GetColour();
		m_uToolsFlags = m_pxAsuraRoot->GetToolsFlags();
		m_uStyleChildEditableDataFlags = m_pxAsuraRoot->GetStyleChildEditableDataFlags();
	}
	else
	{
		m_uFlags = 0;
		m_xColour = 0xFFFFFFFF;
		m_uToolsFlags = 0;
		m_uStyleChildEditableDataFlags = 0;
	}

	m_bChanged = false;
	m_bPosOptionsChanged = false;
	m_bIsStyleChanged = false;
	m_bStyleContainerChanged = false;
	m_bDisplayConditionChanged = false;
	m_bModifierConditionChanged = false;
	m_bBeingDestroyed = false;
	m_bIsClampedChanged = false;

	if(m_pxAsuraRoot)
	{
		m_pxAsuraRoot->SetScaledWorldBounds(m_pxAsuraRoot->GetScaledWorldBounds());
	}
	
	m_fX = m_fY = m_fW = m_fH = 0.0f;

	m_bMoved = false;
	m_bResized = false;

	m_bTranslucencyChanged = false;
	m_iTranslucencyMode = 0;

	m_bCompValChanged = false;
}

void Tools_GUIMenu_Root::InitialiseNewItem()
{
	//Setup the initial rectangle
	float fWidth,fHeight;
	GetInitialSize(fWidth,fHeight);
	Asura_Vector_2 xPos = m_pxAsuraRoot->GetUnscaledLocalPos();
	if (xPos.x < 0.0f)
	{
		xPos.x = 0.0f;
	}
	if (xPos.y < 0.0f)
	{
		xPos.y = 0.0f;
	}
	if (m_pxAsuraRoot->GetParentObject() && ClampToParent())
	{
		Asura_Vector_2 xParentDims(m_pxAsuraRoot->GetParentObject()->GetUnscaledLocalBounds().GetDimension());
		if (fWidth > xParentDims.x)
		{
			fWidth = xParentDims.x;
		}
		if (fHeight > xParentDims.y)
		{
			fHeight = xParentDims.y;
		}
		if (xPos.x + fWidth > xParentDims.x)
		{
			xPos.x = xParentDims.x - fWidth;
		}
		if (xPos.y + fHeight > xParentDims.y)
		{
			xPos.y = xParentDims.y - fHeight;
		}
	}

	Asura_Bounding_Rectangle xRect;
	xRect.MinX = xPos.x;
	xRect.MinY = xPos.y;
	xRect.MaxX = xPos.x + fWidth;
	xRect.MaxY = xPos.y + fHeight;

	if (m_pxAsuraRoot->GetParentObject() && m_pxAsuraRoot->GetParentObject()->GetScaledWorldBounds().GetDimension().MagnitudeSquared() > 0.0f)
	{
		xRect.Displace(m_pxAsuraRoot->GetParentObject()->GetScaledWorldPos() + m_pxAsuraRoot->GetParentObject()->GetChildPosOffset());
		SetRectangle(xRect);
	}
	else
	{
		m_pxAsuraRoot->SetUnscaledLocalBounds(xRect);
	}

	// Setup the creation comment.
	AddCreationComment();


	m_iCompCond1 = 0;
	m_iCompCond2 = 0;

	// set export resources flag by default 
	m_uToolsFlags |= ASURA_GUIMENU_TOOLS_FLAG_EXPORTRESOURCES;
	m_pxAsuraRoot->SetToolsFlags(m_uToolsFlags);
}	


Tools_GUIMenu_Root::~Tools_GUIMenu_Root()
{
	Asura_Assert(!m_bSelected,"Menu item should have been deselected before being deleted");

	//delete any children
	while(m_xChildren.size()) delete m_xChildren.first_entry();

	//remove from tree view
	Tools_Mode_GUIMenu::GetInstance()->HandleItemDeletion(this);

	//remove from the parent's list
	if(m_pxToolsParent)
	{
		m_pxToolsParent->RemoveChild(this);
	}

	DeleteModifierList();
	DeleteAnimatorList();

	RemoveFromHashTree();
	s_xList.delete_entry(this);
}

void Tools_GUIMenu_Root::Destroy()
{
	m_bBeingDestroyed = true;
	SetModified();

	if(m_pxAsuraRoot )
	{	
		//Attempt to fix endless recursion caused by deleting menu items that have their own ID as the style ID.
		//This is being caused by the way the list box menu item IDs are being generated , and will
		//need a proper fix elsewhere , once I can work out what to do with it.
		//RAR 06/09/2007
		if( m_pxAsuraRoot->GetStyleObjectHash() == m_pxAsuraRoot->GetID() ) 
		{
			m_pxAsuraRoot->SetStyleObjectHash(0);
		}

		//Remove any references to this item
		Tools_Mode_GUIMenu::RemoveReferencesToMenuItem(m_pxAsuraRoot->GetID());
	}
	
	//Make sure the fast lookup system in the asura system doesn't refer to this.
	//Just going to clear the lot to be safe
	//RAR 24/07/2007
	Asura_GUIMenu_System::ResetFastWidgetLookUpTree();
	

	//destroy the children as well
	while(m_xChildren.size())
	{
		m_xChildren.first_entry()->Destroy();
	}

	//Tools_GUIMenu_Root* pxToolsParent = m_pxToolsParent;

	//remove from the asura parent
	if(m_pxAsuraRoot)
	{
		if(m_pxAsuraRoot->GetParentObject())
		{
			m_pxAsuraRoot->GetParentObject()->RemoveFromThisContainer(m_pxAsuraRoot);
		}

		//delete the asura data
		if(IsMenu())
		{
			Asura_GUIMenu_System::DestroyMenuPage( static_cast<Asura_GUIMenu_Menu_Page*>(m_pxAsuraRoot), true);
		}
		else
		{
			delete m_pxAsuraRoot;
		}
	}

	//and the tools data
	delete this;

}

void Tools_GUIMenu_Root::AddToHashTree()
{
	if(IsFakeMenuItem()) return;
	if(m_bInHashTree)
	{
		Asura_Assert(0,"Already added to hash tree");
	}

	Asura_Assert( m_pxAsuraRoot,"Asura Root should not be NULL" );

	if( m_pxAsuraRoot )
	{
		m_uID = m_pxAsuraRoot->GetID();
	}

	#if 1
    //Don't bother adding anything that doesn't have a menu page as a parent,grandparent etc.
	//This avoids issues caused by list box entries not having unique IDs.
	//(Which could well be a problem anyway , but thats a fix for another day).
	//RAR 18/05/2007
	#if 0
	const Asura_GUIMenu_Root* pxRoot = m_pxAsuraRoot;
	while(pxRoot->GetParentObject()) pxRoot = pxRoot->GetParentObject();
	if(pxRoot->GetType() != Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE)
	{
		return;
	}
	#endif

	if(s_xHashTree.AddNode(m_uID,this))
	{
		m_bInHashTree = true;
	}
	else
	{
		Tools_GUIMenu_Root** ppxExisting = s_xHashTree.GetDataByHash(m_uID);
		Asura_Assert(ppxExisting,"");

		Asura_Assertf(0,("ID of GUIMenu item %s matches that of %s.\nThis is likely to be unhealthy.",GetName(),(*ppxExisting)->GetName()));

	}
	#endif
}

void Tools_GUIMenu_Root::RemoveFromHashTree()
{
	if(!m_bInHashTree) return;

	bool bOkay = s_xHashTree.DeleteNodeByHash(m_uID);
	Asura_Assert(bOkay,"Failed to remove tools guimenu item from hash tree");
	m_bInHashTree = false;
}


Tools_GUIMenu_Root* Tools_GUIMenu_Root::GetItemFromPosition(const Asura_Vector_2& xPos,Tools_GUIMenu_PickItem* pxPickItem /*= 0*/, bool bPreferWidget /*=true*/)
{
	Tools_GUIMenu_Root* pxFoundChild = 0;
	
	//Search backwards so the topmost item is preferred
	for(LIB<Tools_GUIMenu_Root*> m_xChildLIB(&m_xChildren);!m_xChildLIB.done();m_xChildLIB.next())
	{
		Tools_GUIMenu_Root* pxItem = m_xChildLIB()->GetItemFromPosition(xPos,pxPickItem,bPreferWidget);

		if(pxItem)
		{
			
			//Found an item at this position.
			//Go with it if its a widget , or if we don't care about whether its a widget.
			if(!bPreferWidget) return pxItem;
			if(pxItem->IsWidget()) return pxItem;

			//Otherwise take note of it , if this is the first one found.
			if(!pxFoundChild) pxFoundChild = pxItem;
		}
	}



	//check this item
	if(pxPickItem)
	{
		if(!pxPickItem->IsValidSelection(this))
		{
			//This isn't selectable ,so go with whatever child was found
			return pxFoundChild;
		}
	}

	if(!Tools_Mode_GUIMenu::ShouldAllowMouseSelectionOfHiddenItems() && IsHidden() && !IsSelected())
	{
		//This is hidden , and we aren't allowing selection of hidden items
		return pxFoundChild;
	}

	

	Asura_Bounding_Rectangle xRect = GetRectangle();
	bool bCursorInThis = xRect.Contains(xPos) ? true : false;

	if(bCursorInThis)
	{
		//Position is within this item
		//Go with this if a widget or an element loose in the menu.
		if(IsWidget() || (m_pxToolsParent && m_pxToolsParent->IsMenu())) return this;

		//Otherwise prefer a child item if one was found.
		return pxFoundChild ? pxFoundChild : this;
	}

	return pxFoundChild;

}

void Tools_GUIMenu_Root::RenderRecursive()
{
	if(!IsHidden()) Render();

	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->RenderRecursive();
	}
}

void Tools_GUIMenu_Root::RenderOutlineRecursive(u_int uColour) const
{
	RenderOutline(uColour);
	for(CLIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->RenderOutlineRecursive(uColour);
	}
}


void Tools_GUIMenu_Root::RenderOutline(u_int uColour) const
{
	if(!Tools_Mode_GUIMenu::ShouldRenderOutlineForHiddenItems() && IsHidden())
	{
		//This item is hidden and we aren't rendering the outline for hidden items.
		//Render it regardless however if it is selected
		if(!IsSelected())
		{
			return;
		}
	}

	Asura_Bounding_Rectangle xRect = GetScreenRectangle();
	
	//render the bounding rect
	RenderRectangle(xRect,uColour);
	
	if( m_pxAsuraRoot && NeedsPosOptions() && IsSelected())
	{
		Asura_Vector_2 xOrigin(m_pxAsuraRoot->m_xPosOrigin);
		xOrigin.x *= xRect.GetWidth();
		xOrigin.y *= xRect.GetHeight();
		xOrigin += xRect.GetTopLeft();
		float fSize = 4.0f * Asura_Maths::FloatMod(Asura_Timers::GetLocalUnscaledTime(), 1.0f);
		Asura_Bounding_Rectangle xSquare(-fSize, -fSize, fSize, fSize);
		xSquare.Displace(xOrigin);
		RenderRectangle(xSquare,uColour);
		xSquare.Set(-fSize, 0.0f, fSize, 0.0f);
		xSquare.Displace(xOrigin);
		RenderRectangle(xSquare,uColour);
		xSquare.Set(0.0f, -fSize, 0.0f, fSize);
		xSquare.Displace(xOrigin);
		RenderRectangle(xSquare,uColour);
	}
}

void Tools_GUIMenu_Root::RenderEditHandles() const
{
	if(!CanBeResized()) return;

	//get the overall rectangle
	Asura_Bounding_Rectangle xRect = GetScreenRectangle();
	
	const float fSize = 5.0f;
	const u_int uColour = 0xffffffff;

	//draw a square at each corner
	Asura_Bounding_Rectangle xSquare(-fSize,-fSize,0.0f,0.0f);

	//top left
	xSquare.MinX += xRect.MinX;
	xSquare.MaxX += xRect.MinX;
	xSquare.MinY += xRect.MinY;
	xSquare.MaxY += xRect.MinY;
	RenderRectangle(xSquare,uColour);

	//top right
	xSquare.MinX += fSize + xRect.GetWidth();
	xSquare.MaxX += fSize + xRect.GetWidth();
	RenderRectangle(xSquare,uColour);

	//bottom right
	xSquare.MinY += fSize + xRect.GetHeight();
	xSquare.MaxY += fSize + xRect.GetHeight();
	RenderRectangle(xSquare,uColour);

	//bottom left
	xSquare.MinX -= fSize + xRect.GetWidth();
	xSquare.MaxX -= fSize + xRect.GetWidth();
	RenderRectangle(xSquare,uColour);

	//draw a small line at the centre of each edge
	float fMidX = (xRect.MinX + xRect.MaxX)/2.0f;
	float fMidY = (xRect.MinY + xRect.MaxY)/2.0f;

	//top
	Asura_Render::Render2DLine(fMidX,xRect.MinY,fMidX,xRect.MinY-fSize,uColour);
	//bottom
	Asura_Render::Render2DLine(fMidX,xRect.MaxY,fMidX,xRect.MaxY+fSize,uColour);
	//left
	Asura_Render::Render2DLine(xRect.MinX,fMidY,xRect.MinX-fSize,fMidY,uColour);
	//right
	Asura_Render::Render2DLine(xRect.MaxX,fMidY,xRect.MaxX+fSize,fMidY,uColour);

}

Asura_Bounding_Rectangle Tools_GUIMenu_Root::GetRectangle() const
{
	if (m_pxAsuraRoot)
	{
		return m_pxAsuraRoot->GetScaledWorldBounds();
	}
	return Asura_Bounding_Rectangle(0.0f, 0.0f, 0.0f, 0.0f);
}


void Tools_GUIMenu_Root::RenderRectangle(const Asura_Bounding_Rectangle& xRect, u_int uColour) const
{
	Asura_Render::Render2DLine(xRect.MinX,xRect.MinY,xRect.MaxX,xRect.MinY,uColour);
	Asura_Render::Render2DLine(xRect.MaxX,xRect.MinY,xRect.MaxX,xRect.MaxY,uColour);
	Asura_Render::Render2DLine(xRect.MaxX,xRect.MaxY,xRect.MinX,xRect.MaxY,uColour);
	Asura_Render::Render2DLine(xRect.MinX,xRect.MaxY,xRect.MinX,xRect.MinY,uColour);
}


Asura_Bounding_Rectangle Tools_GUIMenu_Root::GetScreenRectangle() const
{
	return Tools_Mode_GUIMenu::GetInstance()->ConvertFromMenuCoords(GetRectangle());
}

void Tools_GUIMenu_Root::StorePreDragState()
{
	if (m_pxAsuraRoot)
	{
		m_xPreDragRect = m_pxAsuraRoot->GetUnscaledLocalBounds();
	}
	else
	{
		m_xPreDragRect.Set(0.0f, 0.0f, 0.0f, 0.0f);
	}
}

void Tools_GUIMenu_Root::GetPreDragState(Asura_Bounding_Rectangle& xRect)
{
	xRect = m_xPreDragRect;
	if (m_pxToolsParent)
	{
		xRect.Displace(m_pxToolsParent->GetRectangle().GetTopLeft());
	}
}

u_int Tools_GUIMenu_Root::GetExtentsToDrag(const Asura_Vector_2& xPos) const
{

	float fZoom = Tools_Mode_GUIMenu::GetInstance()->GetZoom();


	if(CanBeMoved())
	{
		//if in a slightly reduced rectangle , then we are moving this
		Asura_Bounding_Rectangle xRect = GetRectangle();
		xRect.MinX += 2.0f/fZoom;
		xRect.MaxX -= 2.0f/fZoom;
		xRect.MinY += 2.0f/fZoom;
		xRect.MaxY -= 2.0f/fZoom;
		

		if(xRect.Contains(xPos))
		{
			return TOOLS_MENUS_DRAG_MOVE;
		}
	}

	if(CanBeResized())
	{
		//check distance from each edge
		Asura_Bounding_Rectangle xRect = GetRectangle();
		xRect.Displace(xPos*-1.0f);

		const float fTol = 5.0f / fZoom;

		u_int uFlags = 0;
		if(CanEditWidth())
		{
			if(Asura_Maths::Abs(xRect.MaxX) <= fTol) uFlags |= TOOLS_MENUS_DRAG_MAXX;
			else if(Asura_Maths::Abs(xRect.MinX) <= fTol) uFlags |= TOOLS_MENUS_DRAG_MINX;
		}
		if(CanEditHeight())
		{
			if(Asura_Maths::Abs(xRect.MaxY) <= fTol) uFlags |= TOOLS_MENUS_DRAG_MAXY;
			else if(Asura_Maths::Abs(xRect.MinY) <= fTol) uFlags |= TOOLS_MENUS_DRAG_MINY;
		}

		return uFlags;

	}

	return 0;
}

void Tools_GUIMenu_Root::UpdateDrag(const Asura_Vector_2& xOffset,u_int uDragFlags)
{
	
	//determine the new rectangle
	Asura_Bounding_Rectangle xPreDragRect;
	GetPreDragState(xPreDragRect);
	Asura_Bounding_Rectangle xRect = xPreDragRect;

	if(uDragFlags & TOOLS_MENUS_DRAG_MOVE)
	{
		//get the new top left position.
		if(xOffset.x)
		{
			xRect.MinX += xOffset.x;
			xRect.MaxX += xOffset.x;

			//Try snapping both min and max
			float fSnappedMin,fSnappedMax;
			float fScoreMin,fScoreMax;
			fSnappedMin = GetSnapValue(xRect.MinX,true,&fScoreMin);
			fSnappedMax = GetSnapValue(xRect.MaxX,true,&fScoreMax);

			//snap the extent that gave the best score
			if(fScoreMin > fScoreMax)
			{
				xRect.MinX = fSnappedMin;
				xRect.MaxX = xPreDragRect.MaxX + (xRect.MinX - xPreDragRect.MinX);
			}
			else
			{
				xRect.MaxX = fSnappedMax;
				xRect.MinX = xPreDragRect.MinX + (xRect.MaxX - xPreDragRect.MaxX);
			}
		}

		if(xOffset.y)
		{
			xRect.MinY += xOffset.y;
			xRect.MaxY += xOffset.y;

			//Try snapping both min and max
			float fSnappedMin,fSnappedMax;
			float fScoreMin,fScoreMax;
			fSnappedMin = GetSnapValue(xRect.MinY,false,&fScoreMin);
			fSnappedMax = GetSnapValue(xRect.MaxY,false,&fScoreMax);

			//snap the extent that gave the best score
			if(fScoreMin > fScoreMax)
			{
				xRect.MinY = fSnappedMin;
				xRect.MaxY = xPreDragRect.MaxY + (xRect.MinY - xPreDragRect.MinY);
			}
			else
			{
				xRect.MaxY = fSnappedMax;
				xRect.MinY = xPreDragRect.MinY + (xRect.MaxY - xPreDragRect.MaxY);
			}

		}

	

	}
	else
	{
		if(xOffset.x)
		{
			if(uDragFlags & TOOLS_MENUS_DRAG_MINX)
			{
				xRect.MinX += xOffset.x;
				xRect.MinX = GetSnapValue(xRect.MinX,true);

			}
			else if(uDragFlags & TOOLS_MENUS_DRAG_MAXX)
			{
				xRect.MaxX += xOffset.x;
				xRect.MaxX = GetSnapValue(xRect.MaxX,true);
			}
		}
		if(xOffset.y)
		{
			if(uDragFlags & TOOLS_MENUS_DRAG_MINY)
			{
				xRect.MinY += xOffset.y;
				xRect.MinY = GetSnapValue(xRect.MinY,false);

			}
			else if(uDragFlags & TOOLS_MENUS_DRAG_MAXY)
			{
				xRect.MaxY += xOffset.y;
				xRect.MaxY = GetSnapValue(xRect.MaxY,false);

			}
		}
	}

	// prevent -ve rect from being applied to menu object
	if( xRect.MaxX < xRect.MinX )
	{
		xRect.MinX = GetRectangle().MinX;
		xRect.MaxX = GetRectangle().MaxX;
	}

	if( xRect.MaxY < xRect.MinY )
	{
		xRect.MinY = GetRectangle().MinY;
		xRect.MaxY = GetRectangle().MaxY;
	}

	MoveOrResizeRect(xPreDragRect, xRect, uDragFlags, true, true);
}


void Tools_GUIMenu_Root::CalculateExtents()
{
	if (m_pxAsuraRoot && m_pxAsuraRoot->GetParentObject())
	{
		m_pxAsuraRoot->GetParentObject()->SetScaledWorldBounds(m_pxAsuraRoot->GetParentObject()->GetScaledWorldBounds());
	}
}

void Tools_GUIMenu_Root::MoveOrResizeRect(const Asura_Bounding_Rectangle& xOldRect, const Asura_Bounding_Rectangle& xNewRect, u_int uDragFlags, bool bClampToParent, bool bUsePreDragRect)
{
	Asura_Bounding_Rectangle xRect(xNewRect);
	float fMinWidth = 1.0f;
	float fMinHeight = 1.0f;
	if( Tools_Mode_GUIMenu::ShouldRepositionChildrenWithinParent())
	{
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
		{
			fMinWidth = Asura_Maths::Max(fMinWidth, xChildLIF()->GetRectangle().GetWidth());
			fMinHeight = Asura_Maths::Max(fMinHeight, xChildLIF()->GetRectangle().GetHeight());
		}
	}
	if (xRect.GetWidth() < fMinWidth)
	{
		if (uDragFlags & TOOLS_MENUS_DRAG_MAXX)
		{
			xRect.MaxX = xRect.MinX + fMinWidth;
		}
		else if (uDragFlags & TOOLS_MENUS_DRAG_MINX)
		{
			xRect.MinX = xRect.MaxX - fMinWidth;
		}
		else
		{
			Asura_Assert(0, "Width reduced to zero without sides changing");
		}
	}
	if (xRect.GetHeight() < fMinHeight)
	{
		if (uDragFlags & TOOLS_MENUS_DRAG_MAXY)
		{
			xRect.MaxY = xRect.MinY + fMinHeight;
		}
		else if (uDragFlags & TOOLS_MENUS_DRAG_MINY)
		{
			xRect.MinY = xRect.MaxY - fMinHeight;
		}
		else
		{
			Asura_Assert(0, "height reduced to zero without ends changing");
		}
	}
	// prevent menu object frombeing moved|resized outside of parent
	if(bClampToParent && ClampToParent())
	{
		ClampToParentRect(xRect, uDragFlags);
	}

	if( Tools_Mode_GUIMenu::ShouldRepositionChildrenWithinParent())
	{
		UpdateRectAndRepositionChildren(xRect, true);
	}
	else
	{
		if (!Tools_Mode_GUIMenu::ShouldResizeChildrenWithParent()
			&& m_xChildren.size() > 0
			&& (uDragFlags & TOOLS_MENUS_DRAG_MOVE) == 0)
		{
			Asura_Bounding_Rectangle xChildren;
			xChildren.SetTopLeft(xRect.GetBottomRight());
			xChildren.SetBottomRight(xRect.GetTopLeft());
			for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
			{
				if ((xChildLIF()->m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_ISUNCLAMPED) == 0)
				{
					xChildren.Set(xChildLIF()->GetRectangle().GetTopLeft());
					xChildren.Set(xChildLIF()->GetRectangle().GetBottomRight());
				}
			}
			if (xChildren.GetTopLeft().x < xRect.MinX)
			{
				uDragFlags |= TOOLS_MENUS_DRAG_MINX;
				xRect.MinX = xChildren.GetTopLeft().x;
			}
			if (xChildren.GetBottomRight().x > xRect.MaxX)
			{
				uDragFlags |= TOOLS_MENUS_DRAG_MAXX;
				xRect.MaxX = xChildren.GetBottomRight().x;
			}
			if (xChildren.GetTopLeft().y < xRect.MinY)
			{
				uDragFlags |= TOOLS_MENUS_DRAG_MINY;
				xRect.MinY = xChildren.GetTopLeft().y;
			}
			if (xChildren.GetBottomRight().y > xRect.MaxY)
			{
				uDragFlags |= TOOLS_MENUS_DRAG_MAXY;
				xRect.MaxY = xChildren.GetBottomRight().y;
			}
		}
		//let derived classes deal with the new rect
		LogUndo_Rectangle(xRect);
		SetRectangle(xRect);

		//update the children as well
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
		{
			xChildLIF()->UpdateAfterParentDrag(xOldRect,xRect,uDragFlags,bUsePreDragRect);
		}
	}

	SetModified();

}


void Tools_GUIMenu_Root::SetRectangle(const Asura_Bounding_Rectangle& xRect)
{
	if( m_pxAsuraRoot)
	{
		if (m_pxAsuraRoot->GetParentObject())
		{
			// Tools Rectangle()  is in world coordinates whilst Asura bounds are in local coordinates (relative to parent)
			Asura_Vector_2 xOffset( m_pxAsuraRoot->GetParentObject()->GetScaledWorldPos() + m_pxAsuraRoot->GetParentObject()->GetChildPosOffset());
			xOffset = xOffset * -1.0f;

			Asura_Bounding_Rectangle xLocalRect( xRect );
		
			xLocalRect.Displace( xOffset );

			m_pxAsuraRoot->SetUnscaledLocalBounds( xLocalRect );
			m_pxAsuraRoot->GetParentObject()->SetScaledWorldBounds(m_pxAsuraRoot->GetParentObject()->GetScaledWorldBounds());
		}
		else
		{
			m_pxAsuraRoot->SetUnscaledLocalBounds( xRect );
		}
	}
}


void Tools_GUIMenu_Root::UpdateRectAndRepositionChildren(const Asura_Bounding_Rectangle& xRectangleArg, bool bUsePreDragRect)
{
	Asura_Bounding_Rectangle xNewRect( xRectangleArg );

	struct Tools_GUIMenu_ResizeData
	{
		Tools_GUIMenu_Root* m_pxItem;

		Asura_Bounding_Rectangle m_xOldRect;
		Asura_Bounding_Rectangle m_xNewRect;

		Asura_Vector_2 m_xBestOffset;
		float m_fBestScore;

		bool m_bGroupWidget;
	 
	};
	
	Asura_Bounding_Rectangle xOldRect = GetRectangle();
	if (bUsePreDragRect)
	{
		GetPreDragState(xOldRect);
	}

	if(!m_xChildren.size())
	{
		LogUndo_Rectangle(xNewRect);
		SetRectangle(xNewRect);
		return;
	}

	// if this object contains any child items that are larger than xNewRect in x|y then 
	// prevent resize in x|y direction - NDB 210508
	for( LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next() )
	{
		if (xChildLIF()->ClampToParent())
		{
			if( xChildLIF()->GetRectangle().GetWidth() > xNewRect.GetWidth() )
			{
				xNewRect.MinX = xOldRect.MinX;
				xNewRect.MaxX = xOldRect.MaxX;
			}

			if( xChildLIF()->GetRectangle().GetHeight() > xNewRect.GetHeight() )
			{
				xNewRect.MinY = xOldRect.MinY;
				xNewRect.MaxY = xOldRect.MaxY;
			}
		}
	}
	
	//Get a list of items to move.
	List<Tools_GUIMenu_Root*> xItemList = m_xChildren;

	const int iNumItem = xItemList.size();
	if(!iNumItem)
	{
		LogUndo_Rectangle(xNewRect);
		SetRectangle(xNewRect);
		return;
	}

	const float fCornerWeight = Tools_Mode_GUIMenu::GetRespositionChildrenCornerWeighting();
	const float fCentreWeight = Tools_Mode_GUIMenu::GetRespositionChildrenCentreWeighting();
	const float fStickTogetherWeight = Tools_Mode_GUIMenu::GetRespositionChildrenStickTogetherWeighting();



	
	Tools_GUIMenu_ResizeData* pxResizeData = new Tools_GUIMenu_ResizeData[iNumItem];

	//build working data for each child
	for(int i=0; i<iNumItem; i++)
	{
		Tools_GUIMenu_Root* pxItem = xItemList[i];
		Tools_GUIMenu_ResizeData* pxData = &pxResizeData[i];

		pxData->m_pxItem = pxItem;
		pxData->m_xOldRect = pxItem->GetRectangle();
		if (bUsePreDragRect)
		{
			pxItem->GetPreDragState(pxData->m_xOldRect);
		}
		pxData->m_xNewRect = pxData->m_xOldRect;
		pxData->m_bGroupWidget = (pxItem->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_GROUP);

		//Determine whether this item should move with the left/middle or right of the parent

		float fLeftDist = Asura_Maths::Abs(pxData->m_xOldRect.MinX-xOldRect.MinX);
		float fCentreDist = Asura_Maths::Abs(pxData->m_xOldRect.CalculateCentre().x - xOldRect.CalculateCentre().x);
		float fRightDist = Asura_Maths::Abs(pxData->m_xOldRect.MaxX-xOldRect.MaxX);

		fLeftDist = fCornerWeight ? fLeftDist/fCornerWeight : Asura_Maths::LargeFloat;
		fCentreDist = fCentreWeight ? fCentreDist/fCentreWeight : Asura_Maths::LargeFloat;
		fRightDist = fCornerWeight ? fRightDist/fCornerWeight : Asura_Maths::LargeFloat;

		pxData->m_fBestScore = 0.0f;
		if(fLeftDist <= fCentreDist && fLeftDist <= fRightDist)
		{
			pxData->m_fBestScore += fLeftDist;
			pxData->m_xBestOffset.x = xNewRect.MinX - xOldRect.MinX;
		}
		else if(fRightDist <= fCentreDist)
		{
			pxData->m_fBestScore += fRightDist;
			pxData->m_xBestOffset.x = xNewRect.MaxX - xOldRect.MaxX;
		}
		else
		{
			pxData->m_fBestScore += fCentreDist;
			pxData->m_xBestOffset.x = xNewRect.CalculateCentre().x - xOldRect.CalculateCentre().x;
		}

		//Similarly for the vertical distance
		float fTopDist = Asura_Maths::Abs(pxData->m_xOldRect.MinY-xOldRect.MinY);
		fCentreDist = Asura_Maths::Abs(pxData->m_xOldRect.CalculateCentre().y - xOldRect.CalculateCentre().y);
		float fBottomDist = Asura_Maths::Abs(pxData->m_xOldRect.MaxY-xOldRect.MaxY);

		fTopDist = fCornerWeight ? fTopDist/fCornerWeight : Asura_Maths::LargeFloat;
		fCentreDist = fCentreWeight ? fCentreDist/fCentreWeight : Asura_Maths::LargeFloat;
		fBottomDist = fCornerWeight ? fBottomDist/fCornerWeight : Asura_Maths::LargeFloat;


		if(fTopDist <= fCentreDist && fTopDist <= fBottomDist)
		{
			pxData->m_fBestScore += fTopDist;
			pxData->m_xBestOffset.y = xNewRect.MinY - xOldRect.MinY;
		}
		else if(fBottomDist <= fCentreDist)
		{
			pxData->m_fBestScore += fBottomDist;
			pxData->m_xBestOffset.y = xNewRect.MaxY - xOldRect.MaxY;
		}
		else
		{
			pxData->m_fBestScore += fCentreDist;
			pxData->m_xBestOffset.y = xNewRect.CalculateCentre().y - xOldRect.CalculateCentre().y;
		}

	}

	for(int iIndex=0; iIndex<iNumItem; iIndex++)
	{
		//search for the next best item to place
		float fBestScore = Asura_Maths::LargeFloat;
		int iBestIndex = iIndex;
		bool bBestIsGroup = true;//favor non-groups over groups

		if(fStickTogetherWeight)
		{
			for(int i=iIndex; i<iNumItem; i++)
			{
				Tools_GUIMenu_ResizeData* pxData = &pxResizeData[i];

				if(iIndex)
				{
					//see if a better can be made by anchoring against the most recently placed item
					Tools_GUIMenu_ResizeData* pxData2 = &pxResizeData[iIndex-1];

					const Asura_Bounding_Rectangle xOldRect1 = pxData->m_xOldRect;
					const Asura_Bounding_Rectangle xOldRect2 = pxData2->m_xOldRect;

					float fXOverlap = Asura_Maths::Min(xOldRect1.MaxX,xOldRect2.MaxX) - Asura_Maths::Max(xOldRect1.MinX,xOldRect2.MinX);
					float fYOverlap = Asura_Maths::Min(xOldRect1.MaxY,xOldRect2.MaxY) - Asura_Maths::Max(xOldRect1.MinY,xOldRect2.MinY);

					float fScore = Asura_Maths::Max(0.0f,-fXOverlap);
					fScore += Asura_Maths::Max(0.0f,-fYOverlap);
					fScore /= fStickTogetherWeight;

					if(fScore < pxData->m_fBestScore)
					{
						//place relative to the previous instead
						pxData->m_xBestOffset.x = pxData2->m_xNewRect.MinX - pxData2->m_xOldRect.MinX;
						pxData->m_xBestOffset.y = pxData2->m_xNewRect.MinY - pxData2->m_xOldRect.MinY;
						pxData->m_fBestScore = fScore;
					}
				}
				
				//is this the best item to place so far?
				if((pxData->m_fBestScore < fBestScore) || (!pxData->m_bGroupWidget && bBestIsGroup))
				{
					fBestScore = pxData->m_fBestScore;
					iBestIndex = i;
					bBestIsGroup = pxData->m_bGroupWidget;
				}
			}
		}
		
		//swap the item found into this slot
		if(iBestIndex != iIndex)
		{
			Tools_GUIMenu_ResizeData xTemp = pxResizeData[iIndex];
			pxResizeData[iIndex] = pxResizeData[iBestIndex];
			pxResizeData[iBestIndex] = xTemp;
		}

		//and apply the offset
		pxResizeData[iIndex].m_xNewRect.Displace(pxResizeData[iIndex].m_xBestOffset);
	}

	

	LogUndo_Rectangle(xNewRect);
	SetRectangle(xNewRect);
	

	//update all the children with the new rects
	for(int i=0;i<iNumItem;i++)
	{
		Tools_GUIMenu_ResizeData* pxData = &pxResizeData[i];

		pxData->m_pxItem->MoveOrResizeRect(GetRectangle(), pxData->m_xNewRect,TOOLS_MENUS_DRAG_MOVE, false, bUsePreDragRect);
	}


	delete [] pxResizeData;
}


float Tools_GUIMenu_Root::GetSnapValue(float fCurrentValue,bool bXAxis,float* pfScore)
{
	bool bSnapAgainstSiblings = Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL);

	const float fMaxSnapDistance = 10.0f;

	float fBestSnap = 0.0f;
	float fBestDist = Asura_Maths::LargeFloat;
	if(bSnapAgainstSiblings)
	{
	   		
		//Check for suitable snap points against sibling items
		for(CLIF<Tools_GUIMenu_Root*> xItemLIF(GetParent()->GetChildList());!xItemLIF.done();xItemLIF.next())
		{
			Tools_GUIMenu_Root* pxItem = xItemLIF();
			if(pxItem == this) continue;

			Asura_Bounding_Rectangle xOtherRect = pxItem->GetRectangle();

			//Test against min then max
			for(int iMin=0;iMin<2;iMin++)
			{
				float fSnap;
				if(iMin)
				{
					//Test against MinX/MinY
					fSnap = bXAxis ? xOtherRect.MinX : xOtherRect.MinY;
				}
				else
				{
					//Test against MaxX/MaxY
					fSnap = bXAxis ? xOtherRect.MaxX : xOtherRect.MaxY;
				}

				float fDist = Asura_Maths::Abs(fSnap-fCurrentValue);
				if(fDist<= fMaxSnapDistance && fDist < fBestDist)
				{
					fBestSnap = fSnap;
					fBestDist = fDist;
				}
			}
		}
		
	}
	if(fBestDist != Asura_Maths::LargeFloat)
	{
		if(pfScore) *pfScore = fMaxSnapDistance - fBestDist;
		
		return fBestSnap;

	}
	else
	{
		//failed to find suitable snap point ,so snap to grid (or nearest integer)
		float fNewValue = bXAxis ? Tools_Mode_GUIMenu::GetInstance()->SnapX(fCurrentValue) : Tools_Mode_GUIMenu::GetInstance()->SnapY(fCurrentValue);
		if(pfScore) *pfScore = -Asura_Maths::Abs(fNewValue-fCurrentValue);

		return fNewValue;
	}

}




void Tools_GUIMenu_Root::ClampToParentRect(Asura_Bounding_Rectangle& xRect, u_int uDragFlags)
{
	//get the extents to clamp to
	Asura_Bounding_Rectangle xClampRect;
	if(GetParent()->IsFakeMenuItem())
	{
		xClampRect.MinX = 0.0f;
		xClampRect.MinY = 0.0f;
		xClampRect.MaxX = Asura_Maths::LargeFloat;
		xClampRect.MaxY = Asura_Maths::LargeFloat;
	}
	else if(GetParent()->GetAsuraData()->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_PATH)
	{
		//If the parent is a path , just clamp to the menu instead.
		xClampRect = GetMenuPage()->GetRectangle();
	}
	else
	{
		xClampRect = GetParent()->GetRectangle();
	}

	if(uDragFlags & TOOLS_MENUS_DRAG_MOVE)
	{
		//if moving ,try to preserve the size
		if(xRect.MinX < xClampRect.MinX)
		{
			xRect.MaxX += xClampRect.MinX - xRect.MinX;
			xRect.MinX = xClampRect.MinX;
		}
		else if(xRect.MaxX > xClampRect.MaxX)
		{
			xRect.MinX += xClampRect.MaxX - xRect.MaxX;
			xRect.MaxX = xClampRect.MaxX;
		}
		if(xRect.MinY < xClampRect.MinY)
		{
			xRect.MaxY += xClampRect.MinY - xRect.MinY;
			xRect.MinY = xClampRect.MinY;
		}
		else if(xRect.MaxY > xClampRect.MaxY)
		{
			xRect.MinY += xClampRect.MaxY - xRect.MaxY;
			xRect.MaxY = xClampRect.MaxY;
		}
	}

	if(xRect.MinX < xClampRect.MinX) xRect.MinX = xClampRect.MinX;
	if(xRect.MaxX < xRect.MinX) xRect.MinX = xRect.MaxX;
	
	if(xRect.MaxX > xClampRect.MaxX) xRect.MaxX = xClampRect.MaxX;
	if(xRect.MaxX < xRect.MinX) xRect.MaxX = xRect.MinX;

	if(xRect.MinY < xClampRect.MinY) xRect.MinY = xClampRect.MinY;
	if(xRect.MaxY < xRect.MinY) xRect.MinY = xRect.MaxY;

	if(xRect.MaxY > xClampRect.MaxY) xRect.MaxY = xClampRect.MaxY;
	if(xRect.MaxY < xRect.MinY) xRect.MaxY = xRect.MinY;
}

void Tools_GUIMenu_Root::ClampToParentRect()
{
	Asura_Bounding_Rectangle xOldRect = GetRectangle();
	Asura_Bounding_Rectangle xNewRect = GetRectangle();
	ClampToParentRect(xNewRect,TOOLS_MENUS_DRAG_MOVE);

	if(xOldRect.MinX != xNewRect.MinX || xOldRect.MaxX != xNewRect.MaxX || xOldRect.MinY != xNewRect.MinY || xOldRect.MaxY != xNewRect.MaxY)
	{
		LogUndo_Rectangle(xNewRect);
		SetRectangle(xNewRect);

		//update the children as well
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
		{
			xChildLIF()->UpdateAfterParentDrag(xOldRect,xNewRect,TOOLS_MENUS_DRAG_MOVE,false);
		}
	}
}

void Tools_GUIMenu_Root::ResizePostChildChanges()
{
	if (!GetAsuraData())
	{
		return;
	}
	if ((m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_AUTOSHRINK) != 0
		&& IsWidget())
	{
		Asura_Bounding_Rectangle xChildren;
		xChildren.SetTopLeft(GetRectangle().GetBottomRight());
		xChildren.SetBottomRight(GetRectangle().GetTopLeft());
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
		{
			xChildren.Set(xChildLIF()->GetRectangle().GetTopLeft());
			xChildren.Set(xChildLIF()->GetRectangle().GetBottomRight());
		}
		if (xChildren.MaxX > xChildren.MinX
			&& xChildren.MaxY > xChildren.MinY)
		{
			if (GetRectangle().GetTopLeft() != xChildren.GetTopLeft())
			{
				for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
				{
					Asura_Bounding_Rectangle xChildBounds = xChildLIF()->GetRectangle();
					xChildBounds.Displace(GetRectangle().GetTopLeft() - xChildren.GetTopLeft());
					xChildLIF()->SetRectangle(xChildBounds);
				}
			}
			SetRectangle(xChildren);
		}
	}
	else if ((m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_GROWONCHILDMOVE) != 0)
	{
		GetAsuraData()->FixupBoundsFromChildren();
	}
}

void Tools_GUIMenu_Root::AddChild(Tools_GUIMenu_Root* pxItem)
{
	m_xChildren.add_entry(pxItem);
}

void Tools_GUIMenu_Root::RemoveChild(Tools_GUIMenu_Root* pxItem)
{
	m_xChildren.delete_entry(pxItem);
	ResizePostChildChanges();
}

bool Tools_GUIMenu_Root::ClampToParent() const
{
	if(!m_pxAsuraRoot) return false;

	if ((m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_ISUNCLAMPED) != 0)
	{
		return false;
	}

	// NY - 03 October 2008 - allow child to leave if parent will autogrow to enclose it
	if (m_pxAsuraRoot->GetParentObject()
		&& (m_pxAsuraRoot->GetParentObject()->GetToolsFlags() & ASURA_GUIMENU_TOOLS_FLAG_GROWONCHILDMOVE) != 0)
	{
		return false;
	}
	return true;
}


void Tools_GUIMenu_Root::OnSelection()
{
	m_bSelected = true;
	CreateOverlay();

	s_pxCurrentSelectedRoot = this;
}

void Tools_GUIMenu_Root::OnDeselection()
{
	s_pxCurrentSelectedRoot = NULL;

	NotifyParentOnDeselection();

	DeleteOverlay();
	m_bSelected = false;

	// -- This performs a check on the display conditions.
	// -- If there is a valid console command specified but there isn't a value to compare against, it will display a warning message
	// -- onscreen and in message logs.
	if( m_pxAsuraRoot )
	{	
		Asura_GUIMenu_ConditionVarManager* pxManager = &m_pxAsuraRoot->m_xDisplayConditions;

		for(u_int i=0;i<pxManager->m_uNumConditionVars;i++)
		{
			Asura_GUIMenu_ConditionVar* pxCondVar = &pxManager->m_pxConditionVars[i];
			if( pxCondVar->IsValueBlank() && ( !pxCondVar->IsVarBlank() || !pxCondVar->IsCmdBlank() ) )
			{
				Tools_Timed_Message_System::AddMessage(0xFFFF0000, "GUIMenu object '%s' is using '%s' but does not have a value to compare against.", m_pxAsuraRoot->GetNameAsChar(), pxCondVar->GetName().GetString());
			}
		}
	}
}

void Tools_GUIMenu_Root::NotifyParentOnDeselection( void)
{
	if( m_pxToolsParent)
	{
		m_pxToolsParent->NotifyParentOnDeselection();
	}
}

void Tools_GUIMenu_Root::CreateOverlay()
{	
	char szText[100];
	Asura_PrintfToBfr(szText,"%s - %s",sizeof(szText),true,GetName(),GetTypeName());
	
	Asura_Overlay* pxOverlay;
	pxOverlay = new Asura_Overlay(szText,false,&s_xOverlayPosition,&s_uOverlayMinimised);
	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f,3.0f);

	s_pxTabsDialog = new Asura_Tabs_Dialog(xOffset, 35);
	pxOverlay->AddDialog(s_pxTabsDialog);
	xOffset.y += 3.0f;
	pxOverlay->SetCurrentParentDialog(s_pxTabsDialog);

	m_xTabsStart = xOffset;
	m_xTabsEnd   = xOffset;

	s_iStyleTab = -1;
	s_iModifierTab = -1;
	s_iAnimatorTab = -1;
	s_iDisplayConditionTab = -1;
	s_iPlatformTab = -1;

	if( !m_pxAsuraRoot || IsFakeMenuItem() )
	{
		s_pxTabsDialog->AddTab("Main");
		xOffset.y = m_xTabsStart.y;

		AddBasicOverlayControls(pxOverlay,xOffset);
		
		//end of position tab
		if(xOffset.y > m_xTabsEnd.y) 
		{
			m_xTabsEnd.y = xOffset.y;
		}
	}
	else
	{
		s_pxTabsDialog->AddTab("Main");
		xOffset.y = m_xTabsStart.y;

		AddOverlayControls(pxOverlay,xOffset);

		// if this is part of a container group, add any extra overlay controls for the parent widget
		if( m_pxToolsParent )
		{
			m_pxToolsParent->AddParentOverlayControls( pxOverlay, xOffset, this );
		}

		//end of main tab
		if(xOffset.y > m_xTabsEnd.y)
		{
			m_xTabsEnd.y = xOffset.y;
		}

		s_pxTabsDialog->AddTab("Position");
		xOffset.y = m_xTabsStart.y;

		AddBasicOverlayControls(pxOverlay,xOffset);
		
		//end of position tab
		if(xOffset.y > m_xTabsEnd.y) 
		{
			m_xTabsEnd.y = xOffset.y;
		}

		Asura_Dialog* pxDialog = 0;
		//platform tab
		s_pxTabsDialog->AddTab("Platform");
		s_iPlatformTab = s_pxTabsDialog->GetSelected();
		xOffset.y = m_xTabsStart.y;

		for(int i=0; i<TOOLS_PLATFORM_NUM_PLATFORMS; i++)
		{
			if(!Tools_Level_Export::IsPlatformSupported((Tools_Level_Export::EXPORT_TYPE)i)) continue;

			pxDialog = new Asura_FlagTickbox_Dialog( Tools_Platform::GetPlatformName(i), xOffset, &m_pxAsuraRoot->m_uPlatforms, 1<<i, &m_bChanged);
			pxDialog->SetHelpText("Enables this menu item for this platform.");
			pxDialog->SetIsEnabledFunction(CanEditPlatforms, (int) this);
			pxOverlay->AddDialog(pxDialog);

			xOffset.y += Asura_Dialog::DefaultSpacing();
		}
		xOffset.y += Asura_Dialog::LargeSpacing() - Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("All", xOffset, SetAllPlatforms, (int) this);
		pxDialog->SetHelpText("Enables this menu item for all platforms.");
		pxDialog->SetIsEnabledFunction(CanEditPlatforms, (int) this);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("None", xOffset, ClearAllPlatforms, (int) this);
		pxDialog->SetHelpText("Disables this menu item for all platforms.");
		pxDialog->SetIsEnabledFunction(CanEditPlatforms, (int) this);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();


		//end of platform tab
		if(xOffset.y > m_xTabsEnd.y)
		{
			m_xTabsEnd.y = xOffset.y;
		}

		// CW - Add any extra tabs if required
		xOffset.y = m_xTabsStart.y;
		AddExtraOverlayControls(pxOverlay, s_pxTabsDialog, xOffset);
		if(xOffset.y > m_xTabsEnd.y) { m_xTabsEnd.y = xOffset.y; }
		//end of extra tabs
		
		//Create a style editing tab
		s_pxTabsDialog->AddTab("Style");
		s_iStyleTab = s_pxTabsDialog->GetSelected();
		xOffset.y = m_xTabsStart.y;

		pxDialog = new Asura_Function_Dialog("Goto Master Copy",xOffset,SelectStyleMaster,(int)this);
		pxDialog->SetHelpText("Selects the master copy of this item from the style.");
		pxDialog->SetIsEnabledFunction(CanSelectStyleMaster,(int)this);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Dialog("Style",xOffset);
		pxDialog->SetHelpText("Indicates if this menu item is the root of an instance of a style.");
		pxDialog->m_iControlID = Asura_GetHashID("UsesStyle");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Dialog("Gen By Style",xOffset);
		pxDialog->SetHelpText("Indicates whether this menu item is an automatically generated child of a style instance.");
		pxDialog->m_iControlID = Asura_GetHashID("GenByStyle");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Dialog("Inherited",xOffset);
		pxDialog->SetHelpText("Indicates whether this item inherits properties from another. Mostly for debugging purposes.");
		pxDialog->m_iControlID = Asura_GetHashID("Inherited");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Remove Style",xOffset,RemoveStyle,(int)this);
		pxDialog->SetHelpText("This will unflag this item as using the current style.");
		pxDialog->SetIsEnabledFunction(CanRemoveStyle,(int)this);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();

		if(IsMenu())
		{
			pxDialog = new Asura_FlagTickbox_Dialog("Style Container",xOffset,&m_uToolsFlags,ASURA_GUIMENU_TOOLS_FLAG_STYLECONTAINER,&m_bStyleContainerChanged);
			pxDialog->SetHelpText("Marks this menu as being a container for styles.\nOnly members of such menus can have the 'Is Style' flag set.\nStyle containers aren't considered to be 'proper' menus , and so won't be included in exports.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
		}
	
		pxDialog = new Asura_FlagTickbox_Dialog("Is Style",xOffset,&m_uToolsFlags,ASURA_GUIMENU_TOOLS_FLAG_ISSTYLE,&m_bIsStyleChanged);
		pxDialog->SetHelpText("Marks this menu item as a 'style'.\nInstances of style items can be placed via the style placement overlay , and any changes to the style item will affect the instances.");
		pxDialog->SetIsEnabledFunction(CanBeStyle,(int)this);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();

		pxDialog = new Asura_Dialog("Editable properties in instances:",xOffset);
		pxDialog->SetHelpText("The properties that can be edited in instances of this style.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		//add all the local data flags
		for(u_int i=0;i<32;i++)
		{
			u_int uVal = 1<<i;
			const char* szFlagName = GetLocalDataFlagName(uVal);
			if(!szFlagName) continue;

			pxDialog = new Asura_FlagTickbox_Dialog(szFlagName,xOffset,&m_uStyleChildEditableDataFlags,uVal,&m_bChanged);
			pxDialog->SetIsEnabledFunction(CanEditStyleFlags,(int)this);
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
		}

		//end of style tab
		if(xOffset.y > m_xTabsEnd.y) 
		{
			m_xTabsEnd.y = xOffset.y;
		}

		//Start of modifier tab
		s_pxTabsDialog->AddTab("Modifier");
		s_iModifierTab = s_pxTabsDialog->GetSelected();
		xOffset.y = m_xTabsStart.y;

		UpdateModifierList();
		AddModifierOverlay( pxOverlay,xOffset );

		//delete old list of modifier controls.
		while(s_xModifierDialogList.size()) s_xModifierDialogList.delete_first_entry();

		//end of modifier tab
		if(xOffset.y > m_xTabsEnd.y) 
		{
			m_xTabsEnd.y = xOffset.y;
		}

		//start of animators tab
		s_pxTabsDialog->AddTab("Animator");
		s_iAnimatorTab = s_pxTabsDialog->GetSelected();
		xOffset.y = m_xTabsStart.y;

		UpdateAnimatorList();
		AddAnimatorOverlay( pxOverlay,xOffset );

		//delete old list of animator controls.
		while(s_xAnimatorDialogList.size()) s_xAnimatorDialogList.delete_first_entry();

		//end of animators tab
		if(xOffset.y > m_xTabsEnd.y) m_xTabsEnd.y = xOffset.y;

		//start of display conditions tab
		s_pxTabsDialog->AddTab("Disp Cond");
		s_iDisplayConditionTab = s_pxTabsDialog->GetSelected();
		xOffset.y = m_xTabsStart.y;

		Asura_GUIMenu_ConditionVarManager* pxManager = &m_pxAsuraRoot->m_xDisplayConditions;

		bool bDisplayCondEnabled = ShouldStyleUseLocalDataFor(Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_DISPLAY_CONDITIONS);

		pxDialog = new Asura_Function_Dialog("Add Display Condition",xOffset,AddDisplayConditionVar,(int)this);
		pxDialog->SetHelpText("Add a new console var (or cmd) display condition.");
		pxDialog->SetEnabled(bDisplayCondEnabled);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_DropDown_List_Dialog(xOffset, g_aszLogicOperators, (int*)&pxManager->m_eOperator, ASURA_GUIMENU_LOGIC_NUMTYPES, ASURA_GUIMENU_LOGIC_NUMTYPES, NULL, &m_bChanged, "Operator");
		pxDialog->SetHelpText("This determines how the results of the display conditions are combined if there is more than one.");
		pxDialog->SetEnabled(bDisplayCondEnabled);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();

		Asura_Subwindow_Dialog* pxSubwindowDialog = s_pxDispCondSubwindowDialog = new Asura_Subwindow_Dialog(xOffset, 50.0f, 20.0f, true);
		pxOverlay->AddDialog(pxSubwindowDialog);
		
		//Add the display conditions to the subwindow dialog
		pxOverlay->PushCurrentParentDialog(pxSubwindowDialog);
		Asura_Vector_2 xSubwindowOffset(1.0f,1.0f);
		for(u_int i=0;i<pxManager->m_uNumConditionVars;i++)
		{
			pxManager->m_pxConditionVars[i].AddOverlayControls( pxOverlay, xSubwindowOffset, &m_bDisplayConditionChanged, bDisplayCondEnabled );
		}
		pxOverlay->PopCurrentParentDialog();

		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Divider_Dialog(xOffset);
		pxDialog->SetRelativePosition(pxSubwindowDialog, true, false);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
		
		
		pxDialog = new Asura_Dialog("Internal Display Conditions :",xOffset);
		pxDialog->SetRelativePosition(pxSubwindowDialog, true, false);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		const Asura_GUIMenu_Display_Condition_Params* pxParams = m_pxAsuraRoot->GetInternalDisplayCondition( 0);
		m_iCompVal1 = pxParams->m_iDisplayConditionThreshold;


		for(int i=0; i<g_uNumDisplayCondModes; i++)
		{
			if( g_axDisplayCondModes[i].m_eMode == pxParams->m_eConditionCompare)
			{
				m_iCompCond1 = i;
				break;
			}
		}

		pxDialog = new Asura_DropDown_List_Dialog( xOffset,
											&g_apcDisplayCondNames[0],
											&m_iCompCond1,
											g_uNumDisplayCondModes, 
											g_uNumDisplayCondModes,
											NULL, &m_bCompValChanged);
		pxDialog->SetEnabled(bDisplayCondEnabled);
		pxDialog->SetRelativePosition(pxSubwindowDialog, true, false);
		pxOverlay->AddDialog( pxDialog);

		Asura_Vector_2 xPos( xOffset);
		xPos.x += 7.0f;

		pxDialog = new Asura_Numerical_Dialog("Compare 1",xPos, &m_iCompVal1, INT_MIN, INT_MAX, 1, "%d",&m_bCompValChanged);
		pxDialog->SetEnabled( m_iCompCond1 != 0 && bDisplayCondEnabled);
		pxDialog->SetRelativePosition(pxSubwindowDialog, true, false);
		pxOverlay->AddDialog(pxDialog);
		xOffset.x = 1.0f;
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxParams = m_pxAsuraRoot->GetInternalDisplayCondition( 1);
		m_iCompVal2 = pxParams->m_iDisplayConditionThreshold;


		for( int i=0; i<g_uNumDisplayCondModes; i++)
		{
			if( g_axDisplayCondModes[i].m_eMode == pxParams->m_eConditionCompare)
			{
				m_iCompCond2 = i;
				break;
			}
		}

		pxDialog = new Asura_DropDown_List_Dialog( xOffset,
													&g_apcDisplayCondNames[0],
													&m_iCompCond2,
													g_uNumDisplayCondModes, 
													g_uNumDisplayCondModes,
													NULL, &m_bCompValChanged);
		
		pxDialog->SetEnabled(bDisplayCondEnabled);
		pxDialog->SetRelativePosition(pxSubwindowDialog, true, false);
		pxOverlay->AddDialog( pxDialog);

		xPos = xOffset;
		xPos.x += 7.0f;

		pxDialog = new Asura_Numerical_Dialog("Compare 2",xPos, &m_iCompVal2, INT_MIN, INT_MAX, 1, "%d",&m_bCompValChanged);
		pxDialog->SetEnabled( m_iCompCond2 != 0 && bDisplayCondEnabled);
		pxDialog->SetRelativePosition(pxSubwindowDialog, true, false);
		pxOverlay->AddDialog(pxDialog);
		xOffset.x = 1.0f;
		xOffset.y += Asura_Dialog::DefaultSpacing();
		
		//end of display conditions tab
		if(xOffset.y > m_xTabsEnd.y)
		{
			m_xTabsEnd.y = xOffset.y;
		}

	}

	//end of tabs
	xOffset.y = m_xTabsEnd.y + 1.0f;
	pxOverlay->SetCurrentParentDialog(0);

	//Different number of tabs on the file items , so keep a different store of the selected tab,
	// 17/07/08, TP - This has been changed to keep track of the selected tab name rather then the tab number
	if(IsFakeMenuItem())
	{
		static Asura_String s_xSelectedTabName;
		s_pxTabsDialog->SetSelectedTabPointerByName(&s_xSelectedTabName);
	}
	else
	{
		static Asura_String s_xSelectedTabName;
		s_pxTabsDialog->SetSelectedTabPointerByName(&s_xSelectedTabName);
	}

	if(pxOverlay->m_pxDialogList)
	{
		pxOverlay->m_uID = TOOLS_OVERLAY_GUIMENU_SELECTED;
		Asura_Overlay_System::SubmitNewOverlay(pxOverlay,false);
		UpdateOverlay();

		UpdateModifierOverlayControls();
		UpdateAnimatorOverlayControls();
		UpdateTabLabels();

		m_bOverlayCreated = true;
	}
	else
	{
		delete pxOverlay;
	}
}

void Tools_GUIMenu_Root::DeleteOverlay()
{
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_GUIMENU_SELECTED);
	s_pxModifierListDialog = 0;
	s_pxAnimatorListDialog = 0;
	s_pxDispCondSubwindowDialog = 0;
	while(s_xModifierDialogList.size()) s_xModifierDialogList.delete_first_entry();
	while(s_xAnimatorDialogList.size()) s_xAnimatorDialogList.delete_first_entry();

	m_bOverlayCreated = false;
}

void Tools_GUIMenu_Root::RecreateOverlay()
{
	if( m_bOverlayCreated )
	{
		DeleteOverlay();
		CreateOverlay();
	}
}

void Tools_GUIMenu_Root::AddModifierOverlay( Asura_Overlay* pxOverlay,Asura_Vector_2& xOffset )
{
	Asura_Dialog* pxDialog;
	pxDialog = new Asura_Function_Dialog("Add Modifier",xOffset,AddModifier,(int)this);
	pxDialog->SetIsEnabledFunction(CanAddModifier,(int)this);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog("Delete Modifier",xOffset,DeleteModifier,(int)this);
	pxDialog->SetIsEnabledFunction(IsEditableModifierSelected,(int)this);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::LargeSpacing();

	//list of current modifiers
	pxDialog = s_pxModifierListDialog = new Asura_List_Dialog(xOffset,m_pszModifierStrings,&m_iModifierIndex,8,m_iModifierListSize,NULL,&m_bModifierIndexChanged);
	// (MH - 10.04.2007) all items now support some modifiers I think so commenting out this line.
	// pxDialog->SetEnabled(GetSupportedModifiers()!=0);//grey out if the menu item doesn't support any modifiers
	pxDialog->SetHelpText("List of modifiers for this menu item.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += 8*1.2f + 1.0f;

	//states that the current modifier applies to
	pxDialog = new Asura_Dialog("Used in states :", xOffset);
	pxOverlay->AddDialog(pxDialog);
	pxDialog->SetIsEnabledFunction(IsEditableModifierSelected,(int)this);
	xOffset.y += Asura_Dialog::SmallSpacing();

	for(u_int i=0; i<g_uNumModifierStates; i++)
	{
		if(g_axStates[i].m_uValue & ASURA_GUIMENU_ACTION_FLAG_ALL)
		{
			pxDialog = new Asura_FlagTickbox_Dialog(g_axStates[i].m_szName,xOffset,&m_uModifierStates,g_axStates[i].m_uValue,&m_bModifierChanged);
			pxDialog->SetHelpText("Indicates whether the selected modifier applies when the menu item is in this state.");
			pxDialog->SetIsEnabledFunction(IsEditableModifierSelected,(int)this);
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
		}
	}

	xOffset.y += Asura_Dialog::LargeSpacing()-Asura_Dialog::DefaultSpacing();
		
	//keep track of the insertion point for controls that change depending on the modifier type
	s_xModifierDialogOffset = xOffset;
}

void Tools_GUIMenu_Root::AddAnimatorOverlay( Asura_Overlay* pxOverlay,Asura_Vector_2& xOffset )
{
	Asura_Dialog* pxDialog;

	pxDialog = new Asura_Function_Dialog("Add Animator",xOffset,AddAnimator,(int)this);
	pxDialog->SetHelpText("Add an animator sequence to this menu item");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog("Delete Animator",xOffset,DeleteAnimator,(int)this);
	pxDialog->SetHelpText("Deletes the selected animator sequence from this menu item");
	pxDialog->SetIsEnabledFunction(IsEditableAnimatorSelected,(int)this);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::LargeSpacing();

	//list of current animators
	pxDialog = s_pxAnimatorListDialog = new Asura_List_Dialog(xOffset,m_pszAnimatorStrings,&m_iAnimatorIndex,8,m_iAnimatorListSize,NULL,&m_bAnimatorIndexChanged);
	pxDialog->SetHelpText("List of animators for this menu item.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += 8*1.2f + 1.0f;

	CopyFromAsuraAnimator();

	//speed for the current animator
	pxDialog = new Asura_Numerical_Dialog("Speed",xOffset,&m_fAnimatorSpeed,0.0f,999.0f,1.0f,"%.3f",&m_bAnimatorChanged);
	pxDialog->SetHelpText("Speed multiplier for the selected animator sequence");
	pxDialog->SetIsEnabledFunction(IsEditableAnimatorSelected,(int)this);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog("Delay",xOffset,&m_fAnimatorDelay,0.0f,999.0f,1.0f,"%.3f",&m_bAnimatorChanged);
	pxDialog->SetHelpText("Delay before the animation starts. The animation will hold on the first frame until this time has passed.");
	pxDialog->SetIsEnabledFunction(IsEditableAnimatorSelected,(int)this);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();


	s_xAnimatorDialogOffset = xOffset;
}

void Tools_GUIMenu_Root::AddOverlayControls(Asura_Overlay* pxOverlay,Asura_Vector_2& xOffset)
{
	Asura_Dialog* pxDialog;

	if( m_pxAsuraRoot && !IsFakeMenuItem() )
	{
		pxDialog = new Asura_Function_Dialog("Rename",xOffset,Rename,(int)this);
		pxDialog->SetHelpText("Rename this menu item");
		pxDialog->SetEnabled(CanBeRenamed());
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
	}	

	//Colour editing
	pxDialog = new Asura_Dialog("Colour",xOffset);
	pxOverlay->AddDialog(pxDialog);

	xOffset.x = pxDialog->m_xMaxCoord.x + 1.0f;
	Tools_ColourPicker_Dialog* pxColourDialog = new Tools_ColourPicker_Dialog("Colour",xOffset,Asura_Vector_2(1.5f,1.0f),&m_xColour.m_fR,&m_xColour.m_fG,&m_xColour.m_fB,1.0f,&m_bChanged);
	pxDialog->SetIsEnabledFunction(CanEditColour,(int)this);
	pxColourDialog->EnableAlphaEditing(&m_xColour.m_fA);
	pxOverlay->AddDialog(pxColourDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();
	xOffset.x = 1.0f;

	xOffset.y += Asura_Dialog::LargeSpacing()-Asura_Dialog::DefaultSpacing();

	m_iTranslucencyMode = FindTranslucencyDropListIndex();
	if( m_pxAsuraRoot && (m_iTranslucencyMode == -1) )
	{
		// could not find a matching mode, so assert and correct engine data to match as no translucency.
		Asura_Assert( m_iTranslucencyMode != -1, "Tools_GUIMenu_Root::AddOverlayControls - m_iTranslucencyMode == -1.  Correcting engine data to compensate.");

		m_iTranslucencyMode = 0;
		m_pxAsuraRoot->SetTranslucencyMode( g_axTranslucencyModes[m_iTranslucencyMode].m_eMode);
	}

	m_bTranslucencyChanged = false;

	pxDialog = new Asura_DropDown_List_Dialog( xOffset,
												&g_apcTranslucencyNames[0],
												&m_iTranslucencyMode,
												g_uNumTranslucencyModes, 
												g_uNumTranslucencyModes,
												NULL, &m_bTranslucencyChanged, "Translucency Mode");

	pxOverlay->AddDialog( pxDialog);
	pxDialog->SetIsEnabledFunction(CanEditTranslucency,(int)this);
	xOffset.y += Asura_Dialog::DefaultSpacing();
}

// If the state of the Hide tickbox menu item changes then recursively change the
// state of all its children.
void Tools_GUIMenu_Root::HideTickboxStateChanged()
{
	if ( GetSelectedInstance()->m_bHidden == true )
	{ 
		// Hide all children.
		GetSelectedInstance()->SetHiddenRecursive(true);
	}
	else
	{
		// Show all children.
		GetSelectedInstance()->SetHiddenRecursive(false);
	}
}

void Tools_GUIMenu_Root::AddBasicOverlayControls(Asura_Overlay* pxOverlay,Asura_Vector_2& xOffset)
{

	Asura_Dialog* pxDialog;

	const float fDefaultX = xOffset.x;

	if( !m_pxAsuraRoot || IsFakeMenuItem() )
	{
		pxDialog = new Asura_Function_Dialog("Rename",xOffset,Rename,(int)this);
		pxDialog->SetHelpText("Rename this menu item");
		pxDialog->SetEnabled(CanBeRenamed());
		pxOverlay->AddDialog(pxDialog);
		xOffset.x += 13.0f;
	}
	
	if (!IsMenu())
	{
		pxDialog = new Asura_FlagTickbox_Dialog("Unclamp from Parent",xOffset,&m_uToolsFlags,ASURA_GUIMENU_TOOLS_FLAG_ISUNCLAMPED,&m_bIsClampedChanged);
		pxDialog->SetHelpText("If ticked this object will no longer be bound to it's parent's area.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
	}

	if (IsWidget())
	{
		pxDialog = new Asura_FlagTickbox_Dialog("Autoshrink To Children",xOffset,&m_uToolsFlags,ASURA_GUIMENU_TOOLS_FLAG_AUTOSHRINK,&m_bChanged);
		pxDialog->SetHelpText("If ticked this object will shrink to fit it's children when one is moved or removed");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
	}

	// NY - 20 October 2008 - more formal way of saying "is a container" needed
	if (IsWidget()
		|| (m_pxAsuraRoot && m_pxAsuraRoot->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_PATH)
		|| IsMenu())
	{
		pxDialog = new Asura_FlagTickbox_Dialog("Grow on child move/resize",xOffset,&m_uToolsFlags,ASURA_GUIMENU_TOOLS_FLAG_GROWONCHILDMOVE,&m_bChanged);
		pxDialog->SetHelpText("If ticked this object can grow to allow children to leave it's old borders.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
	}

	Asura_Tickbox_Dialog* pxTickDialog = new Asura_Tickbox_Dialog("Hide",xOffset,&m_bHidden);
	// If the state of the Hide tickbox menu item changes then recursively change the
	// state of all its children.
	pxTickDialog->SetClickedFunction(HideTickboxStateChanged);

	pxTickDialog->SetHelpText("Hide/unhides the tools rendering of this menu item");
	pxOverlay->AddDialog(pxTickDialog);
	xOffset.x = fDefaultX;
	xOffset.y += Asura_Dialog::DefaultSpacing();

	//position controls
	pxDialog = new Asura_Numerical_Dialog("X",xOffset,&m_fX,0.0f,9999.0f,1.0f,"%.2f",&m_bMoved);
	pxDialog->SetHelpText("X coordinate of menu item");
	pxDialog->SetEnabled(CanBeMoved());
	pxOverlay->AddDialog(pxDialog);

	xOffset.x += 15.0f;
	pxDialog = new Asura_Numerical_Dialog("Y",xOffset,&m_fY,0.0f,9999.0f,1.0f,"%.2f",&m_bMoved);

	pxDialog->SetHelpText("Y coordinate of menu item");
	pxDialog->SetEnabled(CanBeMoved());
	pxOverlay->AddDialog(pxDialog);
	xOffset.x = 1.0f;
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog("Width",xOffset,&m_fW,0.0f,9999.0f,1.0f,"%.2f",&m_bResized);
	pxDialog->SetEnabled(CanEditDisplayWidth());
	pxOverlay->AddDialog(pxDialog);

	xOffset.x += 15.0f;
	pxDialog = new Asura_Numerical_Dialog("Height",xOffset,&m_fH,0.0f,9999.0f,1.0f,"%.2f",&m_bResized);
	pxDialog->SetEnabled(CanEditDisplayHeight());
	pxOverlay->AddDialog(pxDialog);
	xOffset.x = 1.0f;
	xOffset.y += Asura_Dialog::DefaultSpacing();

	// NY - 20 November 2008 - menu specific items added directly here, so they look sensible on screen
	if (IsMenu())
	{
		Asura_GUIMenu_Menu_Page* pxMenu = static_cast<Asura_GUIMenu_Menu_Page*>(m_pxAsuraRoot);
		pxDialog = new Asura_Numerical_Dialog("Virtual Width",xOffset,&pxMenu->GetVirtualSizePtr()->x,0.0f,9999.0f,1.0f,"%.2f",&m_bChanged);
		pxDialog->SetEnabled(CanEditDisplayWidth());
		pxOverlay->AddDialog(pxDialog);

		xOffset.x += 20.0f;
		pxDialog = new Asura_Numerical_Dialog("Virtual Height",xOffset,&pxMenu->GetVirtualSizePtr()->y,0.0f,9999.0f,1.0f,"%.2f",&m_bResized);
		pxDialog->SetEnabled(CanEditDisplayHeight());
		pxOverlay->AddDialog(pxDialog);
		xOffset.x = 1.0f;
		xOffset.y += Asura_Dialog::DefaultSpacing();
	}
	
	//Add flags , may want to filter based on which make sense for a given type of menu item.
	u_int uFlagMask = GetFlagsToEdit();
	for(u_int i=0;i<g_uNumMenuFlags;i++)
	{
		if(uFlagMask & g_axFlags[i].m_uValue)
		{
			pxDialog = new Asura_FlagTickbox_Dialog(g_axFlags[i].m_szName,xOffset,&m_uFlags,g_axFlags[i].m_uValue,&m_bChanged);
			pxDialog->SetHelpText(g_axFlags[i].m_szHelpText);
			pxDialog->SetIsEnabledFunction(CanEditFlags,(int)this);
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
		}
	}

	pxDialog = new Asura_Function_Dialog("Center Within Parent",xOffset,CenterWithinParent,(int)this);
	pxDialog->SetHelpText("Position the center of this object at the center of its parent");
	pxDialog->SetEnabled(CanBeMoved());
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::LargeSpacing();

	//ordering
	pxDialog = new Asura_Function_Dialog("Move Backwards",xOffset,MoveBackwards,(int)this);
	pxDialog->SetHelpText("Moves this item earlier in the list , resulting in it being drawn behind other items.");
	pxDialog->SetIsEnabledFunction(CanMoveToBack,(int)this);
	pxOverlay->AddDialog(pxDialog);

	xOffset.x += 12.0f;
	pxDialog = new Asura_Function_Dialog("Move to Back",xOffset,MoveToBack,(int)this);
	pxDialog->SetHelpText("Moves this item to the start of the the list , resulting in it being drawn behind other items.");
	pxDialog->SetIsEnabledFunction(CanMoveToBack,(int)this);
	pxOverlay->AddDialog(pxDialog);
	xOffset.x -= 12.0f;
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog("Move Forwards",xOffset,MoveForwards,(int)this);
	pxDialog->SetHelpText("Moves this item later in the list , resulting in it being drawn in front of other items.");
	pxDialog->SetIsEnabledFunction(CanMoveToFront,(int)this);
	pxOverlay->AddDialog(pxDialog);

	xOffset.x += 12.0f;
	pxDialog = new Asura_Function_Dialog("Move to Front",xOffset,MoveToFront,(int)this);
	pxDialog->SetHelpText("Moves this item to the end of the list , resulting in it being drawn in front of other items.");
	pxDialog->SetIsEnabledFunction(CanMoveToFront,(int)this);
	pxOverlay->AddDialog(pxDialog);
	xOffset.x -= 12.0f;
	xOffset.y += Asura_Dialog::LargeSpacing();

	pxDialog = new Asura_Function_Dialog("Add to group",xOffset,AddToGroup,(int)this);
	pxDialog->SetHelpText("Adds this to an existing group widget.");
	pxDialog->SetIsEnabledFunction(CanAddToGroup,(int)this);
	pxOverlay->AddDialog(pxDialog);

	xOffset.x += 12.0f;
	pxDialog = new Asura_Function_Dialog("Remove from group",xOffset,RemoveFromGroup,(int)this);
	pxDialog->SetHelpText("Removes this from a group widget , and makes the item a direct child of the menu page.");
	pxDialog->SetIsEnabledFunction(CanRemoveFromGroup,(int)this);
	pxOverlay->AddDialog(pxDialog);
	xOffset.x -= 12.0f;
	xOffset.y += Asura_Dialog::LargeSpacing();

	// Comments Controls
	Asura_Char acBuffer[32];
	
	if(m_pxAsuraRoot) 
	{
		Asura_PrintfToBfr( acBuffer, "Comments (%d)", 32, true, m_pxAsuraRoot->GetCommentCount());
	}

	pxDialog = new Asura_Function_Dialog(acBuffer, xOffset, EditComments,(int)this);
	pxDialog->SetHelpText("User can read, edit or add comments.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::LargeSpacing();

	// Position Controls
	if( m_pxAsuraRoot && NeedsPosOptions() )
	{
		pxDialog = new Asura_DropDown_List_Dialog(xOffset,
													g_aszHorzPosModeNames,
													static_cast<int*>(static_cast<void*>(&m_pxAsuraRoot->m_aePosMode[0])),//TODO - less hacky
													Asura_GUIMenu_Root::NUM_POS_MODES,
													Asura_GUIMenu_Root::NUM_POS_MODES,
													NULL, &m_bPosOptionsChanged, "Horizontal Position Mode");
		pxDialog->SetEnabled(CanEditAnchoring());
		pxDialog->SetHelpText("How to position this item horizontally if the screen res is changed");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing() * 1.2f;

		pxDialog = new Asura_DropDown_List_Dialog(xOffset,
													g_aszVertPosModeNames,
													static_cast<int*>(static_cast<void*>(&m_pxAsuraRoot->m_aePosMode[1])),
													Asura_GUIMenu_Root::NUM_POS_MODES,
													Asura_GUIMenu_Root::NUM_POS_MODES,
													NULL, &m_bPosOptionsChanged, "Vertical Position Mode");
		pxDialog->SetEnabled(CanEditAnchoring());
		pxDialog->SetHelpText("How to position this item vertically if the screen res is changed");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();
		
		pxDialog = new Asura_Function_Dialog( "Apply Anchoring To Children", xOffset ,&ApplyAnchoringFlagsToChildrenCallback,&m_bChanged );
		pxDialog->SetEnabled(CanEditAnchoring());
		pxDialog->SetHelpText("Copy objects anchoring flags to all its children");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Numerical_Dialog("Origin X", xOffset, &m_xPixelOrigin.x, -10000.0f, 10000.0f, 0.5f, "%.1f", &m_bPosOriginChanged );
		pxDialog->SetHelpText("X origin pos");
		pxDialog->SetEnabled(CanEditAnchoring());
		pxOverlay->AddDialog(pxDialog);

		pxDialog = new Asura_Numerical_Dialog("Origin Y", xOffset + Asura_Vector_2(20.0f, 0.0f), &m_xPixelOrigin.y, -10000.0f, 10000.0f, 0.5f, "%.1f", &m_bPosOriginChanged);
		pxDialog->SetHelpText("Y origin pos");
		pxDialog->SetEnabled(CanEditAnchoring());
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();
	}

	// Dimension Scaling controls
	pxDialog = new Asura_StringDisplay_Dialog("Scale Dimensions", xOffset);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	const Asura_Hash_ID uWidthRadioButtonGroupID = 0xfd6b3cec; //"GUIMenuWidth"
	pxDialog = new Asura_FlagTickbox_Dialog( "Width To Parent Width", xOffset, m_pxAsuraRoot->GetScalingFlagsPtr(), 
											 Asura_GUIMenu_Root::ASURA_GUIMENU_ELEMENT_FLAG_SCALE_DIMENSION_X_TO_PARENTX, &m_bScaleFlagChanged);
	pxDialog->SetEnabled(CanEditScaling());
	pxDialog->SetRadioButtonGroup(uWidthRadioButtonGroupID, false);
	pxDialog->SetHelpText("When ticked, this will scale the object's width to its parents width.");
	pxOverlay->AddDialog(pxDialog);

	pxDialog = new Asura_FlagTickbox_Dialog( "Width To Parent Height", xOffset + Asura_Vector_2(20.0f, 0.0f), m_pxAsuraRoot->GetScalingFlagsPtr(), 
											 Asura_GUIMenu_Root::ASURA_GUIMENU_ELEMENT_FLAG_SCALE_DIMENSION_X_TO_PARENTY, &m_bScaleFlagChanged);
	pxDialog->SetEnabled(CanEditScaling());
	pxDialog->SetRadioButtonGroup(uWidthRadioButtonGroupID, false);
	pxDialog->SetHelpText("When ticked, this will scale the object's width to its parents height.");
	pxOverlay->AddDialog(pxDialog);

	xOffset.y += Asura_Dialog::DefaultSpacing();

	const Asura_Hash_ID uHeightRadioButtonGroupID = 0x962d66c1; //"GUIMenuHeight"
	pxDialog = new Asura_FlagTickbox_Dialog( "Height To Parent Height", xOffset, m_pxAsuraRoot->GetScalingFlagsPtr(), 
											 Asura_GUIMenu_Root::ASURA_GUIMENU_ELEMENT_FLAG_SCALE_DIMENSION_Y_TO_PARENTY, &m_bScaleFlagChanged);
	pxDialog->SetEnabled(CanEditScaling());
	pxDialog->SetRadioButtonGroup(uHeightRadioButtonGroupID, false);
	pxDialog->SetHelpText("When ticked, this will scale the object's height to its parents height.");
	pxOverlay->AddDialog(pxDialog);

	pxDialog = new Asura_FlagTickbox_Dialog( "Height To Parent Width", xOffset + Asura_Vector_2(20.0f, 0.0f), m_pxAsuraRoot->GetScalingFlagsPtr(), 
											 Asura_GUIMenu_Root::ASURA_GUIMENU_ELEMENT_FLAG_SCALE_DIMENSION_Y_TO_PARENTX, &m_bScaleFlagChanged);
	pxDialog->SetEnabled(CanEditScaling());
	pxDialog->SetRadioButtonGroup(uHeightRadioButtonGroupID, false);
	pxDialog->SetHelpText("When ticked, this will scale the object's height to its parents width.");
	pxOverlay->AddDialog(pxDialog);

	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog( "Apply Scaling To Children", xOffset,ApplyScalingFlagsToChildrenCallback, &m_bScaleFlagChanged);
	pxDialog->SetEnabled(CanEditScaling());
	pxDialog->SetHelpText("Copy objects dimension scaling flags to all its children");
	pxOverlay->AddDialog(pxDialog);

	xOffset.y += Asura_Dialog::DefaultSpacing();
}

void Tools_GUIMenu_Root::Update()
{
	if (m_bPosOriginChanged && m_pxAsuraRoot)
	{
		m_pxAsuraRoot->m_xPosOrigin = m_xPixelOrigin;
		if (m_pxAsuraRoot->GetUnscaledLocalBounds().GetWidth() > 1.0f)
		{
			m_pxAsuraRoot->m_xPosOrigin.x /= m_pxAsuraRoot->GetUnscaledLocalBounds().GetWidth();
		}
		if (m_pxAsuraRoot->GetUnscaledLocalBounds().GetHeight() > 1.0f)
		{
			m_pxAsuraRoot->m_xPosOrigin.y /= m_pxAsuraRoot->GetUnscaledLocalBounds().GetHeight();
		}
		m_bPosOriginChanged = false;
	}

	//being resized using the overlay controls?
	if(m_bMoved || m_bResized)
	{

		Asura_Bounding_Rectangle xOldRect = GetRectangle();
		Asura_Bounding_Rectangle xNewRect;
		xNewRect.MinX = m_fX;
		xNewRect.MinY = m_fY;
		xNewRect.MaxX = m_fX+m_fW;
		xNewRect.MaxY = m_fY+m_fH;

		u_int uDragFlags = 0;
		if(m_bMoved) uDragFlags |= TOOLS_MENUS_DRAG_MOVE;
		if(m_bResized) uDragFlags |= TOOLS_MENUS_DRAG_MAXX|TOOLS_MENUS_DRAG_MAXY; 

		MoveOrResizeRect(GetRectangle(), xNewRect, uDragFlags, true, false);
		
		m_bResized = false;
		m_bMoved = false;

	}
	else
	{
		//make sure the overlay extent values are up to date
		Asura_Bounding_Rectangle xRect = GetRectangle();
		m_fX = xRect.MinX;
		m_fY = xRect.MinY;
		m_fW = xRect.MaxX - xRect.MinX;
		m_fH = xRect.MaxY - xRect.MinY;
	}

	if(m_bStyleContainerChanged)
	{
		//Menu is being unflagged as a style container. Make sure it doesn't contain any styles
		if(!(m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_STYLECONTAINER))
		{
			if(ContainsStyles())
			{
				ShowMessageOverlay("This menu can't be unflagged as a style container since it still contains some members that are styles");
				m_uToolsFlags |= ASURA_GUIMENU_TOOLS_FLAG_STYLECONTAINER;

			}
		}
		m_bStyleContainerChanged = false;
		m_bChanged = true;
	}
	
	if(m_bIsStyleChanged)
	{
		if(!IsStyle())
		{
			//Warn if being unflagged as a style
			if(m_pxAsuraRoot && ShowYesNoOverlay("This will cause all existing items that are using this to have their style removed\nGo ahead and unflag this as being a style?"))
			{
				Tools_Mode_GUIMenu::RemoveReferencesToStyle(m_pxAsuraRoot->GetID());
			}
			else
			{
				m_uToolsFlags |= ASURA_GUIMENU_TOOLS_FLAG_ISSTYLE;
			}
		}
		else
		{
			//If this has become a style , then set the flags for allowing positions to be altered in the instances , since
			//this will almost always be needed for the root item in a style.
			m_uStyleChildEditableDataFlags |= Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_POSITION;
		}


		//update the list of styles in the style overlay
		Tools_Mode_GUIMenu::UpdateStyleList();

		m_bIsStyleChanged = false;
		m_bChanged = true;
	}

	if(m_bIsClampedChanged)
	{
		if (ClampToParent())
		{
			ClampToParentRect();
		}
		else if ((m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_ISUNCLAMPED) == 0
			&& m_pxToolsParent)
		{
			// NY - 15 April 2009 - have to force these flags to store for next function to work
			m_pxAsuraRoot->SetToolsFlags(m_uToolsFlags);
			m_pxToolsParent->ResizePostChildChanges();
		}
		m_bChanged = true;
		m_bIsClampedChanged = false;
	}

	if( m_pxAsuraRoot && m_bDisplayConditionChanged)
	{
		//If the display condition console variable isn't blank ,then make sure the comparison isn't set to none
		Asura_GUIMenu_ConditionVarManager* pxManager = &m_pxAsuraRoot->m_xDisplayConditions;

		for(u_int i=0;i<pxManager->m_uNumConditionVars;i++)
		{
			Asura_GUIMenu_ConditionVar* pxCondVar = &pxManager->m_pxConditionVars[i];
			if((!pxCondVar->IsVarBlank() || !pxCondVar->IsCmdBlank()) && pxCondVar->IsConditionBlank() )
			{
				pxCondVar->SetCondition( ASURA_GUIMENU_CONDITION_EQUAL );
			}
		}
		
		m_bDisplayConditionChanged = false;
		m_bChanged = true;
	}

	if( m_pxAsuraRoot && m_bModifierConditionChanged)
	{
		//If the modfier condition console variable isn't blank ,then make sure the comparison isn't set to none
		Asura_GUIMenu_ConditionVarManager* pxManager(NULL);

		if( m_iModifierIndex < static_cast<int>(m_pxAsuraRoot->GetModifierCount()) )
		{
			pxManager = m_pxAsuraRoot->GetModifier(m_iModifierIndex)->GetActivationConditions();
		}

		if(pxManager)
		{
			for( u_int u(0);u<pxManager->m_uNumConditionVars;++u )
			{
				Asura_GUIMenu_ConditionVar* pxCondVar = &pxManager->m_pxConditionVars[u];

				if((!pxCondVar->IsVarBlank() || !pxCondVar->IsCmdBlank()) && pxCondVar->IsConditionBlank() )
				{
					pxCondVar->SetCondition( ASURA_GUIMENU_CONDITION_EQUAL );
				}
			}
			
			m_bModifierConditionChanged = false;
			m_bChanged = true;
		}
	}

	if(m_bAnimatorConditionChanged && m_pxAsuraRoot)
	{
		//If the modfier condition console variable isn't blank ,then make sure the comparison isn't set to none
		Asura_GUIMenu_ConditionVarManager* pxManager(NULL);

		if( m_iAnimatorIndex < static_cast<int>(m_pxAsuraRoot->GetAnimatorCount()) )
		{
			pxManager = m_pxAsuraRoot->GetAnimator(m_iAnimatorIndex)->GetStartConditions();
		}

		if(pxManager)
		{
			for( u_int u(0);u<pxManager->m_uNumConditionVars;++u )
			{
				Asura_GUIMenu_ConditionVar* pxCondVar = &pxManager->m_pxConditionVars[u];

				if((!pxCondVar->IsVarBlank() || !pxCondVar->IsCmdBlank()) && pxCondVar->IsConditionBlank() )
				{
					pxCondVar->SetCondition( ASURA_GUIMENU_CONDITION_EQUAL );
				}
			}
			
			m_bAnimatorConditionChanged = false;
			m_bChanged = true;
		}
	}

	if(m_bModifierIndexChanged && IsSelected())
	{
		UpdateModifierOverlayControls();
		m_bModifierIndexChanged = false;
	}
	
	if(m_bModifierChanged)
	{
		CopyToAsuraModifier();
		m_bModifierChanged = false;
		SetModified();
	}

	if(m_bAnimatorIndexChanged && IsSelected())
	{
		CopyFromAsuraAnimator();
		UpdateAnimatorOverlayControls();
		m_bAnimatorIndexChanged = false;
	}

	if(m_bAnimatorChanged)
	{
		CopyToAsuraAnimator();
		m_bAnimatorChanged = false;
		SetModified();
	}

	if(m_bPosOptionsChanged)
	{
		m_bPosOptionsChanged = false;
		m_bChanged = true;

		//update the overlay in case the X/Y settings need to be displayed differently now. RAR 02/06/2008
		RecreateOverlay();
	}

	if(m_bChanged)
	{
		if(NeedsPosOptions())
		{
			SetModified();
		}

		CopyToAsura();
		m_bChanged = false;
		SetModified();
	}

	if( m_pxAsuraRoot && m_bTranslucencyChanged )
	{
		m_bTranslucencyChanged = false;
		m_pxAsuraRoot->SetTranslucencyMode( g_axTranslucencyModes[m_iTranslucencyMode].m_eMode);
		SetModified();
	}

	if( m_pxAsuraRoot && m_bCompValChanged )
	{
		m_pxAsuraRoot->RemoveAllInternalDisplayConditions();

		if( m_iCompCond1 != 0)
		{
			m_pxAsuraRoot->AddInternalDisplayCondition(m_iCompVal1, static_cast<Asura_GUIMenu_Display_Condition>(m_iCompCond1) );
		}

		if( m_iCompCond2 != 0)
		{
			m_pxAsuraRoot->AddInternalDisplayCondition(m_iCompVal2, static_cast<Asura_GUIMenu_Display_Condition>(m_iCompCond2) );
		}

		Tools_GUIMenu_Root::DeleteOverlay();
		Tools_GUIMenu_Root::CreateOverlay();

		SetModified();
		m_bCompValChanged = false;
	}

	if(m_bSelected)
	{
		UpdateTabLabels();
	}

	Asura_Assert( m_iCompCond1>=0,"Negative display condition selection index" );
	Asura_Assert( m_iCompCond2>=0,"Negative display condition selection index" );

	if( m_bScaleFlagChanged)
	{
		m_bScaleFlagChanged = false;
		DeleteOverlay();
		CreateOverlay();
		m_bChanged = true;
		SetModified();
	}

	if (m_pxAsuraRoot)
	{
		m_xPixelOrigin = m_pxAsuraRoot->m_xPosOrigin;
		if (m_pxAsuraRoot->GetUnscaledLocalBounds().GetWidth() > 1.0f)
		{
			m_xPixelOrigin.x *= m_pxAsuraRoot->GetUnscaledLocalBounds().GetWidth();
		}
		if (m_pxAsuraRoot->GetUnscaledLocalBounds().GetHeight() > 1.0f)
		{
			m_xPixelOrigin.y *= m_pxAsuraRoot->GetUnscaledLocalBounds().GetHeight();
		}
	}
}

void Tools_GUIMenu_Root::UpdateRecursive()
{
	Update();

	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->UpdateRecursive();
	}
}

void Tools_GUIMenu_Root::CopyToAsura()
{
	if( m_pxAsuraRoot )
	{
		for( u_int u(0);u<g_uNumMenuFlags;++u )
		{
			u_int uValue = g_axFlags[u].m_uValue;
			bool bSet = (m_uFlags & uValue) ? true : false;
			m_pxAsuraRoot->ChangeFlag(uValue,bSet);
		}

		m_pxAsuraRoot->SetColour(m_xColour);
		m_pxAsuraRoot->SetToolsFlags(m_uToolsFlags);
		m_pxAsuraRoot->SetStyleChildEditableDataFlags(m_uStyleChildEditableDataFlags);
	}
}

void Tools_GUIMenu_Root::CopyFromAsura()
{
	if( m_pxAsuraRoot )
	{
		m_uFlags = m_pxAsuraRoot->GetFlags();
		m_xColour = m_pxAsuraRoot->GetColour();
	}
}

void Tools_GUIMenu_Root::UpdateOverlay()
{
	if(IsSelected())
	{
		Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_GUIMENU_SELECTED);
		if(pxOverlay) UpdateOverlayControls(pxOverlay);
	}

	Asura_Assert( m_iCompCond1>=0,"Negative display condition selection index" );
	Asura_Assert( m_iCompCond2>=0,"Negative display condition selection index" );
}

void Tools_GUIMenu_Root::UpdateOverlayControls(Asura_Overlay* pxOverlay)
{
	if( !m_pxAsuraRoot || IsFakeMenuItem() ) return;

	char szText[100];
 	
	//update style instance label
//	Asura_Hash_ID uInheritedID = m_pxAsuraRoot->GetInheritedObjectHash();
// SK 02.03.07 - Replaced original call with new method.
	Asura_Hash_ID uInheritedID = m_pxAsuraRoot->GetStyleObjectHash();

	if((m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_STYLEINSTANCE) && uInheritedID)
	{
		Tools_GUIMenu_Root* pxStyleItem = Tools_Mode_GUIMenu::GetInstance()->FindItemByID(uInheritedID);
		if(pxStyleItem)
		{
			Asura_PrintfToBfr(szText,"Style : %s",sizeof(szText),true,pxStyleItem->GetName());
		}
		else
		{
			strcpy(szText,"Style : Unknown");
		}
	}
	else
	{
		strcpy(szText,"Style : None");
	}
	pxOverlay->UpdateDialogLabel(Asura_GetHashID("UsesStyle"),szText);


	//update generated by style label
	Asura_PrintfToBfr(szText,"Gen By Style : %s",sizeof(szText),true,IsGeneratedByStyle() ? "Yes" : "No");
	pxOverlay->UpdateDialogLabel(Asura_GetHashID("GenByStyle"),szText);

	//update inherited label
	Asura_PrintfToBfr(szText,"Inherited : %s",sizeof(szText),true,uInheritedID ? "Yes" : "No");
	pxOverlay->UpdateDialogLabel(Asura_GetHashID("Inherited"),szText);

	Asura_Assert( m_iCompCond1>=0,"Negative display condition selection index" );
	Asura_Assert( m_iCompCond2>=0,"Negative display condition selection index" );
}


Tools_GUIMenu_Widget_Base* Tools_GUIMenu_Root::FindWidget(Asura_Hash_ID uID)
{
	//is this the one we are after?
	if(IsWidget())
	{
		if( m_pxAsuraRoot && (m_pxAsuraRoot->GetID() == uID) )
		{
			return (Tools_GUIMenu_Widget_Base*) this;
		}
	}	

	//recurse through thr children
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		Tools_GUIMenu_Widget_Base* pxWidget = xChildLIF()->FindWidget(uID);
		if(pxWidget) return pxWidget;
	}
	return 0;
}

void Tools_GUIMenu_Root::Rename()
{
	Asura_Assert(!s_bIsRenaming, "already renaming");

	GetString_Overlay xOverlay("Rename",GetName());
	const char* szNewName = 0;

	do
	{
		if(!xOverlay.DoModal()) return;
		szNewName = xOverlay.GetString();

		//abort if no name was chosen
		if(!szNewName || !*szNewName) return;

		//make sure the name isn't already in use
		if( m_pxAsuraRoot && m_pxToolsParent )
		{
			bool bOkay = true;
			if(IsMenu())
			{
				//Can't just check the siblings for menus , since the name needs to be unique across all files.
				//So just check all the menus in the menu system directly.
				for (u_int u = 0; u < Asura_GUIMenu_System::GetCurrentMenuListCount(); ++u)
				{
					if(Asura_GUIMenu_System::GetMenuPageByIndex(u) == m_pxAsuraRoot) continue;
					if(!stricmp(Asura_GUIMenu_System::GetMenuPageByIndex(u)->GetNameAsChar(), szNewName))
					{
						bOkay = false;
						break;
					}
				}
				if(!bOkay)
				{
					ShowMessageOverlay("That name is already in use by another menu.");
					szNewName = 0;
				}

			}
			else
			{
				for(LIF<Tools_GUIMenu_Root*> xSiblingLIF(&m_pxToolsParent->m_xChildren);!xSiblingLIF.done();xSiblingLIF.next())
				{
					if(xSiblingLIF() == this) continue;
					if(!stricmp(xSiblingLIF()->GetName(),szNewName))
					{
						bOkay = false;
						break;
					}
				}
				if(!bOkay)
				{
					ShowMessageOverlay("That name is already in use by a sibling menu item.");
					szNewName = 0;
				}
			}
		}

	}
	while(!szNewName);

	s_bIsRenaming = true;

	if( m_pxAsuraRoot )
	{
		if(!strcmp(szNewName,GetName()) )
		{
			//name is unchanged ,except possibly by case.
			m_pxAsuraRoot->SetName(szNewName);
			m_xName = szNewName;
		}
		else
		{

			m_pxAsuraRoot->SetName(szNewName);
			m_xName = szNewName;

			//now need to recurse down updating the IDs , and fixing up any links
			RecalculateID();
		}
	}

	SetModified();
		
	if(IsSelected())
	{
		//update the overlay's title
		Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_GUIMENU_SELECTED);
		if(pxOverlay) pxOverlay->SetTitle(szNewName);
	}	

	//update the name on the tree view
	Tools_Mode_GUIMenu::GetInstance()->UpdateNameOnTree(this);

	//If a style , then the style overlay needs updating as well
	if(IsStyle()) Tools_Mode_GUIMenu::UpdateStyleList();


	s_bIsRenaming = false;

}

void Tools_GUIMenu_Root::RecalculateID()
{

	if( m_pxAsuraRoot )
	{
		//update the ID for this item
		Asura_Hash_ID uOldID = m_pxAsuraRoot->GetID();
		m_pxAsuraRoot->GenerateHashID();
		Asura_Hash_ID uNewID = m_pxAsuraRoot->GetID();

		Asura_Assert(uOldID,"Old ID was 0");
		Asura_Assert(uNewID,"New ID is 0");


		if(uOldID != uNewID)
		{
			//Make sure the fast lookup system in the asura system doesn't refer to this.
			//Just going to clear the lot to be safe
			//RAR 24/07/2007
			Asura_GUIMenu_System::ResetFastWidgetLookUpTree();
		}


		//update in hash tree
		RemoveFromHashTree();
		AddToHashTree();

		if(uOldID)
		{
			if(uOldID != uNewID)
			{
				//update any references to this
	//			GetMenuPage()->UpdateReferencesRecursive(uOldID,uNewID);

				// SK - 18.01.07 : Needed to change to the following code.
				// -- We must check all menu pages and not just the parent of the existing one.
				// -- i added a widget button 'LinkTo' hash and this hash can link to
				// -- any menu or widget that's a child of that menu.
				for(LIF<Tools_GUIMenu_Root*> xMenuPageLIF(&s_xList);!xMenuPageLIF.done();xMenuPageLIF.next())
				{
					if( xMenuPageLIF()->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE)
					{
						xMenuPageLIF()->UpdateReferencesRecursive(uOldID,uNewID,false);
					}
				}

				// PAZ - change display condition references to widgets as well
				// PAZ - but only need to do this if we are renaming a widget
				if( IsWidget() )
				{
					// find the menu page that we are on - we will want to update all references on this menu page
					Tools_GUIMenu_Root* pxRoot = this;
					while( pxRoot != NULL )
					{
						if( pxRoot->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE )
						{
							char szNewID[ 32 ];
							Asura_PrintfToBfr( szNewID, "%d", sizeof( szNewID ), true, (int)uNewID );

							pxRoot->UpdateWidgetReferencesRecursive( uOldID, uNewID, szNewID );
							break;
						}
						pxRoot = pxRoot->m_pxToolsParent;
					}
				}
			}
		}

		//update child IDs
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
		{
			xChildLIF()->RecalculateID();
		}
	}
}

void Tools_GUIMenu_Root::UpdateReferencesRecursive(Asura_Hash_ID uOldID,Asura_Hash_ID uNewID,bool bPostCopy)
{
	if(uOldID == 0)	return;
	
	
	//update this
	UpdateReferences(uOldID,uNewID,bPostCopy);
	//and the children
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->UpdateReferencesRecursive(uOldID,uNewID,bPostCopy);
	}
}

void Tools_GUIMenu_Root::UpdateReferences(Asura_Hash_ID uOldID,Asura_Hash_ID uNewID,bool bPostCopy)
{
	if(!m_pxAsuraRoot) return;

	if(!bPostCopy)
	{
		if(m_pxAsuraRoot->GetStyleObjectHash() == uOldID)
		{
			Asura_Assert(uNewID,"Not expecting style object hash to be set to zero via UpdateReferences()");
			if(uNewID != 0)
			{
				m_pxAsuraRoot->SetStyleObjectHash(uNewID);
				SetModified();
			}
		}
	}

	if(bPostCopy)
	{
		Asura_GUIMenu_ConditionVarManager &xDisplayConditions = m_pxAsuraRoot->m_xDisplayConditions;
		if( xDisplayConditions.m_pxConditionVars == NULL )
		{
			return;
		}

		const u_int uDisplayConditionCount = xDisplayConditions.m_uNumConditionVars;
		for( u_int uDisplayCondition = 0; uDisplayCondition < uDisplayConditionCount; uDisplayCondition++ )
		{
			Asura_GUIMenu_ConditionVar* pxConditionVar = &xDisplayConditions.m_pxConditionVars[ uDisplayCondition ];

			const bool bNotWidget = Asura_GUIMenu_ConditionVar::IsNotWidgetHashConsoleVar( (int)pxConditionVar );
			if( bNotWidget )
			{
				// not a widget display condition
				continue;
			}

			const char* const szValue	= pxConditionVar->GetValue();
			Asura_Hash_ID uWidgetHash	= 0;
			 Asura_StringUtil::GetIntValue( szValue,(int*)&uWidgetHash );
			if( uWidgetHash == uOldID )
			{
				char szNewID[ 32 ];
				Asura_PrintfToBfr( szNewID, "%d", sizeof( szNewID ), true, (int)uNewID );

				pxConditionVar->SetValue( szNewID );
				SetModified();
			}
		}
	}
}

void Tools_GUIMenu_Root::UpdateWidgetReferencesRecursive( Asura_Hash_ID uOldID, Asura_Hash_ID uNewID, const char* const szNewID )
{
	if( uOldID == 0 )
	{
		return;
	}
	//update this
	UpdateWidgetReferences( uOldID, uNewID, szNewID );
	//and the children
	for( LIF<Tools_GUIMenu_Root*> xChildLIF( &m_xChildren ); !xChildLIF.done(); xChildLIF.next() )
	{
		xChildLIF()->UpdateWidgetReferencesRecursive( uOldID, uNewID, szNewID );
	}

}

void Tools_GUIMenu_Root::UpdateWidgetReferences( Asura_Hash_ID uOldID, Asura_Hash_ID uNewID, const char* const szNewID )
{
	Asura_GUIMenu_Root* const pxRoot = GetAsuraData();
	if( pxRoot == NULL )
	{
		return;
	}

	Asura_GUIMenu_ConditionVarManager &xDisplayConditions = pxRoot->m_xDisplayConditions;
	if( xDisplayConditions.m_pxConditionVars == NULL )
	{
		return;
	}

	const u_int uDisplayConditionCount = xDisplayConditions.m_uNumConditionVars;
	for( u_int uDisplayCondition = 0; uDisplayCondition < uDisplayConditionCount; uDisplayCondition++ )
	{
		Asura_GUIMenu_ConditionVar* pxConditionVar = &xDisplayConditions.m_pxConditionVars[ uDisplayCondition ];

		const bool bNotWidget = Asura_GUIMenu_ConditionVar::IsNotWidgetHashConsoleVar( (int)pxConditionVar );
		if( bNotWidget )
		{
			// not a widget display condition
			continue;
		}

		const char* const szValue	= pxConditionVar->GetValue();
		Asura_Hash_ID uWidgetHash	= 0;
		Asura_StringUtil::GetIntValue( szValue,(int*)&uWidgetHash );
		if( uWidgetHash == uOldID )
		{
			pxConditionVar->SetValue( szNewID );
			SetModified();
		}
	}
}

void Tools_GUIMenu_Root::UpdateAfterParentDrag(const Asura_Bounding_Rectangle& xOldParentRect,const Asura_Bounding_Rectangle& xNewParentRect,u_int uDragFlags,bool bUsePreDragRect)
{
	// NY - 27 August 2008 - this could do with a cleanup - it's written as if menu items use worldspace coords, which they don't
	// this leads to oddness like taking old position relative to parent's new position - the child moves with it's parent *anyway*, since it's pos is relative to it

	if(!m_pxToolsParent) return;

	Asura_Bounding_Rectangle xCurRect = GetRectangle();
	Asura_Bounding_Rectangle xOldRect = xCurRect;
	if (bUsePreDragRect)
	{
		GetPreDragState(xOldRect);
	}
	Asura_Bounding_Rectangle xNewRect = xOldRect;

	if(uDragFlags & TOOLS_MENUS_DRAG_MOVE)
	{
		// NY - 27 August 2008 - no change required to handle this
	}

	if(Tools_Mode_GUIMenu::ShouldResizeChildrenWithParent())
	{
		//scale along with the parent	

		if(uDragFlags & (TOOLS_MENUS_DRAG_MINX|TOOLS_MENUS_DRAG_MAXX))
		{
			//stretch/shrink in X axis
			float fOldParentWidth = xOldParentRect.GetWidth();
			float fNewParentWidth = xNewParentRect.GetWidth();

			if(fOldParentWidth)
			{
				//get proportion of MinX in old parent rect
				float fMinXProp = (xNewRect.MinX - xNewParentRect.MinX)/fOldParentWidth;// see comment at top of func

				//and set so that the same proportion is used in the new rect
				xNewRect.MinX = (fMinXProp * fNewParentWidth) + xNewParentRect.MinX;

				//and the same for MaxX
				float fMaxXProp = (xNewRect.MaxX - xNewParentRect.MinX)/fOldParentWidth;// see comment at top of func
				xNewRect.MaxX = (fMaxXProp * fNewParentWidth) + xNewParentRect.MinX;
			}
		}

		if(uDragFlags & (TOOLS_MENUS_DRAG_MINY|TOOLS_MENUS_DRAG_MAXY))
		{
			//stretch/shrink in Y axis
			float fOldParentHeight = xOldParentRect.GetHeight();
			float fNewParentHeight = xNewParentRect.GetHeight();

			if(fOldParentHeight)
			{
				float fMinYProp = (xNewRect.MinY - xNewParentRect.MinY)/fOldParentHeight;// see comment at top of func
				xNewRect.MinY = (fMinYProp * fNewParentHeight) + xNewParentRect.MinY;

				float fMaxYProp = (xNewRect.MaxY - xNewParentRect.MinY)/fOldParentHeight;// see comment at top of func
				xNewRect.MaxY = (fMaxYProp * fNewParentHeight) + xNewParentRect.MinY;
			}
		}
	}
	else
	{
		if ((uDragFlags & TOOLS_MENUS_DRAG_MINX) != 0)
		{
			float fDeltaX = xNewParentRect.MinX - xOldParentRect.MinX;

			xNewRect.MinX -= fDeltaX;
			xNewRect.MaxX -= fDeltaX;
		}
		if ((uDragFlags & TOOLS_MENUS_DRAG_MINY) != 0)
		{
			float fDeltaY = xNewParentRect.MinY - xOldParentRect.MinY;

			xNewRect.MinY -= fDeltaY;
			xNewRect.MaxY -= fDeltaY;
		}
	}
	
	//may need to clamp to parent rect , especially if not resizing with the parent
	if(ClampToParent())
	{
		ClampToParentRect(xNewRect,uDragFlags);
	}

	if(xCurRect.MinX != xNewRect.MinX || xCurRect.MaxX != xNewRect.MaxX || xCurRect.MinY != xNewRect.MinY || xCurRect.MaxY != xNewRect.MaxY)
	{
		//update with the new rectangle
		LogUndo_Rectangle(xNewRect);
		SetRectangle(xNewRect);

		//update children as well
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
		{
			xChildLIF()->UpdateAfterParentDrag(xOldRect,xNewRect,uDragFlags,bUsePreDragRect);
		}
	}

	// update tools on-screen rectangle
	CalculateExtents();
}

bool Tools_GUIMenu_Root::CanMoveToFront()
{
	if(IsFakeMenuItem()) return false;
	return static_cast<int>(GetIndexInParent()) < m_pxToolsParent->m_xChildren.size()-1;

}

void Tools_GUIMenu_Root::MoveForwards()
{
	if(!CanMoveToFront()) return;
	u_int uIndex = GetIndexInParent();
	SetIndexInParent(uIndex+1);
	SetModified();
}

void Tools_GUIMenu_Root::MoveToFront()
{
	if(!CanMoveToFront()) return;
	SetIndexInParent(m_pxToolsParent->m_xChildren.size()-1);
	SetModified();
}



bool Tools_GUIMenu_Root::CanMoveToBack()
{
	if(IsFakeMenuItem()) return false;
	return GetIndexInParent() > 0;

}

void Tools_GUIMenu_Root::CenterWithinParent()
{
	// reposition the object s.t. its center has the same world-space 
	// coordinates as its parent's center - NDB

	if( GetAsuraData() && GetAsuraData()->GetParentObject() )
	{
		Asura_Vector_2 xPosition( GetAsuraData()->GetParentObject()->GetUnscaledLocalBounds().GetDimension() - GetAsuraData()->GetUnscaledLocalBounds().GetDimension() );

		xPosition.x *= 0.5f;
		xPosition.y *= 0.5f;

		GetAsuraData()->SetUnscaledLocalPos( xPosition );
	}
}

void Tools_GUIMenu_Root::MoveBackwards()
{
	if(!CanMoveToBack()) return;

	u_int uIndex = GetIndexInParent();
	if(uIndex)
	{
		SetIndexInParent(uIndex-1);
	}
	SetModified();
}

void Tools_GUIMenu_Root::MoveToBack()
{
	if(!CanMoveToBack()) return;
	SetIndexInParent(0);
	SetModified();
}


u_int Tools_GUIMenu_Root::GetIndexInParent() const
{
	u_int uIndex = 0;
	for(CLIF<Tools_GUIMenu_Root*> xChildLIF(&m_pxToolsParent->m_xChildren);!xChildLIF.done();xChildLIF.next(),uIndex++)
	{
		if(xChildLIF() == this) return uIndex;
	}

	Asura_Assert(0,"Failed to find in parent list");
	return 0;
}

void Tools_GUIMenu_Root::SetIndexInParent(u_int uIndex,bool bUpdateAsuraAndTree)
{
	Asura_Assert(m_pxToolsParent,"");

	uIndex = Asura_Maths::ClampToRange(uIndex,0u,(u_int)(m_pxToolsParent->m_xChildren.size()-1));
	
	//remove from the parent's list
	m_pxToolsParent->m_xChildren.delete_entry(this);

	//and re-insert at the desired index
	if(uIndex == (u_int)m_pxToolsParent->m_xChildren.size())
	{
		m_pxToolsParent->m_xChildren.add_entry(this);
	}
	else
	{
		m_pxToolsParent->m_xChildren.add_entry_before(this,m_pxToolsParent->m_xChildren[uIndex]);
	}

	if(bUpdateAsuraAndTree)	m_pxToolsParent->UpdateChildOrderInAsuraDataAndTree();
}

void Tools_GUIMenu_Root::UpdateChildOrderInAsuraDataAndTree()
{
	bool bRecreateOverlay = false;

	if(IsFile())
	{
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
		{
			//remove and then add each menu to get them in the right order

			Asura_Assert(xChildLIF()->GetAsuraData()->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE, "incorrect cast");

			Asura_GUIMenu_System::RemoveFromMenuList(static_cast<Asura_GUIMenu_Menu_Page*>(xChildLIF()->GetAsuraData()));
			Asura_GUIMenu_System::AddToMenuList(static_cast<Asura_GUIMenu_Menu_Page*>(xChildLIF()->GetAsuraData()));
		}

	}
	else
	{
		//Directly reorder the children in Asura_GUIMenu_Root to prevent side effects from being triggered
		//as a result of removing and adding them again. (Fixes bug with list box population functions being lost).
		//RAR 26/06/2008
		// NY - 08 September 2008 - reworked to cope with tools-only children (some items
		u_int uCommonChildren = 0;
		Asura_GUIMenu_Root** apxCommonChildren = new Asura_GUIMenu_Root*[m_xChildren.size()];
		for(int i=0; i<m_xChildren.size(); i++)
		{
			for (u_int u = 0; u < m_pxAsuraRoot->m_usContainerPartsCount; ++u)
			{
				if (m_pxAsuraRoot->m_ppxContainerParts[u] == m_xChildren[i]->m_pxAsuraRoot)
				{
					apxCommonChildren[uCommonChildren] = m_xChildren[i]->m_pxAsuraRoot;
					++uCommonChildren;
					break;
				}
			}
		}
		Asura_Assert(uCommonChildren == m_pxAsuraRoot->m_usContainerPartsCount, "Number of children in tools data doesn't match that in the asura data.");
		if(uCommonChildren == m_pxAsuraRoot->m_usContainerPartsCount)
		{
			for (u_int u = 0; u < uCommonChildren; ++u)
			{
				m_pxAsuraRoot->m_ppxContainerParts[u] = apxCommonChildren[u];
			}
		}
		delete [] apxCommonChildren;
	}
	
	//update the treeview as well
	Tools_Mode_GUIMenu::GetInstance()->UpdateChildOrderOnTree(this);

	// re-create the overlay of the selected child
	if( bRecreateOverlay )
	{
		Tools_Mode_GUIMenu::GetSelectedItem()->CreateOverlay();
	}	
}

int Tools_GUIMenu_Root::GetType() const
{
	return m_pxAsuraRoot ? m_pxAsuraRoot->GetType() : Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_NONE;
}


void Tools_GUIMenu_Root::Copy(const Tools_GUIMenu_Root* pxSource,u_int uCopyFlags)
{
	//use the virtual function for doing most of the copying
	Copy(pxSource);

	//delete the animators copied via Asura_GUIMenu_Root::Copy() since that may
	//have copied more than is wanted
	//RAR 13/06/2008
	if(m_pxAsuraRoot)
	{
		while(m_pxAsuraRoot->GetAnimatorCount()) m_pxAsuraRoot->DeleteAnimator(0);
	}
	
	//copy animators
	//Don't copy animators when doing a copy as part of applying a style , since that will be done when
	//updating from the style instead.
	//RAR 29/06/2007
	if( m_pxAsuraRoot && !(uCopyFlags & TOOLS_MENUS_COPY_STYLE))
	{
		const Asura_GUIMenu_Root* pxAsuraSource = (pxSource->m_pxAsuraRoot);
		for(u_int i=0;i<pxAsuraSource->GetAnimatorCount();i++)
		{
			const Asura_GUIMenu_Animator* pxSourceAnimator = pxAsuraSource->GetAnimator(i);

			//ignore animators that come from a style , since they will be created as needed when updating from the style
			if(pxSourceAnimator->IsGeneratedByStyle()) continue;

			Asura_GUIMenu_Animator* pxDestAnimator = m_pxAsuraRoot->AddAnimator(pxSourceAnimator->GetSequenceName());

			if(pxDestAnimator)
			{
				*pxDestAnimator = *pxSourceAnimator;
			}
		}
	}

	if(uCopyFlags & TOOLS_MENUS_COPY_STYLE)
	{
		//This copy operation is part of applying a style
		if(uCopyFlags & TOOLS_MENUS_COPY_STYLEINSTANCE)
		{
			SetStyleInstance(true);		
		}
		else
		{
			SetGeneratedByStyle(true);		
		}

		//Set the destination to use the source as its inherited object
		SetStyleItem(pxSource);
	}
	else if(pxSource->IsStyleInstance())
	{
		//Doing a standard copy operation, but the source is using a style.
		//So apply that style to this
		ApplyStyle(pxSource->m_pxAsuraRoot->GetStyleObjectHash(),true);
	}
	else if((uCopyFlags & TOOLS_MENUS_COPY_COPYSTYLEHASH) && pxSource->m_pxAsuraRoot->GetStyleObjectHash())
	{
		//If we get here ,then we are in the process of copying a child of an item that is using a style.
		//Apply the style hash now ,so that when ApplyStyle() is finally applied to the parent , it will
		//be able to find the child members correctly.
		//RAR 15/03/2007

		Tools_GUIMenu_Root* pxStyleItem = Tools_Mode_GUIMenu::GetInstance()->FindItemByID(pxSource->m_pxAsuraRoot->GetStyleObjectHash());
		if(pxStyleItem)
		{
			SetGeneratedByStyle(pxSource->IsGeneratedByStyle());
			SetStyleItem(pxStyleItem);
		}

	}

	//Copy the child editable flags , unless in the process of applying a style
	if(!(uCopyFlags & (TOOLS_MENUS_COPY_STYLE|TOOLS_MENUS_COPY_COPYSTYLEHASH)))
	{
		m_uStyleChildEditableDataFlags = pxSource->m_uStyleChildEditableDataFlags;
		m_pxAsuraRoot->SetStyleChildEditableDataFlags(m_uStyleChildEditableDataFlags);	
	}
}


void Tools_GUIMenu_Root::Copy(const Tools_GUIMenu_Root* pxSource)
{
	//copy tools data
	m_uFlags = pxSource->m_uFlags;
	m_xColour = pxSource->m_xColour;
	m_fW = pxSource->m_fW;
	m_fH = pxSource->m_fH;
	m_iTranslucencyMode = pxSource->m_iTranslucencyMode;

	//not all of the tools flags should be copied
	static const u_int uToolsFlagsToPreserve = (ASURA_GUIMENU_TOOLS_FLAG_ISSTYLE|ASURA_GUIMENU_TOOLS_FLAG_GENERATEDBYSTYLE|ASURA_GUIMENU_TOOLS_FLAG_STYLEINSTANCE|ASURA_GUIMENU_TOOLS_FLAG_STYLECONTAINER);
	m_uToolsFlags &= uToolsFlagsToPreserve;
	m_uToolsFlags |= (pxSource->m_uToolsFlags & ~uToolsFlagsToPreserve);

	//copy asura data
	m_pxAsuraRoot->Copy( pxSource->m_pxAsuraRoot );

	//set the tools flags to the ones we wanted
	m_pxAsuraRoot->SetToolsFlags( m_uToolsFlags );
}


int Tools_GUIMenu_Root::FindTranslucencyDropListIndex( void)
{
	u_int i;
	int iRetVal = -1;
	
	if( m_pxAsuraRoot )
	{
		ASURA_TRANSLUCENCY_MODE eTransMode = m_pxAsuraRoot->GetTranslucencyMode();
	
		for( i=0; i<g_uNumTranslucencyModes; i++)
		{
			if( g_axTranslucencyModes[i].m_eMode == eTransMode)
			{
				iRetVal = i;
				break;
			}
		}
	}
	return iRetVal;
}

void Tools_GUIMenu_Root::CheckRequiredReferencesRecursive()
{
	CheckRequiredReferences();

	//check children as well
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->CheckRequiredReferencesRecursive();
	}
}

Tools_GUIMenu_Root* Tools_GUIMenu_Root::FindByID(Asura_Hash_ID uID)
{
	
	#if 0
	//check this
	if(m_pxAsuraRoot && m_pxAsuraRoot->GetID() == uID) return this;

	//and the children
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		Tools_GUIMenu_Root* pxItem = xChildLIF()->FindByID(uID);
		if(pxItem) return pxItem;
	}
	return 0;
	#else

	Tools_GUIMenu_Root** ppxExisting = s_xHashTree.GetDataByHash(uID);
	if(!ppxExisting)
	{
		return 0;
	}

	Asura_Assert((*ppxExisting)->GetAsuraData()->GetID() == uID,"GUImenu ID differs in tools data from asura data");
	return *ppxExisting;
	#endif

}

void Tools_GUIMenu_Root::PostMenuPreviewCleanupRecursive()
{
	if(m_pxAsuraRoot) m_pxAsuraRoot->PostMenuPreviewCleanup();

	//check children as well
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->PostMenuPreviewCleanupRecursive();
	}
}

const char* Tools_GUIMenu_Root::GetLocalDataFlagName(u_int uFlagValue) const
{
	switch(uFlagValue)
	{
		case Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_POSITION :
			return "Position";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_COLOUR :
			return "Colour";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_DISPLAY_CONDITIONS :
			return "Display Conditions";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_TRANSLUCENCY :
			return "Translucency";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_FLAGS :
			return "Flags";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_ANCHOR :
			return "Position / Anchoring modes";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_SCALING :
			return "Scaling";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_PLATFORMS :
			return "Platforms";
			break;

		default :
			return 0;

	}
}

// returns whether this object supports e.g. position, or UVs etc.
bool Tools_GUIMenu_Root::IsModifierTypeSupported( ASURA_GUIMENU_MODIFY_TYPE eType ) const
{
	switch (eType)
	{
	case ASURA_GUIMENU_MODIFY_POSITION:
	case ASURA_GUIMENU_MODIFY_COLOUR:
	case ASURA_GUIMENU_MODIFY_TRANSLUCENCY_MODE:
	case ASURA_GUIMENU_MODIFY_ALPHA_SCALED:
	case ASURA_GUIMENU_MODIFY_POSITION_RELATIVE:
		return true;
	default:
		return false;
	}
}


bool Tools_GUIMenu_Root::IsStyle() const
{
	if(!m_pxAsuraRoot) return false;

	return (m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_ISSTYLE) ? true : false;
}

bool Tools_GUIMenu_Root::IsStyleContainer() const
{
	if(!m_pxAsuraRoot) return false;

	return (m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_STYLECONTAINER) ? true : false;
}

bool Tools_GUIMenu_Root::IsStyleMember() const
{
	for(const Tools_GUIMenu_Root* pxItem = this;pxItem;pxItem = pxItem->m_pxToolsParent)
	{
		if(pxItem->IsStyle()) return true;
	}
	return false;
}


void Tools_GUIMenu_Root::SetGeneratedByStyle(bool bSet)
{
	if(!m_pxAsuraRoot) return;

	if(bSet)
	{
		m_uToolsFlags |= ASURA_GUIMENU_TOOLS_FLAG_GENERATEDBYSTYLE;
	}
	else
	{
		m_uToolsFlags &=~ ASURA_GUIMENU_TOOLS_FLAG_GENERATEDBYSTYLE;
	}
	m_bChanged = true;
}

bool Tools_GUIMenu_Root::IsGeneratedByStyle() const
{
	if(!m_pxAsuraRoot) return false;

	return (m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_GENERATEDBYSTYLE) ? true : false;
}

void Tools_GUIMenu_Root::SetStyleInstance(bool bSet)
{
	if(!m_pxAsuraRoot) return;

	if(bSet)
	{
		m_uToolsFlags |= ASURA_GUIMENU_TOOLS_FLAG_STYLEINSTANCE;
	}
	else
	{
		m_uToolsFlags &=~ ASURA_GUIMENU_TOOLS_FLAG_STYLEINSTANCE;
	}
	m_bChanged = true;
}

bool Tools_GUIMenu_Root::IsStyleInstance() const
{
	if(!m_pxAsuraRoot) return false;

	return (m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_STYLEINSTANCE) ? true : false;
}


void Tools_GUIMenu_Root::UpdateStyleInstances(Asura_Hash_ID uStyleID /*= 0*/)
{
	if(m_pxAsuraRoot && IsStyleInstance())
	{
		//Is this using a style?
		Asura_Hash_ID uInheritedID = m_pxAsuraRoot->GetStyleObjectHash();

		if(uInheritedID && (uInheritedID == uStyleID || uStyleID == 0))
		{
			//Find the tools item for the style
			Tools_GUIMenu_Root* pxStyleItem = Tools_Mode_GUIMenu::GetInstance()->FindItemByID(uInheritedID);

			if(pxStyleItem)
			{
				//Make sure the types match
				if(pxStyleItem->GetType() != GetType())
				{
					//Completely the wrong type , probably safest just to remove the style completely
					DivorceFromStyle(true);
				}
				else
				{
					UpdateFromStyle(pxStyleItem);
				}
			}
		}
	}

	//check children
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->UpdateStyleInstances(uStyleID);
	}
}

void Tools_GUIMenu_Root::UpdateFromStyle(const Tools_GUIMenu_Root* pxStyleItem)
{
	Asura_Assert(m_pxAsuraRoot,"");

	//update inheritence flags
	SetStyleItem(pxStyleItem);

	Asura_Bounding_Rectangle xOldRect = GetRectangle();

	// SK 05.03.07 - not sure if this should be here but it seems like it the most logical place.
	// -- This tells the engine object to update it's settings from the master style assigned to it.
	m_pxAsuraRoot->UpdateLocalDataFromStyle();
	
	//Refresh data from the asura item
	CopyFromAsura();

	//check style children
	for(CLIF<Tools_GUIMenu_Root*> xStyleChildLIF(&pxStyleItem->m_xChildren);!xStyleChildLIF.done();xStyleChildLIF.next())
	{
		const Tools_GUIMenu_Root* pxStyleChild = xStyleChildLIF();
		//See if the equivalent item already exists
		Tools_GUIMenu_Root* pxChild = 0;
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
		{
			if(xChildLIF()->m_pxAsuraRoot->GetStyleObjectHash() == pxStyleChild->m_pxAsuraRoot->GetID())
			{
				pxChild = xChildLIF();
				break;
			}
		}


		if(pxChild)
		{
			//confirm that the matching child is of the right type
			if(pxChild->GetType() != pxStyleChild->GetType())
			{
				pxChild->Destroy();
				pxChild = 0;
			}
		}
		
		if(!pxChild)
		{
			//Child doesn't exist yet , so create it by copying
			pxChild = Tools_Mode_GUIMenu::GetInstance()->CreateCopy(this,pxStyleChild,TOOLS_MENUS_COPY_STYLE);
		}

		if(pxChild)
		{
			//Force the generated by style flag to be on here , to fix an error with the flags that is creeping
			//in somewhere. Should be safe since it has already been determined that the child item has the correct
			//style hash.
			//RAR 28/01/2009
			if(!pxChild->IsGeneratedByStyle())
			{
				pxChild->SetGeneratedByStyle(true);
			}
			pxChild->UpdateFromStyle(pxStyleChild);
		}
	}
	//Check for any automatically generated children that are no longer wanted
	List<Tools_GUIMenu_Root*> xDeleteList;

	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		if(!xChildLIF()->IsGeneratedByStyle()) continue;

		bool bKeep = false;
		for(CLIF<Tools_GUIMenu_Root*> xStyleChildLIF(&pxStyleItem->m_xChildren);!xStyleChildLIF.done();xStyleChildLIF.next())
		{
			if(xChildLIF()->m_pxAsuraRoot->GetStyleObjectHash() == xStyleChildLIF()->m_pxAsuraRoot->GetID())
			{
				bKeep = true;
				break;
			}
		}

		if(!bKeep)
		{		
			xDeleteList.add_entry(xChildLIF());
		}
	}

	//delete the children marked for deletion
	for(LIF<Tools_GUIMenu_Root*> xDeleteLIF(&xDeleteList);!xDeleteLIF.done();xDeleteLIF.next())
	{
		xDeleteLIF()->Destroy();
		SetModified();
	}

	//sort the generated children so that they are in the same order relative to each other as in the style
	int iPreviousIndex = -1;
	bool bOrderChanged = false;
	for(CLIF<Tools_GUIMenu_Root*> xStyleChildLIF(&pxStyleItem->m_xChildren);!xStyleChildLIF.done();xStyleChildLIF.next())
	{
		const Tools_GUIMenu_Root* pxStyleChild = xStyleChildLIF();
		//find the matching item
		Tools_GUIMenu_Root* pxChild = 0;
		int iCurrentIndex = 0;
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next(),iCurrentIndex++)
		{
			if(xChildLIF()->m_pxAsuraRoot->GetStyleObjectHash() == pxStyleChild->m_pxAsuraRoot->GetID())
			{
				pxChild = xChildLIF();
				break;
			}
		}

		if(pxChild)
		{
			//If the instance of this item is earlier than the instance of the previous one , then move it
			//to be just after the previous.
			//(which is done by giving it the same index as the previous).
			if(iCurrentIndex < iPreviousIndex)
			{
				pxChild->SetIndexInParent(iPreviousIndex,false);
				iCurrentIndex = iPreviousIndex;
				bOrderChanged = true;
			}
			iPreviousIndex = iCurrentIndex;
		}
	}
	if(bOrderChanged) UpdateChildOrderInAsuraDataAndTree();

	CalculateExtents();

	//If the update from style is causing the rectangle to change ,then log the change for undo
	//RAR 20/09/2007
	Asura_Bounding_Rectangle xNewRect = GetRectangle();
	if(xOldRect != xNewRect)
	{
		Tools_Mode_GUIMenu::LogUndo_Rectangle(this,xOldRect);
	}

	RecreateOverlay();
}

void Tools_GUIMenu_Root::DivorceFromStyle(bool bFirst)
{
	//unflag this as using the style
	if(bFirst)
	{
		m_uToolsFlags &=~ ASURA_GUIMENU_TOOLS_FLAG_STYLEINSTANCE;
	}
	else
	{
		if(!(m_uToolsFlags & ASURA_GUIMENU_TOOLS_FLAG_GENERATEDBYSTYLE))
		{
			return;
		}
		//unflag this as being generated by a style
		m_uToolsFlags &=~ASURA_GUIMENU_TOOLS_FLAG_GENERATEDBYSTYLE;
	}
	m_pxAsuraRoot->SetToolsFlags(m_uToolsFlags);

	//unflag animators as belonging to styles
	for(u_int i=0; i<m_pxAsuraRoot->GetAnimatorCount(); i++)
	{
		m_pxAsuraRoot->GetAnimator(i)->SetGeneratedByStyle(false);
	}
	

// SK 02.03.07 - Replacement for new method call.
	m_pxAsuraRoot->SetStyleObject(0);

//	m_pxAsuraRoot->SetInheritedObject(0);

	//and unflag the children as being generated by the style
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->DivorceFromStyle(false);
	}

	SetModified();
}	

void Tools_GUIMenu_Root::SetStyleItem(const Tools_GUIMenu_Root* pxStyleItem)
{
	if(!m_pxAsuraRoot) return;

	//only expecting this to be done on an item that has already been marked as a style instance ,or generated by a style
	if(!(m_uToolsFlags & (ASURA_GUIMENU_TOOLS_FLAG_GENERATEDBYSTYLE|ASURA_GUIMENU_TOOLS_FLAG_STYLEINSTANCE)))
	{
		Asura_Assert(0,"Not expecting this function to be called on menu items that haven't been marked as part of a style instance");
		return;
	}

	Asura_Assert(pxStyleItem->GetType() == GetType(),"");

// SK 02.03.07 - Replacement for new method call.
//	m_pxAsuraRoot->SetInheritedObject(const_cast<Asura_GUIMenu_Root*>(pxStyleItem->GetAsuraData()));
//	m_pxAsuraRoot->SetInheritanceUseLocalDataFlags(pxStyleItem->m_uStyleUseLocalDataFlags);
	m_pxAsuraRoot->SetStyleObject(const_cast<Asura_GUIMenu_Root*>(pxStyleItem->GetAsuraData()));
	m_pxAsuraRoot->SetStyleUseLocalDataFlags(pxStyleItem->m_uStyleChildEditableDataFlags);

}

void Tools_GUIMenu_Root::SetModified()
{
	
	if(m_pxAsuraRoot && IsStyle())
	{
		//Style has been modified , let the tools mode know , so it can do an update on it next frame
		Tools_Mode_GUIMenu::FlagStyleForUpdate(m_pxAsuraRoot->GetID());
	}

	if(m_pxToolsParent) m_pxToolsParent->SetModified();
}

bool Tools_GUIMenu_Root::CanEditStyleFlags()
{
	return IsStyleMember();
}

const char* Tools_GUIMenu_Root::GetTypeName() const
{
	if(!m_pxAsuraRoot) return 0;

	return Tools_Mode_GUIMenu::GetInstance()->GetMenuItemTypeName(GetType());
}

void Tools_GUIMenu_Root::GetNameForTree(char* szOutput,int iBufferLength) const
{
	const char* szName = GetName();

	if(m_pxAsuraRoot && GetType() != Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE)
	{

		//If the name doesn't contain the type name , then tack on an abbreviateed version
		const char* szTypeName = GetTypeName();
		const char* szShortTypeName = Tools_Mode_GUIMenu::GetInstance()->GetShortMenuItemTypeName(GetType());

		if(szTypeName && szShortTypeName)
		{
			if(!strstr(szName,szTypeName))
			{
				//Add the shortened type name on to the end
				Asura_PrintfToBfr(szOutput,"%s (%s)",iBufferLength,true,szName,szShortTypeName);
				return;
			}
		}
	}

	Asura_PrintfToBfr(szOutput,"%s",iBufferLength,true,szName);
}

void Tools_GUIMenu_Root::ApplyStyle(Asura_Hash_ID uStyleID, bool bKeepChildren)
{
	//make sure the proposed item is a style
	Tools_GUIMenu_Root* pxStyleItem = Tools_Mode_GUIMenu::GetInstance()->FindItemByID(uStyleID);
	if(!pxStyleItem || !pxStyleItem->IsStyle()) return;

	//Can't apply styles to automatically generated elements
	if(IsGeneratedByStyle()) return;

	//Item must have a matching type
	if(GetType() !=  pxStyleItem->GetType()) return;

	//Make sure this won't result in recursive style inclusion
	Tools_GUIMenu_Root* pxItem = pxStyleItem;
	while(pxItem)
	{
		if(pxItem == this) return;//style is using this item , so can't apply it
		
		if(pxItem->IsStyleInstance())
		{
			// SK 02.03.07 - Replaced original call with new method.
//			pxItem = Tools_Mode_GUIMenu::GetInstance()->FindItemByID(pxItem->GetInheritedObjectHash());
			pxItem = Tools_Mode_GUIMenu::GetInstance()->FindItemByID(pxItem->GetStyleObjectHash());
		}		
		else
		{
			pxItem = 0;
		}
	}

	//some data gets preserved for use after the style is applied.
	//currently this is just for keeping text IDs, but a more generalised system may be needed if
	//other data needs to be kept. RAR 01/05/2007
	bool bPreservedText = false;
	Asura_Hash_ID uPreservedTextID = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID uPreservedTextPage = ASURA_HASH_ID_UNSET;
	if(!IsMenu())
	{
		bPreservedText = GetTextToPreserve(uPreservedTextID, uPreservedTextPage);
	}

	if(!bKeepChildren)
	{
		//For menus delete any children that were generated by a style
		//For widgets (and I guess elements) kill of all existing children.
		for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();)
		{
			//get child , and move iterator on , since the entry will be removed from the list by deletion
			Tools_GUIMenu_Root* pxChild = xChildLIF();
			xChildLIF.next();

			if(pxChild->IsGeneratedByStyle() || !IsMenu())
			{
				if(IsMenu() && !bPreservedText)
				{
					pxChild->GetTextToPreserve(uPreservedTextID, uPreservedTextPage);
				}
				pxChild->Destroy();
			}
		}
	}
	

	//flag as using the new style
	SetStyleInstance(true);
	SetStyleItem(pxStyleItem);

	//Do an update to generate the children
	UpdateFromStyle(pxStyleItem);

	if(bPreservedText)
	{
		//put back the text that was kept
		ApplyPreservedText(uPreservedTextID, uPreservedTextPage);
	}
}

// SK 02.03.07 - added to account for separate style functionality in engine code
Asura_Hash_ID Tools_GUIMenu_Root::GetStyleObjectHash() const
{
	return m_pxAsuraRoot ? m_pxAsuraRoot->GetStyleObjectHash() : 0;
}




bool Tools_GUIMenu_Root::CanRemoveStyle()
{
	return IsStyleInstance();
}

void Tools_GUIMenu_Root::RemoveStyle()
{
	if(IsStyleInstance())
	{
		DivorceFromStyle(true);
		UpdateOverlay();
	}
}

bool Tools_GUIMenu_Root::CanSelectStyleMaster()
{
	return IsStyleInstance() || IsGeneratedByStyle();
}

void Tools_GUIMenu_Root::SelectStyleMaster()
{
	if(m_pxAsuraRoot && IsStyleInstance() || IsGeneratedByStyle())
	{
		//save this item so that it can be reselected using F12
		Tools_Mode_GUIMenu::GetInstance()->SaveSelectionToHotkey(11,GetID());
		Tools_Mode_GUIMenu::GetInstance()->SetSelectionByID(m_pxAsuraRoot->GetStyleObjectHash());
	}													  
}

// Can edit 
bool Tools_GUIMenu_Root::CanEditColour()
{
	return ShouldStyleUseLocalDataFor(Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_COLOUR);
}

bool Tools_GUIMenu_Root::CanEditTranslucency()
{
	return ShouldStyleUseLocalDataFor(Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_TRANSLUCENCY);
}

bool Tools_GUIMenu_Root::CanEditFlags()
{
	return ShouldStyleUseLocalDataFor(Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_FLAGS);
}

bool Tools_GUIMenu_Root::CanEditAnchoring()
{
	return ShouldStyleUseLocalDataFor(Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_ANCHOR);
}

bool Tools_GUIMenu_Root::CanEditScaling()
{
	return ShouldStyleUseLocalDataFor(Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_SCALING);
}

bool Tools_GUIMenu_Root::CanEditPlatforms()
{
	return ShouldStyleUseLocalDataFor(Asura_GUIMenu_Root::ASURA_GUIMENU_ROOT_LOCAL_FLAG_PLATFORMS);
}


bool Tools_GUIMenu_Root::ShouldStyleUseLocalDataFor(u_int uFlag) const
{
	if(!m_pxAsuraRoot) return false;

	if(!m_pxAsuraRoot->GetStyleObjectHash()) return true;

	return (m_pxAsuraRoot->GetStyleUseLocalDataFlags() & uFlag) != 0;
}

bool Tools_GUIMenu_Root::ContainsStyles() const
{
	if(IsStyle()) return true;

	//check the children
	for(CLIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		if(xChildLIF()->ContainsStyles()) return true;
	}
	return false;
}

bool Tools_GUIMenu_Root::CanBeStyle()
{
	//The parent menu page must be a style container
	return GetMenuPage()->IsStyleContainer();
}

void Tools_GUIMenu_Root::AddToPreviewOverlayRecursive() const
{
	AddToPreviewOverlay();
	for(CLIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->AddToPreviewOverlayRecursive();
	}
}

void Tools_GUIMenu_Root::AddToPreviewOverlay() const
{
	if(!m_pxAsuraRoot) return;

	// iterate over condition vars
	for(u_int i=0;i<m_pxAsuraRoot->m_xDisplayConditions.m_uNumConditionVars;i++)
	{
		if(!m_pxAsuraRoot->m_xDisplayConditions.m_pxConditionVars[i].IsVarBlank())
		{
			Tools_GUIMenu_PreviewOverlay::RegisterConsoleVariable(m_pxAsuraRoot->m_xDisplayConditions.m_pxConditionVars[i].GetName().GetString(),Asura_CommandConsole_VarRepository::Var::TYPE_INVALID);
		}
		else if (!m_pxAsuraRoot->m_xDisplayConditions.m_pxConditionVars[i].IsCmdBlank())
		{
			Tools_GUIMenu_PreviewOverlay::RegisterConsoleCommand(m_pxAsuraRoot->m_xDisplayConditions.m_pxConditionVars[i].GetName().GetString());
		}
	}

	// iterate over modifier vars
	Asura_GUIMenu_Modifier*			   pxModifier(NULL);
	Asura_GUIMenu_ConditionVarManager* pxManager(NULL);

	for( u_int uModifier(0);uModifier<m_pxAsuraRoot->GetModifierCount();++uModifier )
	{
		pxModifier = m_pxAsuraRoot->GetModifier(uModifier);
		
		if( pxModifier )
		{
			pxManager = pxModifier->GetActivationConditions();
			AddToPreviewOverlay( pxManager->m_pxConditionVars,pxManager->m_pxConditionVars + pxManager->m_uNumConditionVars );
		}
	}

	// iterate over animator vars
	Asura_GUIMenu_Animator*	pxAnimator(NULL);

	for( u_int uAnimator(0);uAnimator<m_pxAsuraRoot->GetAnimatorCount();++uAnimator )
	{
		pxAnimator = m_pxAsuraRoot->GetAnimator(uAnimator);
		
		if( pxAnimator )
		{
			pxManager = pxAnimator->GetStartConditions();
			AddToPreviewOverlay( pxManager->m_pxConditionVars,pxManager->m_pxConditionVars + pxManager->m_uNumConditionVars );

			const Asura_GUIMenu_Animator_Sequence* pxSequence = NULL;

			pxSequence = pxAnimator->GetSequence();

			if ( pxSequence )
			{
				const Asura_GUIMenu_ConsoleVar xSeqVar = pxSequence->GetConsoleVar();

				if ( xSeqVar.GetHash() != ASURA_HASH_ID_UNSET )
				{
					// Add var to preview overlay
					Tools_GUIMenu_PreviewOverlay::RegisterConsoleVariable( xSeqVar.GetName().GetString(),xSeqVar.GetType() );
				}
			}
		}
	}

}

void Tools_GUIMenu_Root::AddToPreviewOverlay( Asura_GUIMenu_ConditionVar* const pxBegin,Asura_GUIMenu_ConditionVar* const pxEnd ) const
{
	for( Asura_GUIMenu_ConditionVar* pxCurrent(pxBegin);pxCurrent<pxEnd;++pxCurrent )
	{
		Tools_GUIMenu_PreviewOverlay::RegisterConsoleVariable( pxCurrent->GetName().GetString(),Asura_CommandConsole_VarRepository::Var::TYPE_INVALID );
	}
}

bool Tools_GUIMenu_Root::VerifyRecursive()
{
	bool bRes = true;

	bRes &= Verify();
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		bRes &= xChildLIF()->VerifyRecursive();
	}

	return bRes;
}

bool Tools_GUIMenu_Root::Verify()
{
	if(!m_pxAsuraRoot) return true;

	bool bRes = true;

	//check for problems with styles
	if(IsStyleInstance())
	{
		Asura_Hash_ID uStyleHash = m_pxAsuraRoot->GetStyleObjectHash();
		if(uStyleHash)
		{
			Tools_GUIMenu_Root* pxStyleItem = Tools_Mode_GUIMenu::GetInstance()->FindItemByID(uStyleHash);
			if(pxStyleItem)
			{
				if(pxStyleItem == this)
				{
					Tools_Mode_GUIMenu::AddVerifyMessage(this,"%s is using itself as a style.",GetName());
					bRes = false;
				}
				if(!pxStyleItem->IsStyle())
				{
					Tools_Mode_GUIMenu::AddVerifyMessage(this,"%s is using %s as a style , but that item isn't flagged as a stlye.",GetName(),pxStyleItem->GetName());
					bRes = false;
				}
			}
			else
			{
				Tools_Mode_GUIMenu::AddVerifyMessage(this,"%s is flagged as a style instance , but the master copy of the style couldn't be found.",GetName());
				bRes = false;
			}
		}
		else
		{
			Tools_Mode_GUIMenu::AddVerifyMessage(this,"%s is flagged as a style instance , but has no style hash value.",GetName());
			bRes = false;
		}
	}

	// Display a warning message for textlistboxes as they are being phased out.
	if ( GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_TEXTLISTBOX )
	{
		Tools_Mode_GUIMenu::AddVerifyMessage(this,"%s is a 'Text Listbox Widget' which should no longer be used. Please replace with a list box widget.",GetName());
		bRes = false;
	}

	//check for missing animators
	bool bAnyDuplicatedAnimators = false;
	for(u_int i=0;i<m_pxAsuraRoot->GetAnimatorCount();i++)
	{
		const Asura_GUIMenu_Animator* pxAnimator = m_pxAsuraRoot->GetAnimator(i);
		
		if(!pxAnimator->IsGeneratedByStyle())//Only check the original copy of the animator , to cut down on the number of errors produced
		{
			const char* szSeqName = pxAnimator->GetSequenceName();

			if(!Asura_GUIMenu_Animator_Storage::GetSequenceByHash(Asura_GetHashID(szSeqName)))
			{
				Tools_Mode_GUIMenu::AddVerifyMessage(this,"%s uses animator sequence %s , which doesn't exist.",GetName(),szSeqName);
				bRes = false;
			}
		}
		
		//check for duplicate animators
		for(u_int j=i+1;j<m_pxAsuraRoot->GetAnimatorCount() && !bAnyDuplicatedAnimators;j++)
		{
			const Asura_GUIMenu_Animator* pxAnimator2 = m_pxAsuraRoot->GetAnimator(j);
			if(!strcmp(pxAnimator->GetSequenceName(), pxAnimator2->GetSequenceName()))
			{
				Tools_Mode_GUIMenu::AddVerifyMessage(this,"%s has some duplicated animators.",GetName());
				bAnyDuplicatedAnimators = true;
				bRes = false;
			}
		}
	}

	return bRes;
}



Asura_Hash_ID Tools_GUIMenu_Root::GetID() const
{
	if(!m_pxAsuraRoot) return 0;
	Asura_Assert(m_pxAsuraRoot->GetID() == m_uID,"GUImenu ID differs in tools data from asura data");
	return m_uID;
}



static int SortFileCallback(const void* p1,const void* p2)
{
	const Tools_GUIMenu_File* pxFile1 = *(const Tools_GUIMenu_File**)p1;
	const Tools_GUIMenu_File* pxFile2 = *(const Tools_GUIMenu_File**)p2;

	//sort on sortkey first
	int iSortKey1 = pxFile1->GetSortKey();
	int iSortKey2 = pxFile2->GetSortKey();

	if(iSortKey1 < iSortKey2) return -1;
	if(iSortKey1 > iSortKey2) return 1;

	//otherwise sort on name , but put the level specific file first
	const char* szName1 = pxFile1->GetName();
	const char* szName2 = pxFile2->GetName();

	if(!stricmp(szName1,Tools_GUIMenu_System::GetLevelSpecificFile())) return -1;
	if(!stricmp(szName2,Tools_GUIMenu_System::GetLevelSpecificFile())) return 1;

	return stricmp(szName1,szName2);
}

void Tools_GUIMenu_Root::SortFiles() 
{
	if(m_pxToolsParent)
	{
		Asura_Assert(!m_pxToolsParent,"Only expecting this to be called on the root item");
		return;
	}

	//get an array of childrem
	int iNumFiles = m_xChildren.size();
	Tools_GUIMenu_Root** ppxFiles = new Tools_GUIMenu_Root*[iNumFiles];
	for(int i=0;i<iNumFiles;i++)
	{
		ppxFiles[i] = m_xChildren[i];
	}

	//sort the array
	qsort(ppxFiles,iNumFiles,sizeof(Tools_GUIMenu_Root*),SortFileCallback);

	//update the list with the new ordering
	while(m_xChildren.size()) m_xChildren.delete_first_entry();
	for(int i=0;i<iNumFiles;i++)
	{
		m_xChildren.add_entry(ppxFiles[i]);
	}
	delete [] ppxFiles;

	//update the ordering in the tree view
	Tools_Mode_GUIMenu::GetInstance()->UpdateChildOrderOnTree(this);
}

void Tools_GUIMenu_Root::AddModifier()
{
	//populate list selection overlay with the available types
	ListSelection_Overlay xOverlay("Select modifier type");

	bool bIsStyle = IsStyleMember();
	bool bIsStyleInstance = IsStyleInstance() || IsGeneratedByStyle();

	// start at 1 because 0 is the invalid value.
	for(int i = 1; i < ASURA_GUIMENU_NUM_MODIFY_TYPES; i++)
	{
		ASURA_GUIMENU_MODIFY_TYPE eModifyType = static_cast<ASURA_GUIMENU_MODIFY_TYPE>(i);
		if (!IsModifierTypeSupported(eModifyType)) continue;

		u_int uInheritanceFlag = Asura_GUIMenu_Modifier::GetCorrespondingInheritanceFlag(eModifyType);
		if(bIsStyleInstance)
		{
			//Style instances can only add modifiers for data that can be edited in them
			if(uInheritanceFlag & ~m_pxAsuraRoot->GetStyleUseLocalDataFlags()) continue;

		}
		if(bIsStyle)
		{
			//Styles should only have modifiers for the data that they control
			if(uInheritanceFlag & m_pxAsuraRoot->GetStyleChildEditableDataFlags())continue;
		}

		const char* szName = Asura_GUIMenu_Modifier::GetModifyTypeName(eModifyType);
		if(szName)
		{
			xOverlay.AddItem(szName, i);
		}
	}

	if(!xOverlay.GetNumItems())
	{
		ShowMessageOverlay("There aren't any modifiers that can be added to this menu item");
		return;
	}

	//get selection from user
	if(!xOverlay.DoModal()) return;
	ASURA_GUIMENU_MODIFY_TYPE eSelectedModifyType = static_cast<ASURA_GUIMENU_MODIFY_TYPE>(xOverlay.GetSelectionData());

	//create the modifier
	int iModifierIndex = m_pxAsuraRoot->CreateModifier(0, eSelectedModifyType);
	if(iModifierIndex<0)
	{
		ShowMessageOverlay("Failed to create the modifier. (Probably reached maximum allowed).");
		return;
	}

	InitialiseModifier(m_pxAsuraRoot->GetModifier(iModifierIndex));

	SetModified();

	//update the list on the overlay ,and select the new entry
	UpdateModifierList();
	m_iModifierIndex = iModifierIndex;

	UpdateModifierOverlayControls();
	
}

bool Tools_GUIMenu_Root::CanAddModifier()
{
// (MH - 10.04.2007) commented all this out until we add something to indicate
// whether a modifier came from a style or not.
//	//Make sure this item supports modifiers
//	u_int uModifierFlags = GetSupportedModifiers();
//	if(!uModifierFlags) return false;
//
//	//And that they aren't all disabled from being a style instance
//	if(IsStyleInstance() || IsGeneratedByStyle())
//	{
//		uModifierFlags &= m_pxAsuraRoot->GetStyleUseLocalDataFlags();
//	}
//
//	return uModifierFlags!=0;
	return true;
}

void Tools_GUIMenu_Root::DeleteModifier()
{
	if( m_iModifierIndex < static_cast<int>(m_pxAsuraRoot->GetModifierCount()) ) 
	{
		//delete the modifier from the asura data
		m_pxAsuraRoot->DeleteModifier(m_iModifierIndex);
		SetModified();

		//update the overlay to match
		UpdateModifierList();
		UpdateModifierOverlayControls();
	}
}

bool Tools_GUIMenu_Root::IsModifierSelected()
{
	return m_iModifierIndex < static_cast<int>(m_pxAsuraRoot->GetModifierCount());
}

bool Tools_GUIMenu_Root::IsEditableModifierSelected()
{
	//any modifier selected?
	if(m_iModifierIndex >= static_cast<int>(m_pxAsuraRoot->GetModifierCount()) ) return false;

	//if this is a member of style instance , then the modifiers affected by the style won't be editable
	if(!m_pxAsuraRoot->GetStyleObjectHash()) return true;

	const Asura_GUIMenu_Modifier* pxModifier = m_pxAsuraRoot->GetModifier(m_iModifierIndex);

	return (~m_pxAsuraRoot->GetStyleUseLocalDataFlags() & pxModifier->GetCorrespondingInheritanceFlag()) == 0;
}

void Tools_GUIMenu_Root::UpdateModifierList()
{
	DeleteModifierList();
	
	Asura_Assert(m_pxAsuraRoot,"Not expecting this function to be called for fake menu items.");
	if(!m_pxAsuraRoot) return;

	if(m_pxAsuraRoot->GetModifierCount())
	{
		m_iModifierListSize = m_pxAsuraRoot->GetModifierCount();
		//for now just label each modifier by the data that it modifies

		m_pszModifierStrings = new const char*[m_iModifierListSize];

		for( int i(0);i<m_iModifierListSize;++i )
		{
			Asura_GUIMenu_Modifier* pxModifier = m_pxAsuraRoot->GetModifier(i);

			m_pszModifierStrings[i] = Asura_GUIMenu_Modifier::GetModifyTypeName(pxModifier->GetModifyType());	
			if(!m_pszModifierStrings[i])
			{
				m_pszModifierStrings[i] = "*Unknown*";
			}
		}
	}
	else
	{
		m_iModifierListSize = 1;
		m_pszModifierStrings = new const char*[1];
		m_pszModifierStrings[0] = "*No Modifiers*";
	}

	m_iModifierIndex = Asura_Maths::ClampToRange( m_iModifierIndex,0,m_iModifierListSize-1 );

	//update overlay if it already exists
	if(s_pxModifierListDialog) 
	{
		s_pxModifierListDialog->ReplaceStrings(m_iModifierListSize,m_pszModifierStrings);
	}
}

void Tools_GUIMenu_Root::DeleteModifierList()
{
	delete [] m_pszModifierStrings;
	m_pszModifierStrings = 0;
	m_iModifierListSize = 0;
}

void Tools_GUIMenu_Root::UpdateModifierOverlayControls()
{
	if(!IsSelected()) return;
	if(!m_pxAsuraRoot) return;
	if(!s_pxTabsDialog) return;

	Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_GUIMENU_SELECTED);
	if(!pxOverlay) return;

	//deallocate/shutdown anything else that was setup for editing the previous modifier
	CleanupModifierEditing();

	//delete existing modifier controls
	while(s_xModifierDialogList.size())
	{
		pxOverlay->DeleteSingleDialog(s_xModifierDialogList.first_entry());
		s_xModifierDialogList.delete_first_entry();
	}

	m_uModifierStates = 0;
	m_bModifierChanged = false;

	//Determine the selected modifier
	if( m_iModifierIndex >= static_cast<int>(m_pxAsuraRoot->GetModifierCount()) ) return;
	Asura_GUIMenu_Modifier* pxModifier = m_pxAsuraRoot->GetModifier(m_iModifierIndex);
	if(!pxModifier) return;

	//copy common modifier data into our local store
	m_uModifierStates = pxModifier->GetStateBeingModified();

	//make sure the modifier tab is selected
	Asura_Assert(s_iModifierTab != -1, "");
	int iPreviousTab = s_pxTabsDialog->GetSelected();
	if(iPreviousTab != s_iModifierTab)
	{
		s_pxTabsDialog->SelectTab(s_iModifierTab);
	}

	s_pxTabsDialog->ClearTab(s_iModifierTab);

	//add the controls for this modifier
	Asura_Vector_2 xOffset( m_xTabsStart );

	pxOverlay->SetCurrentParentDialog(s_pxTabsDialog);
	
	AddModifierOverlay( pxOverlay,xOffset );
	AddModifierActivationControls(pxModifier,xOffset);
	AddModifierOverlayControls(pxModifier,xOffset);
		
	//reselect the initial tab
	pxOverlay->SetCurrentParentDialog(0);
	if(iPreviousTab != s_iModifierTab)
	{
		s_pxTabsDialog->SelectTab(iPreviousTab);
	}

	//some controls need UpdateOverlay() called to get their labels set correctly
	UpdateOverlay();
}

void Tools_GUIMenu_Root::AddModifierDialog(Asura_Dialog* pxDialog)
{
	Asura_Assert(IsSelected(),"");
	Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_GUIMENU_SELECTED);
	Asura_Assert(pxOverlay,"");

	pxOverlay->AddDialog(pxDialog);
	if(!IsEditableModifierSelected())
	{
		//Modifier is controlled by a style , so don't allow it to be edited.
		pxDialog->SetEnabled(false);
	}
	s_xModifierDialogList.add_entry(pxDialog);
}

void Tools_GUIMenu_Root::AddModifierOverlayControls(Asura_GUIMenu_Modifier* pxModifier, Asura_Vector_2& xOffset )
{
	Asura_Dialog* pxDialog;

	switch(pxModifier->GetModifyType())
	{
		case ASURA_GUIMENU_MODIFY_POSITION:
		{
			m_xModifierData_Vector2 = pxModifier->GetVector2Data();

			pxDialog = new Asura_Numerical_Dialog("X Offset",xOffset,&m_xModifierData_Vector2.x,-9999.0f,9999.0f,1.0f,"%.0f",&m_bModifierChanged);
			pxDialog->SetHelpText("The offset to add when the modifier is active.");
			AddModifierDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Numerical_Dialog("Y Offset",xOffset,&m_xModifierData_Vector2.y,-9999.0f,9999.0f,1.0f,"%.0f",&m_bModifierChanged);
			pxDialog->SetHelpText("The offset to add when the modifier is active.");
			AddModifierDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();

			
		}
		break;

		case ASURA_GUIMENU_MODIFY_POSITION_RELATIVE:
		{
			m_xModifierData_Vector2 = pxModifier->GetVector2Data();

			pxDialog = new Asura_Numerical_Dialog("X Offset",xOffset,&m_xModifierData_Vector2.x,-1.0f,1.0f,0.001f,"%1.3f",&m_bModifierChanged);
			pxDialog->SetHelpText("The offset to applied on this frame in relative 0-1 offsets.  The 0-1 actual pixel offset is calculated based on the menu width.");
			AddModifierDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Numerical_Dialog("Y Offset",xOffset,&m_xModifierData_Vector2.y,-1.0f,1.0f,0.001f,"%1.3f",&m_bModifierChanged);
			pxDialog->SetHelpText("The offset to applied on this frame in relative 0-1 offsets.  The 0-1 actual pixel offset is calculated based on the menu height.");
			AddModifierDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
		}
		break;

		case ASURA_GUIMENU_MODIFY_COLOUR:
		{
			m_xModifierData_Colour = pxModifier->GetColourData();

			pxDialog = new Asura_Dialog("Colour",xOffset);
			AddModifierDialog(pxDialog);

			xOffset.x = pxDialog->m_xMaxCoord.x + 1.0f;
			Tools_ColourPicker_Dialog* pxColourDialog = new Tools_ColourPicker_Dialog("Colour",xOffset,Asura_Vector_2(1.5f,1.0f),&m_xModifierData_Colour.m_fR,&m_xModifierData_Colour.m_fG,&m_xModifierData_Colour.m_fB,1.0f,&m_bModifierChanged);
			pxColourDialog->SetHelpText("The colour to use when the modifier is active");
			pxColourDialog->EnableAlphaEditing(&m_xModifierData_Colour.m_fA);
			AddModifierDialog(pxColourDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
			xOffset.x = 1.0f;

		}
		break;

		case ASURA_GUIMENU_MODIFY_TRANSLUCENCY_MODE:
		{
			m_iModifierData = pxModifier->GetIntData();

			pxDialog = new Asura_DropDown_List_Dialog( xOffset, &g_apcTranslucencyNames[0], &m_iModifierData, g_uNumTranslucencyModes, g_uNumTranslucencyModes, NULL, &m_bModifierChanged, "Translucency Mode");
			pxDialog->SetHelpText("The translucency mode to use when the modifier is active");
			AddModifierDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
		}
		break;

		case ASURA_GUIMENU_MODIFY_ALPHA_SCALED:
		{
			m_fModifierData= pxModifier->GetFloatData();

			pxDialog = new Asura_Numerical_Dialog("Alpha scale",xOffset,&m_fModifierData,0.0f,1.0f,0.001f,"%.3f",&m_bModifierChanged);
			pxDialog->SetHelpText("The scale to apply to the alpha value.");
			AddModifierDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
			break;
		}

		default :
		{
			Asura_Assert(false, "unhandled case");
			break;
		}
	}
}

void Tools_GUIMenu_Root::AddModifierActivationControls( Asura_GUIMenu_Modifier* pxModifier, Asura_Vector_2& xOffset )
{
	Asura_Dialog* pxDialog(NULL);

	// Activation condition console vars that cause the current modifier to be applied 
	Asura_GUIMenu_ConditionVarManager* pxModifierConditions(NULL);

	if( pxModifier )
	{
		pxModifierConditions = pxModifier->GetActivationConditions();
	}

	if( pxModifierConditions )
	{
		xOffset.y += Asura_Dialog::SmallSpacing();
			
		pxDialog = new Asura_Dialog("Used With Condition :", xOffset);
		AddModifierDialog(pxDialog);
		xOffset.y += Asura_Dialog::SmallSpacing();

		pxDialog = new Asura_Function_Dialog("Add Activation Condition",xOffset,AddModifierActivationConditionVar,(int)this);
		pxDialog->SetHelpText("Add a new console var activation condition for the selected modifier.");
		AddModifierDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_DropDown_List_Dialog(xOffset, g_aszLogicOperators, (int*)&pxModifierConditions->m_eOperator, ASURA_GUIMENU_LOGIC_NUMTYPES, ASURA_GUIMENU_LOGIC_NUMTYPES, NULL, &m_bChanged, "Operator");
		pxDialog->SetHelpText("This determines how the results of the activation conditions are combined if there is more than one.");
		AddModifierDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();

		Asura_Assert(IsSelected(),"");
		Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_GUIMENU_SELECTED);
		Asura_Assert(pxOverlay,"");

		//Hopefully there shouldn't be so many activation conditions that just adding them all 'as is' will be a problem.
		for( u_int u(0);u<pxModifierConditions->m_uNumConditionVars;++u )
		{
			// keep record of all new'd Asura_Dialogs in s_xModifierDialogList so they can be released when the selected modifier is changed
			pxModifierConditions->m_pxConditionVars[u].AddOverlayControls( pxOverlay, xOffset, &m_bModifierConditionChanged, IsEditableModifierSelected(),&s_xModifierDialogList );
		}
		
		pxDialog = new Asura_Divider_Dialog(xOffset);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
	}
}

void Tools_GUIMenu_Root::InitialiseModifier(Asura_GUIMenu_Modifier* pxModifier)
{
	Asura_Assert(m_pxAsuraRoot,"Not expecting this function to be called on fake menu items");
	if(!m_pxAsuraRoot) return;

	switch(pxModifier->GetModifyType())
	{
		case ASURA_GUIMENU_MODIFY_POSITION:
			pxModifier->SetData(Asura_Vector_2(0.0f, 0.0f));
			break;

		case ASURA_GUIMENU_MODIFY_POSITION_RELATIVE:
			pxModifier->SetData(Asura_Vector_2(0.0f, 0.0f));
			break;

		case ASURA_GUIMENU_MODIFY_COLOUR:
			pxModifier->SetData(m_pxAsuraRoot->GetColour());
			break;

		case ASURA_GUIMENU_MODIFY_TRANSLUCENCY_MODE:
			pxModifier->SetData((int)m_pxAsuraRoot->GetTranslucencyMode());
			break;

		case ASURA_GUIMENU_MODIFY_ALPHA_SCALED:
			pxModifier->SetData( 1.0f );
			break;

		default :
			Asura_Assert(0,"Failed to set default data for newly created modifier.");
			break;
	}
}


void Tools_GUIMenu_Root::CopyToAsuraModifier()
{
	//Determine the selected modifier
	if(m_iModifierIndex >= (int)m_pxAsuraRoot->GetModifierCount()) return;
	Asura_GUIMenu_Modifier* pxModifier = m_pxAsuraRoot->GetModifier(m_iModifierIndex);
	if(!pxModifier) return;

	pxModifier->SetStateToModify(m_uModifierStates);

	//set data based on the modifier type
	switch(pxModifier->GetDataType())
	{
		case Asura_GUIMenu_Modifier::DATA_TYPE_NONE :
			Asura_Assert(0,"Modifier hasn't been assigned a type yet");
			break;

		case Asura_GUIMenu_Modifier::DATA_TYPE_UINT :
			pxModifier->SetData(m_uModifierData);
			break;

		case Asura_GUIMenu_Modifier::DATA_TYPE_INT :
			pxModifier->SetData(m_iModifierData);
			break;

		case Asura_GUIMenu_Modifier::DATA_TYPE_FLOAT :
			pxModifier->SetData(m_fModifierData);
			break;

		case Asura_GUIMenu_Modifier::DATA_TYPE_RGBA :
			pxModifier->SetData(m_xModifierData_Colour);
			break;

		case Asura_GUIMenu_Modifier::DATA_TYPE_VECTOR_2 :
			pxModifier->SetData(m_xModifierData_Vector2);
			break;

		case Asura_GUIMenu_Modifier::DATA_TYPE_UNICODE_STRING :
			//convert the string back to unicode and set in the modifier
			Asura_UnicodeChar wszText[200];
			Asura_PrintfToBfr(wszText,L"%S",sizeof(wszText)/sizeof(Asura_UnicodeChar),true,m_xModifierData_String.GetString());
			pxModifier->SetData(wszText);
			break;

		case Asura_GUIMenu_Modifier::DATA_TYPE_CHAR_STRING :
			pxModifier->SetData(m_xModifierData_String.GetString());
			break;

		case Asura_GUIMenu_Modifier::DATA_TYPE_UV_SET :
			pxModifier->SetData(m_xModifierData_UV);
			break;

		case Asura_GUIMenu_Modifier::DATA_TYPE_TEXTUREINDEX :
			pxModifier->SetTextureIndexData(m_iModifierData);
			break;

		default :
			Asura_Assertf(0,("Unknown modifier type '%d'",pxModifier->GetDataType()));
			break;
	}
}

u_int Tools_GUIMenu_Root::GetNumMenuItemStates()
{
	return g_uNumModifierStates;
}

const char* Tools_GUIMenu_Root::GetMenuItemStateName(u_int uIndex)
{
	Asura_Assert(uIndex<g_uNumModifierStates,"");
	return g_axStates[uIndex].m_szName;
}

u_int Tools_GUIMenu_Root::GetMenuItemStateValue(u_int uIndex)
{
	Asura_Assert(uIndex<g_uNumModifierStates,"");
	return g_axStates[uIndex].m_uValue;
}

void Tools_GUIMenu_Root::AddAnimator()
{
	ListSelection_Overlay xListOverlay("Select animator sequence to add");

	//fill a list selection overlay with all acceptable sequences
	for(u_int i=0;i<Asura_GUIMenu_Animator_Storage::GetNumberOfSequences();i++)
	{
		const Asura_GUIMenu_Animator_Sequence* pxSeq = Asura_GUIMenu_Animator_Storage::GetSequenceByIndex(i);
	
		if(IsAnimatorAllowed(pxSeq))
		{
			xListOverlay.AddItem(pxSeq->GetName());			
		}
	}

	if(!xListOverlay.GetNumItems())
	{
		ShowMessageOverlay("There aren't any sequences that can be added to this menu item");
		return;
	}


	if(!xListOverlay.DoModal()) return;

	AddAnimator(xListOverlay.GetSelectionString());
}

void Tools_GUIMenu_Root::AddAnimator(const char* szSequenceName)
{
	//make sure this animator hasn't already been added
	for(u_int i=0;i<m_pxAsuraRoot->GetAnimatorCount(); i++)
	{
		const Asura_GUIMenu_Animator* pxAnimator = m_pxAsuraRoot->GetAnimator(i);
		if(!stricmp(pxAnimator->GetSequenceName(),szSequenceName))
		{
			Tools_Timed_Message_System::AddMessage(0xffff00,"%s already uses %s",GetName(),szSequenceName);
			return;
		}
	}

	Asura_GUIMenu_Animator* pxAnim = m_pxAsuraRoot->AddAnimator(szSequenceName);
	if(!pxAnim)
	{
		ShowMessageOverlay("Failed to add animator. Probably reached maximum allowed for the menu item.");
		return;
	}

	SetModified();

	//update the list on the overlay ,and select the new entry
	UpdateAnimatorList();
	m_iModifierIndex = m_pxAsuraRoot->GetAnimatorCount()-1;

	CopyFromAsuraAnimator();
	UpdateAnimatorOverlayControls();

	Tools_Timed_Message_System::AddMessage(0xffffff,"%s added to %s",szSequenceName,GetName());

}

bool Tools_GUIMenu_Root::IsAnimatorAllowed(const Asura_GUIMenu_Animator_Sequence* pxSeq) const
{
	if(!m_pxAsuraRoot) return false;

	if(IsStyleInstance() || IsGeneratedByStyle())
	{
		//items that are created by styles should only use animators for the fade in and fade out states
		if(!(pxSeq->GetStateFlags() & (ASURA_GUIMENU_ACTION_FLAG_IS_MENU_FADE_IN|ASURA_GUIMENU_ACTION_FLAG_IS_MENU_FADE_OUT)))
		{
			return false;
		}
	}
	//Allow all other animators for now
	//(For elements we could filter out those that don't apply , but I can't be bothered at the moment...)
	return true;
}


void Tools_GUIMenu_Root::DeleteAnimator()
{
	if(m_iAnimatorIndex >= (int)m_pxAsuraRoot->GetAnimatorCount()) return;

	//delete the animator from the asura data
	m_pxAsuraRoot->DeleteAnimator(m_iAnimatorIndex);
	SetModified();

	//update the overlay to match
	UpdateAnimatorList();
	CopyFromAsuraAnimator();
	UpdateAnimatorOverlayControls();
}


bool Tools_GUIMenu_Root::IsEditableAnimatorSelected()
{
	//any animator selected?
	if(m_iAnimatorIndex >= (int)m_pxAsuraRoot->GetAnimatorCount()) return false;

	//Can't edit animators that come from styles
	return !m_pxAsuraRoot->GetAnimator(m_iAnimatorIndex)->IsGeneratedByStyle();
}

void Tools_GUIMenu_Root::UpdateAnimatorList()
{
	DeleteAnimatorList();
	
	Asura_Assert(m_pxAsuraRoot,"Not expecting this function to be called for fake menu items.");
	if(!m_pxAsuraRoot) return;


	if(m_pxAsuraRoot->GetAnimatorCount())
	{
		m_iAnimatorListSize = m_pxAsuraRoot->GetAnimatorCount();

		//get the name of each animator sequence
		m_pszAnimatorStrings = new char*[m_iAnimatorListSize];

		for(int i=0;i<m_iAnimatorListSize;i++)
		{
			Asura_GUIMenu_Animator* pxAnimator = m_pxAsuraRoot->GetAnimator(i);
			const char* szName = pxAnimator->GetSequenceName();

			m_pszAnimatorStrings[i] = new char[strlen(szName)+1];
			strcpy(m_pszAnimatorStrings[i], szName);

		}
	}
	else
	{
		m_iAnimatorListSize = 1;
		m_pszAnimatorStrings = new char*[1];
		m_pszAnimatorStrings[0] = new char[20];
		strcpy(m_pszAnimatorStrings[0], "*No Animators*");
	}

	if(m_iAnimatorIndex >= m_iAnimatorListSize) m_iAnimatorIndex = m_iAnimatorListSize-1;

	//update overlay if it already exists
	if(s_pxAnimatorListDialog) s_pxAnimatorListDialog->ReplaceStrings(m_iAnimatorListSize,m_pszAnimatorStrings);

}

void Tools_GUIMenu_Root::DeleteAnimatorList()
{
	for(int i=0;i<m_iAnimatorListSize;i++)
	{
		delete [] m_pszAnimatorStrings[i];
	}
	delete [] m_pszAnimatorStrings;
	m_pszAnimatorStrings = 0;
	m_iAnimatorListSize = 0;
}



void Tools_GUIMenu_Root::CopyToAsuraAnimator()
{
	//Determine the selected animator
	if(m_iAnimatorIndex >= (int)m_pxAsuraRoot->GetAnimatorCount()) return;
	Asura_GUIMenu_Animator* pxAnimator = m_pxAsuraRoot->GetAnimator(m_iAnimatorIndex);
	if(!pxAnimator) return;

	pxAnimator->SetSpeed(m_fAnimatorSpeed);
	pxAnimator->SetDelay(m_fAnimatorDelay);
	pxAnimator->SetShouldStartActive( m_bAnimatorShouldStartActive );
	pxAnimator->SetInitialiseToEnd( m_bAnimatorInitialiseToEnd );
}

void Tools_GUIMenu_Root::CopyFromAsuraAnimator()
{
	//Determine the selected animator
	if(m_iAnimatorIndex >= (int)m_pxAsuraRoot->GetAnimatorCount()) return;
	Asura_GUIMenu_Animator* pxAnimator = m_pxAsuraRoot->GetAnimator(m_iAnimatorIndex);
	if(!pxAnimator) return;

	m_fAnimatorSpeed = pxAnimator->GetSpeed();
	m_fAnimatorDelay = pxAnimator->GetDelay();
}

void Tools_GUIMenu_Root::HandleRenameAnimator(const char* szOldName, const char* szNewName)
{
	if(m_pxAsuraRoot)
	{
		//see if this is using the animator
		for(u_int i=0;i<m_pxAsuraRoot->GetAnimatorCount(); i++)
		{
			Asura_GUIMenu_Animator* pxAnimator = m_pxAsuraRoot->GetAnimator(i);
			if(!stricmp(szOldName, pxAnimator->GetSequenceName()))
			{
				//update this sequence
				pxAnimator->SetSequence(szNewName);
				SetModified();

				if(IsSelected())
				{
					UpdateAnimatorList();
				}
				break;
			}
		}
	}

	//update child menu items
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->HandleRenameAnimator(szOldName, szNewName);
	}
}

void Tools_GUIMenu_Root::HandleDeleteAnimator(const char* szName)
{
	if(m_pxAsuraRoot)
	{
		//see if this is using the animator
		for(u_int i=0;i<m_pxAsuraRoot->GetAnimatorCount(); i++)
		{
			Asura_GUIMenu_Animator* pxAnimator = m_pxAsuraRoot->GetAnimator(i);
			if(!stricmp(szName, pxAnimator->GetSequenceName()))
			{
				//delete this sequence
				m_pxAsuraRoot->DeleteAnimator(i);
				SetModified();

				if(IsSelected())
				{
					UpdateAnimatorList();
					m_bAnimatorIndexChanged = true;
				}
				i--;
			}
		}
	}

	//update child menu items
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->HandleDeleteAnimator(szName);
	}
}

void Tools_GUIMenu_Root::AddAnimatorDialog( Asura_Dialog* pxDialog )
{
	Asura_Assert(IsSelected(),"");
	Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_GUIMENU_SELECTED);
	Asura_Assert(pxOverlay,"");

	pxOverlay->AddDialog(pxDialog);

	if( !IsEditableAnimatorSelected() )
	{
		//Modifier is controlled by a style , so don't allow it to be edited.
		pxDialog->SetEnabled(false);
	}

	s_xAnimatorDialogList.add_entry(pxDialog);
}

void Tools_GUIMenu_Root::UpdateAnimatorOverlayControls()
{
	if(!IsSelected()) return;
	if(!m_pxAsuraRoot) return;
	if(!s_pxTabsDialog) return;

	Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_GUIMENU_SELECTED);
	if(!pxOverlay) return;

	//delete existing animator controls
	while(s_xAnimatorDialogList.size())
	{
		pxOverlay->DeleteSingleDialog(s_xAnimatorDialogList.first_entry());
		s_xAnimatorDialogList.delete_first_entry();
	}

	m_bAnimatorChanged = false;


	//make sure the Animator tab is selected
	Asura_Assert(s_iAnimatorTab != -1, "");
	int iPreviousTab = s_pxTabsDialog->GetSelected();
	if(iPreviousTab != s_iAnimatorTab)
	{
		s_pxTabsDialog->SelectTab(s_iAnimatorTab);
	}

	s_pxTabsDialog->ClearTab(s_iAnimatorTab);

	//add the controls for this Animator
	Asura_Vector_2 xOffset( m_xTabsStart );

	pxOverlay->SetCurrentParentDialog(s_pxTabsDialog);
	AddAnimatorOverlay( pxOverlay,xOffset );

	//Determine the selected modifier
	Asura_GUIMenu_Animator* pxAnimator = 0;
	if(m_iAnimatorIndex < static_cast<int>(m_pxAsuraRoot->GetAnimatorCount()) )
	{
		pxAnimator = m_pxAsuraRoot->GetAnimator(m_iAnimatorIndex);
	}
	if(pxAnimator)
	{
		m_bAnimatorShouldStartActive = pxAnimator->ShouldStartActive();

		Asura_Dialog* pxDialog( new Asura_Tickbox_Dialog("Activate when menu opens",xOffset,&m_bAnimatorShouldStartActive,&m_bAnimatorChanged ) );
		pxDialog->SetHelpText("If ticked the selected animator will be applied when the menu page opens (does not apply to looping animators)");
		pxOverlay->AddDialog(pxDialog);

		xOffset.y += Asura_Dialog::DefaultSpacing();

		m_bAnimatorInitialiseToEnd = pxAnimator->GetInitialiseToEnd();

		pxDialog = new Asura_Tickbox_Dialog("Start at end when menu opens",xOffset,&m_bAnimatorInitialiseToEnd,&m_bAnimatorChanged );
		pxDialog->SetHelpText("Start the animation at its end position when the page opens. Prevents the animation playing when transitioning into a menu page.");
		pxOverlay->AddDialog(pxDialog);

		AddAnimatorResetControls(pxAnimator,xOffset);
	}
	//reselect the initial tab
	pxOverlay->SetCurrentParentDialog(0);
	if(iPreviousTab != s_iAnimatorTab)
	{
		s_pxTabsDialog->SelectTab(iPreviousTab);
	}

	//some controls need UpdateOverlay() called to get their labels set correctly
	UpdateOverlay();
}

void Tools_GUIMenu_Root::AddAnimatorResetControls( Asura_GUIMenu_Animator* pxAnimator, Asura_Vector_2& xOffset )
{
	Asura_Dialog* pxDialog(NULL);

	// Activation condition console vars that cause the current Animator to be applied 
	Asura_GUIMenu_ConditionVarManager* pxConditions(NULL);

	if( pxAnimator )
	{
		pxConditions = pxAnimator->GetStartConditions();
	}

	if( pxConditions )
	{
		xOffset.y += Asura_Dialog::SmallSpacing();
			
		pxDialog = new Asura_Dialog("Reset On Condition:", xOffset);
		AddAnimatorDialog(pxDialog);
		xOffset.y += Asura_Dialog::SmallSpacing();

		pxDialog = new Asura_Function_Dialog("Add Reset Condition",xOffset,AddAnimatorResetConditionVar,(int)this);
		pxDialog->SetHelpText("Add a new console variable reset condition for the selected animator.");
		AddAnimatorDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_DropDown_List_Dialog(xOffset, g_aszLogicOperators, (int*)&pxConditions->m_eOperator, ASURA_GUIMENU_LOGIC_NUMTYPES, ASURA_GUIMENU_LOGIC_NUMTYPES, NULL, &m_bChanged, "Operator");
		pxDialog->SetHelpText("This determines how the results of the reset conditions are combined if there is more than one.");
		AddAnimatorDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();

		Asura_Assert(IsSelected(),"");
		Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_GUIMENU_SELECTED);
		Asura_Assert(pxOverlay,"");

		//Hopefully there shouldn't be so many conditions that just adding them all 'as is' will be a problem.
		for( u_int u(0);u<pxConditions->m_uNumConditionVars;++u )
		{
			// keep record of all new'd Asura_Dialogs in s_xAnimatorDialogList so they can be released when the selected Animator is changed
			pxConditions->m_pxConditionVars[u].AddOverlayControls( pxOverlay, xOffset, &m_bAnimatorConditionChanged, IsEditableAnimatorSelected(),&s_xAnimatorDialogList );
		}
		
		pxDialog = new Asura_Divider_Dialog(xOffset);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
	}	
}


bool Tools_GUIMenu_Root::ConfirmDeletion()
{
	//get confirmation when deleting styles
	if(IsStyle())
	{
		return ShowYesNoOverlay("'%s' is a stlye , if it is deleted then any instances of it will be divorced from the style.\nWould you like to delete it?",GetName());
	}
	return true;
}

bool Tools_GUIMenu_Root::GetTextToPreserve(Asura_Hash_ID& uTextID, Asura_Hash_ID& uTextPage) const
{
	for(CLIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		if(xChildLIF()->GetTextToPreserve(uTextID, uTextPage))
		{
			return true;
		}
	}
	return false;
}

void Tools_GUIMenu_Root::ApplyPreservedText(Asura_Hash_ID uTextID, Asura_Hash_ID uTextPage)
{
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		//Only recurse through children that are generated by the style.
		//This prevents text being applied to non style buttons , or style instances , when a menu
		//has a style applied to it.
		if(xChildLIF()->IsGeneratedByStyle())
		{
			xChildLIF()->ApplyPreservedText(uTextID, uTextPage);
		}
	}

}

bool Tools_GUIMenu_Root::CanAddToGroup()
{
	if(!GetParent()) return false;

	//allow for items that are direct children of a menu
	return GetParent()->IsMenu();
}

void Tools_GUIMenu_Root::AddToGroup()
{
	//prompt for group to add to
	Tools_GUIMenu_PickItem_AddToGroup* pxPickItem = new Tools_GUIMenu_PickItem_AddToGroup(this);
	Tools_Mode_GUIMenu::GetInstance()->StartPromptedSelection(pxPickItem);
}

void Tools_GUIMenu_Root::AddToGroup(Tools_GUIMenu_Root* pxGroup)
{
	Asura_Assert(pxGroup,"");
	
	//make sure it is actually a group
	if(pxGroup->GetType() != Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_GROUP) return;

	//make sure the group is in the same menu page (should always be the case with the current selection process)
	if(GetMenuPage() != pxGroup->GetMenuPage()) return;

	//Attempt the move
	ChangeParent(pxGroup);
}

bool Tools_GUIMenu_Root::CanRemoveFromGroup()
{
	if(!GetParent()) return false;

	//Can remove if the parent is a group widget
	return GetParent()->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_GROUP;
}

void Tools_GUIMenu_Root::RemoveFromGroup()
{
	if(!GetParent()) return;
	if(GetParent()->GetType() != Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_GROUP) return;

	//change the parent to be the menu page
	ChangeParent(GetMenuPage());
}

void Tools_GUIMenu_Root::ChangeParent(Tools_GUIMenu_Root* pxNewParent)
{
	Asura_Assert(pxNewParent && !pxNewParent->IsFakeMenuItem(),"");

	Asura_Assert(!IsMenu() && !IsFile(),"This function doesn't currently work for changing the parent of menus and files");

	if(pxNewParent == GetParent()) return;

	//make sure the parent isn't contained within this
	if(pxNewParent->IsDescendentOf(this))
	{
		ShowMessageOverlay("Can't change the parent since the new parent is contained within item being moved.");
		return;
	}

	//make sure the parent doesn't already have an item with this name
	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&pxNewParent->m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		if(!stricmp(xChildLIF()->GetName(),GetName()))
		{
			ShowMessageOverlay("The destination group already has a child with the same name.");
			return;
		}
	}

	//store the current position
	Asura_Bounding_Rectangle xRect = GetRectangle();

	//change the parent in the asura data
	Tools_GUIMenu_Root* pxOldParent = GetParent();
	pxOldParent->GetAsuraData()->RemoveFromThisContainer(m_pxAsuraRoot);
	pxNewParent->GetAsuraData()->AddToThisContainer(m_pxAsuraRoot);

	//update the hierarchy of tools menu items , and the treeview
	GetParent()->RemoveChild(this);
	pxNewParent->AddChild(this);
	m_pxToolsParent = pxNewParent;
	Tools_Mode_GUIMenu::GetInstance()->UpdateParentInTree(this);

	//set the position again , since it will have been recalculated using the local positions
	SetRectangle(xRect);

	//update the IDs
	s_bIsRenaming = true;
	RecalculateID();
	s_bIsRenaming = false;

	pxOldParent->CalculateExtents();
	pxNewParent->GetAsuraData()->FixupBoundsFromChildren();
	pxNewParent->CalculateExtents();

	//flag this and the old parent as modified
	pxOldParent->SetModified();
	SetModified();		

	// update overlay controls in light of new parent
	RecreateOverlay();
}

void Tools_GUIMenu_Root::RecalculateIDAfterRename()
{
	s_bIsRenaming = true;
	RecalculateID();
	s_bIsRenaming = false;

}

void Tools_GUIMenu_Root::AddDisplayConditionVar()
{
	Asura_GUIMenu_ConditionVarManager* pxManager = &m_pxAsuraRoot->m_xDisplayConditions;

	//create an enlarged array, and copy any old data
	Asura_GUIMenu_ConditionVar* pxNewVars = new Asura_GUIMenu_ConditionVar[pxManager->m_uNumConditionVars+1];

	for(u_int i=0;i<pxManager->m_uNumConditionVars;i++)
	{
		pxNewVars[i].Copy(&pxManager->m_pxConditionVars[i]);
	}

	delete [] pxManager->m_pxConditionVars;
	pxManager->m_pxConditionVars = pxNewVars;
	pxManager->m_uNumConditionVars++;

	//rebuild the overlay to add the controls for the new var
	DeleteOverlay();
	CreateOverlay();

	//Scroll down to the bottom to make the new display condition visible
	if(s_pxDispCondSubwindowDialog)
	{
		s_pxDispCondSubwindowDialog->ScrollToBottom();
	}

	SetModified();
}

void Tools_GUIMenu_Root::AddModifierActivationConditionVar()
{
	Asura_GUIMenu_ConditionVarManager* pxManager = m_pxAsuraRoot->GetModifier(m_iModifierIndex)->GetActivationConditions();

	//create an enlarged array, and copy any old data
	Asura_GUIMenu_ConditionVar* pxNewVars = new Asura_GUIMenu_ConditionVar[pxManager->m_uNumConditionVars+1];

	for( u_int u=0;u<pxManager->m_uNumConditionVars;++u )
	{
		pxNewVars[u].Copy( &pxManager->m_pxConditionVars[u] );
	}

	delete [] pxManager->m_pxConditionVars;
	pxManager->m_pxConditionVars = pxNewVars;
	pxManager->m_uNumConditionVars++;

	//rebuild the overlay to add the controls for the new var
	DeleteOverlay();
	CreateOverlay();

	SetModified();
}

void Tools_GUIMenu_Root::AddAnimatorResetConditionVar()
{
	Asura_GUIMenu_ConditionVarManager* pxManager = m_pxAsuraRoot->GetAnimator(m_iAnimatorIndex)->GetStartConditions();

	//create an enlarged array, and copy any old data
	Asura_GUIMenu_ConditionVar* pxNewVars = new Asura_GUIMenu_ConditionVar[pxManager->m_uNumConditionVars+1];

	for( u_int u(0);u<pxManager->m_uNumConditionVars;++u )
	{
		pxNewVars[u].Copy( &pxManager->m_pxConditionVars[u] );
	}

	delete [] pxManager->m_pxConditionVars;
	pxManager->m_pxConditionVars = pxNewVars;
	pxManager->m_uNumConditionVars++;

	//rebuild the overlay to add the controls for the new var
	DeleteOverlay();
	CreateOverlay();

	SetModified();
}

void Tools_GUIMenu_Root::UpdateTabLabels()
{
	if(IsFakeMenuItem()) return;
	if(!m_bSelected) return;
	if(!s_pxTabsDialog) return;

	char acLabel[100];

	if(s_iStyleTab != -1)
	{
		bool bAddStar = CanEditStyleFlags() || IsGeneratedByStyle() || IsStyleInstance() || IsStyleContainer();

		Asura_PrintfToBfr(acLabel,"%sStyle",sizeof(acLabel),true,bAddStar ? "*" : "");
		s_pxTabsDialog->RenameTab(s_iStyleTab, acLabel, false);	
	}

	if(s_iModifierTab != -1)
	{
		bool bAddStar = m_pxAsuraRoot->GetModifierCount() != 0;

		Asura_PrintfToBfr(acLabel,"%sModifier",sizeof(acLabel),true,bAddStar ? "*" : "");
		s_pxTabsDialog->RenameTab(s_iModifierTab, acLabel, false);	
	}

	if(s_iAnimatorTab != -1)
	{
		bool bAddStar = m_pxAsuraRoot->GetAnimatorCount() != 0;

		Asura_PrintfToBfr(acLabel,"%sAnimator",sizeof(acLabel),true,bAddStar ? "*" : "");
		s_pxTabsDialog->RenameTab(s_iAnimatorTab, acLabel, false);	
	}

	if(s_iDisplayConditionTab != -1)
	{
		bool bAddStar = m_pxAsuraRoot->m_xDisplayConditions.m_uNumConditionVars != 0;

		Asura_PrintfToBfr(acLabel,"%sDisp Cond",sizeof(acLabel),true,bAddStar ? "*" : "");
		s_pxTabsDialog->RenameTab(s_iDisplayConditionTab, acLabel, false);	

	}

	if(s_iPlatformTab != -1)
	{
		bool bAddStar = false;
		//Add an asterisk to the name if there any platforms supported by the project that
		//this menu item isn't flagged for.
		for(int i=0; i<TOOLS_PLATFORM_NUM_PLATFORMS; i++)
		{
			if(!Tools_Level_Export::IsPlatformSupported((Tools_Level_Export::EXPORT_TYPE)i)) continue;
			if(!(m_pxAsuraRoot->m_uPlatforms & (1<<i)))
			{
				bAddStar = true;
				break;
			}
		}
		
		Asura_PrintfToBfr(acLabel,"%sPlatform",sizeof(acLabel),true,bAddStar ? "*" : "");
		s_pxTabsDialog->RenameTab(s_iPlatformTab, acLabel, false);	
	
	}

}

void Tools_GUIMenu_Root::LogUndo_Rectangle(const Asura_Bounding_Rectangle& xNewRect)
{
	//log for undo if the rect has changed
	Asura_Bounding_Rectangle xRect = GetRectangle();
	if(xRect != xNewRect)
	{
		Tools_Mode_GUIMenu::LogUndo_Rectangle(this,xRect);
	}
}

void Tools_GUIMenu_Root::SetRectangleRecursive()
{
	if(m_pxAsuraRoot)
	{
		SetRectangle(GetRectangle());
	}

	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->SetRectangleRecursive();
	}
	
}

//Reset the scale world bounds as this can be changed when previewing a gui menu
//Tools requires scaled bounds and unscaled bound to remain the same during editing.
void Tools_GUIMenu_Root::ResizeScaledWorldBoundsRecursive()
{
	if(m_pxAsuraRoot && m_pxAsuraRoot->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE )
	{
		m_pxAsuraRoot->Resize(m_pxAsuraRoot->GetUnscaledLocalBounds());
	}

	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->ResizeScaledWorldBoundsRecursive();
	}
}

void Tools_GUIMenu_Root::SetHiddenRecursive(bool bHide)
{
	m_bHidden = bHide;

	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->SetHiddenRecursive(bHide);
	}
}

bool Tools_GUIMenu_Root::IsHidden() const
{
	if(m_bHidden) return true;
	
	if(Tools_Mode_GUIMenu::GetHideSiblings() && IsElement())
	{
		//Check for a sibling item being selected
		Tools_GUIMenu_Root* pxSelected = Tools_Mode_GUIMenu::GetSelectedItem();

		if(pxSelected && pxSelected!=this && pxSelected->GetParent() == GetParent())
		{
			return true;
		}
	}

	//Make sure this and all the parents are supposed to exist on the current platform
	for(const Tools_GUIMenu_Root* pxItem = this; pxItem; pxItem = pxItem->GetParent())
	{
		if(pxItem->m_pxAsuraRoot && !pxItem->m_pxAsuraRoot->ShouldExportToPlatform(Tools_Mode_GUIMenu::GetPreviewPlatform()))
		{
			return true;
		}
	}

	return false;
}

const bool Tools_GUIMenu_Root::FindAndReplaceConsoleVarName( const Asura_UnicodeChar* wszName,const Asura_UnicodeChar* wszReplacementName )
{
	bool bMatchFound(false);

	if( m_pxAsuraRoot && wszName && wszReplacementName )
	{
		// Call method on asura root object
		m_pxAsuraRoot->FindAndReplaceConsoleVarName( wszName,wszReplacementName );
	}

	return bMatchFound;
}


void Tools_GUIMenu_Root::EditComments()
{
	Tool_Comments_Overlay xCommentsOverlay( "Comments", m_pxAsuraRoot);
	xCommentsOverlay.DoModal();

	DeleteOverlay();
	CreateOverlay();
}

// -------------------------------------------------------------------------------------

void Tools_GUIMenu_Root::ResetAnchoring()
{
	if( GetAsuraData() )
	{
		GetAsuraData()->m_aePosMode[Asura_GUIMenu_Root::ASURA_GUIMENU_POSITION_MODE_AXIS_HORIZONTAL] = Asura_GUIMenu_Root::POS_NORMAL;
		GetAsuraData()->m_aePosMode[Asura_GUIMenu_Root::ASURA_GUIMENU_POSITION_MODE_AXIS_VERTICLE]   = Asura_GUIMenu_Root::POS_NORMAL;
	}
}

void Tools_GUIMenu_Root::SetScalingFlags( const u_int uFlags )
{
	if( m_pxAsuraRoot )
	{
		m_pxAsuraRoot->SetScalingFlags(uFlags);
	}
}

void Tools_GUIMenu_Root::SetPosMode( const u_int uAxis,const Asura_GUIMenu_Root::Asura_GUIMenu_Anchoring_Flag ePosMode )
{
	if( GetAsuraData() )
	{
		GetAsuraData()->SetPosMode(uAxis,ePosMode);
	}
}

void Tools_GUIMenu_Root::ApplyScalingFlagsToChildren()
{
	if( GetAsuraData() )
	{
		GetAsuraData()->ApplyScalingFlagsToChildren();
		
		m_bScaleFlagChanged = true;
	}
}

void Tools_GUIMenu_Root::ApplyAnchoringFlagsToChildren()
{
	if( GetAsuraData() )
	{
		GetAsuraData()->ApplyAnchoringFlagsToChildren();

		m_bChanged = true;
	}
}

void Tools_GUIMenu_Root::ApplyScalingFlagsToChildrenCallback()
{
	if( GetSelectedInstance() )
	{
		GetSelectedInstance()->ApplyScalingFlagsToChildren();

		Tools_Timed_Message_System::AddMessage(0xFFFFFFFF, "%s: Copied scaling flags to children",GetSelectedInstance()->GetAsuraData()->GenerateFullyQualifiedName().GetString() );
	}
}

void Tools_GUIMenu_Root::ApplyAnchoringFlagsToChildrenCallback()
{
	if( GetSelectedInstance() )
	{
		GetSelectedInstance()->ApplyAnchoringFlagsToChildren();

		Tools_Timed_Message_System::AddMessage(0xFFFFFFFF, "%s: Copied anchoring flags to children",GetSelectedInstance()->GetAsuraData()->GenerateFullyQualifiedName().GetString() );
	}
}

void Tools_GUIMenu_Root::SetAllPlatforms()
{
	if(m_pxAsuraRoot)
	{
		m_pxAsuraRoot->m_uPlatforms = 0xffffffff;
		m_bChanged = true;
	}
}

void Tools_GUIMenu_Root::ClearAllPlatforms()
{
	if(m_pxAsuraRoot)
	{
		m_pxAsuraRoot->m_uPlatforms = 0;
		m_bChanged = true;
	}
}

void Tools_GUIMenu_Root::SetIsClampedToParent(bool bClampedToParent)
{
	if(bClampedToParent)
	{
		m_uToolsFlags ^= ASURA_GUIMENU_TOOLS_FLAG_ISUNCLAMPED;
	}
	else
	{
		m_uToolsFlags |= ASURA_GUIMENU_TOOLS_FLAG_ISUNCLAMPED;
	}
	m_bChanged = true;
}

void Tools_GUIMenu_Root::AddCreationComment()
{
	// Setup the creation comment.
	if(m_pxAsuraRoot)
	{
		Asura_String xComment;
		Asura_Char acUserName[uTOOLS_GUIMENU_MAX_COMMENT_STRING_LENGTH];
		acUserName[0] = '\0';
		Asura_Windows::GetUserNameFromPC( acUserName, uTOOLS_GUIMENU_MAX_COMMENT_STRING_LENGTH);

		xComment = "Created by ";
		xComment += acUserName;

		m_pxAsuraRoot->AddComment( acUserName, xComment.GetString());
	}
}

// Get the index of the current tab selected in the dialog box.
u_int Tools_GUIMenu_Root::GetSelectedDialogTab() 
{ 
	Asura_Assert(s_pxTabsDialog != NULL,"s_pxTabsDialog not expected to be NULL"); 
	return s_pxTabsDialog->GetSelected(); 
}

// Is the Animator tab selected.
bool Tools_GUIMenu_Root::IsAnimatorTabSelected() 
{ 
	return static_cast<int>(GetSelectedDialogTab()) == s_iAnimatorTab;
}

// Is the Modifier tab selected.
bool Tools_GUIMenu_Root::IsModifierTabSelected() 
{ 
	return static_cast<int>(GetSelectedDialogTab()) == s_iModifierTab;
}

// Public stub function to call tools function declared as OVERLAY_VOID_CALLBACK(DeleteModifier)
void Tools_GUIMenu_Root::DeleteCurrentModifier()
{
	DeleteModifier();
}

// Public stub function to call tools function declared as OVERLAY_VOID_CALLBACK(DeleteAnimator)
void Tools_GUIMenu_Root::DeleteCurrentAnimator()
{
	DeleteAnimator();
}

bool Tools_GUIMenu_Root::UsesTexture(int iTexture) const
{
	if(!m_pxAsuraRoot) return false;	

	//check for textures used by modifiers
	for(int i=0; i<m_pxAsuraRoot->GetModifierCount(); i++)
	{
		const Asura_GUIMenu_Modifier* pxModifier = m_pxAsuraRoot->GetModifier(i);
		if(pxModifier->GetDataType() == Asura_GUIMenu_Modifier::DATA_TYPE_TEXTUREINDEX)
		{
			if(pxModifier->GetTextureIndexData() == iTexture) return true;
		}
	}
	return false;
}

void Tools_GUIMenu_Root::SetFontRecursive( const char* szFont)
{
	SetFont(szFont);

	for(LIF<Tools_GUIMenu_Root*> xChildLIF(&m_xChildren);!xChildLIF.done();xChildLIF.next())
	{
		xChildLIF()->SetFontRecursive(szFont);
	}
}

/////////////////////////////////////////////////////////////////////////////////////////
/*--------------------**
** Tools_GUIMenu_File **
**--------------------*/

bool Tools_GUIMenu_File::s_bIgnoreSetModified = false;

Tools_GUIMenu_File::Tools_GUIMenu_File(const char* szName,Tools_GUIMenu_Root* pxToolsParent)
:Tools_GUIMenu_Root(0,pxToolsParent,szName)
{
	m_iSortKey = Tools_GUIMenu_System::GetFileSortKey(szName);
	m_bSortKeyChanged = false;
}


bool Tools_GUIMenu_File::ConfirmDeletion()
{
	//Probably no point in allowing deletion of files in this way ,since the user would need to fiddle around and delete
	//them from perforce anyway.
	//RAR 09/02/2007
	ShowMessageOverlay("Files can't be deleted in this way.\nDelete them by hand and remove from perforce.");
	return false;
}

bool Tools_GUIMenu_File::IsValidChildType(int iItemType) const
{
	return iItemType == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE;
}


void Tools_GUIMenu_File::AddBasicOverlayControls(Asura_Overlay* pxOverlay,Asura_Vector_2& xOffset)
{
	//Not adding any parent class controls at the moment , since they are mostly irrelevant to the fake menu items

	Asura_Dialog* pxDialog = new Asura_Function_Dialog("Export File",xOffset,ExportFile,(int)this);
	pxDialog->SetIsEnabledFunction(CanExportFile,(int) this);
	pxDialog->SetHelpText("Exports the menus that belong to this file.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog("Sort Key",xOffset,&m_iSortKey,0,9999,1,"%d",&m_bSortKeyChanged);
	pxDialog->SetHelpText("This value is used for determining the order of the files in the tree view.\nAny files with an equal value will be sorted alphabetically , with the level specific file coming first.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();	
}

bool Tools_GUIMenu_File::CanExportFile()
{
	//Don't want to export the level specific file in this way
	return stricmp(GetName(),Tools_GUIMenu_System::GetLevelSpecificFile()) != 0;
}

void Tools_GUIMenu_File::ExportFile()
{
	if(!CanExportFile()) return;

	Tools_Level_Export::ExportGUIMenus(GetName());
}

void Tools_GUIMenu_File::Update()
{
	PARENT::Update();

	if(m_bSortKeyChanged)
	{
		Tools_GUIMenu_System::SetFileSortKey(GetName(),m_iSortKey);
		m_bSortKeyChanged = false;
		SetModified();

		//reorder chilren in parent
		m_pxToolsParent->SortFiles();
	}
}

void Tools_GUIMenu_File::SetModified()
{
	if(!s_bIgnoreSetModified)
	{
		Tools_GUIMenu_System::SetModified(GetName());
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*-------------------**
** Tool_Comments_Overlay **
**-------------------*/

bool Tool_Comments_Overlay::ReturnValue;
Asura_List<Asura_GUIMenu_ToolComment>*	Tool_Comments_Overlay::s_pxCommentList;
Asura_GUIMenu_Root* Tool_Comments_Overlay::s_pxRootObject;
bool Tool_Comments_Overlay::s_bRefreshLayout;

Tool_Comments_Overlay::Tool_Comments_Overlay( Asura_String _Title, Asura_GUIMenu_Root* pxRootObject)//Asura_List<Asura_GUIMenu_ToolComment>*pxList)
:Tools_Modal_Overlay(_Title)
{
	Asura_Assert( pxRootObject, "The root object pointer is NULL.");
	if(pxRootObject)
	{
		s_pxRootObject = pxRootObject;
		s_pxCommentList = pxRootObject->GetCommentListPtr();
	}

	m_bDisableCancel = false;

	s_bRefreshLayout = false;
}


bool Tool_Comments_Overlay::DoModal()
{
	s_bRefreshLayout = false;
	m_bInputDebounced = !Asura_UserInput::DebouncedHasAnyKeyBeenPressed();
	ReturnValue = false;
	ShowOverlay();
	return ReturnValue;
}

void Tool_Comments_Overlay::InitialiseOverlay(class Asura_Overlay* Overlay)
{
	//setup the controls on the overlay
	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f,2.0f);
	Asura_Dialog* pxDialog;
	Asura_GUIMenu_ToolComment* pxComment;

	pxDialog = new Asura_Function_Dialog("Add Comment",xOffset,AddComment);
	Overlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::LargeSpacing();

	Asura_Subwindow_Dialog* pxSubWindow = new Asura_Subwindow_Dialog( xOffset, 40, 15, false);
	Overlay->AddDialog(pxSubWindow);

	Asura_Vector_2 xPos( 0.0f, 0.0f);

	for( int i=0; i<s_pxCommentList->GetNumEntries(); i++)
	{
		pxDialog = new Asura_Function_Dialog( "Edit", xPos, _EditComment, i);
		pxSubWindow->AddDialog(pxDialog);

		xPos.x += 8.0f;
		pxDialog = new Asura_Function_Dialog( "Remove", xPos, _RemoveComment, i);
		pxSubWindow->AddDialog(pxDialog);
		xPos.x -= 8.0f;
		xPos.y+=Asura_Dialog::DefaultSpacing();

		pxComment = s_pxCommentList->GetEntryByIndex( i);
		pxComment->AddOverlayControls( pxSubWindow, xPos);	
	}
	
	xOffset.y = pxSubWindow->m_xMaxCoord.y + Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog("Close",xOffset,CloseSelected,&Overlay->m_bShouldClose);
	Overlay->AddDialog(pxDialog);
	xOffset.y+=2.0f;
}

void Tool_Comments_Overlay::Update()
{
	if(m_bInputDebounced)
	{
		if(Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_ENTER))
		{
			GetOverlay()->m_bShouldClose = true;			
			CloseSelected();
			return;
		}
		if(Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_ESCAPE) && !m_bDisableCancel)
		{
			GetOverlay()->m_bShouldClose = true;			
			CloseSelected();
			return;
		}
	}
	else
	{
		m_bInputDebounced = !Asura_UserInput::DebouncedHasAnyKeyBeenPressed();
	}		

	if( s_bRefreshLayout)
	{
		RebuildOverlay();
		s_bRefreshLayout = false;
		ReturnValue = true;
	}
}

void Tool_Comments_Overlay::_EditComment( int iValue)
{
	Asura_GUIMenu_ToolComment* pxComment = s_pxCommentList->GetEntryByIndex( iValue);

	GetString_Overlay xCommentsOverlay( "Edit Comment", pxComment->GetCommentString(), uTOOLS_GUIMENU_MAX_COMMENT_STRING_LENGTH);
	if( xCommentsOverlay.DoModal())
	{
		Asura_Char acUserName[uTOOLS_GUIMENU_MAX_COMMENT_STRING_LENGTH];
		acUserName[0] = '\0';

		Asura_Windows::GetUserNameFromPC( acUserName, uTOOLS_GUIMENU_MAX_COMMENT_STRING_LENGTH);

		pxComment->Set( acUserName, xCommentsOverlay.GetString());
		s_bRefreshLayout = true;
	}
}

void Tool_Comments_Overlay::_RemoveComment( int iValue)
{
	Asura_GUIMenu_ToolComment* pxComment = s_pxCommentList->GetEntryByIndex( iValue);
	s_pxCommentList->RemoveFromList( pxComment);
	delete pxComment;

	s_bRefreshLayout = true;
}


void Tool_Comments_Overlay::AddComment( void)
{
	GetString_Overlay xCommentsOverlay( "Add Comment", "", uTOOLS_GUIMENU_MAX_COMMENT_STRING_LENGTH);
	if( xCommentsOverlay.DoModal())
	{
		Asura_Char acUserName[uTOOLS_GUIMENU_MAX_COMMENT_STRING_LENGTH];
		acUserName[0] = '\0';

		Asura_Windows::GetUserNameFromPC( acUserName, uTOOLS_GUIMENU_MAX_COMMENT_STRING_LENGTH);

//		pxComment->Set( acUserName, xCommentsOverlay.GetString());
		
		s_pxRootObject->AddComment( acUserName, xCommentsOverlay.GetString());
		s_bRefreshLayout = true;
	}
}


#endif //ASURA_USE_GUI_MENU_SYSTEM

