コード例 #1
0
ファイル: CinemaManager.cpp プロジェクト: krichter722/0ad
void CCinemaManager::Update(const float deltaRealTime)
{
	if (g_Game->m_Paused != m_CinematicSimulationData.m_Paused)
	{
		m_CinematicSimulationData.m_Paused = g_Game->m_Paused;

		// sn - session gui object
		IGUIObject *sn = g_GUI->FindObjectByName("sn");

		// GUI visibility
		if (sn)
		{
			if (m_CinematicSimulationData.m_Paused)
				sn->SetSetting("hidden", L"false");
			else
				sn->SetSetting("hidden", L"true");
		}
	}

	if (m_CinematicSimulationData.m_PathQueue.empty() || !m_CinematicSimulationData.m_Enabled || m_CinematicSimulationData.m_Paused)
		return;
	
	if (HotkeyIsPressed("leave"))
	{
		// TODO: implement skip
	}
	
	m_CinematicSimulationData.m_PathQueue.front().Play(deltaRealTime);
}
コード例 #2
0
JSBool JSI_IGUIObject::getComputedSize(JSContext* cx, uintN argc, jsval* vp)
{
	UNUSED2(argc);

	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
	if (!e)
		return JS_FALSE;

	e->UpdateCachedSize();
	CRect size = e->m_CachedActualSize;

	JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
	try
	{
		g_ScriptingHost.SetObjectProperty_Double(obj, "left", size.left);
		g_ScriptingHost.SetObjectProperty_Double(obj, "right", size.right);
		g_ScriptingHost.SetObjectProperty_Double(obj, "top", size.top);
		g_ScriptingHost.SetObjectProperty_Double(obj, "bottom", size.bottom);
	}
	catch (PSERROR_Scripting_ConversionFailed)
	{
		debug_warn(L"Error creating size object!");
		return JS_FALSE;
	}

	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
	return JS_TRUE;
}
コード例 #3
0
ファイル: CGUI.cpp プロジェクト: Valvador/PyroSpaceFork
void CGUI::Xeromyces_ReadTooltip(XMBElement Element, CXeromyces* pFile)
{
	// Read the tooltip, and store it as a specially-named object

	IGUIObject* object = new CTooltip;

	XMBAttributeList attributes = Element.GetAttributes();
	for (int i=0; i<attributes.Count; ++i)
	{
		XMBAttribute attr = attributes.Item(i);
		CStr attr_name (pFile->GetAttributeString(attr.Name));
		CStr attr_value (attr.Value);

		if (attr_name == "name")
		{
			object->SetName("__tooltip_" + attr_value);
		}
		else
		{
			object->SetSetting(attr_name, attr_value.FromUTF8());
		}
	}

	AddObject(object);
}
コード例 #4
0
JSBool JSI_IGUIObject::blur(JSContext* cx, uintN argc, jsval* vp)
{
	UNUSED2(argc);

	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
	if (!e)
		return JS_FALSE;

	e->GetGUI()->SetFocusedObject(NULL);

	JS_SET_RVAL(cx, vp, JSVAL_VOID);
	return JS_TRUE;
}
コード例 #5
0
JSBool JSI_IGUIObject::toString(JSContext* cx, uintN argc, jsval* vp)
{
	UNUSED2(argc);

	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
	if (!e)
		return JS_FALSE;

	char buffer[256];
	snprintf(buffer, 256, "[GUIObject: %s]", e->GetName().c_str());
	buffer[255] = 0;
	JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer)));
	return JS_TRUE;
}
コード例 #6
0
ファイル: CinemaManager.cpp プロジェクト: krichter722/0ad
void CCinemaManager::SetEnabled(bool enabled)
{
	// TODO: maybe assert?
	if (m_CinematicSimulationData.m_PathQueue.empty() && enabled)
	{
		enabled = false;
		m_CinematicSimulationData.m_Paused = true;
	}

	if (m_CinematicSimulationData.m_Enabled == enabled)
		return;

	// TODO: Enabling/Disabling does not work if the session GUI page is not the top page.
	// This can happen in various situations, for example when the player wins/looses the game
	// while the cinematic is running (a message box is the top page in this case). 
	// It might be better to disable the whole GUI during the cinematic instead of a specific 
	// GUI object.
	
	// sn - session gui object
	IGUIObject *sn = g_GUI->FindObjectByName("sn");
	CmpPtr<ICmpRangeManager> cmpRangeManager(g_Game->GetSimulation2()->GetSimContext().GetSystemEntity());
	CmpPtr<ICmpTerritoryManager> cmpTerritoryManager(g_Game->GetSimulation2()->GetSimContext().GetSystemEntity());

	// GUI visibility
	if (sn)
	{
		if (enabled)
			sn->SetSetting("hidden", L"true");
		else
			sn->SetSetting("hidden", L"false");
	}

	// Overlay visibility
	g_Renderer.SetOptionBool(CRenderer::Option::OPT_SILHOUETTES, !enabled);
	if (cmpRangeManager)
	{
		if (enabled)
			m_CinematicSimulationData.m_MapRevealed = cmpRangeManager->GetLosRevealAll(-1);
		// TODO: improve m_MapRevealed state and without fade in
		cmpRangeManager->SetLosRevealAll(-1, enabled);
	}
	if (cmpTerritoryManager)
		cmpTerritoryManager->SetVisibility(!enabled);
	ICmpSelectable::SetOverrideVisibility(!enabled);
	ICmpOverlayRenderer::SetOverrideVisibility(!enabled);

	m_CinematicSimulationData.m_Enabled = enabled;
}
コード例 #7
0
ファイル: CGUI.cpp プロジェクト: 2asoft/0ad
void CGUI::Xeromyces_ReadTooltip(XMBElement Element, CXeromyces* pFile)
{
	IGUIObject* object = new CTooltip;

	for (XMBAttribute attr : Element.GetAttributes())
	{
		CStr attr_name(pFile->GetAttributeString(attr.Name));
		CStr attr_value(attr.Value);

		if (attr_name == "name")
			object->SetName("__tooltip_" + attr_value);
		else
			object->SetSetting(attr_name, attr_value.FromUTF8());
	}

	AddObject(object);
}
コード例 #8
0
ファイル: ScriptGlue.cpp プロジェクト: Gallaecio/0ad
JSBool GetGUIObjectByName(JSContext* cx, uintN argc, jsval* vp)
{
	JSU_REQUIRE_PARAMS(1);

	try
	{
		CStr name = ToPrimitive<CStr>(cx, JS_ARGV(cx, vp)[0]);
		IGUIObject* guiObj = g_GUI->FindObjectByName(name);
		if (guiObj)
			JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(guiObj->GetJSObject()));
		else
			JS_SET_RVAL(cx, vp, JSVAL_NULL);
		return JS_TRUE;
	}
	catch (PSERROR_Scripting&)
	{
		return JS_FALSE;
	}
}
コード例 #9
0
ファイル: GUITooltip.cpp プロジェクト: Marlinc/0ad
void GUITooltip::HideTooltip(const CStr& style, CGUI* gui)
{
	// Ignore attempts to use tooltip ""
	if (style.empty())
		return;

	IGUIObject* tooltipobj = gui->FindObjectByName("__tooltip_"+style);
	if (! tooltipobj)
	{
		LOGERROR(L"Cannot find tooltip named '%hs'", style.c_str());
		return;
	}

	CStr usedObjectName;
	if (GUI<CStr>::GetSetting(tooltipobj, "use_object", usedObjectName) == PSRETURN_OK
		&& !usedObjectName.empty())
	{
		IGUIObject* usedobj = gui->FindObjectByName(usedObjectName);
		if (! usedobj)
		{
			LOGERROR(L"Cannot find object named '%hs' used by tooltip '%hs'", usedObjectName.c_str(), style.c_str());
			return;
		}

		// Clear the caption
		usedobj->SetSetting("caption", L"");
		SGUIMessage msg(GUIM_SETTINGS_UPDATED, "caption");
		usedobj->HandleMessage(msg);

		bool hideobject = true;
		GUI<bool>::GetSetting(tooltipobj, "hide_object", hideobject);

		// If hide_object was enabled, hide it
		if (hideobject)
			GUI<bool>::SetSetting(usedobj, "hidden", true);
	}
	else
	{
		GUI<bool>::SetSetting(tooltipobj, "hidden", true);
	}

}
コード例 #10
0
ファイル: CGUI.cpp プロジェクト: Valvador/PyroSpaceFork
InReaction CGUI::HandleEvent(const SDL_Event_* ev)
{
	InReaction ret = IN_PASS;

	if (ev->ev.type == SDL_HOTKEYDOWN)
	{
		const char* hotkey = static_cast<const char*>(ev->ev.user.data1);
		std::map<CStr, std::vector<IGUIObject*> >::iterator it = m_HotkeyObjects.find(hotkey);
		if (it != m_HotkeyObjects.end())
		{
			for (size_t i = 0; i < it->second.size(); ++i)
			{
				it->second[i]->SendEvent(GUIM_PRESSED, "press");
			}
		}
	}

	else if (ev->ev.type == SDL_MOUSEMOTION)
	{
		// Yes the mouse position is stored as float to avoid
		//  constant conversions when operating in a
		//  float-based environment.
		m_MousePos = CPos((float)ev->ev.motion.x, (float)ev->ev.motion.y);

		SGUIMessage msg(GUIM_MOUSE_MOTION);
		GUI<SGUIMessage>::RecurseObject(GUIRR_HIDDEN | GUIRR_GHOST, m_BaseObject, 
										&IGUIObject::HandleMessage, 
										msg);
	}

	// Update m_MouseButtons. (BUTTONUP is handled later.)
	else if (ev->ev.type == SDL_MOUSEBUTTONDOWN)
	{
		switch (ev->ev.button.button)
		{
		case SDL_BUTTON_LEFT:
		case SDL_BUTTON_RIGHT:
		case SDL_BUTTON_MIDDLE:
			m_MouseButtons |= Bit<unsigned int>(ev->ev.button.button);
			break;
		default:
			break;
		}
	}

	// Update m_MousePos (for delayed mouse button events)
	CPos oldMousePos = m_MousePos;
	if (ev->ev.type == SDL_MOUSEBUTTONDOWN || ev->ev.type == SDL_MOUSEBUTTONUP)
	{
		m_MousePos = CPos((float)ev->ev.button.x, (float)ev->ev.button.y);
	}

	// Only one object can be hovered
	IGUIObject *pNearest = NULL;

	// TODO Gee: (2004-09-08) Big TODO, don't do the below if the SDL_Event is something like a keypress!
	try
	{
		PROFILE( "mouse events" );
		// TODO Gee: Optimizations needed!
		//  these two recursive function are quite overhead heavy.

		// pNearest will after this point at the hovered object, possibly NULL
		pNearest = FindObjectUnderMouse();

		// Is placed in the UpdateMouseOver function
		//if (ev->ev.type == SDL_MOUSEMOTION && pNearest)
		//	pNearest->ScriptEvent("mousemove");

		// Now we'll call UpdateMouseOver on *all* objects,
		//  we'll input the one hovered, and they will each
		//  update their own data and send messages accordingly
		
		GUI<IGUIObject*>::RecurseObject(GUIRR_HIDDEN | GUIRR_GHOST, m_BaseObject, 
										&IGUIObject::UpdateMouseOver, 
										pNearest);

		if (ev->ev.type == SDL_MOUSEBUTTONDOWN)
		{
			switch (ev->ev.button.button)
			{
			case SDL_BUTTON_LEFT:
				// Focus the clicked object (or focus none if nothing clicked on)
				SetFocusedObject(pNearest);

				if (pNearest)
					ret = pNearest->SendEvent(GUIM_MOUSE_PRESS_LEFT, "mouseleftpress");
				break;

			case SDL_BUTTON_RIGHT:
				if (pNearest)
					ret = pNearest->SendEvent(GUIM_MOUSE_PRESS_RIGHT, "mouserightpress");
				break;

#if !SDL_VERSION_ATLEAST(2, 0, 0)
			case SDL_BUTTON_WHEELDOWN: // wheel down
				if (pNearest)
					ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_DOWN, "mousewheeldown");
				break;

			case SDL_BUTTON_WHEELUP: // wheel up
				if (pNearest)
					ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_UP, "mousewheelup");
				break;
#endif
			default:
				break;
			}
		}
