Merge branch 'futureproof_layers' into 'master'

Add layer size, make layers API more flexible

See merge request OpenMW/openmw!1724
pull/3226/head
Petr Mikheev 3 years ago
commit fbc84465c5

@ -7,6 +7,7 @@
#include <components/lua_ui/resources.hpp> #include <components/lua_ui/resources.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/misc/stringops.hpp>
#include "context.hpp" #include "context.hpp"
#include "actions.hpp" #include "actions.hpp"
@ -83,36 +84,33 @@ namespace MWLua
class InsertLayerAction final : public Action class InsertLayerAction final : public Action
{ {
public: public:
InsertLayerAction(std::string_view name, std::string_view afterName, InsertLayerAction(std::string_view name, size_t index,
LuaUi::Layers::Options options, LuaUtil::LuaState* state) LuaUi::Layer::Options options, LuaUtil::LuaState* state)
: Action(state) : Action(state)
, mName(name) , mName(name)
, mAfterName(afterName) , mIndex(index)
, mOptions(options) , mOptions(options)
{} {}
void apply(WorldView&) const override void apply(WorldView&) const override
{ {
size_t index = LuaUi::Layers::indexOf(mAfterName); LuaUi::Layer::insert(mIndex, mName, mOptions);
if (index == LuaUi::Layers::size())
throw std::logic_error(std::string("Layer not found"));
LuaUi::Layers::insert(index, mName, mOptions);
} }
std::string toString() const override std::string toString() const override
{ {
std::string result("Insert UI layer \""); std::string result("Insert UI layer \"");
result += mName; result += mName;
result += "\" after \""; result += "\" at \"";
result += mAfterName; result += mIndex;
result += "\""; result += "\"";
return result; return result;
} }
private: private:
std::string mName; std::string mName;
std::string mAfterName; size_t mIndex;
LuaUi::Layers::Options mOptions; LuaUi::Layer::Options mOptions;
}; };
// Lua arrays index from 1 // Lua arrays index from 1
@ -227,37 +225,58 @@ namespace MWLua
return element; return element;
}; };
auto uiLayer = context.mLua->sol().new_usertype<LuaUi::Layer>("UiLayer");
uiLayer["name"] = sol::property([](LuaUi::Layer& self) { return self.name(); });
uiLayer["size"] = sol::property([](LuaUi::Layer& self) { return self.size(); });
uiLayer[sol::meta_function::to_string] = [](LuaUi::Layer& self)
{
return Misc::StringUtils::format("UiLayer(%s)", self.name());
};
sol::table layers = context.mLua->newTable(); sol::table layers = context.mLua->newTable();
layers[sol::meta_function::length] = []() layers[sol::meta_function::length] = []()
{ {
return LuaUi::Layers::size(); return LuaUi::Layer::count();
}; };
layers[sol::meta_function::index] = [](size_t index) layers[sol::meta_function::index] = [](size_t index)
{ {
index = fromLuaIndex(index); index = fromLuaIndex(index);
return LuaUi::Layers::at(index); return LuaUi::Layer(index);
}; };
layers["indexOf"] = [](std::string_view name) -> sol::optional<size_t> layers["indexOf"] = [](std::string_view name) -> sol::optional<size_t>
{ {
size_t index = LuaUi::Layers::indexOf(name); size_t index = LuaUi::Layer::indexOf(name);
if (index == LuaUi::Layers::size()) if (index == LuaUi::Layer::count())
return sol::nullopt; return sol::nullopt;
else else
return toLuaIndex(index); return toLuaIndex(index);
}; };
layers["insertAfter"] = [context](std::string_view afterName, std::string_view name, const sol::object& opt) layers["insertAfter"] = [context](std::string_view afterName, std::string_view name, const sol::object& opt)
{ {
LuaUi::Layers::Options options; LuaUi::Layer::Options options;
options.mInteractive = LuaUtil::getValueOrDefault(LuaUtil::getFieldOrNil(opt, "interactive"), true);
size_t index = LuaUi::Layer::indexOf(afterName);
if (index == LuaUi::Layer::count())
throw std::logic_error(std::string("Layer not found"));
index++;
context.mLuaManager->addAction(std::make_unique<InsertLayerAction>(name, index, options, context.mLua));
};
layers["insertBefore"] = [context](std::string_view beforename, std::string_view name, const sol::object& opt)
{
LuaUi::Layer::Options options;
options.mInteractive = LuaUtil::getValueOrDefault(LuaUtil::getFieldOrNil(opt, "interactive"), true); options.mInteractive = LuaUtil::getValueOrDefault(LuaUtil::getFieldOrNil(opt, "interactive"), true);
context.mLuaManager->addAction(std::make_unique<InsertLayerAction>(name, afterName, options, context.mLua)); size_t index = LuaUi::Layer::indexOf(beforename);
if (index == LuaUi::Layer::count())
throw std::logic_error(std::string("Layer not found"));
context.mLuaManager->addAction(std::make_unique<InsertLayerAction>(name, index, options, context.mLua));
}; };
{ {
auto pairs = [layers](const sol::object&) auto pairs = [layers](const sol::object&)
{ {
auto next = [](const sol::table& l, size_t i) -> sol::optional<std::tuple<size_t, std::string>> auto next = [](const sol::table& l, size_t i) -> sol::optional<std::tuple<size_t, LuaUi::Layer>>
{ {
if (i < LuaUi::Layers::size()) if (i < LuaUi::Layer::count())
return std::make_tuple(i + 1, LuaUi::Layers::at(i)); return std::make_tuple(i + 1, LuaUi::Layer(i));
else else
return sol::nullopt; return sol::nullopt;
}; };

@ -0,0 +1,29 @@
#include "layers.hpp"
#include <components/debug/debuglog.hpp>
namespace LuaUi
{
size_t Layer::indexOf(std::string_view name)
{
for (size_t i = 0; i < count(); i++)
if (at(i)->getName() == name)
return i;
return count();
}
void Layer::insert(size_t index, std::string_view name, Options options)
{
if (index > count())
throw std::logic_error("Invalid layer index");
if (indexOf(name) < count())
Log(Debug::Error) << "Layer \"" << name << "\" already exists";
else
{
auto layer = MyGUI::LayerManager::getInstance()
.createLayerAt(std::string(name), "OverlappedLayer", index);
auto overlappedLayer = dynamic_cast<MyGUI::OverlappedLayer*>(layer);
overlappedLayer->setPick(options.mInteractive);
}
}
}

@ -6,50 +6,63 @@
#include <MyGUI_LayerManager.h> #include <MyGUI_LayerManager.h>
#include <MyGUI_OverlappedLayer.h> #include <MyGUI_OverlappedLayer.h>
#include <osg/Vec2f>
namespace LuaUi namespace LuaUi
{ {
namespace Layers // this wrapper is necessary, because the MyGUI LayerManager
// stores layers in a vector and their indices could change
class Layer
{ {
struct Options { public:
bool mInteractive; Layer(size_t index)
}; : mName(at(index)->getName())
, mCachedIndex(index)
size_t size() {}
{
return MyGUI::LayerManager::getInstance().getLayerCount(); const std::string& name() const noexcept { return mName; };
} const osg::Vec2f size()
{
std::string at(size_t index) MyGUI::ILayer* p = refresh();
{ MyGUI::IntSize size = p->getSize();
if (index >= size()) return osg::Vec2f(size.width, size.height);
throw std::logic_error("Invalid layer index"); }
return MyGUI::LayerManager::getInstance().getLayer(index)->getName();
} struct Options
{
size_t indexOf(std::string_view name) bool mInteractive;
{ };
for (size_t i = 0; i < size(); i++)
if (at(i) == name) static size_t count()
return i; {
return size(); return MyGUI::LayerManager::getInstance().getLayerCount();
} }
void insert(size_t index, std::string_view name, Options options) static size_t indexOf(std::string_view name);
{
if (index > size()) static void insert(size_t index, std::string_view name, Options options);
throw std::logic_error("Invalid layer index");
if (indexOf(name) < size()) private:
Log(Debug::Error) << "Layer \"" << name << "\" already exists"; static MyGUI::ILayer* at(size_t index)
else {
if (index >= count())
throw std::logic_error("Invalid layer index");
return MyGUI::LayerManager::getInstance().getLayer(index);
}
MyGUI::ILayer* refresh()
{ {
auto layer = MyGUI::LayerManager::getInstance() MyGUI::ILayer* p = at(mCachedIndex);
.createLayerAt(std::string(name), "OverlappedLayer", index); if (p->getName() != mName)
auto overlappedLayer = dynamic_cast<MyGUI::OverlappedLayer*>(layer); {
overlappedLayer->setPick(options.mInteractive); mCachedIndex = indexOf(mName);
p = at(mCachedIndex);
}
return p;
} }
} std::string mName;
} size_t mCachedIndex;
};
} }
#endif // OPENMW_LUAUI_LAYERS #endif // OPENMW_LUAUI_LAYERS

@ -77,15 +77,20 @@
-- @field #Content content Optional @{openmw.ui#Content} of children layouts -- @field #Content content Optional @{openmw.ui#Content} of children layouts
--- ---
-- Layers. Implements [iterables#List](iterables.html#List) of #string. -- @type Layer
-- @field #string name Name of the layer
-- @field openmw.util#vector2 size Size of the layer in pixels
---
-- Layers. Implements [iterables#List](iterables.html#List) of #Layer.
-- @type Layers -- @type Layers
-- @list <#string> -- @list <#Layer>
-- @usage -- @usage
-- ui.layers.insertAfter('HUD', 'NewLayer', { interactive = true }) -- ui.layers.insertAfter('HUD', 'NewLayer', { interactive = true })
-- local fourthLayerName = ui.layers[4] -- local fourthLayer = ui.layers[4]
-- local windowsIndex = ui.layers.indexOf('Windows') -- local windowsIndex = ui.layers.indexOf('Windows')
-- for i, name in ipairs(ui.layers) do -- for i, layer in ipairs(ui.layers) do
-- print('layer', i, name) -- print('layer', i, layer.name, layer.size)
-- end -- end
--- ---
@ -101,6 +106,13 @@
-- @param #string name Name of the new layer -- @param #string name Name of the new layer
-- @param #table options Table with a boolean `interactive` field (default is true). Layers with interactive = false will ignore all mouse interactions. -- @param #table options Table with a boolean `interactive` field (default is true). Layers with interactive = false will ignore all mouse interactions.
---
-- Creates a layer and inserts it before another layer (shifts indexes of some other layers).
-- @function [parent=#Layers] insertBefore
-- @param #string beforeName Name of the layer before which the new layer will be inserted
-- @param #string name Name of the new layer
-- @param #table options Table with a boolean `interactive` field (default is true). Layers with interactive = false will ignore all mouse interactions.
--- ---
-- Content. An array-like container, which allows to reference elements by their name. -- Content. An array-like container, which allows to reference elements by their name.
-- Implements [iterables#List](iterables.html#List) of #Layout and [iterables#Map](iterables.html#Map) of #string to #Layout. -- Implements [iterables#List](iterables.html#List) of #Layout and [iterables#Map](iterables.html#Map) of #string to #Layout.

Loading…
Cancel
Save