Fix 768c84aa46 style, add tests.

Patch by: @bb
Small fixes by: @Stan
Reviewed by: @vladislavbelov
Differential Revision: https://code.wildfiregames.com/D3103
This was SVN commit r24665.
This commit is contained in:
Stan 2021-01-17 15:44:14 +00:00
parent 4c4da81cc4
commit 3872ee43b5
9 changed files with 142 additions and 29 deletions

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<styles>
<style name="default"/>
</styles>

View File

@ -0,0 +1,15 @@
var called1 = 0;
var called2 = 0;
var called3 = 0;
var called4 = 0;
var obj1 = Engine.GetGUIObjectByName("obj1");
var obj3 = Engine.GetGUIObjectByName("obj3");
obj1.onTick = () => { ++called1; };
Engine.GetGUIObjectByName("obj2").onTick = () => {
++called2;
delete obj1.onTick;
delete obj3.onTick;
Engine.GetGUIObjectByName("obj4").onTick = () => { ++called4; };
};
obj3.onTick = () => { ++called3; };

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<objects>
<object name="obj1"/>
<object name="obj2"/>
<object name="obj3"/>
<object name="obj4"/>
<script file="gui/event/event.js"/>
</objects>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<page>
<include>common/styles.xml</include>
<include>event/event.xml</include>
</page>

View File

@ -9,6 +9,7 @@
<a:documentation/>
<choice>
<ref name="objects"/>
<ref name="styles"/>
</choice>
</start>
<define name="objects">
@ -16,6 +17,7 @@
<zeroOrMore>
<choice>
<ref name="script"/>
<ref name="object"/>
</choice>
</zeroOrMore>
</element>
@ -33,4 +35,23 @@
</interleave>
</element>
</define>
<define name="object">
<element name="object">
<optional>
<attribute name="name"/>
</optional>
</element>
</define>
<define name="styles">
<element name="styles">
<zeroOrMore>
<ref name="style"/>
</zeroOrMore>
</element>
</define>
<define name="style">
<element name="style">
<attribute name="name"/>
</element>
</define>
</grammar>

View File

