Index: source/gui/CChart.cpp =================================================================== --- source/gui/CChart.cpp +++ source/gui/CChart.cpp @@ -38,6 +38,15 @@ void CChart::HandleMessage(SGUIMessage& Message) { // TODO: implement zoom + switch (Message.type) + { + case GUIM_SETTINGS_UPDATED: + { + UpdateSeries(); + break; + } + } + } void CChart::Draw() @@ -47,16 +56,14 @@ if (!GetGUI()) return; - UpdateSeries(); + if (m_Series.empty()) + return; const float bz = GetBufferedZ(); CRect rect = GetChartRect(); const float width = rect.GetWidth(); const float height = rect.GetHeight(); - if (m_Series.empty()) - return; - // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture. glDepthMask(0); @@ -93,6 +100,7 @@ continue; std::vector vertices; + vertices.reserve(data.m_Points.size() * 3); for (const CVector2D& point : data.m_Points) { vertices.push_back(rect.left + (point.X - leftBottom.X) * scale.X); @@ -131,10 +139,10 @@ GUI::GetSettingPointer(this, "series_color", pSeriesColor); m_Series.clear(); + m_Series.resize(pSeries->m_Series.size()); for (size_t i = 0; i < pSeries->m_Series.size(); ++i) { - m_Series.resize(m_Series.size() + 1); - CChartData& data = m_Series.back(); + CChartData& data = m_Series[i]; if (i < pSeriesColor->m_Items.size() && !GUI::ParseColor(pSeriesColor->m_Items[i].GetOriginalString(), data.m_Color, 0)) LOGWARNING("GUI: Error parsing 'series_color' (\"%s\")", utf8_from_wstring(pSeriesColor->m_Items[i].GetOriginalString())); Index: source/gui/CGUISeries.h =================================================================== --- source/gui/CGUISeries.h +++ source/gui/CGUISeries.h @@ -29,4 +29,4 @@ std::vector> m_Series; }; -#endif +#endif // INCLUDED_CGUISERIES Index: source/gui/scripting/GuiScriptConversions.cpp =================================================================== --- source/gui/scripting/GuiScriptConversions.cpp +++ source/gui/scripting/GuiScriptConversions.cpp @@ -17,11 +17,12 @@ #include "precompiled.h" -#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/ScriptConversions.h" #include "gui/IGUIObject.h" #include "lib/external_libraries/libsdl.h" #include "ps/Hotkey.h" +#include "maths/Vector2D.h" #define SET(obj, name, value) STMT(JS::RootedValue v_(cx); AssignOrToJSVal(cx, &v_, (value)); JS_SetProperty(cx, obj, (name), v_)) // ignore JS_SetProperty return value, because errors should be impossible @@ -121,3 +122,23 @@ else ret.setObject(*val->GetJSObject()); } + +template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CGUIString& val) +{ + ScriptInterface::ToJSVal(cx, ret, val.GetOriginalString()); +} + +template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CGUIString& out) +{ + std::wstring val; + if (!ScriptInterface::FromJSVal(cx, v, val)) + return false; + out.SetValue(val); + return true; +} + +// define some vectors +JSVAL_VECTOR(CVector2D) +JSVAL_VECTOR(std::vector) +JSVAL_VECTOR(CGUIString) + Index: source/gui/scripting/JSInterface_IGUIObject.cpp =================================================================== --- source/gui/scripting/JSInterface_IGUIObject.cpp +++ source/gui/scripting/JSInterface_IGUIObject.cpp @@ -284,17 +284,7 @@ { CGUIList value; GUI::GetSetting(e, propName, value); - - JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); - vp.setObject(*obj); - - for (u32 i = 0; i < value.m_Items.size(); ++i) - { - JS::RootedValue val(cx); - ScriptInterface::ToJSVal(cx, &val, value.m_Items[i].GetOriginalString()); - JS_SetElement(cx, obj, i, val); - } - + ScriptInterface::ToJSVal(cx, vp, value.m_Items); break; } @@ -302,28 +292,7 @@ { CGUISeries value; GUI::GetSetting(e, propName, value); - - JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); - vp.setObject(*obj); - - for (u32 i = 0; i < value.m_Series.size(); ++i) - { - JS::RootedObject inner_obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); - for (u32 j = 0; j < value.m_Series[i].size(); ++j) - { - JS::RootedObject val(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); - - JS::RootedValue val_x(cx), val_y(cx); - ScriptInterface::ToJSVal(cx, &val_x, value.m_Series[i][j].X); - ScriptInterface::ToJSVal(cx, &val_y, value.m_Series[i][j].Y); - JS_SetElement(cx, val, 0, val_x); - JS_SetElement(cx, val, 1, val_y); - - JS_SetElement(cx, inner_obj, j, val); - } - JS_SetElement(cx, obj, i, inner_obj); - } - + ScriptInterface::ToJSVal(cx, vp, value.m_Series); break; } @@ -585,98 +554,27 @@ case GUIST_CGUIList: { - u32 length; - if (!vp.isObject() || !JS_GetArrayLength(cx, vpObj, &length)) - { - JS_ReportError(cx, "List only accepts a GUIList object"); - return false; - } - CGUIList list; - - for (u32 i = 0; i < length; ++i) + if (ScriptInterface::FromJSVal(cx, vp, list.m_Items)) + GUI::SetSetting(e, propName, list); + else { - JS::RootedValue element(cx); - if (!JS_GetElement(cx, vpObj, i, &element)) - { - JS_ReportError(cx, "Failed to get list element"); - return false; - } - - std::wstring value; - if (!ScriptInterface::FromJSVal(cx, element, value)) - return false; - - CGUIString str; - str.SetValue(value); - - list.m_Items.push_back(str); + JS_ReportError(cx, "Failed to get list '%s'", propName.c_str()); + return false; } - - GUI::SetSetting(e, propName, list); break; } case GUIST_CGUISeries: { - u32 length; - if (!vp.isObject() || !JS_GetArrayLength(cx, vpObj, &length)) - { - JS_ReportError(cx, "Table only accepts a GUISeries object"); - return false; - } - CGUISeries series; - series.m_Series.resize(length); - for (u32 i = 0; i < length; ++i) + if (ScriptInterface::FromJSVal(cx, vp, series.m_Series)) + GUI::SetSetting(e, propName, series); + else { - JS::RootedValue data_value(cx); - if (!JS_GetElement(cx, vpObj, i, &data_value)) - { - JS_ReportError(cx, "Failed to get a data of series"); - return false; - } - - JS::RootedObject data(cx, data_value.toObjectOrNull()); - u32 data_length; - if (!JS_GetArrayLength(cx, data, &data_length)) - { - JS_ReportError(cx, "Series only accepts a chart data"); - return false; - } - - series.m_Series[i].resize(data_length); - for (u32 j = 0; j < data_length; ++j) - { - JS::RootedValue element_value(cx); - if (!JS_GetElement(cx, data, j, &element_value)) - { - JS_ReportError(cx, "Failed to get a chart data element"); - return false; - } - - JS::RootedObject element(cx, element_value.toObjectOrNull()); - u32 element_length; - if (!JS_GetArrayLength(cx, element, &element_length) || element_length < 2) - { - JS_ReportError(cx, "Chart data only accepts a point"); - return false; - } - - JS::RootedValue element_x(cx), element_y(cx); - if (!JS_GetElement(cx, element, 0, &element_x) || !JS_GetElement(cx, element, 1, &element_y)) - { - JS_ReportError(cx, "Failed to get a chart point"); - return false; - } - - if (!ScriptInterface::FromJSVal(cx, element_x, series.m_Series[i][j].X) || - !ScriptInterface::FromJSVal(cx, element_y, series.m_Series[i][j].Y)) - return false; - } + JS_ReportError(cx, "Invalid value for chart series '%s'", propName.c_str()); + return false; } - - GUI::SetSetting(e, propName, series); break; } Index: source/scriptinterface/ScriptConversions.h =================================================================== --- /dev/null +++ source/scriptinterface/ScriptConversions.h @@ -0,0 +1,87 @@ +/* Copyright (C) 2016 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 . + */ + +#ifndef INCLUDED_SCRIPTCONVERSIONS +#define INCLUDED_SCRIPTCONVERSIONS + +#include "ScriptInterface.h" +#include "scriptinterface/ScriptExtraHeaders.h" // for typed arrays and JS::ToNumber + +#include + +template static void ToJSVal_vector(JSContext* cx, JS::MutableHandleValue ret, const std::vector& val) +{ + JSAutoRequest rq(cx); + JS::RootedObject obj(cx, JS_NewArrayObject(cx, 0)); + if (!obj) + { + ret.setUndefined(); + return; + } + + ENSURE(val.size() <= std::numeric_limits::max()); + for (u32 i = 0; i < val.size(); ++i) + { + JS::RootedValue el(cx); + ScriptInterface::ToJSVal(cx, &el, val[i]); + JS_SetElement(cx, obj, i, el); + } + ret.setObject(*obj); +} + +#define FAIL(msg) STMT(JS_ReportError(cx, msg); return false) + +template static bool FromJSVal_vector(JSContext* cx, JS::HandleValue v, std::vector& out) +{ + JSAutoRequest rq(cx); + JS::RootedObject obj(cx); + if (!v.isObject()) + FAIL("Argument must be an array"); + obj = &v.toObject(); + if (!(JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj))) + FAIL("Argument must be an array"); + + u32 length; + if (!JS_GetArrayLength(cx, obj, &length)) + FAIL("Failed to get array length"); + out.reserve(length); + for (u32 i = 0; i < length; ++i) + { + JS::RootedValue el(cx); + if (!JS_GetElement(cx, obj, i, &el)) + FAIL("Failed to read array element"); + T el2; + if (!ScriptInterface::FromJSVal(cx, el, el2)) + return false; + out.push_back(el2); + } + return true; +} + +#undef FAIL + +#define JSVAL_VECTOR(T) \ +template<> void ScriptInterface::ToJSVal >(JSContext* cx, JS::MutableHandleValue ret, const std::vector& val) \ +{ \ + ToJSVal_vector(cx, ret, val); \ +} \ +template<> bool ScriptInterface::FromJSVal >(JSContext* cx, JS::HandleValue v, std::vector& out) \ +{ \ + return FromJSVal_vector(cx, v, out); \ +} + +#endif //INCLUDED_SCRIPTCONVERSIONS Index: source/scriptinterface/ScriptConversions.cpp =================================================================== --- source/scriptinterface/ScriptConversions.cpp +++ source/scriptinterface/ScriptConversions.cpp @@ -17,18 +17,16 @@ #include "precompiled.h" -#include "ScriptInterface.h" +#include "ScriptConversions.h" #include "graphics/Entity.h" +#include "maths/Vector2D.h" #include "ps/utf16string.h" -#include "ps/CLogger.h" #include "ps/CStr.h" -#include "scriptinterface/ScriptExtraHeaders.h" // for typed arrays - -#define FAIL(msg) STMT(JS_ReportError(cx, msg); return false) // Implicit type conversions often hide bugs, so warn about them #define WARN_IF_NOT(c, v) STMT(if (!(c)) { JS_ReportWarning(cx, "Script value conversion check failed: %s (got type %s)", #c, InformalValueTypeName(v)); }) +#define FAIL(msg) STMT(JS_ReportError(cx, msg); return false) // TODO: SpiderMonkey: Follow upstream progresses about JS_InformalValueTypeName in the API // https://bugzilla.mozilla.org/show_bug.cgi?id=1285917 @@ -376,71 +374,15 @@ } //////////////////////////////////////////////////////////////// -// Compound types: - -template static void ToJSVal_vector(JSContext* cx, JS::MutableHandleValue ret, const std::vector& val) -{ - JSAutoRequest rq(cx); - JS::RootedObject obj(cx, JS_NewArrayObject(cx, 0)); - if (!obj) - { - ret.setUndefined(); - return; - } - for (u32 i = 0; i < val.size(); ++i) - { - JS::RootedValue el(cx); - ScriptInterface::ToJSVal(cx, &el, val[i]); - JS_SetElement(cx, obj, i, el); - } - ret.setObject(*obj); -} - -template static bool FromJSVal_vector(JSContext* cx, JS::HandleValue v, std::vector& out) -{ - JSAutoRequest rq(cx); - JS::RootedObject obj(cx); - if (!v.isObject()) - FAIL("Argument must be an array"); - obj = &v.toObject(); - if (!(JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj))) - FAIL("Argument must be an array"); - - u32 length; - if (!JS_GetArrayLength(cx, obj, &length)) - FAIL("Failed to get array length"); - out.reserve(length); - for (u32 i = 0; i < length; ++i) - { - JS::RootedValue el(cx); - if (!JS_GetElement(cx, obj, i, &el)) - FAIL("Failed to read array element"); - T el2; - if (!ScriptInterface::FromJSVal(cx, el, el2)) - return false; - out.push_back(el2); - } - return true; -} - +// Compound types // Instantiate various vector types: -#define VECTOR(T) \ - template<> void ScriptInterface::ToJSVal >(JSContext* cx, JS::MutableHandleValue ret, const std::vector& val) \ - { \ - ToJSVal_vector(cx, ret, val); \ - } \ - template<> bool ScriptInterface::FromJSVal >(JSContext* cx, JS::HandleValue v, std::vector& out) \ - { \ - return FromJSVal_vector(cx, v, out); \ - } - -VECTOR(int) -VECTOR(u32) -VECTOR(u16) -VECTOR(std::string) -VECTOR(std::wstring) -VECTOR(CStr8) +JSVAL_VECTOR(int) +JSVAL_VECTOR(u32) +JSVAL_VECTOR(u16) +JSVAL_VECTOR(std::string) +JSVAL_VECTOR(std::wstring) +JSVAL_VECTOR(CStr8) class IComponent; @@ -453,3 +395,25 @@ { return FromJSVal_vector(cx, v, out); } + +template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CVector2D& val) +{ + std::vector vec = {val.X, val.Y}; + ToJSVal_vector(cx, ret, vec); +} + +template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CVector2D& out) +{ + std::vector vec; + + if (!FromJSVal_vector(cx, v, vec)) + return false; + + if (vec.size() != 2) + return false; + + out.X = vec[0]; + out.Y = vec[1]; + + return true; +} Index: source/simulation2/scripting/EngineScriptConversions.cpp =================================================================== --- source/simulation2/scripting/EngineScriptConversions.cpp +++ source/simulation2/scripting/EngineScriptConversions.cpp @@ -17,8 +17,7 @@ #include "precompiled.h" -#include "scriptinterface/ScriptInterface.h" -#include "scriptinterface/ScriptExtraHeaders.h" // for typed arrays +#include "scriptinterface/ScriptConversions.h" #include "maths/Fixed.h" #include "maths/FixedVector2D.h" @@ -299,21 +298,5 @@ ret.setObject(*obj); } -// TODO: This is copy-pasted from scriptinterface/ScriptConversions.cpp (#define VECTOR stuff), would be nice to remove the duplication -template<> void ScriptInterface::ToJSVal >(JSContext* cx, JS::MutableHandleValue ret, const std::vector& val) -{ - JSAutoRequest rq(cx); - JS::RootedObject obj(cx, JS_NewArrayObject(cx, 0)); - if (!obj) - { - ret.setUndefined(); - return; - } - for (size_t i = 0; i < val.size(); ++i) - { - JS::RootedValue el(cx); - ScriptInterface::ToJSVal(cx, &el, val[i]); - JS_SetElement(cx, obj, i, el); - } - ret.setObject(*obj); -} +// define vectors +JSVAL_VECTOR(CFixedVector2D)