#include "element.hpp" #include #include "content.hpp" #include "widgetlist.hpp" namespace LuaUi { std::string widgetType(const sol::table& layout) { return layout.get_or("type", std::string("LuaWidget")); } Content content(const sol::table& layout) { auto optional = layout.get>("content"); if (optional.has_value()) return optional.value(); else return Content(); } void setProperties(LuaUi::WidgetExtension* ext, const sol::table& layout) { ext->setProperties(layout.get("props")); } void setEventCallbacks(LuaUi::WidgetExtension* ext, const sol::table& layout) { ext->clearCallbacks(); auto events = layout.get>("events"); if (events.has_value()) { events.value().for_each([ext](const sol::object& name, const sol::object& callback) { if (name.is() && callback.is()) ext->setCallback(name.as(), callback.as()); else if (!name.is()) Log(Debug::Warning) << "UI event key must be a string"; else if (!callback.is()) Log(Debug::Warning) << "UI event handler for key \"" << name.as() << "\" must be an openmw.async.callback"; }); } } void setLayout(LuaUi::WidgetExtension* ext, const sol::table& layout) { ext->setLayout(layout); } LuaUi::WidgetExtension* createWidget(const sol::table& layout, LuaUi::WidgetExtension* parent) { std::string type = widgetType(layout); std::string skin = layout.get_or("skin", std::string()); std::string layer = layout.get_or("layer", std::string("Windows")); std::string name = layout.get_or("name", std::string()); static auto widgetTypeMap = widgetTypeToName(); if (widgetTypeMap.find(type) == widgetTypeMap.end()) throw std::logic_error(std::string("Invalid widget type ") += type); MyGUI::Widget* widget = MyGUI::Gui::getInstancePtr()->createWidgetT( type, skin, MyGUI::IntCoord(), MyGUI::Align::Default, layer, name); LuaUi::WidgetExtension* ext = dynamic_cast(widget); if (!ext) throw std::runtime_error("Invalid widget!"); ext->create(layout.lua_state(), widget); if (parent != nullptr) widget->attachToWidget(parent->widget()); setEventCallbacks(ext, layout); setProperties(ext, layout); setLayout(ext, layout); Content cont = content(layout); for (size_t i = 0; i < cont.size(); i++) ext->addChild(createWidget(cont.at(i), ext)); return ext; } void destroyWidget(LuaUi::WidgetExtension* ext) { ext->destroy(); MyGUI::Gui::getInstancePtr()->destroyWidget(ext->widget()); } void updateWidget(const sol::table& layout, LuaUi::WidgetExtension* ext) { setEventCallbacks(ext, layout); setProperties(ext, layout); setLayout(ext, layout); Content newContent = content(layout); size_t oldSize = ext->childCount(); size_t newSize = newContent.size(); size_t minSize = std::min(oldSize, newSize); for (size_t i = 0; i < minSize; i++) { LuaUi::WidgetExtension* oldWidget = ext->childAt(i); sol::table newChild = newContent.at(i); if (oldWidget->widget()->getTypeName() != widgetType(newChild)) { destroyWidget(oldWidget); ext->assignChild(i, createWidget(newChild, ext)); } else updateWidget(newChild, oldWidget); } for (size_t i = minSize; i < oldSize; i++) destroyWidget(ext->eraseChild(i)); for (size_t i = minSize; i < newSize; i++) ext->addChild(createWidget(newContent.at(i), ext)); } void Element::create() { assert(!mRoot); if (!mRoot) mRoot = createWidget(mLayout, nullptr); } void Element::update() { if (mRoot && mUpdate) updateWidget(mLayout, mRoot); mUpdate = false; } void Element::destroy() { if (mRoot) destroyWidget(mRoot); mRoot = nullptr; } }