Fix Lobby/MP Gamesetup chat lag with many messages.
CText requires re-rendering every message when adding a new one, which quickly becomes very slow. Use CList and a custom method to work around this. These classes are in need of a more complete refactoring. Based on a patch by: nani Differential Revision: https://code.wildfiregames.com/D1781 This was SVN commit r24306.
This commit is contained in:
parent
dcc73561c2
commit
f78d3ddf71
@ -102,7 +102,6 @@
|
||||
scroll_bottom="true"
|
||||
textcolor="white"
|
||||
text_align="left"
|
||||
text_valign="center"
|
||||
/>
|
||||
|
||||
<style name="TutorialPanel"
|
||||
|
@ -32,7 +32,7 @@ class ChatMessagesPanel
|
||||
text = this.timestampWrapper.format(text);
|
||||
|
||||
this.chatHistory += this.chatHistory ? "\n" + text : text;
|
||||
this.chatText.caption = this.chatHistory;
|
||||
this.chatText.addItem(text);
|
||||
}
|
||||
|
||||
addStatusMessage(text)
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="chatPanel" type="image" sprite="ModernDarkBoxGold">
|
||||
|
||||
<object name="chatText" type="text" size="2 2 100%-2 100%-28" style="ChatPanel"/>
|
||||
<object name="chatText" type="list" size="2 2 100%-2 100%-28" style="ChatPanel"/>
|
||||
|
||||
<object name="chatInput" type="input" size="4 100%-26 100%-96 100%-4" style="ModernInput" max_length="1024"/>
|
||||
|
||||
|
@ -24,6 +24,7 @@ class ChatMessagesPanel
|
||||
text = this.timestampWrapper.format(timestamp, text);
|
||||
|
||||
this.chatHistory += this.chatHistory ? "\n" + text : text;
|
||||
this.chatText.addItem(text);
|
||||
|
||||
if (!this.hasUpdate)
|
||||
{
|
||||
@ -38,7 +39,6 @@ class ChatMessagesPanel
|
||||
{
|
||||
if (this.hasUpdate)
|
||||
{
|
||||
this.chatText.caption = this.chatHistory;
|
||||
this.hasUpdate = false;
|
||||
this.xmppMessages.unregisterMessageBatchProcessedHandler(this.flushEvent);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
<script directory="gui/lobby/LobbyPage/Chat/StatusMessages/"/>
|
||||
<script directory="gui/lobby/LobbyPage/Chat/SystemMessages/"/>
|
||||
|
||||
<object name="chatText" size="0 0 100% 100%-28" type="text" style="ChatPanel" font="sans-13"/>
|
||||
<object name="chatText" size="0 0 100% 100%-28" type="list" style="ChatPanel" font="sans-13"/>
|
||||
<object name="chatInput" size="0 100%-26 100%-72 100%-4" type="input" style="ModernInput" font="sans-13" max_length="1024"/>
|
||||
<object name="chatSubmit" size="100%-72 100%-26 100%-4 100%-4" type="button" style="StoneButton">
|
||||
<translatableAttribute id="caption">Send</translatableAttribute>
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -38,6 +38,7 @@ void CGUI::AddObjectTypes()
|
||||
{
|
||||
m_ProxyData.insert(JSI_GUIProxy<IGUIObject>::CreateData(*m_ScriptInterface));
|
||||
m_ProxyData.insert(JSI_GUIProxy<CText>::CreateData(*m_ScriptInterface));
|
||||
m_ProxyData.insert(JSI_GUIProxy<CList>::CreateData(*m_ScriptInterface));
|
||||
|
||||
AddObjectType("button", &CButton::ConstructObject);
|
||||
AddObjectType("chart", &CChart::ConstructObject);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -23,6 +23,7 @@
|
||||
#include "gui/CGUIScrollBarVertical.h"
|
||||
#include "gui/SettingTypes/CGUIColor.h"
|
||||
#include "gui/SettingTypes/CGUIList.h"
|
||||
#include "gui/Scripting/JSInterface_GUIProxy.h"
|
||||
#include "lib/external_libraries/libsdl.h"
|
||||
#include "lib/timer.h"
|
||||
|
||||
@ -60,6 +61,7 @@ CList::CList(CGUI& pGUI)
|
||||
RegisterSetting("font", m_Font);
|
||||
RegisterSetting("scrollbar", m_ScrollBar);
|
||||
RegisterSetting("scrollbar_style", m_ScrollBarStyle);
|
||||
RegisterSetting("scroll_bottom", m_ScrollBottom);
|
||||
RegisterSetting("sound_disabled", m_SoundDisabled);
|
||||
RegisterSetting("sound_selected", m_SoundSelected);
|
||||
RegisterSetting("sprite", m_Sprite);
|
||||
@ -92,25 +94,40 @@ CList::~CList()
|
||||
}
|
||||
|
||||
void CList::SetupText()
|
||||
{
|
||||
SetupText(false);
|
||||
}
|
||||
|
||||
void CList::SetupText(bool append)
|
||||
{
|
||||
m_Modified = true;
|
||||
|
||||
m_ItemsYPositions.resize(m_List.m_Items.size() + 1);
|
||||
|
||||
// Delete all generated texts. Some could probably be saved,
|
||||
// but this is easier, and this function will never be called
|
||||
// continuously, or even often, so it'll probably be okay.
|
||||
m_GeneratedTexts.clear();
|
||||
if (!append)
|
||||
// Delete all generated texts.
|
||||
// TODO: try to be cleverer if we want to update items before the end.
|
||||
m_GeneratedTexts.clear();
|
||||
|
||||
float width = GetListRect().GetWidth();
|
||||
// remove scrollbar if applicable
|
||||
|
||||
bool bottom = false;
|
||||
if (m_ScrollBar && GetScrollBar(0).GetStyle())
|
||||
{
|
||||
if (m_ScrollBottom && GetScrollBar(0).GetPos() > GetScrollBar(0).GetMaxPos() - 1.5f)
|
||||
bottom = true;
|
||||
|
||||
// remove scrollbar if applicable
|
||||
width -= GetScrollBar(0).GetStyle()->m_Width;
|
||||
}
|
||||
|
||||
// Generate texts
|
||||
float buffered_y = 0.f;
|
||||
|
||||
for (size_t i = 0; i < m_List.m_Items.size(); ++i)
|
||||
if (append)
|
||||
buffered_y = m_ItemsYPositions[m_List.m_Items.size() - 1];
|
||||
|
||||
for (size_t i = append ? m_List.m_Items.size() - 1 : 0; i < m_List.m_Items.size(); ++i)
|
||||
{
|
||||
CGUIText* text;
|
||||
|
||||
@ -141,6 +158,9 @@ void CList::SetupText()
|
||||
GetScrollBar(0).SetY(rect.top);
|
||||
GetScrollBar(0).SetZ(GetBufferedZ());
|
||||
GetScrollBar(0).SetLength(rect.bottom - rect.top);
|
||||
|
||||
if (bottom)
|
||||
GetScrollBar(0).SetPos(GetScrollBar(0).GetMaxPos());
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,18 +400,11 @@ void CList::DrawList(const int& selected, const CGUISpriteInstance& sprite, cons
|
||||
}
|
||||
}
|
||||
|
||||
void CList::AddItem(const CStrW& str, const CStrW& data)
|
||||
void CList::AddItem(const CGUIString& str, const CGUIString& data)
|
||||
{
|
||||
CGUIString gui_string;
|
||||
gui_string.SetValue(str);
|
||||
|
||||
// Do not send a settings-changed message
|
||||
m_List.m_Items.push_back(gui_string);
|
||||
|
||||
CGUIString data_string;
|
||||
data_string.SetValue(data);
|
||||
|
||||
m_ListData.m_Items.push_back(data_string);
|
||||
m_List.m_Items.push_back(str);
|
||||
m_ListData.m_Items.push_back(data);
|
||||
|
||||
// TODO Temp
|
||||
SetupText();
|
||||
@ -403,7 +416,9 @@ bool CList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile)
|
||||
|
||||
if (child.GetNodeName() == elmt_item)
|
||||
{
|
||||
AddItem(child.GetText().FromUTF8(), child.GetText().FromUTF8());
|
||||
CGUIString vlist;
|
||||
vlist.SetValue(child.GetText().FromUTF8());
|
||||
AddItem(vlist, vlist);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -485,3 +500,33 @@ int CList::GetHoveredItem()
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CList::CreateJSObject()
|
||||
{
|
||||
ScriptRequest rq(m_pGUI.GetScriptInterface());
|
||||
|
||||
js::ProxyOptions options;
|
||||
options.setClass(&JSI_GUIProxy<CList>::ClassDefinition());
|
||||
|
||||
JS::RootedValue cppObj(rq.cx), data(rq.cx);
|
||||
cppObj.get().setPrivate(this);
|
||||
data.get().setPrivate(GetGUI().GetProxyData(&JSI_GUIProxy<CList>::Singleton()));
|
||||
m_JSObject.init(rq.cx, js::NewProxyObject(rq.cx, &JSI_GUIProxy<CList>::Singleton(), cppObj, nullptr, options));
|
||||
js::SetProxyReservedSlot(m_JSObject, 0, data);
|
||||
}
|
||||
|
||||
bool CList::Script_AddItem(JSContext* cx, uint argc, JS::Value* vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
CList* e = static_cast<CList*>(js::GetProxyPrivate(args.thisv().toObjectOrNull()).toPrivate());
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
ScriptInterface& scriptInterface = *ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
|
||||
ScriptRequest rq(scriptInterface);
|
||||
CGUIString text;
|
||||
if (!ScriptInterface::FromJSVal(rq, args.get(0), text))
|
||||
return false;
|
||||
e->AddItem(text, text);
|
||||
return true;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -38,6 +38,8 @@ class CList : public IGUIObject, public IGUIScrollBarOwner, public IGUITextOwner
|
||||
{
|
||||
GUI_OBJECT(CList)
|
||||
|
||||
friend JSI_GUIProxy<CList>;
|
||||
|
||||
public:
|
||||
CList(CGUI& pGUI);
|
||||
virtual ~CList();
|
||||
@ -55,15 +57,19 @@ public:
|
||||
/**
|
||||
* Adds an item last to the list.
|
||||
*/
|
||||
virtual void AddItem(const CStrW& str, const CStrW& data);
|
||||
virtual void AddItem(const CGUIString& str, const CGUIString& data);
|
||||
|
||||
protected:
|
||||
|
||||
static bool Script_AddItem(JSContext* cx, uint argc, JS::Value* vp);
|
||||
|
||||
/**
|
||||
* Sets up text, should be called every time changes has been
|
||||
* made that can change the visual.
|
||||
* @param append - if true, we assume we only need to render the new element at the end of the list.
|
||||
*/
|
||||
virtual void SetupText();
|
||||
virtual void SetupText(bool append);
|
||||
|
||||
/**
|
||||
* @see IGUIObject#HandleMessage()
|
||||
@ -80,6 +86,8 @@ protected:
|
||||
*/
|
||||
virtual void Draw();
|
||||
|
||||
virtual void CreateJSObject();
|
||||
|
||||
/**
|
||||
* Easy select elements functions
|
||||
*/
|
||||
@ -123,6 +131,7 @@ protected:
|
||||
CStrW m_Font;
|
||||
bool m_ScrollBar;
|
||||
CStr m_ScrollBarStyle;
|
||||
bool m_ScrollBottom;
|
||||
CStrW m_SoundDisabled;
|
||||
CStrW m_SoundSelected;
|
||||
CGUISpriteInstance m_Sprite;
|
||||
|
@ -192,7 +192,9 @@ bool COList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile
|
||||
|
||||
if (child.GetNodeName() == elmt_item)
|
||||
{
|
||||
AddItem(child.GetText().FromUTF8(), child.GetText().FromUTF8());
|
||||
CGUIString vlist;
|
||||
vlist.SetValue(child.GetText().FromUTF8());
|
||||
AddItem(vlist, vlist);
|
||||
return true;
|
||||
}
|
||||
else if (child.GetNodeName() == elmt_column)
|
||||
|
@ -259,7 +259,7 @@ void CText::CreateJSObject()
|
||||
ScriptRequest rq(m_pGUI.GetScriptInterface());
|
||||
|
||||
js::ProxyOptions options;
|
||||
options.setClass(&JSI_GUIProxy<IGUIObject>::ClassDefinition());
|
||||
options.setClass(&JSI_GUIProxy<CText>::ClassDefinition());
|
||||
|
||||
JS::RootedValue cppObj(rq.cx), data(rq.cx);
|
||||
cppObj.get().setPrivate(this);
|
||||
|
80
source/gui/Scripting/JSInterface_CList.cpp
Normal file
80
source/gui/Scripting/JSInterface_CList.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "JSInterface_GUIProxy.h"
|
||||
|
||||
#include "gui/CGUI.h"
|
||||
#include "gui/CGUISetting.h"
|
||||
#include "gui/ObjectBases/IGUIObject.h"
|
||||
#include "gui/ObjectTypes/CList.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "scriptinterface/ScriptExtraHeaders.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
// Include the definition of the generic templates.
|
||||
#include "JSInterface_GUIProxy_impl.h"
|
||||
|
||||
namespace {
|
||||
struct SData
|
||||
{
|
||||
JS::PersistentRootedObject m_ToString;
|
||||
JS::PersistentRootedObject m_Focus;
|
||||
JS::PersistentRootedObject m_Blur;
|
||||
JS::PersistentRootedObject m_GetComputedSize;
|
||||
JS::PersistentRootedObject m_AddItem;
|
||||
};
|
||||
}
|
||||
|
||||
template <>
|
||||
bool JSI_GUIProxy<CList>::funcGetter(JS::HandleObject proxy, const std::string& propName, JS::MutableHandleValue vp) const
|
||||
{
|
||||
const SData& data = *static_cast<const SData*>(js::GetProxyReservedSlot(proxy, 0).toPrivate());
|
||||
if (propName == "toString")
|
||||
return vp.setObjectOrNull(data.m_ToString), true;
|
||||
if (propName == "focus")
|
||||
return vp.setObjectOrNull(data.m_Focus), true;
|
||||
if (propName == "blur")
|
||||
return vp.setObjectOrNull(data.m_Blur), true;
|
||||
if (propName == "getComputedSize")
|
||||
return vp.setObjectOrNull(data.m_GetComputedSize), true;
|
||||
if (propName == "addItem")
|
||||
return vp.setObjectOrNull(data.m_AddItem), true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::pair<const js::BaseProxyHandler*, void*> JSI_GUIProxy<CList>::CreateData(ScriptInterface& scriptInterface)
|
||||
{
|
||||
SData* data = new SData();
|
||||
ScriptRequest rq(scriptInterface);
|
||||
|
||||
#define func(class, func) &apply_to<CList, class, &class::func>
|
||||
data->m_ToString.init(rq.cx, JS_GetFunctionObject(JS_NewFunction(rq.cx, func(IGUIObject, toString), 0, 0, "toString")));
|
||||
data->m_Focus.init(rq.cx, JS_GetFunctionObject(JS_NewFunction(rq.cx, func(IGUIObject, focus), 0, 0, "focus")));
|
||||
data->m_Blur.init(rq.cx, JS_GetFunctionObject(JS_NewFunction(rq.cx, func(IGUIObject, blur), 0, 0, "blur")));
|
||||
data->m_GetComputedSize.init(rq.cx, JS_GetFunctionObject(JS_NewFunction(rq.cx, func(IGUIObject, getComputedSize), 0, 0, "getComputedSize")));
|
||||
#undef func
|
||||
data->m_AddItem.init(rq.cx, JS_GetFunctionObject(JS_NewFunction(rq.cx, CList::Script_AddItem, 0, 0, "addItem")));
|
||||
|
||||
return { &Singleton(), data };
|
||||
}
|
||||
|
||||
template class JSI_GUIProxy<CList>;
|
Loading…
Reference in New Issue
Block a user