#if SDL_VERSION_ATLEAST(2, 0, 0)
		else if (ev->ev.type == SDL_MOUSEWHEEL)
		{
			if (ev->ev.wheel.y < 0)
			{
				if (pNearest)
					ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_DOWN, "mousewheeldown");
			}
			else if (ev->ev.wheel.y > 0)
			{
				if (pNearest)
					ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_UP, "mousewheelup");
			}
		}
#endif
		else if (ev->ev.type == SDL_MOUSEBUTTONUP)
		{
			switch (ev->ev.button.button)
			{
			case SDL_BUTTON_LEFT:
				if (pNearest)
				{
					double timeElapsed = timer_Time() - pNearest->m_LastClickTime[SDL_BUTTON_LEFT];
					pNearest->m_LastClickTime[SDL_BUTTON_LEFT] = timer_Time();
					
					//Double click?
					if (timeElapsed < SELECT_DBLCLICK_RATE)
					{
						ret = pNearest->SendEvent(GUIM_MOUSE_DBLCLICK_LEFT, "mouseleftdoubleclick");
					}
					else
					{
						ret = pNearest->SendEvent(GUIM_MOUSE_RELEASE_LEFT, "mouseleftrelease");
					}
				}
				break;
			case SDL_BUTTON_RIGHT:
				if (pNearest)
				{
					double timeElapsed = timer_Time() - pNearest->m_LastClickTime[SDL_BUTTON_RIGHT];
					pNearest->m_LastClickTime[SDL_BUTTON_RIGHT] = timer_Time();
					
					//Double click?
					if (timeElapsed < SELECT_DBLCLICK_RATE)
					{
						ret = pNearest->SendEvent(GUIM_MOUSE_DBLCLICK_RIGHT, "mouserightdoubleclick");
					}
					else
					{
						ret = pNearest->SendEvent(GUIM_MOUSE_RELEASE_RIGHT, "mouserightrelease");
					}
				}
				break;
			}

			// Reset all states on all visible objects
			GUI<>::RecurseObject(GUIRR_HIDDEN, m_BaseObject, 
									&IGUIObject::ResetStates);

			// It will have reset the mouse over of the current hovered, so we'll
			//  have to restore that
			if (pNearest)
				pNearest->m_MouseHovering = true;
		}
	}
	catch (PSERROR_GUI& e)
	{
		UNUSED2(e);
		debug_warn(L"CGUI::HandleEvent error");
		// TODO Gee: Handle
	}

	// BUTTONUP's effect on m_MouseButtons is handled after
	// everything else, so that e.g. 'press' handlers (activated
	// on button up) see which mouse button had been pressed.
	if (ev->ev.type == SDL_MOUSEBUTTONUP)
	{
		switch (ev->ev.button.button)
		{
		case SDL_BUTTON_LEFT:
		case SDL_BUTTON_RIGHT:
		case SDL_BUTTON_MIDDLE:
			m_MouseButtons &= ~Bit<unsigned int>(ev->ev.button.button);
			break;
		default:
			break;
		}
	}

	// Restore m_MousePos (for delayed mouse button events)
	if (ev->ev.type == SDL_MOUSEBUTTONDOWN || ev->ev.type == SDL_MOUSEBUTTONUP)
	{
		m_MousePos = oldMousePos;
	}

	// Handle keys for input boxes
	if (GetFocusedObject())
	{
		if (
			(ev->ev.type == SDL_KEYDOWN &&
				ev->ev.key.keysym.sym != SDLK_ESCAPE &&
				!g_keys[SDLK_LCTRL] && !g_keys[SDLK_RCTRL] &&
				!g_keys[SDLK_LALT] && !g_keys[SDLK_RALT]) 
			|| ev->ev.type == SDL_HOTKEYDOWN
			)
		{
			ret = GetFocusedObject()->ManuallyHandleEvent(ev);
		}
		// else will return IN_PASS because we never used the button.
	}

	return ret;
}
コード例 #11
0
ファイル: CGUI.cpp プロジェクト: Valvador/PyroSpaceFork
void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObject *pParent, const std::vector<std::pair<CStr, CStr> >& NameSubst, boost::unordered_set<VfsPath>& Paths)
{
	ENSURE(pParent);
	int i;

	// Our object we are going to create
	IGUIObject *object = NULL;

	XMBAttributeList attributes = Element.GetAttributes();

	// Well first of all we need to determine the type
	CStr type (attributes.GetNamedItem(pFile->GetAttributeID("type")));
	if (type.empty())
		type = "empty";

	// Construct object from specified type
	//  henceforth, we need to do a rollback before aborting.
	//  i.e. releasing this object
	object = ConstructObject(type);

	if (!object)
	{
		// Report error that object was unsuccessfully loaded
		LOGERROR(L"GUI: Unrecognized object type \"%hs\"", type.c_str());
		return;
	}

	// Cache some IDs for element attribute names, to avoid string comparisons
	#define ELMT(x) int elmt_##x = pFile->GetElementID(#x)
	#define ATTR(x) int attr_##x = pFile->GetAttributeID(#x)
	ELMT(object);
	ELMT(action);
	ELMT(repeat);
	ATTR(style);
	ATTR(type);
	ATTR(name);
	ATTR(hotkey);
	ATTR(z);
	ATTR(on);
	ATTR(file);

	//
	//	Read Style and set defaults
	//
	//	If the setting "style" is set, try loading that setting.
	//
	//	Always load default (if it's available) first!
	//
	CStr argStyle (attributes.GetNamedItem(attr_style));

	if (m_Styles.count("default") == 1)
		object->LoadStyle(*this, "default");

	if (! argStyle.empty())
	{
		// additional check
		if (m_Styles.count(argStyle) == 0)
		{
			LOGERROR(L"GUI: Trying to use style '%hs' that doesn't exist.", argStyle.c_str());
		}
		else object->LoadStyle(*this, argStyle);
	}
	

	//
	//	Read Attributes
	//

	bool NameSet = false;
	bool ManuallySetZ = false; // if z has been manually set, this turn true

	CStr hotkeyTag;

	// Now we can iterate all attributes and store
	for (i=0; i<attributes.Count; ++i)
	{
		XMBAttribute attr = attributes.Item(i);

		// If value is "null", then it is equivalent as never being entered
		if (CStr(attr.Value) == "null")
			continue;

		// Ignore "type" and "style", we've already checked it
		if (attr.Name == attr_type || attr.Name == attr_style)
			continue;

		// Also the name needs some special attention
		if (attr.Name == attr_name)
		{
			CStr name (attr.Value);

			// Apply the requested substitutions
			for (size_t j = 0; j < NameSubst.size(); ++j)
				name.Replace(NameSubst[j].first, NameSubst[j].second);

			object->SetName(name);
			NameSet = true;
			continue;
		}

		// Wire up the hotkey tag, if it has one
		if (attr.Name == attr_hotkey)
			hotkeyTag = attr.Value;

		if (attr.Name == attr_z)
			ManuallySetZ = true;

		// Try setting the value
		if (object->SetSetting(pFile->GetAttributeString(attr.Name), attr.Value.FromUTF8(), true) != PSRETURN_OK)
		{
			LOGERROR(L"GUI: (object: %hs) Can't set \"%hs\" to \"%ls\"", object->GetPresentableName().c_str(), pFile->GetAttributeString(attr.Name).c_str(), attr.Value.FromUTF8().c_str());

			// This is not a fatal error
		}
	}

	// Check if name isn't set, generate an internal name in that case.
	if (!NameSet)
	{
		object->SetName("__internal(" + CStr::FromInt(m_InternalNameNumber) + ")");
		++m_InternalNameNumber;
	}

	// Attempt to register the hotkey tag, if one was provided
	if (! hotkeyTag.empty())
		m_HotkeyObjects[hotkeyTag].push_back(object);

	CStrW caption (Element.GetText().FromUTF8());
	if (! caption.empty())
	{
		// Set the setting caption to this
		object->SetSetting("caption", caption, true);

		// There is no harm if the object didn't have a "caption"
	}


	//
	//	Read Children
	//

	// Iterate children
	XMBElementList children = Element.GetChildNodes();

	for (i=0; i<children.Count; ++i)
	{
		// Get node
		XMBElement child = children.Item(i);

		// Check what name the elements got
		int element_name = child.GetNodeName();

		if (element_name == elmt_object)
		{
			// Call this function on the child
			Xeromyces_ReadObject(child, pFile, object, NameSubst, Paths);
		}
		else if (element_name == elmt_action)
		{
			// Scripted <action> element

			// Check for a 'file' parameter
			CStrW filename (child.GetAttributes().GetNamedItem(attr_file).FromUTF8());

			CStr code;

			// If there is a file, open it and use it as the code
			if (! filename.empty())
			{
				Paths.insert(filename);
				CVFSFile scriptfile;
				if (scriptfile.Load(g_VFS, filename) != PSRETURN_OK)
				{
					LOGERROR(L"Error opening GUI script action file '%ls'", filename.c_str());
					throw PSERROR_GUI_JSOpenFailed();
				}

				code = scriptfile.DecodeUTF8(); // assume it's UTF-8
			}

			// Read the inline code (concatenating to the file code, if both are specified)
			code += CStr(child.GetText());

			CStr action = CStr(child.GetAttributes().GetNamedItem(attr_on));
			
			// We need to set the GUI this object belongs to because RegisterScriptHandler requires an associated GUI.
			object->SetGUI(this);
			object->RegisterScriptHandler(action.LowerCase(), code, this);
		}
		else if (element_name == elmt_repeat)
		{
			Xeromyces_ReadRepeat(child, pFile, object, Paths);
		}
		else
		{
			// Try making the object read the tag.
			if (!object->HandleAdditionalChildren(child, pFile))
			{
				LOGERROR(L"GUI: (object: %hs) Reading unknown children for its type", object->GetPresentableName().c_str());
			}
		}
	} 

	//
	//	Check if Z wasn't manually set
	//
	if (!ManuallySetZ)
	{
		// Set it automatically to 10 plus its parents
		bool absolute;
		GUI<bool>::GetSetting(object, "absolute", absolute);

		// If the object is absolute, we'll have to get the parent's Z buffered,
		//  and add to that!
		if (absolute)
		{
			GUI<float>::SetSetting(object, "z", pParent->GetBufferedZ() + 10.f, true);
		}
		else
		// If the object is relative, then we'll just store Z as "10"
		{
			GUI<float>::SetSetting(object, "z", 10.f, true);
		}
	}


	//
	//	Input Child
	//

	try
	{
		if (pParent == m_BaseObject)
			AddObject(object);
		else
			pParent->AddChild(object);
	}
	catch (PSERROR_GUI& e)
	{
		LOGERROR(L"GUI error: %hs", e.what());
	}
}
コード例 #12
0
JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
{
	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL);
	if (!e)
		return JS_FALSE;

	jsval idval;
	if (!JS_IdToValue(cx, id, &idval))
		return JS_FALSE;

	std::string propName;
	if (!ScriptInterface::FromJSVal(cx, idval, propName))
		return JS_FALSE;

	// Skip some things which are known to be functions rather than properties.
	// ("constructor" *must* be here, else it'll try to GetSettingType before
	// the private IGUIObject* has been set (and thus crash). The others are
	// partly for efficiency, and also to allow correct reporting of attempts to
	// access nonexistent properties.)
	if (propName == "constructor" ||
		propName == "prototype"   ||
		propName == "toString"    ||
		propName == "focus"       ||
		propName == "blur"        ||
		propName == "getComputedSize"
	   )
		return JS_TRUE;

	// Use onWhatever to access event handlers
	if (propName.substr(0, 2) == "on")
	{
		CStr eventName (CStr(propName.substr(2)).LowerCase());
		std::map<CStr, JSObject**>::iterator it = e->m_ScriptHandlers.find(eventName);
		if (it == e->m_ScriptHandlers.end())
			*vp = JSVAL_NULL;
		else
			*vp = OBJECT_TO_JSVAL(*(it->second));
		return JS_TRUE;
	}


	// Handle the "parent" property specially
	if (propName == "parent")
	{
		IGUIObject* parent = e->GetParent();
		if (parent)
		{
			// If the object isn't parentless, return a new object
			*vp = OBJECT_TO_JSVAL(parent->GetJSObject());
		}
		else
		{
			// Return null if there's no parent
			*vp = JSVAL_NULL;
		}
		return JS_TRUE;
	}
	// Also handle "name" specially
	else if (propName == "name")
	{
		*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, e->GetName().c_str()));
		return JS_TRUE;
	}
	// Handle all other properties
	else
	{
		// Retrieve the setting's type (and make sure it actually exists)
		EGUISettingType Type;
		if (e->GetSettingType(propName, Type) != PSRETURN_OK)
		{
			JS_ReportError(cx, "Invalid GUIObject property '%s'", propName.c_str());
			return JS_FALSE;
		}

		// (All the cases are in {...} to avoid scoping problems)
		switch (Type)
		{
		case GUIST_bool:
			{
				bool value;
				GUI<bool>::GetSetting(e, propName, value);
				*vp = value ? JSVAL_TRUE : JSVAL_FALSE;
				break;
			}

		case GUIST_int:
			{
				int value;
				GUI<int>::GetSetting(e, propName, value);
				*vp = INT_TO_JSVAL(value);
				break;
			}

		case GUIST_float:
			{
				float value;
				GUI<float>::GetSetting(e, propName, value);
				// Create a garbage-collectable double
				return JS_NewNumberValue(cx, value, vp);
			}

		case GUIST_CColor:
			{
				CColor colour;
				GUI<CColor>::GetSetting(e, propName, colour);
				JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL);
				*vp = OBJECT_TO_JSVAL(obj); // root it

				jsval c;
				// Attempt to minimise ugliness through macrosity
				#define P(x) if (!JS_NewNumberValue(cx, colour.x, &c)) return JS_FALSE; JS_SetProperty(cx, obj, #x, &c)
					P(r);
					P(g);
					P(b);
					P(a);
				#undef P

				break;
			}

		case GUIST_CClientArea:
			{
				CClientArea area;
				GUI<CClientArea>::GetSetting(e, propName, area);
				JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL);
				*vp = OBJECT_TO_JSVAL(obj); // root it
				try
				{
				#define P(x, y, z) g_ScriptingHost.SetObjectProperty_Double(obj, #z, area.x.y)
					P(pixel,	left,	left);
					P(pixel,	top,	top);
					P(pixel,	right,	right);
					P(pixel,	bottom,	bottom);
					P(percent,	left,	rleft);
					P(percent,	top,	rtop);
					P(percent,	right,	rright);
					P(percent,	bottom,	rbottom);
				#undef P
				}
				catch (PSERROR_Scripting_ConversionFailed)
				{
					debug_warn(L"Error creating size object!");
					break;
				}

				break;
			}

		case GUIST_CGUIString:
			{
				CGUIString value;
				GUI<CGUIString>::GetSetting(e, propName, value);
				*vp = ScriptInterface::ToJSVal(cx, value.GetOriginalString());
				break;
			}

		case GUIST_CStr:
			{
				CStr value;
				GUI<CStr>::GetSetting(e, propName, value);
				*vp = ScriptInterface::ToJSVal(cx, value);
				break;
			}

		case GUIST_CStrW:
			{
				CStrW value;
				GUI<CStrW>::GetSetting(e, propName, value);
				*vp = ScriptInterface::ToJSVal(cx, value);
				break;
			}

		case GUIST_CGUISpriteInstance:
			{
				CGUISpriteInstance *value;
				GUI<CGUISpriteInstance>::GetSettingPointer(e, propName, value);
				*vp = ScriptInterface::ToJSVal(cx, value->GetName());
				break;
			}

		case GUIST_EAlign:
			{
				EAlign value;
				GUI<EAlign>::GetSetting(e, propName, value);
				CStr word;
				switch (value)
				{
				case EAlign_Left: word = "left"; break;
				case EAlign_Right: word = "right"; break;
				case EAlign_Center: word = "center"; break;
				default: debug_warn(L"Invalid EAlign!"); word = "error"; break;
				}
				*vp = ScriptInterface::ToJSVal(cx, word);
				break;
			}

		case GUIST_EVAlign:
			{
				EVAlign value;
				GUI<EVAlign>::GetSetting(e, propName, value);
				CStr word;
				switch (value)
				{
				case EVAlign_Top: word = "top"; break;
				case EVAlign_Bottom: word = "bottom"; break;
				case EVAlign_Center: word = "center"; break;
				default: debug_warn(L"Invalid EVAlign!"); word = "error"; break;
				}
				*vp = ScriptInterface::ToJSVal(cx, word);
				break;
			}

		case GUIST_CGUIList:
			{
				CGUIList value;
				GUI<CGUIList>::GetSetting(e, propName, value);

				JSObject *obj = JS_NewArrayObject(cx, 0, NULL);
				*vp = OBJECT_TO_JSVAL(obj); // root it
				
				for (size_t i = 0; i < value.m_Items.size(); ++i)
				{
					jsval val = ScriptInterface::ToJSVal(cx, value.m_Items[i].GetOriginalString());
					JS_SetElement(cx, obj, (jsint)i, &val);
				}

				break;
			}

		default:
			JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str());
			DEBUG_WARN_ERR(ERR::LOGIC);
			return JS_FALSE;
		}

		return JS_TRUE;
	}
}
コード例 #13
0
JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsid id, JSBool UNUSED(strict), jsval* vp)
{
	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL);
	if (!e)
		return JS_FALSE;

	jsval idval;
	if (!JS_IdToValue(cx, id, &idval))
		return JS_FALSE;

	std::string propName;
	if (!ScriptInterface::FromJSVal(cx, idval, propName))
		return JS_FALSE;

	if (propName == "name")
	{
		std::string value;
		if (!ScriptInterface::FromJSVal(cx, *vp, value))
			return JS_FALSE;
		e->SetName(value);
		return JS_TRUE;
	}

	// Use onWhatever to set event handlers
	if (propName.substr(0, 2) == "on")
	{
		if (!JSVAL_IS_OBJECT(*vp) || !JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(*vp)))
		{
			JS_ReportError(cx, "on- event-handlers must be functions");
			return JS_FALSE;
		}

		CStr eventName (CStr(propName.substr(2)).LowerCase());
		e->SetScriptHandler(eventName, JSVAL_TO_OBJECT(*vp));

		return JS_TRUE;
	}

	// Retrieve the setting's type (and make sure it actually exists)
	EGUISettingType Type;
	if (e->GetSettingType(propName, Type) != PSRETURN_OK)
	{
		JS_ReportError(cx, "Invalid setting '%s'", propName.c_str());
		return JS_TRUE;
	}

	switch (Type)
	{

	case GUIST_CStr:
		{
			std::string value;
			if (!ScriptInterface::FromJSVal(cx, *vp, value))
				return JS_FALSE;

			GUI<CStr>::SetSetting(e, propName, value);
			break;
		}

	case GUIST_CStrW:
		{
			std::wstring value;
			if (!ScriptInterface::FromJSVal(cx, *vp, value))
				return JS_FALSE;

			GUI<CStrW>::SetSetting(e, propName, value);
			break;
		}

	case GUIST_CGUISpriteInstance:
		{
			std::string value;
			if (!ScriptInterface::FromJSVal(cx, *vp, value))
				return JS_FALSE;

			GUI<CGUISpriteInstance>::SetSetting(e, propName, CGUISpriteInstance(value));
			break;
		}

	case GUIST_CGUIString:
		{
			std::wstring value;
			if (!ScriptInterface::FromJSVal(cx, *vp, value))
				return JS_FALSE;

			CGUIString str;
			str.SetValue(value);
			GUI<CGUIString>::SetSetting(e, propName, str);
			break;
		}

	case GUIST_EAlign:
		{
			std::string value;
			if (!ScriptInterface::FromJSVal(cx, *vp, value))
				return JS_FALSE;

			EAlign a;
			if (value == "left") a = EAlign_Left;
			else if (value == "right") a = EAlign_Right;
			else if (value == "center" || value == "centre") a = EAlign_Center;
			else
			{
				JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')");
				return JS_FALSE;
			}
			GUI<EAlign>::SetSetting(e, propName, a);
			break;
		}

	case GUIST_EVAlign:
		{
			std::string value;
			if (!ScriptInterface::FromJSVal(cx, *vp, value))
				return JS_FALSE;

			EVAlign a;
			if (value == "top") a = EVAlign_Top;
			else if (value == "bottom") a = EVAlign_Bottom;
			else if (value == "center" || value == "centre") a = EVAlign_Center;
			else
			{
				JS_ReportError(cx, "Invalid alignment (should be 'top', 'bottom' or 'center')");
				return JS_FALSE;
			}
			GUI<EVAlign>::SetSetting(e, propName, a);
			break;
		}

	case GUIST_int:
		{
			int32 value;
			if (JS_ValueToInt32(cx, *vp, &value) == JS_TRUE)
				GUI<int>::SetSetting(e, propName, value);
			else
			{
				JS_ReportError(cx, "Cannot convert value to int");
				return JS_FALSE;
			}
			break;
		}

	case GUIST_float:
		{
			jsdouble value;
			if (JS_ValueToNumber(cx, *vp, &value) == JS_TRUE)
				GUI<float>::SetSetting(e, propName, (float)value);
			else
			{
				JS_ReportError(cx, "Cannot convert value to float");
				return JS_FALSE;
			}
			break;
		}

	case GUIST_bool:
		{
			JSBool value;
			if (JS_ValueToBoolean(cx, *vp, &value) == JS_TRUE)
				GUI<bool>::SetSetting(e, propName, value||0); // ||0 to avoid int-to-bool compiler warnings
			else
			{
				JS_ReportError(cx, "Cannot convert value to bool");
				return JS_FALSE;
			}
			break;
		}

	case GUIST_CClientArea:
		{
			if (JSVAL_IS_STRING(*vp))
			{
				std::wstring value;
				if (!ScriptInterface::FromJSVal(cx, *vp, value))
					return JS_FALSE;

				if (e->SetSetting(propName, value) != PSRETURN_OK)
				{
					JS_ReportError(cx, "Invalid value for setting '%s'", propName.c_str());
					return JS_FALSE;
				}
			}
			else if (JSVAL_IS_OBJECT(*vp) && JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), &JSI_GUISize::JSI_class, NULL))
			{
				CClientArea area;
				GUI<CClientArea>::GetSetting(e, propName, area);

				JSObject* obj = JSVAL_TO_OBJECT(*vp);
				#define P(x, y, z) area.x.y = (float)g_ScriptingHost.GetObjectProperty_Double(obj, #z)
					P(pixel,	left,	left);
					P(pixel,	top,	top);
					P(pixel,	right,	right);
					P(pixel,	bottom,	bottom);
					P(percent,	left,	rleft);
					P(percent,	top,	rtop);
					P(percent,	right,	rright);
					P(percent,	bottom,	rbottom);
				#undef P

				GUI<CClientArea>::SetSetting(e, propName, area);
			}
			else
			{
				JS_ReportError(cx, "Size only accepts strings or GUISize objects");
				return JS_FALSE;
			}
			break;
		}

	case GUIST_CColor:
		{
			if (JSVAL_IS_STRING(*vp))
			{
				std::wstring value;
				if (!ScriptInterface::FromJSVal(cx, *vp, value))
					return JS_FALSE;

				if (e->SetSetting(propName, value) != PSRETURN_OK)
				{
					JS_ReportError(cx, "Invalid value for setting '%s'", propName.c_str());
					return JS_FALSE;
				}
			}
			else if (JSVAL_IS_OBJECT(*vp) && JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), &JSI_GUIColor::JSI_class, NULL))
			{
				CColor colour;
				JSObject* obj = JSVAL_TO_OBJECT(*vp);
				jsval t; double s;
				#define PROP(x) JS_GetProperty(cx, obj, #x, &t); \
								JS_ValueToNumber(cx, t, &s); \
								colour.x = (float)s
				PROP(r); PROP(g); PROP(b); PROP(a);
				#undef PROP

				GUI<CColor>::SetSetting(e, propName, colour);
			}
			else
			{
				JS_ReportError(cx, "Color only accepts strings or GUIColor objects");
				return JS_FALSE;
			}
			break;
		}

	case GUIST_CGUIList:
		{
			JSObject* obj = JSVAL_TO_OBJECT(*vp);
			jsuint length;
			if (JSVAL_IS_OBJECT(*vp) && JS_GetArrayLength(cx, obj, &length) == JS_TRUE)
			{
				CGUIList list;

				for (int i=0; i<(int)length; ++i)
				{
					jsval element;
					if (! JS_GetElement(cx, obj, i, &element))
					{
						JS_ReportError(cx, "Failed to get list element");
						return JS_FALSE;
					}

					std::wstring value;
					if (!ScriptInterface::FromJSVal(cx, element, value))
						return JS_FALSE;

					CGUIString str;
					str.SetValue(value);
					
					list.m_Items.push_back(str);
				}

				GUI<CGUIList>::SetSetting(e, propName, list);
			}
			else
			{
				JS_ReportError(cx, "List only accepts a GUIList object");
				return JS_FALSE;
			}
			break;
		}

		// TODO Gee: (2004-09-01) EAlign and EVAlign too.

	default:
		JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str());
		break;
	}

	return !JS_IsExceptionPending(cx);
}
コード例 #14
0
ファイル: GUITooltip.cpp プロジェクト: Marlinc/0ad
void GUITooltip::ShowTooltip(IGUIObject* obj, CPos pos, const CStr& style, CGUI* gui)
{
	ENSURE(obj);

	// Ignore attempts to use tooltip ""
	if (style.empty())
		return;

	// Get the object referenced by 'tooltip_style'
	IGUIObject* tooltipobj = gui->FindObjectByName("__tooltip_"+style);
	if (! tooltipobj)
	{
		LOGERROR(L"Cannot find tooltip named '%hs'", style.c_str());
		return;
	}

	IGUIObject* usedobj = tooltipobj; // object actually used to display the tooltip in

	CStr usedObjectName;
	if (GUI<CStr>::GetSetting(tooltipobj, "use_object", usedObjectName) == PSRETURN_OK
		&& !usedObjectName.empty())
	{
		usedobj = gui->FindObjectByName(usedObjectName);
		if (! usedobj)
		{
			LOGERROR(L"Cannot find object named '%hs' used by tooltip '%hs'", usedObjectName.c_str(), style.c_str());
			return;
		}

		// Unhide the object. (If it had use_object and hide_object="true",
		// still unhide it, because the used object might be hidden by default)
		GUI<bool>::SetSetting(usedobj, "hidden", false);
	}
	else
	{
		// Unhide the object
		GUI<bool>::SetSetting(usedobj, "hidden", false);

		// Store mouse position inside the CTooltip
		if (GUI<CPos>::SetSetting(usedobj, "_mousepos", pos) != PSRETURN_OK)
			debug_warn(L"Failed to set tooltip mouse position");
	}

	// Retrieve object's 'tooltip' setting
	CStrW text;
	if (m_IsIconTooltip)
	{
		// Use icon tooltip property
		if (GUI<CStrW>::GetSetting(obj, "_icon_tooltip", text) != PSRETURN_OK)
			debug_warn(L"Failed to retrieve icon tooltip text"); // shouldn't fail
	}
	else
	{
		// Use normal tooltip property
		if (GUI<CStrW>::GetSetting(obj, "tooltip", text) != PSRETURN_OK)
			debug_warn(L"Failed to retrieve tooltip text"); // shouldn't fail
	}

	// Do some minimal processing ("\n" -> newline, etc)
	text = text.UnescapeBackslashes();

	// Set tooltip's caption
	if (usedobj->SetSetting("caption", text) != PSRETURN_OK)
		debug_warn(L"Failed to set tooltip caption"); // shouldn't fail

	// Make the tooltip object regenerate its text
	SGUIMessage msg(GUIM_SETTINGS_UPDATED, "caption");
	usedobj->HandleMessage(msg);
}
コード例 #15
0
ファイル: CGUI.cpp プロジェクト: 2asoft/0ad
void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObject* pParent, std::vector<std::pair<CStr, CStr> >& NameSubst, boost::unordered_set<VfsPath>& Paths, u32 nesting_depth)
{
	ENSURE(pParent);

	XMBAttributeList attributes = Element.GetAttributes();

	CStr type(attributes.GetNamedItem(pFile->GetAttributeID("type")));
	if (type.empty())
		type = "empty";

	// Construct object from specified type
	//  henceforth, we need to do a rollback before aborting.
	//  i.e. releasing this object
	IGUIObject* object = ConstructObject(type);

	if (!object)
	{
		LOGERROR("GUI: Unrecognized object type \"%s\"", type.c_str());
		return;
	}

	// Cache some IDs for element attribute names, to avoid string comparisons
	#define ELMT(x) int elmt_##x = pFile->GetElementID(#x)
	#define ATTR(x) int attr_##x = pFile->GetAttributeID(#x)
	ELMT(object);
	ELMT(action);
	ELMT(repeat);
	ELMT(translatableAttribute);
	ELMT(translate);
	ELMT(attribute);
	ELMT(keep);
	ELMT(include);
	ATTR(style);
	ATTR(type);
	ATTR(name);
	ATTR(hotkey);
	ATTR(z);
	ATTR(on);
	ATTR(file);
	ATTR(directory);
	ATTR(id);
	ATTR(context);

	//
	//	Read Style and set defaults
	//
	//	If the setting "style" is set, try loading that setting.
	//
	//	Always load default (if it's available) first!
	//
	CStr argStyle(attributes.GetNamedItem(attr_style));

	if (m_Styles.count("default") == 1)
		object->LoadStyle(*this, "default");

	if (!argStyle.empty())
	{
		if (m_Styles.count(argStyle) == 0)
			LOGERROR("GUI: Trying to use style '%s' that doesn't exist.", argStyle.c_str());
		else
			object->LoadStyle(*this, argStyle);
	}

	bool NameSet = false;
	bool ManuallySetZ = false;

	CStrW inclusionPath;
	CStr hotkeyTag;

	for (XMBAttribute attr : attributes)
	{
		// If value is "null", then it is equivalent as never being entered
		if (CStr(attr.Value) == "null")
			continue;

		// Ignore "type" and "style", we've already checked it
		if (attr.Name == attr_type || attr.Name == attr_style)
			continue;

		if (attr.Name == attr_name)
		{
			CStr name(attr.Value);

			for (const std::pair<CStr, CStr>& sub : NameSubst)
				name.Replace(sub.first, sub.second);

			object->SetName(name);
			NameSet = true;
			continue;
		}

		if (attr.Name == attr_hotkey)
			hotkeyTag = attr.Value;

		if (attr.Name == attr_z)
			ManuallySetZ = true;

		if (object->SetSetting(pFile->GetAttributeString(attr.Name), attr.Value.FromUTF8(), true) != PSRETURN_OK)
			LOGERROR("GUI: (object: %s) Can't set \"%s\" to \"%s\"", object->GetPresentableName(), pFile->GetAttributeString(attr.Name), attr.Value);
	}

	// Check if name isn't set, generate an internal name in that case.
	if (!NameSet)
	{
		object->SetName("__internal(" + CStr::FromInt(m_InternalNameNumber) + ")");
		++m_InternalNameNumber;
	}

	if (!hotkeyTag.empty())
		m_HotkeyObjects[hotkeyTag].push_back(object);

	CStrW caption(Element.GetText().FromUTF8());
	if (!caption.empty())
		object->SetSetting("caption", caption, true);

	for (XMBElement child : Element.GetChildNodes())
	{
		// Check what name the elements got
		int element_name = child.GetNodeName();

		if (element_name == elmt_object)
		{
			// Call this function on the child
			Xeromyces_ReadObject(child, pFile, object, NameSubst, Paths, nesting_depth);
		}
		else if (element_name == elmt_action)
		{
			// Scripted <action> element

			// Check for a 'file' parameter
			CStrW filename(child.GetAttributes().GetNamedItem(attr_file).FromUTF8());

			CStr code;

			// If there is a file, open it and use it as the code
			if (!filename.empty())
			{
				Paths.insert(filename);
				CVFSFile scriptfile;
				if (scriptfile.Load(g_VFS, filename) != PSRETURN_OK)
				{
					LOGERROR("Error opening GUI script action file '%s'", utf8_from_wstring(filename));
					throw PSERROR_GUI_JSOpenFailed();
				}

				code = scriptfile.DecodeUTF8(); // assume it's UTF-8
			}

			XMBElementList grandchildren = child.GetChildNodes();
			if (!grandchildren.empty()) // The <action> element contains <keep> and <translate> tags.
				for (XMBElement grandchild : grandchildren)
				{
					if (grandchild.GetNodeName() == elmt_translate)
						code += g_L10n.Translate(grandchild.GetText());
					else if (grandchild.GetNodeName() == elmt_keep)
						code += grandchild.GetText();
				}
			else // It’s pure JavaScript code.
				// Read the inline code (concatenating to the file code, if both are specified)
				code += CStr(child.GetText());

			CStr action = CStr(child.GetAttributes().GetNamedItem(attr_on));

			// We need to set the GUI this object belongs to because RegisterScriptHandler requires an associated GUI.
			object->SetGUI(this);
			object->RegisterScriptHandler(action.LowerCase(), code, this);
		}
		else if (element_name == elmt_repeat)
		{
			Xeromyces_ReadRepeat(child, pFile, object, NameSubst, Paths, nesting_depth);
		}
		else if (element_name == elmt_translatableAttribute)
		{
			// This is an element in the form “<translatableAttribute id="attributeName">attributeValue</translatableAttribute>”.
			CStr attributeName(child.GetAttributes().GetNamedItem(attr_id)); // Read the attribute name.
			if (attributeName.empty())
			{
				LOGERROR("GUI: ‘translatableAttribute’ XML element with empty ‘id’ XML attribute found. (object: %s)", object->GetPresentableName().c_str());
				continue;
			}

			CStr value(child.GetText());
			if (value.empty())
				continue;

			CStr context(child.GetAttributes().GetNamedItem(attr_context)); // Read the context if any.
			if (!context.empty())
			{
				CStr translatedValue(g_L10n.TranslateWithContext(context, value));
				object->SetSetting(attributeName, translatedValue.FromUTF8(), true);
			}
			else
			{
				CStr translatedValue(g_L10n.Translate(value));
				object->SetSetting(attributeName, translatedValue.FromUTF8(), true);
			}
		}
		else if (element_name == elmt_attribute)
		{
			// This is an element in the form “<attribute id="attributeName"><keep>Don’t translate this part
			// </keep><translate>but translate this one.</translate></attribute>”.
			CStr attributeName(child.GetAttributes().GetNamedItem(attr_id)); // Read the attribute name.
			if (attributeName.empty())
			{
				LOGERROR("GUI: ‘attribute’ XML element with empty ‘id’ XML attribute found. (object: %s)", object->GetPresentableName().c_str());
				continue;
			}

			CStr translatedValue;

			for (XMBElement grandchild : child.GetChildNodes())
			{
				if (grandchild.GetNodeName() == elmt_translate)
					translatedValue += g_L10n.Translate(grandchild.GetText());
				else if (grandchild.GetNodeName() == elmt_keep)
					translatedValue += grandchild.GetText();
			}
			object->SetSetting(attributeName, translatedValue.FromUTF8(), true);
		}
		else if (element_name == elmt_include)
		{
			CStrW filename(child.GetAttributes().GetNamedItem(attr_file).FromUTF8());
			CStrW directory(child.GetAttributes().GetNamedItem(attr_directory).FromUTF8());
			if (!filename.empty())
			{
				if (!directory.empty())
					LOGWARNING("GUI: Include element found with file name (%s) and directory name (%s). Only the file will be processed.", utf8_from_wstring(filename), utf8_from_wstring(directory));

				Paths.insert(filename);

				CXeromyces XeroIncluded;
				if (XeroIncluded.Load(g_VFS, filename, "gui") != PSRETURN_OK)
				{
					LOGERROR("GUI: Error reading included XML: '%s'", utf8_from_wstring(filename));
					continue;
				}

				XMBElement node = XeroIncluded.GetRoot();
				if (node.GetNodeName() != XeroIncluded.GetElementID("object"))
				{
					LOGERROR("GUI: Error reading included XML: '%s', root element must have be of type 'object'.", utf8_from_wstring(filename));
					continue;
				}

				if (nesting_depth+1 >= MAX_OBJECT_DEPTH)
				{
					LOGERROR("GUI: Too many nested GUI includes. Probably caused by a recursive include attribute. Abort rendering '%s'.", utf8_from_wstring(filename));
					continue;
				}

				Xeromyces_ReadObject(node, &XeroIncluded, object, NameSubst, Paths, nesting_depth+1);
			}
			else if (!directory.empty())
			{
				if (nesting_depth+1 >= MAX_OBJECT_DEPTH)
				{
					LOGERROR("GUI: Too many nested GUI includes. Probably caused by a recursive include attribute. Abort rendering '%s'.", utf8_from_wstring(directory));
					continue;
				}

				VfsPaths pathnames;
				vfs::GetPathnames(g_VFS, directory, L"*.xml", pathnames);
				for (const VfsPath& path : pathnames)
				{
					// as opposed to loading scripts, don't care if it's loaded before
					// one might use the same parts of the GUI in different situations
					Paths.insert(path);
					CXeromyces XeroIncluded;
					if (XeroIncluded.Load(g_VFS, path, "gui") != PSRETURN_OK)
					{
						LOGERROR("GUI: Error reading included XML: '%s'", path.string8());
						continue;
					}

					XMBElement node = XeroIncluded.GetRoot();
					if (node.GetNodeName() != XeroIncluded.GetElementID("object"))
					{
						LOGERROR("GUI: Error reading included XML: '%s', root element must have be of type 'object'.", path.string8());
						continue;
					}
					Xeromyces_ReadObject(node, &XeroIncluded, object, NameSubst, Paths, nesting_depth+1);
				}

			}
			else
				LOGERROR("GUI: 'include' XML element must have valid 'file' or 'directory' attribute found. (object %s)", object->GetPresentableName().c_str());
		}
		else
		{
			// Try making the object read the tag.
			if (!object->HandleAdditionalChildren(child, pFile))
				LOGERROR("GUI: (object: %s) Reading unknown children for its type", object->GetPresentableName().c_str());
		}
	}

	if (!ManuallySetZ)
	{
		// Set it automatically to 10 plus its parents
		bool absolute;
		GUI<bool>::GetSetting(object, "absolute", absolute);

		if (absolute)
			// If the object is absolute, we'll have to get the parent's Z buffered,
			// and add to that!
			GUI<float>::SetSetting(object, "z", pParent->GetBufferedZ() + 10.f, true);
		else
			// If the object is relative, then we'll just store Z as "10"
			GUI<float>::SetSetting(object, "z", 10.f, true);
	}

	try
	{
		if (pParent == m_BaseObject)
			AddObject(object);
		else
			pParent->AddChild(object);
	}
	catch (PSERROR_GUI& e)
	{
		LOGERROR("GUI error: %s", e.what());
	}
}