@ -43,6 +43,7 @@
#include "scriptinterface/ScriptInterface.h"
#include <string>
#include <unordered_map>
#include <unordered_set>
extern int g_yres;
@ -275,24 +276,24 @@ void CGUI::TickObjects()
void CGUI::SendEventToAll(const CStr& eventName)
{
auto it = m_EventIGUIObjects.find(eventName);
if (it == m_EventIGUIObjects.end())
std::unordered_map<CStr, std::vector<IGUIObject*>>::iterator it = m_EventObjects.find(eventName);
if (it == m_EventObjects.end())
return;
std::set<IGUIObject*> copy = it->second;
for (IGUIObject* pIGUIObject : copy)
pIGUIObject->ScriptEvent(eventName);
std::vector<IGUIObject*> copy = it->second;
for (IGUIObject* object : copy)
object->ScriptEvent(eventName);
}
void CGUI::SendEventToAll(const CStr& eventName, const JS::HandleValueArray& paramData)
{
auto it = m_EventIGUIObjects.find(eventName);
if (it == m_EventIGUIObjects.end())
std::unordered_map<CStr, std::vector<IGUIObject*>>::iterator it = m_EventObjects.find(eventName);
if (it == m_EventObjects.end())
return;
std::set<IGUIObject*> copy = it->second;
for (IGUIObject* pIGUIObject : copy)
pIGUIObject->ScriptEvent(eventName, paramData);
std::vector<IGUIObject*> copy = it->second;
for (IGUIObject* object : copy)
object->ScriptEvent(eventName, paramData);
}
void CGUI::Draw()

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -679,9 +679,9 @@ private:
public:
/**
* Stores all the IGUIObject which listen to a given event.
* Map from event names to object which listen to a given event.
*/
std::map<CStr, std::set<IGUIObject*>> m_EventIGUIObjects;
std::unordered_map<CStr, std::vector<IGUIObject*>> m_EventObjects;
};
#endif // INCLUDED_CGUI

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -31,6 +31,8 @@
#include "scriptinterface/ScriptInterface.h"
#include "soundmanager/ISoundManager.h"
#include <unordered_map>
const CStr IGUIObject::EventNameMouseEnter = "MouseEnter";
const CStr IGUIObject::EventNameMouseMove = "MouseMove";
const CStr IGUIObject::EventNameMouseLeave = "MouseLeave";
@ -347,11 +349,7 @@ void IGUIObject::SetScriptHandler(const CStr& eventName, JS::HandleObject Functi
m_ScriptHandlers[eventName] = JS::Heap<JSObject*>(Function);
auto it = m_pGUI.m_EventIGUIObjects.find(eventName);
if (it == m_pGUI.m_EventIGUIObjects.end())
m_pGUI.m_EventIGUIObjects.emplace(eventName, std::set<IGUIObject*>{this});
else
it->second.insert(this);
m_pGUI.m_EventObjects[eventName].push_back(this);
}
void IGUIObject::UnsetScriptHandler(const CStr& eventName)
@ -365,15 +363,16 @@ void IGUIObject::UnsetScriptHandler(const CStr& eventName)
if (m_ScriptHandlers.empty())
JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetGeneralJSContext(), Trace, this);
{
auto it = m_pGUI.m_EventIGUIObjects.find(eventName);
if (it != m_pGUI.m_EventIGUIObjects.end())
{
it->second.erase(this);
if (!it->second.size())
m_pGUI.m_EventIGUIObjects.erase(eventName);
}
}
std::unordered_map<CStr, std::vector<IGUIObject*>>::iterator it2 = m_pGUI.m_EventObjects.find(eventName);
if (it2 == m_pGUI.m_EventObjects.end())
return;
std::vector<IGUIObject*>& handlers = it2->second;
handlers.erase(std::remove(handlers.begin(), handlers.end(), this), handlers.end());
if (handlers.empty())
m_pGUI.m_EventObjects.erase(it2);
}
InReaction IGUIObject::SendEvent(EGUIMessageType type, const CStr& eventName)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -53,6 +53,65 @@ public:
DeleteDirectory(DataDir()/"_testcache");
}
void test_EventObject()
{
// Load up a test page.
const ScriptInterface& scriptInterface = *(g_GUI->GetScriptInterface());
ScriptRequest rq(scriptInterface);
JS::RootedValue val(rq.cx);
scriptInterface.CreateObject(rq, &val);
ScriptInterface::StructuredClone data = scriptInterface.WriteStructuredClone(JS::NullHandleValue);
g_GUI->PushPage(L"event/page_event.xml", data, JS::UndefinedHandleValue);
const ScriptInterface& pageScriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface());
ScriptRequest prq(pageScriptInterface);
JS::RootedValue global(prq.cx, prq.globalValue());
int called_value = 0;
JS::RootedValue js_called_value(prq.cx);
// Ticking will call the onTick handlers of all object. The second
// onTick is configured to disable the onTick handlers of the first and
// third and enable the fourth. So ticking once will only call the
// first and second object. We don't want the fourth object to be
// called, to avoid infinite additions of objects.
g_GUI->TickObjects();
pageScriptInterface.GetProperty(global, "called1", &js_called_value);
ScriptInterface::FromJSVal(prq, js_called_value, called_value);
TS_ASSERT_EQUALS(called_value, 1);
pageScriptInterface.GetProperty(global, "called2", &js_called_value);
ScriptInterface::FromJSVal(prq, js_called_value, called_value);
TS_ASSERT_EQUALS(called_value, 1);
pageScriptInterface.GetProperty(global, "called3", &js_called_value);
ScriptInterface::FromJSVal(prq, js_called_value, called_value);
TS_ASSERT_EQUALS(called_value, 0);
pageScriptInterface.GetProperty(global, "called4", &js_called_value);
ScriptInterface::FromJSVal(prq, js_called_value, called_value);
TS_ASSERT_EQUALS(called_value, 0);
// Ticking again will still call the second object, but also the fourth.
g_GUI->TickObjects();
pageScriptInterface.GetProperty(global, "called1", &js_called_value);
ScriptInterface::FromJSVal(prq, js_called_value, called_value);
TS_ASSERT_EQUALS(called_value, 1);
pageScriptInterface.GetProperty(global, "called2", &js_called_value);
ScriptInterface::FromJSVal(prq, js_called_value, called_value);
TS_ASSERT_EQUALS(called_value, 2);
pageScriptInterface.GetProperty(global, "called3", &js_called_value);
ScriptInterface::FromJSVal(prq, js_called_value, called_value);
TS_ASSERT_EQUALS(called_value, 0);
pageScriptInterface.GetProperty(global, "called4", &js_called_value);
ScriptInterface::FromJSVal(prq, js_called_value, called_value);
TS_ASSERT_EQUALS(called_value, 1);
}
void test_hotkeysState()
{
// Load up a fake test hotkey when pressing 'a'.