mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-03 01:41:32 +00:00
Styling for Settings
This commit is contained in:
parent
91c32e65c2
commit
52d05be04b
28 changed files with 738 additions and 394 deletions
|
@ -7,11 +7,6 @@ namespace LuaUi
|
||||||
void LuaContainer::updateChildren()
|
void LuaContainer::updateChildren()
|
||||||
{
|
{
|
||||||
WidgetExtension::updateChildren();
|
WidgetExtension::updateChildren();
|
||||||
for (auto w : children())
|
|
||||||
{
|
|
||||||
w->onCoordChange([this](WidgetExtension* child, MyGUI::IntCoord coord)
|
|
||||||
{ updateSizeToFit(); });
|
|
||||||
}
|
|
||||||
updateSizeToFit();
|
updateSizeToFit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,16 +15,39 @@ namespace LuaUi
|
||||||
return MyGUI::IntSize();
|
return MyGUI::IntSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MyGUI::IntSize LuaContainer::templateScalingSize()
|
||||||
|
{
|
||||||
|
return mInnerSize;
|
||||||
|
}
|
||||||
|
|
||||||
void LuaContainer::updateSizeToFit()
|
void LuaContainer::updateSizeToFit()
|
||||||
{
|
{
|
||||||
MyGUI::IntSize size;
|
MyGUI::IntSize innerSize = MyGUI::IntSize();
|
||||||
for (auto w : children())
|
for (auto w : children())
|
||||||
{
|
{
|
||||||
MyGUI::IntCoord coord = w->widget()->getCoord();
|
MyGUI::IntCoord coord = w->calculateCoord();
|
||||||
size.width = std::max(size.width, coord.left + coord.width);
|
innerSize.width = std::max(innerSize.width, coord.left + coord.width);
|
||||||
size.height = std::max(size.height, coord.top + coord.height);
|
innerSize.height = std::max(innerSize.height, coord.top + coord.height);
|
||||||
}
|
}
|
||||||
forceSize(size);
|
MyGUI::IntSize outerSize = innerSize;
|
||||||
updateCoord();
|
for (auto w : templateChildren())
|
||||||
|
{
|
||||||
|
MyGUI::IntCoord coord = w->calculateCoord();
|
||||||
|
outerSize.width = std::max(outerSize.width, coord.left + coord.width);
|
||||||
|
outerSize.height = std::max(outerSize.height, coord.top + coord.height);
|
||||||
|
}
|
||||||
|
mInnerSize = innerSize;
|
||||||
|
mOuterSize = outerSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyGUI::IntSize LuaContainer::calculateSize()
|
||||||
|
{
|
||||||
|
return mOuterSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaContainer::updateCoord()
|
||||||
|
{
|
||||||
|
updateSizeToFit();
|
||||||
|
WidgetExtension::updateCoord();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,18 @@ namespace LuaUi
|
||||||
{
|
{
|
||||||
MYGUI_RTTI_DERIVED(LuaContainer)
|
MYGUI_RTTI_DERIVED(LuaContainer)
|
||||||
|
|
||||||
|
MyGUI::IntSize calculateSize() override;
|
||||||
|
void updateCoord() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updateChildren() override;
|
void updateChildren() override;
|
||||||
MyGUI::IntSize childScalingSize() override;
|
MyGUI::IntSize childScalingSize() override;
|
||||||
|
MyGUI::IntSize templateScalingSize() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateSizeToFit();
|
void updateSizeToFit();
|
||||||
|
MyGUI::IntSize mInnerSize;
|
||||||
|
MyGUI::IntSize mOuterSize;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,18 @@ namespace LuaUi
|
||||||
|
|
||||||
std::string widgetType(const sol::table& layout)
|
std::string widgetType(const sol::table& layout)
|
||||||
{
|
{
|
||||||
return layout.get_or(LayoutKeys::type, defaultWidgetType);
|
sol::object typeField = LuaUtil::getFieldOrNil(layout, LayoutKeys::type);
|
||||||
|
std::string type = LuaUtil::getValueOrDefault(typeField, defaultWidgetType);
|
||||||
|
sol::object templateTypeField = LuaUtil::getFieldOrNil(layout, LayoutKeys::templateLayout, LayoutKeys::type);
|
||||||
|
if (templateTypeField != sol::nil)
|
||||||
|
{
|
||||||
|
std::string templateType = LuaUtil::getValueOrDefault(templateTypeField, defaultWidgetType);
|
||||||
|
if (typeField != sol::nil && templateType != type)
|
||||||
|
throw std::logic_error(std::string("Template layout type ") + type
|
||||||
|
+ std::string(" doesn't match template type ") + templateType);
|
||||||
|
type = templateType;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyWidget(LuaUi::WidgetExtension* ext)
|
void destroyWidget(LuaUi::WidgetExtension* ext)
|
||||||
|
@ -103,18 +114,8 @@ namespace LuaUi
|
||||||
|
|
||||||
WidgetExtension* createWidget(const sol::table& layout)
|
WidgetExtension* createWidget(const sol::table& layout)
|
||||||
{
|
{
|
||||||
sol::object typeField = LuaUtil::getFieldOrNil(layout, LayoutKeys::type);
|
|
||||||
std::string type = LuaUtil::getValueOrDefault(typeField, defaultWidgetType);
|
|
||||||
sol::object templateTypeField = LuaUtil::getFieldOrNil(layout, LayoutKeys::templateLayout, LayoutKeys::type);
|
|
||||||
if (templateTypeField != sol::nil)
|
|
||||||
{
|
|
||||||
std::string templateType = LuaUtil::getValueOrDefault(templateTypeField, defaultWidgetType);
|
|
||||||
if (typeField != sol::nil && templateType != type)
|
|
||||||
throw std::logic_error(std::string("Template layout type ") + type
|
|
||||||
+ std::string(" doesn't match template type ") + templateType);
|
|
||||||
type = templateType;
|
|
||||||
}
|
|
||||||
static auto widgetTypeMap = widgetTypeToName();
|
static auto widgetTypeMap = widgetTypeToName();
|
||||||
|
std::string type = widgetType(layout);
|
||||||
if (widgetTypeMap.find(type) == widgetTypeMap.end())
|
if (widgetTypeMap.find(type) == widgetTypeMap.end())
|
||||||
throw std::logic_error(std::string("Invalid widget type ") += type);
|
throw std::logic_error(std::string("Invalid widget type ") += type);
|
||||||
|
|
||||||
|
@ -242,7 +243,7 @@ namespace LuaUi
|
||||||
if (!mLayer.empty())
|
if (!mLayer.empty())
|
||||||
Log(Debug::Warning) << "Ignoring element's layer " << mLayer << " because it's attached to a widget";
|
Log(Debug::Warning) << "Ignoring element's layer " << mLayer << " because it's attached to a widget";
|
||||||
mAttachedTo->setChildren({ mRoot });
|
mAttachedTo->setChildren({ mRoot });
|
||||||
mRoot->updateCoord();
|
mAttachedTo->updateCoord();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace LuaUi
|
||||||
MyGUI::IntSize flexSize = calculateSize();
|
MyGUI::IntSize flexSize = calculateSize();
|
||||||
int growSize = 0;
|
int growSize = 0;
|
||||||
float growFactor = 0;
|
float growFactor = 0;
|
||||||
if (totalGrow > 0 && !mAutoSized)
|
if (totalGrow > 0)
|
||||||
{
|
{
|
||||||
growSize = primary(flexSize) - primary(childrenSize);
|
growSize = primary(flexSize) - primary(childrenSize);
|
||||||
growFactor = growSize / totalGrow;
|
growFactor = growSize / totalGrow;
|
||||||
|
@ -67,22 +67,32 @@ namespace LuaUi
|
||||||
for (auto* w : children())
|
for (auto* w : children())
|
||||||
{
|
{
|
||||||
MyGUI::IntSize size = w->calculateSize();
|
MyGUI::IntSize size = w->calculateSize();
|
||||||
|
primary(size) += static_cast<int>(growFactor * getGrow(w));
|
||||||
|
float stretch = std::clamp(w->externalValue("stretch", 0.0f), 0.0f, 1.0f);
|
||||||
|
secondary(size) = std::max(secondary(size), static_cast<int>(stretch * secondary(flexSize)));
|
||||||
secondary(childPosition) = alignSize(secondary(flexSize), secondary(size), mArrange);
|
secondary(childPosition) = alignSize(secondary(flexSize), secondary(size), mArrange);
|
||||||
w->forcePosition(childPosition);
|
w->forcePosition(childPosition);
|
||||||
primary(size) += static_cast<int>(growFactor * getGrow(w));
|
|
||||||
w->forceSize(size);
|
w->forceSize(size);
|
||||||
w->updateCoord();
|
w->updateCoord();
|
||||||
primary(childPosition) += primary(size);
|
primary(childPosition) += primary(size);
|
||||||
w->updateCoord();
|
|
||||||
}
|
}
|
||||||
WidgetExtension::updateChildren();
|
WidgetExtension::updateChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MyGUI::IntSize LuaFlex::childScalingSize()
|
||||||
|
{
|
||||||
|
// Call the base method to prevent relativeSize feedback loop
|
||||||
|
MyGUI::IntSize size = WidgetExtension::calculateSize();
|
||||||
|
if (mAutoSized)
|
||||||
|
primary(size) = 0;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
MyGUI::IntSize LuaFlex::calculateSize()
|
MyGUI::IntSize LuaFlex::calculateSize()
|
||||||
{
|
{
|
||||||
MyGUI::IntSize size = WidgetExtension::calculateSize();
|
MyGUI::IntSize size = WidgetExtension::calculateSize();
|
||||||
if (mAutoSized) {
|
if (mAutoSized) {
|
||||||
primary(size) = primary(mChildrenSize);
|
primary(size) = std::max(primary(size), primary(mChildrenSize));
|
||||||
secondary(size) = std::max(secondary(size), secondary(mChildrenSize));
|
secondary(size) = std::max(secondary(size), secondary(mChildrenSize));
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
|
|
|
@ -14,10 +14,8 @@ namespace LuaUi
|
||||||
MyGUI::IntSize calculateSize() override;
|
MyGUI::IntSize calculateSize() override;
|
||||||
void updateProperties() override;
|
void updateProperties() override;
|
||||||
void updateChildren() override;
|
void updateChildren() override;
|
||||||
MyGUI::IntSize childScalingSize() override
|
MyGUI::IntSize childScalingSize() override;
|
||||||
{
|
|
||||||
return MyGUI::IntSize();
|
|
||||||
}
|
|
||||||
void updateCoord() override;
|
void updateCoord() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace LuaUi
|
||||||
{
|
{
|
||||||
changeWidgetSkin("LuaImage");
|
changeWidgetSkin("LuaImage");
|
||||||
mTileRect = dynamic_cast<LuaTileRect*>(getSubWidgetMain());
|
mTileRect = dynamic_cast<LuaTileRect*>(getSubWidgetMain());
|
||||||
|
WidgetExtension::initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaImage::updateProperties()
|
void LuaImage::updateProperties()
|
||||||
|
|
|
@ -6,38 +6,57 @@ namespace LuaUi
|
||||||
{
|
{
|
||||||
void LuaTextEdit::initialize()
|
void LuaTextEdit::initialize()
|
||||||
{
|
{
|
||||||
changeWidgetSkin("LuaTextEdit");
|
mEditBox = createWidget<MyGUI::EditBox>("LuaTextEdit", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default);
|
||||||
|
mEditBox->eventEditTextChange += MyGUI::newDelegate(this, &LuaTextEdit::textChange);
|
||||||
eventEditTextChange += MyGUI::newDelegate(this, &LuaTextEdit::textChange);
|
registerEvents(mEditBox);
|
||||||
|
|
||||||
WidgetExtension::initialize();
|
WidgetExtension::initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaTextEdit::deinitialize()
|
void LuaTextEdit::deinitialize()
|
||||||
{
|
{
|
||||||
eventEditTextChange -= MyGUI::newDelegate(this, &LuaTextEdit::textChange);
|
mEditBox->eventEditTextChange -= MyGUI::newDelegate(this, &LuaTextEdit::textChange);
|
||||||
|
clearEvents(mEditBox);
|
||||||
WidgetExtension::deinitialize();
|
WidgetExtension::deinitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaTextEdit::updateProperties()
|
void LuaTextEdit::updateProperties()
|
||||||
{
|
{
|
||||||
setCaption(propertyValue("text", std::string()));
|
mEditBox->setCaption(propertyValue("text", std::string()));
|
||||||
setFontHeight(propertyValue("textSize", 10));
|
mEditBox->setFontHeight(propertyValue("textSize", 10));
|
||||||
setTextColour(propertyValue("textColor", MyGUI::Colour(0, 0, 0, 1)));
|
mEditBox->setTextColour(propertyValue("textColor", MyGUI::Colour(0, 0, 0, 1)));
|
||||||
setEditMultiLine(propertyValue("multiline", false));
|
mEditBox->setEditMultiLine(propertyValue("multiline", false));
|
||||||
setEditWordWrap(propertyValue("wordWrap", false));
|
mEditBox->setEditWordWrap(propertyValue("wordWrap", false));
|
||||||
|
|
||||||
Alignment horizontal(propertyValue("textAlignH", Alignment::Start));
|
Alignment horizontal(propertyValue("textAlignH", Alignment::Start));
|
||||||
Alignment vertical(propertyValue("textAlignV", Alignment::Start));
|
Alignment vertical(propertyValue("textAlignV", Alignment::Start));
|
||||||
setTextAlign(alignmentToMyGui(horizontal, vertical));
|
mEditBox->setTextAlign(alignmentToMyGui(horizontal, vertical));
|
||||||
|
|
||||||
setEditStatic(propertyValue("readOnly", false));
|
mEditBox->setEditStatic(propertyValue("readOnly", false));
|
||||||
|
|
||||||
WidgetExtension::updateProperties();
|
WidgetExtension::updateProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaTextEdit::textChange(MyGUI::EditBox*)
|
void LuaTextEdit::textChange(MyGUI::EditBox*)
|
||||||
{
|
{
|
||||||
triggerEvent("textChanged", sol::make_object(lua(), getCaption().asUTF8()));
|
triggerEvent("textChanged", sol::make_object(lua(), mEditBox->getCaption().asUTF8()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaTextEdit::updateCoord()
|
||||||
|
{
|
||||||
|
WidgetExtension::updateCoord();
|
||||||
|
{
|
||||||
|
MyGUI::IntSize slotSize = slot()->calculateSize();
|
||||||
|
MyGUI::IntPoint slotPosition = slot()->widget()->getAbsolutePosition() - widget()->getAbsolutePosition();
|
||||||
|
MyGUI::IntCoord slotCoord(slotPosition, slotSize);
|
||||||
|
mEditBox->setCoord(slotCoord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaTextEdit::updateChildren()
|
||||||
|
{
|
||||||
|
WidgetExtension::updateChildren();
|
||||||
|
// otherwise it won't be focusable
|
||||||
|
mEditBox->detachFromWidget();
|
||||||
|
mEditBox->attachToWidget(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace LuaUi
|
namespace LuaUi
|
||||||
{
|
{
|
||||||
class LuaTextEdit : public MyGUI::EditBox, public WidgetExtension
|
class LuaTextEdit : public MyGUI::Widget, public WidgetExtension
|
||||||
{
|
{
|
||||||
MYGUI_RTTI_DERIVED(LuaTextEdit)
|
MYGUI_RTTI_DERIVED(LuaTextEdit)
|
||||||
|
|
||||||
|
@ -15,9 +15,13 @@ namespace LuaUi
|
||||||
void initialize() override;
|
void initialize() override;
|
||||||
void deinitialize() override;
|
void deinitialize() override;
|
||||||
void updateProperties() override;
|
void updateProperties() override;
|
||||||
|
void updateCoord() override;
|
||||||
|
void updateChildren() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void textChange(MyGUI::EditBox*);
|
void textChange(MyGUI::EditBox*);
|
||||||
|
|
||||||
|
MyGUI::EditBox* mEditBox;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace LuaUi
|
||||||
{ "LuaWindow", "Window" },
|
{ "LuaWindow", "Window" },
|
||||||
{ "LuaImage", "Image" },
|
{ "LuaImage", "Image" },
|
||||||
{ "LuaFlex", "Flex" },
|
{ "LuaFlex", "Flex" },
|
||||||
|
{ "LuaContainer", "Container" },
|
||||||
};
|
};
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,37 +35,13 @@ namespace LuaUi
|
||||||
void WidgetExtension::initialize()
|
void WidgetExtension::initialize()
|
||||||
{
|
{
|
||||||
// \todo might be more efficient to only register these if there are Lua callbacks
|
// \todo might be more efficient to only register these if there are Lua callbacks
|
||||||
mWidget->eventKeyButtonPressed += MyGUI::newDelegate(this, &WidgetExtension::keyPress);
|
registerEvents(mWidget);
|
||||||
mWidget->eventKeyButtonReleased += MyGUI::newDelegate(this, &WidgetExtension::keyRelease);
|
|
||||||
mWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &WidgetExtension::mouseClick);
|
|
||||||
mWidget->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &WidgetExtension::mouseDoubleClick);
|
|
||||||
mWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &WidgetExtension::mousePress);
|
|
||||||
mWidget->eventMouseButtonReleased += MyGUI::newDelegate(this, &WidgetExtension::mouseRelease);
|
|
||||||
mWidget->eventMouseMove += MyGUI::newDelegate(this, &WidgetExtension::mouseMove);
|
|
||||||
mWidget->eventMouseDrag += MyGUI::newDelegate(this, &WidgetExtension::mouseDrag);
|
|
||||||
|
|
||||||
mWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &WidgetExtension::focusGain);
|
|
||||||
mWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &WidgetExtension::focusLoss);
|
|
||||||
mWidget->eventKeySetFocus += MyGUI::newDelegate(this, &WidgetExtension::focusGain);
|
|
||||||
mWidget->eventKeyLostFocus += MyGUI::newDelegate(this, &WidgetExtension::focusLoss);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidgetExtension::deinitialize()
|
void WidgetExtension::deinitialize()
|
||||||
{
|
{
|
||||||
clearCallbacks();
|
clearCallbacks();
|
||||||
mWidget->eventKeyButtonPressed.clear();
|
clearEvents(mWidget);
|
||||||
mWidget->eventKeyButtonReleased.clear();
|
|
||||||
mWidget->eventMouseButtonClick.clear();
|
|
||||||
mWidget->eventMouseButtonDoubleClick.clear();
|
|
||||||
mWidget->eventMouseButtonPressed.clear();
|
|
||||||
mWidget->eventMouseButtonReleased.clear();
|
|
||||||
mWidget->eventMouseMove.clear();
|
|
||||||
mWidget->eventMouseDrag.m_event.clear();
|
|
||||||
|
|
||||||
mWidget->eventMouseSetFocus.clear();
|
|
||||||
mWidget->eventMouseLostFocus.clear();
|
|
||||||
mWidget->eventKeySetFocus.clear();
|
|
||||||
mWidget->eventKeyLostFocus.clear();
|
|
||||||
|
|
||||||
mOnCoordChange.reset();
|
mOnCoordChange.reset();
|
||||||
|
|
||||||
|
@ -75,6 +51,39 @@ namespace LuaUi
|
||||||
w->deinitialize();
|
w->deinitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WidgetExtension::registerEvents(MyGUI::Widget* w)
|
||||||
|
{
|
||||||
|
w->eventKeyButtonPressed += MyGUI::newDelegate(this, &WidgetExtension::keyPress);
|
||||||
|
w->eventKeyButtonReleased += MyGUI::newDelegate(this, &WidgetExtension::keyRelease);
|
||||||
|
w->eventMouseButtonClick += MyGUI::newDelegate(this, &WidgetExtension::mouseClick);
|
||||||
|
w->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &WidgetExtension::mouseDoubleClick);
|
||||||
|
w->eventMouseButtonPressed += MyGUI::newDelegate(this, &WidgetExtension::mousePress);
|
||||||
|
w->eventMouseButtonReleased += MyGUI::newDelegate(this, &WidgetExtension::mouseRelease);
|
||||||
|
w->eventMouseMove += MyGUI::newDelegate(this, &WidgetExtension::mouseMove);
|
||||||
|
w->eventMouseDrag += MyGUI::newDelegate(this, &WidgetExtension::mouseDrag);
|
||||||
|
|
||||||
|
w->eventMouseSetFocus += MyGUI::newDelegate(this, &WidgetExtension::focusGain);
|
||||||
|
w->eventMouseLostFocus += MyGUI::newDelegate(this, &WidgetExtension::focusLoss);
|
||||||
|
w->eventKeySetFocus += MyGUI::newDelegate(this, &WidgetExtension::focusGain);
|
||||||
|
w->eventKeyLostFocus += MyGUI::newDelegate(this, &WidgetExtension::focusLoss);
|
||||||
|
}
|
||||||
|
void WidgetExtension::clearEvents(MyGUI::Widget* w)
|
||||||
|
{
|
||||||
|
w->eventKeyButtonPressed.clear();
|
||||||
|
w->eventKeyButtonReleased.clear();
|
||||||
|
w->eventMouseButtonClick.clear();
|
||||||
|
w->eventMouseButtonDoubleClick.clear();
|
||||||
|
w->eventMouseButtonPressed.clear();
|
||||||
|
w->eventMouseButtonReleased.clear();
|
||||||
|
w->eventMouseMove.clear();
|
||||||
|
w->eventMouseDrag.m_event.clear();
|
||||||
|
|
||||||
|
w->eventMouseSetFocus.clear();
|
||||||
|
w->eventMouseLostFocus.clear();
|
||||||
|
w->eventKeySetFocus.clear();
|
||||||
|
w->eventKeyLostFocus.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void WidgetExtension::reset()
|
void WidgetExtension::reset()
|
||||||
{
|
{
|
||||||
// detach all children from the slot widget, in case it gets destroyed
|
// detach all children from the slot widget, in case it gets destroyed
|
||||||
|
@ -188,25 +197,11 @@ namespace LuaUi
|
||||||
|
|
||||||
void WidgetExtension::updateTemplate()
|
void WidgetExtension::updateTemplate()
|
||||||
{
|
{
|
||||||
WidgetExtension* oldSlot = mSlot;
|
|
||||||
WidgetExtension* slot = findDeepInTemplates("slot");
|
WidgetExtension* slot = findDeepInTemplates("slot");
|
||||||
if (slot == nullptr)
|
if (slot == nullptr)
|
||||||
mSlot = this;
|
mSlot = this;
|
||||||
else
|
else
|
||||||
mSlot = slot->mSlot;
|
mSlot = slot->mSlot;
|
||||||
if (mSlot != oldSlot)
|
|
||||||
{
|
|
||||||
MyGUI::IntSize slotSize = mSlot->widget()->getSize();
|
|
||||||
MyGUI::IntPoint slotPosition = mSlot->widget()->getAbsolutePosition() - widget()->getAbsolutePosition();
|
|
||||||
MyGUI::IntCoord slotCoord(slotPosition, slotSize);
|
|
||||||
MyGUI::Widget* clientWidget = mWidget->getClientWidget();
|
|
||||||
if (!clientWidget)
|
|
||||||
clientWidget = mWidget;
|
|
||||||
if (clientWidget->getSubWidgetMain())
|
|
||||||
clientWidget->getSubWidgetMain()->setCoord(slotCoord);
|
|
||||||
if (clientWidget->getSubWidgetText())
|
|
||||||
clientWidget->getSubWidgetText()->setCoord(slotCoord);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidgetExtension::setCallback(const std::string& name, const LuaUtil::Callback& callback)
|
void WidgetExtension::setCallback(const std::string& name, const LuaUtil::Callback& callback)
|
||||||
|
@ -290,10 +285,12 @@ namespace LuaUi
|
||||||
|
|
||||||
MyGUI::IntSize WidgetExtension::parentSize()
|
MyGUI::IntSize WidgetExtension::parentSize()
|
||||||
{
|
{
|
||||||
if (mParent && !mTemplateChild)
|
if (!mParent)
|
||||||
return mParent->childScalingSize();
|
return widget()->getParentSize(); // size of the layer
|
||||||
|
if (mTemplateChild)
|
||||||
|
return mParent->templateScalingSize();
|
||||||
else
|
else
|
||||||
return widget()->getParentSize();
|
return mParent->childScalingSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
MyGUI::IntSize WidgetExtension::calculateSize()
|
MyGUI::IntSize WidgetExtension::calculateSize()
|
||||||
|
@ -334,6 +331,11 @@ namespace LuaUi
|
||||||
return mSlot->widget()->getSize();
|
return mSlot->widget()->getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MyGUI::IntSize WidgetExtension::templateScalingSize()
|
||||||
|
{
|
||||||
|
return widget()->getSize();
|
||||||
|
}
|
||||||
|
|
||||||
void WidgetExtension::triggerEvent(std::string_view name, sol::object argument) const
|
void WidgetExtension::triggerEvent(std::string_view name, sol::object argument) const
|
||||||
{
|
{
|
||||||
auto it = mCallbacks.find(name);
|
auto it = mCallbacks.find(name);
|
||||||
|
|
|
@ -70,16 +70,20 @@ namespace LuaUi
|
||||||
|
|
||||||
virtual MyGUI::IntSize calculateSize();
|
virtual MyGUI::IntSize calculateSize();
|
||||||
virtual MyGUI::IntPoint calculatePosition(const MyGUI::IntSize& size);
|
virtual MyGUI::IntPoint calculatePosition(const MyGUI::IntSize& size);
|
||||||
|
MyGUI::IntCoord calculateCoord();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void initialize();
|
virtual void initialize();
|
||||||
|
void registerEvents(MyGUI::Widget* w);
|
||||||
|
void clearEvents(MyGUI::Widget* w);
|
||||||
|
|
||||||
sol::table makeTable() const;
|
sol::table makeTable() const;
|
||||||
sol::object keyEvent(MyGUI::KeyCode) const;
|
sol::object keyEvent(MyGUI::KeyCode) const;
|
||||||
sol::object mouseEvent(int left, int top, MyGUI::MouseButton button) const;
|
sol::object mouseEvent(int left, int top, MyGUI::MouseButton button) const;
|
||||||
|
|
||||||
MyGUI::IntSize parentSize();
|
MyGUI::IntSize parentSize();
|
||||||
MyGUI::IntCoord calculateCoord();
|
|
||||||
virtual MyGUI::IntSize childScalingSize();
|
virtual MyGUI::IntSize childScalingSize();
|
||||||
|
virtual MyGUI::IntSize templateScalingSize();
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T propertyValue(std::string_view name, const T& defaultValue)
|
T propertyValue(std::string_view name, const T& defaultValue)
|
||||||
|
|
|
@ -111,3 +111,6 @@ Sources can be found in ``resources/vfs/openmw_aux``. In theory mods can overrid
|
||||||
* - :ref:`Settings <Interface Settings>`
|
* - :ref:`Settings <Interface Settings>`
|
||||||
- by player and global scripts
|
- by player and global scripts
|
||||||
- Save, display and track changes of setting values.
|
- Save, display and track changes of setting values.
|
||||||
|
* - :ref:`MWUI <Interface MWUI>`
|
||||||
|
- by player scripts
|
||||||
|
- Morrowind-style UI templates.
|
||||||
|
|
|
@ -476,6 +476,9 @@ The order in which the scripts are started is important. So if one mod should ov
|
||||||
* - :ref:`Settings <Interface Settings>`
|
* - :ref:`Settings <Interface Settings>`
|
||||||
- by player and global scripts
|
- by player and global scripts
|
||||||
- Save, display and track changes of setting values.
|
- Save, display and track changes of setting values.
|
||||||
|
* - :ref:`MWUI <Interface MWUI>`
|
||||||
|
- by player scripts
|
||||||
|
- Morrowind-style UI templates.
|
||||||
|
|
||||||
Event system
|
Event system
|
||||||
============
|
============
|
||||||
|
|
|
@ -82,6 +82,7 @@ Widget types
|
||||||
TextEdit: Accepts text input from the user. <widgets/textedit>
|
TextEdit: Accepts text input from the user. <widgets/textedit>
|
||||||
Image: Renders a texture. <widgets/image>
|
Image: Renders a texture. <widgets/image>
|
||||||
Flex: Aligns children in a column/row <widgets/flex>
|
Flex: Aligns children in a column/row <widgets/flex>
|
||||||
|
Container: Wraps around its children <widgets/container>
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
Container Widget
|
||||||
|
================
|
||||||
|
|
||||||
|
Wraps around its children. Convenient for creating border-type templates.
|
||||||
|
|
||||||
|
Relative size and position don't work for children.
|
||||||
|
|
||||||
|
For template children, relative size and position depend on the children's combined size.
|
|
@ -15,7 +15,8 @@ Properties
|
||||||
- description
|
- description
|
||||||
* - horizontal
|
* - horizontal
|
||||||
- bool (false)
|
- bool (false)
|
||||||
- Flex aligns its children in a row if true, otherwise in a column.
|
- | Flex aligns its children in a row (main axis is horizontal) if true,
|
||||||
|
| otherwise in a column (main axis is vertical).
|
||||||
* - autoSize
|
* - autoSize
|
||||||
- bool (true)
|
- bool (true)
|
||||||
- | If true, Flex will automatically resize to fit its contents.
|
- | If true, Flex will automatically resize to fit its contents.
|
||||||
|
@ -41,3 +42,6 @@ External
|
||||||
- | Grow factor for the child. If there is unused space in the Flex,
|
- | Grow factor for the child. If there is unused space in the Flex,
|
||||||
| it will be split between widgets according to this value.
|
| it will be split between widgets according to this value.
|
||||||
| Has no effect if `autoSize` is `true`.
|
| Has no effect if `autoSize` is `true`.
|
||||||
|
* - stretch
|
||||||
|
- float (0)
|
||||||
|
- | Stretches the child to a percentage of the Flex's cross axis size.
|
||||||
|
|
|
@ -21,6 +21,7 @@ set(LUA_BUILTIN_FILES
|
||||||
scripts/omw/settings/global.lua
|
scripts/omw/settings/global.lua
|
||||||
scripts/omw/settings/common.lua
|
scripts/omw/settings/common.lua
|
||||||
scripts/omw/settings/render.lua
|
scripts/omw/settings/render.lua
|
||||||
|
scripts/omw/settings/renderers.lua
|
||||||
|
|
||||||
l10n/Calendar/en.yaml
|
l10n/Calendar/en.yaml
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ set(LUA_BUILTIN_FILES
|
||||||
scripts/omw/mwui/box.lua
|
scripts/omw/mwui/box.lua
|
||||||
scripts/omw/mwui/text.lua
|
scripts/omw/mwui/text.lua
|
||||||
scripts/omw/mwui/textEdit.lua
|
scripts/omw/mwui/textEdit.lua
|
||||||
|
scripts/omw/mwui/space.lua
|
||||||
scripts/omw/mwui/init.lua
|
scripts/omw/mwui/init.lua
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,120 +1,203 @@
|
||||||
local ui = require('openmw.ui')
|
local ui = require('openmw.ui')
|
||||||
local util = require('openmw.util')
|
local util = require('openmw.util')
|
||||||
|
|
||||||
|
local auxUi = require('openmw_aux.ui')
|
||||||
|
|
||||||
local constants = require('scripts.omw.mwui.constants')
|
local constants = require('scripts.omw.mwui.constants')
|
||||||
|
|
||||||
local v2 = util.vector2
|
local v2 = util.vector2
|
||||||
|
local whiteTexture = ui.texture{ path = 'white' }
|
||||||
|
local menuTransparency = ui._getMenuTransparency()
|
||||||
|
|
||||||
local sideParts = {
|
local sideParts = {
|
||||||
left = util.vector2(0, 0.5),
|
left = v2(0, 0),
|
||||||
right = util.vector2(1, 0.5),
|
right = v2(1, 0),
|
||||||
top = util.vector2(0.5, 0),
|
top = v2(0, 0),
|
||||||
bottom = util.vector2(0.5, 1),
|
bottom = v2(0, 1),
|
||||||
}
|
}
|
||||||
local cornerParts = {
|
local cornerParts = {
|
||||||
top_left_corner = util.vector2(0, 0),
|
top_left = v2(0, 0),
|
||||||
top_right_corner = util.vector2(1, 0),
|
top_right = v2(1, 0),
|
||||||
bottom_left_corner = util.vector2(0, 1),
|
bottom_left = v2(0, 1),
|
||||||
bottom_right_corner = util.vector2(1, 1),
|
bottom_right = v2(1, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
local resources = {}
|
local borderSidePattern = 'textures/menu_thin_border_%s.dds'
|
||||||
|
local borderCornerPattern = 'textures/menu_thin_border_%s_corner.dds'
|
||||||
|
|
||||||
|
local borderResources = {}
|
||||||
do
|
do
|
||||||
local boxBorderPattern = 'textures/menu_thin_border_%s.dds'
|
for k in pairs(sideParts) do
|
||||||
for k, _ in pairs(sideParts) do
|
borderResources[k] = ui.texture{ path = borderSidePattern:format(k) }
|
||||||
resources[k] = ui.texture{ path = boxBorderPattern:format(k) }
|
|
||||||
end
|
end
|
||||||
for k, _ in pairs(cornerParts) do
|
for k in pairs(cornerParts) do
|
||||||
resources[k] = ui.texture{ path = boxBorderPattern:format(k) }
|
borderResources[k] = ui.texture{ path = borderCornerPattern:format(k) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local borderPieces = {}
|
local borderPieces = {}
|
||||||
for k, align in pairs(sideParts) do
|
for k in pairs(sideParts) do
|
||||||
local resource = resources[k]
|
local horizontal = k == 'top' or k == 'bottom'
|
||||||
local horizontal = align.x ~= 0.5
|
borderPieces[k] = {
|
||||||
borderPieces[#borderPieces + 1] = {
|
|
||||||
type = ui.TYPE.Image,
|
type = ui.TYPE.Image,
|
||||||
props = {
|
props = {
|
||||||
resource = resource,
|
resource = borderResources[k],
|
||||||
relativePosition = align,
|
tileH = horizontal,
|
||||||
anchor = align,
|
tileV = not horizontal,
|
||||||
relativeSize = horizontal and v2(0, 1) or v2(1, 0),
|
},
|
||||||
size = (horizontal and v2(1, -2) or v2(-2, 1)) * constants.borderSize,
|
}
|
||||||
tileH = not horizontal,
|
end
|
||||||
tileV = horizontal,
|
for k in pairs(cornerParts) do
|
||||||
|
borderPieces[k] = {
|
||||||
|
type = ui.TYPE.Image,
|
||||||
|
props = {
|
||||||
|
resource = borderResources[k],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
for k, align in pairs(cornerParts) do
|
|
||||||
local resource = resources[k]
|
|
||||||
borderPieces[#borderPieces + 1] = {
|
local function borderTemplates(borderSize)
|
||||||
|
local borderV = v2(1, 1) * borderSize
|
||||||
|
local result = {}
|
||||||
|
result.horizontalLine = {
|
||||||
type = ui.TYPE.Image,
|
type = ui.TYPE.Image,
|
||||||
props = {
|
props = {
|
||||||
resource = resource,
|
resource = borderResources.top,
|
||||||
relativePosition = align,
|
tileH = true,
|
||||||
anchor = align,
|
tileV = false,
|
||||||
size = v2(1, 1) * constants.borderSize,
|
size = v2(0, borderSize),
|
||||||
|
relativeSize = v2(1, 0),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.verticalLine = {
|
||||||
|
type = ui.TYPE.Image,
|
||||||
|
props = {
|
||||||
|
resource = borderResources.left,
|
||||||
|
tileH = false,
|
||||||
|
tileV = true,
|
||||||
|
size = v2(borderSize, 0),
|
||||||
|
relativeSize = v2(0, 1),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result.borders = {
|
||||||
|
content = ui.content {},
|
||||||
|
}
|
||||||
|
for k, v in pairs(sideParts) do
|
||||||
|
local horizontal = k == 'top' or k == 'bottom'
|
||||||
|
local direction = horizontal and v2(1, 0) or v2(0, 1)
|
||||||
|
result.borders.content:add {
|
||||||
|
template = borderPieces[k],
|
||||||
|
props = {
|
||||||
|
position = (direction - v) * borderSize,
|
||||||
|
relativePosition = v,
|
||||||
|
size = (v2(1, 1) - direction * 3) * borderSize,
|
||||||
|
relativeSize = direction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
for k, v in pairs(cornerParts) do
|
||||||
|
result.borders.content:add {
|
||||||
|
template = borderPieces[k],
|
||||||
|
props = {
|
||||||
|
position = -v * borderSize,
|
||||||
|
relativePosition = v,
|
||||||
|
size = borderV,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
result.borders.content:add {
|
||||||
|
external = { slot = true },
|
||||||
|
props = {
|
||||||
|
position = borderV,
|
||||||
|
size = borderV * -2,
|
||||||
|
relativeSize = v2(1, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.box = {
|
||||||
|
type = ui.TYPE.Container,
|
||||||
|
content = ui.content{},
|
||||||
|
}
|
||||||
|
for k, v in pairs(sideParts) do
|
||||||
|
local horizontal = k == 'top' or k == 'bottom'
|
||||||
|
local direction = horizontal and v2(1, 0) or v2(0, 1)
|
||||||
|
result.box.content:add {
|
||||||
|
template = borderPieces[k],
|
||||||
|
props = {
|
||||||
|
position = (direction + v) * borderSize,
|
||||||
|
relativePosition = v,
|
||||||
|
size = (v2(1, 1) - direction) * borderSize,
|
||||||
|
relativeSize = direction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
for k, v in pairs(cornerParts) do
|
||||||
|
result.box.content:add {
|
||||||
|
template = borderPieces[k],
|
||||||
|
props = {
|
||||||
|
position = v * borderSize,
|
||||||
|
relativePosition = v,
|
||||||
|
size = borderV,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
result.box.content:add {
|
||||||
|
external = { slot = true },
|
||||||
|
props = {
|
||||||
|
position = borderV,
|
||||||
|
relativeSize = v2(1, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local backgroundTransparent = {
|
||||||
|
type = ui.TYPE.Image,
|
||||||
|
props = {
|
||||||
|
resource = whiteTexture,
|
||||||
|
color = util.color.rgb(0, 0, 0),
|
||||||
|
alpha = menuTransparency,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
local backgroundSolid = {
|
||||||
|
type = ui.TYPE.Image,
|
||||||
|
props = {
|
||||||
|
resource = whiteTexture,
|
||||||
|
color = util.color.rgb(0, 0, 0),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result.boxTransparent = auxUi.deepLayoutCopy(result.box)
|
||||||
|
result.boxTransparent.content:insert(1, {
|
||||||
|
template = backgroundTransparent,
|
||||||
|
props = {
|
||||||
|
relativeSize = v2(1, 1),
|
||||||
|
size = borderV * 2,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
result.boxSolid = auxUi.deepLayoutCopy(result.box)
|
||||||
|
result.boxSolid.content:insert(1, {
|
||||||
|
template = backgroundSolid,
|
||||||
|
props = {
|
||||||
|
relativeSize = v2(1, 1),
|
||||||
|
size = borderV * 2,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
borderPieces[#borderPieces + 1] = {
|
local thinBorders = borderTemplates(constants.border)
|
||||||
external = {
|
local thickBorders = borderTemplates(constants.thickBorder)
|
||||||
slot = true,
|
|
||||||
},
|
|
||||||
props = {
|
|
||||||
position = v2(1, 1) * (constants.borderSize + constants.padding),
|
|
||||||
size = v2(-2, -2) * (constants.borderSize + constants.padding),
|
|
||||||
relativeSize = v2(1, 1),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
local borders = {
|
|
||||||
content = ui.content(borderPieces)
|
|
||||||
}
|
|
||||||
borders.content:add({
|
|
||||||
external = {
|
|
||||||
slot = true,
|
|
||||||
},
|
|
||||||
props = {
|
|
||||||
size = v2(-2, -2) * constants.borderSize,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
local horizontalLine = {
|
|
||||||
content = ui.content {
|
|
||||||
{
|
|
||||||
type = ui.TYPE.Image,
|
|
||||||
props = {
|
|
||||||
resource = resources.top,
|
|
||||||
tileH = true,
|
|
||||||
tileV = false,
|
|
||||||
size = v2(0, constants.borderSize),
|
|
||||||
relativeSize = v2(1, 0),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
local verticalLine = {
|
|
||||||
content = ui.content {
|
|
||||||
{
|
|
||||||
type = ui.TYPE.Image,
|
|
||||||
props = {
|
|
||||||
resource = resources.left,
|
|
||||||
tileH = false,
|
|
||||||
tileV = true,
|
|
||||||
size = v2(constants.borderSize, 0),
|
|
||||||
relativeSize = v2(0, 1),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return function(templates)
|
return function(templates)
|
||||||
templates.borders = borders
|
for k, t in pairs(thinBorders) do
|
||||||
templates.horizontalLine = horizontalLine
|
templates[k] = t
|
||||||
templates.verticalLine = verticalLine
|
end
|
||||||
|
for k, t in pairs(thickBorders) do
|
||||||
|
templates[k .. 'Thick'] = t
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -2,7 +2,10 @@ local util = require('openmw.util')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
textNormalSize = 16,
|
textNormalSize = 16,
|
||||||
sandColor = util.color.rgb(202 / 255, 165 / 255, 96 / 255),
|
textHeaderSize = 16,
|
||||||
borderSize = 4,
|
headerColor = util.color.rgb(223 / 255, 201 / 255, 159 / 255),
|
||||||
|
normalColor = util.color.rgb(202 / 255, 165 / 255, 96 / 255),
|
||||||
|
border = 2,
|
||||||
|
thickBorder = 4,
|
||||||
padding = 2,
|
padding = 2,
|
||||||
}
|
}
|
|
@ -58,20 +58,26 @@ end
|
||||||
local templates = {}
|
local templates = {}
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Standard rectangular border
|
-- Container that adds padding around its content.
|
||||||
-- @field [parent=#Templates] openmw.ui#Layout border
|
-- @field [parent=#MWUI] #table padding
|
||||||
require('scripts.omw.mwui.borders')(templates)
|
---
|
||||||
|
-- Standard spacing interval
|
||||||
|
-- @field [parent=#MWUI] #number interval
|
||||||
|
require('scripts.omw.mwui.space')(templates)
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Border combined with a transparent background
|
-- Standard rectangular border
|
||||||
|
-- @field [parent=#Templates] openmw.ui#Layout border
|
||||||
|
---
|
||||||
|
-- Container wrapping the content with borders
|
||||||
-- @field [parent=#Templates] openmw.ui#Layout box
|
-- @field [parent=#Templates] openmw.ui#Layout box
|
||||||
---
|
---
|
||||||
-- A transparent background
|
-- Same as box, but with a semi-transparent background
|
||||||
-- @field [parent=#Templates] openmw.ui#Layout backgroundTransparent
|
-- @field [parent=#Templates] openmw.ui#Layout boxTransparent
|
||||||
---
|
---
|
||||||
-- A solid, non-transparent background
|
-- Same as box, but with a solid background
|
||||||
-- @field [parent=#Templates] openmw.ui#Layout backgroundSolid
|
-- @field [parent=#Templates] openmw.ui#Layout boxSolid
|
||||||
require('scripts.omw.mwui.box')(templates)
|
require('scripts.omw.mwui.borders')(templates)
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Standard "sand" colored text
|
-- Standard "sand" colored text
|
||||||
|
|
39
files/builtin_scripts/scripts/omw/mwui/space.lua
Normal file
39
files/builtin_scripts/scripts/omw/mwui/space.lua
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
local ui = require('openmw.ui')
|
||||||
|
local util = require('openmw.util')
|
||||||
|
|
||||||
|
local constants = require('scripts.omw.mwui.constants')
|
||||||
|
|
||||||
|
local borderV = util.vector2(1, 1) * constants.border
|
||||||
|
|
||||||
|
return function(templates)
|
||||||
|
templates.padding = {
|
||||||
|
type = ui.TYPE.Container,
|
||||||
|
content = ui.content {
|
||||||
|
{
|
||||||
|
props = {
|
||||||
|
size = borderV,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
external = { slot = true },
|
||||||
|
props = {
|
||||||
|
position = borderV,
|
||||||
|
relativeSize = util.vector2(1, 1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
props = {
|
||||||
|
position = borderV,
|
||||||
|
relativePosition = util.vector2(1, 1),
|
||||||
|
size = borderV,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templates.interval = {
|
||||||
|
type = ui.TYPE.Widget,
|
||||||
|
props = {
|
||||||
|
size = borderV,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
|
@ -6,10 +6,19 @@ local textNormal = {
|
||||||
type = ui.TYPE.Text,
|
type = ui.TYPE.Text,
|
||||||
props = {
|
props = {
|
||||||
textSize = constants.textNormalSize,
|
textSize = constants.textNormalSize,
|
||||||
textColor = constants.sandColor,
|
textColor = constants.normalColor,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local textHeader = {
|
||||||
|
type = ui.TYPE.Text,
|
||||||
|
props = {
|
||||||
|
textSize = constants.textHeaderSize,
|
||||||
|
textColor = constants.headerColor,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return function(templates)
|
return function(templates)
|
||||||
templates.textNormal = textNormal
|
templates.textNormal = textNormal
|
||||||
|
templates.textHeader = textHeader
|
||||||
end
|
end
|
|
@ -3,6 +3,8 @@ local ui = require('openmw.ui')
|
||||||
|
|
||||||
local constants = require('scripts.omw.mwui.constants')
|
local constants = require('scripts.omw.mwui.constants')
|
||||||
|
|
||||||
|
local borderOffset = util.vector2(1, 1) * constants.border
|
||||||
|
|
||||||
return function(templates)
|
return function(templates)
|
||||||
local borderContent = ui.content {
|
local borderContent = ui.content {
|
||||||
{
|
{
|
||||||
|
@ -12,10 +14,14 @@ return function(templates)
|
||||||
},
|
},
|
||||||
content = ui.content {
|
content = ui.content {
|
||||||
{
|
{
|
||||||
|
props = {
|
||||||
|
position = borderOffset,
|
||||||
|
relativeSize = util.vector2(1, 1),
|
||||||
|
},
|
||||||
external = {
|
external = {
|
||||||
slot = true,
|
slot = true,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -23,10 +29,9 @@ return function(templates)
|
||||||
templates.textEditLine = {
|
templates.textEditLine = {
|
||||||
type = ui.TYPE.TextEdit,
|
type = ui.TYPE.TextEdit,
|
||||||
props = {
|
props = {
|
||||||
|
size = util.vector2(150, constants.textNormalSize) + borderOffset * 4,
|
||||||
textSize = constants.textNormalSize,
|
textSize = constants.textNormalSize,
|
||||||
textColor = constants.sandColor,
|
textColor = constants.normalColor,
|
||||||
textAlignH = ui.ALIGNMENT.Start,
|
|
||||||
textAlignV = ui.ALIGNMENT.Center,
|
|
||||||
multiline = false,
|
multiline = false,
|
||||||
},
|
},
|
||||||
content = borderContent,
|
content = borderContent,
|
||||||
|
@ -35,10 +40,9 @@ return function(templates)
|
||||||
templates.textEditBox = {
|
templates.textEditBox = {
|
||||||
type = ui.TYPE.TextEdit,
|
type = ui.TYPE.TextEdit,
|
||||||
props = {
|
props = {
|
||||||
|
size = util.vector2(150, 5 * constants.textNormalSize) + borderOffset * 4,
|
||||||
textSize = constants.textNormalSize,
|
textSize = constants.textNormalSize,
|
||||||
textColor = constants.sandColor,
|
textColor = constants.normalColor,
|
||||||
textAlignH = ui.ALIGNMENT.Start,
|
|
||||||
textAlignV = ui.ALIGNMENT.Start,
|
|
||||||
multiline = true,
|
multiline = true,
|
||||||
wordWrap = true,
|
wordWrap = true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,8 +21,8 @@ local function validateSettingOptions(options)
|
||||||
if type(options.name) ~= 'string' then
|
if type(options.name) ~= 'string' then
|
||||||
error('Setting must have a name localization key')
|
error('Setting must have a name localization key')
|
||||||
end
|
end
|
||||||
if type(options.description) ~= 'string' then
|
if options.description ~= nil and type(options.description) ~= 'string' then
|
||||||
error('Setting must have a descripiton localization key')
|
error('Setting description key must be a string')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ local function validateGroupOptions(options)
|
||||||
if type(options.name) ~= 'string' then
|
if type(options.name) ~= 'string' then
|
||||||
error('Group must have a name localization key')
|
error('Group must have a name localization key')
|
||||||
end
|
end
|
||||||
if type(options.description) ~= 'string' then
|
if options.description ~= nil and type(options.description) ~= 'string' then
|
||||||
error('Group must have a description localization key')
|
error('Group description key must be a string')
|
||||||
end
|
end
|
||||||
if type(options.settings) ~= 'table' then
|
if type(options.settings) ~= 'table' then
|
||||||
error('Group must have a table of settings')
|
error('Group must have a table of settings')
|
||||||
|
@ -89,8 +89,9 @@ local function registerGroup(options)
|
||||||
settings = {},
|
settings = {},
|
||||||
}
|
}
|
||||||
local valueSection = contextSection(options.key)
|
local valueSection = contextSection(options.key)
|
||||||
for _, opt in ipairs(options.settings) do
|
for i, opt in ipairs(options.settings) do
|
||||||
local setting = registerSetting(opt)
|
local setting = registerSetting(opt)
|
||||||
|
setting.order = i
|
||||||
if group.settings[setting.key] then
|
if group.settings[setting.key] then
|
||||||
error(('Duplicate setting key %s'):format(options.key))
|
error(('Duplicate setting key %s'):format(options.key))
|
||||||
end
|
end
|
||||||
|
@ -123,7 +124,7 @@ return {
|
||||||
local section = contextSection(groupKey)
|
local section = contextSection(groupKey)
|
||||||
saved[groupKey] = {}
|
saved[groupKey] = {}
|
||||||
for key, value in pairs(section:asTable()) do
|
for key, value in pairs(section:asTable()) do
|
||||||
if not group.settings[key].permanentStorage then
|
if group.settings[key] and not group.settings[key].permanentStorage then
|
||||||
saved[groupKey][key] = value
|
saved[groupKey][key] = value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,39 +1,21 @@
|
||||||
local ui = require('openmw.ui')
|
|
||||||
local async = require('openmw.async')
|
|
||||||
local util = require('openmw.util')
|
|
||||||
|
|
||||||
local common = require('scripts.omw.settings.common')
|
local common = require('scripts.omw.settings.common')
|
||||||
local render = require('scripts.omw.settings.render')
|
local render = require('scripts.omw.settings.render')
|
||||||
|
|
||||||
render.registerRenderer('text', function(value, set, arg)
|
require('scripts.omw.settings.renderers')(render.registerRenderer)
|
||||||
return {
|
|
||||||
type = ui.TYPE.TextEdit,
|
|
||||||
props = {
|
|
||||||
size = util.vector2(arg and arg.size or 150, 30),
|
|
||||||
text = value,
|
|
||||||
textColor = util.color.rgb(1, 1, 1),
|
|
||||||
textSize = 15,
|
|
||||||
textAlignV = ui.ALIGNMENT.End,
|
|
||||||
},
|
|
||||||
events = {
|
|
||||||
textChanged = async:callback(function(s) set(s) end),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @type PageOptions
|
-- @type PageOptions
|
||||||
-- @field #string key A unique key
|
-- @field #string key A unique key
|
||||||
-- @field #string l10n A localization context (an argument of core.l10n)
|
-- @field #string l10n A localization context (an argument of core.l10n)
|
||||||
-- @field #string name A key from the localization context
|
-- @field #string name A key from the localization context
|
||||||
-- @field #string description A key from the localization context
|
-- @field #string description A key from the localization context (optional, can be `nil`)
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @type GroupOptions
|
-- @type GroupOptions
|
||||||
-- @field #string key A unique key, starts with "Settings" by convention
|
-- @field #string key A unique key, starts with "Settings" by convention
|
||||||
-- @field #string l10n A localization context (an argument of core.l10n)
|
-- @field #string l10n A localization context (an argument of core.l10n)
|
||||||
-- @field #string name A key from the localization context
|
-- @field #string name A key from the localization context
|
||||||
-- @field #string description A key from the localization context
|
-- @field #string description A key from the localization context (optional, can be `nil`)
|
||||||
-- @field #string page Key of a page which will contain this group
|
-- @field #string page Key of a page which will contain this group
|
||||||
-- @field #number order Groups within the same page are sorted by this number, or their key for equal values.
|
-- @field #number order Groups within the same page are sorted by this number, or their key for equal values.
|
||||||
-- Defaults to 0.
|
-- Defaults to 0.
|
||||||
|
@ -43,7 +25,7 @@ end)
|
||||||
-- @type SettingOptions
|
-- @type SettingOptions
|
||||||
-- @field #string key A unique key
|
-- @field #string key A unique key
|
||||||
-- @field #string name A key from the localization context
|
-- @field #string name A key from the localization context
|
||||||
-- @field #string description A key from the localization context
|
-- @field #string description A key from the localization context (optional, can be `nil`)
|
||||||
-- @field default A default value
|
-- @field default A default value
|
||||||
-- @field #string renderer A renderer key
|
-- @field #string renderer A renderer key
|
||||||
-- @field argument An argument for the renderer
|
-- @field argument An argument for the renderer
|
||||||
|
@ -57,26 +39,33 @@ return {
|
||||||
-- -- In a player script
|
-- -- In a player script
|
||||||
-- local storage = require('openmw.storage')
|
-- local storage = require('openmw.storage')
|
||||||
-- local I = require('openmw.interfaces')
|
-- local I = require('openmw.interfaces')
|
||||||
-- I.Settings.registerGroup({
|
-- I.Settings.registerPage {
|
||||||
|
-- key = 'MyModPage',
|
||||||
|
-- l10n = 'MyMod',
|
||||||
|
-- name = 'My Mod Name',
|
||||||
|
-- description = 'My Mod Description',
|
||||||
|
-- }
|
||||||
|
-- I.Settings.registerGroup {
|
||||||
-- key = 'SettingsPlayerMyMod',
|
-- key = 'SettingsPlayerMyMod',
|
||||||
-- page = 'MyPage',
|
-- page = 'MyModPage',
|
||||||
-- l10n = 'mymod',
|
-- l10n = 'MyMod',
|
||||||
-- name = 'modName',
|
-- name = 'My Group Name',
|
||||||
-- description = 'modDescription',
|
-- description = 'My Group Description',
|
||||||
-- settings = {
|
-- settings = {
|
||||||
-- {
|
-- {
|
||||||
-- key = 'Greeting',
|
-- key = 'Greeting',
|
||||||
-- renderer = 'text',
|
-- renderer = 'textLine',
|
||||||
-- name = 'greetingName',
|
-- name = 'Greeting',
|
||||||
-- description = 'greetingDescription',
|
-- description = 'Text to display when the game starts',
|
||||||
-- default = 'Hello, world!',
|
-- default = 'Hello, world!',
|
||||||
-- argument = {
|
-- permanentStorage = false,
|
||||||
-- size = 200,
|
|
||||||
-- },
|
|
||||||
-- },
|
-- },
|
||||||
-- },
|
-- },
|
||||||
-- })
|
-- }
|
||||||
-- local playerSettings = storage.playerSection('SettingsPlayerMyMod')
|
-- local playerSettings = storage.playerSection('SettingsPlayerMyMod')
|
||||||
|
-- ...
|
||||||
|
-- ui.showMessage(playerSettings:get('Greeting'))
|
||||||
|
-- -- ...
|
||||||
-- -- access a setting page registered by a global script
|
-- -- access a setting page registered by a global script
|
||||||
-- local globalSettings = storage.globalSection('SettingsGlobalMyMod')
|
-- local globalSettings = storage.globalSection('SettingsGlobalMyMod')
|
||||||
interface = {
|
interface = {
|
||||||
|
@ -132,22 +121,19 @@ return {
|
||||||
-- settings = {
|
-- settings = {
|
||||||
-- {
|
-- {
|
||||||
-- key = 'Greeting',
|
-- key = 'Greeting',
|
||||||
-- saveOnly = true,
|
-- permanentStorage = true,
|
||||||
-- default = 'Hi',
|
-- default = 'Hi',
|
||||||
-- renderer = 'text',
|
-- renderer = 'textLine',
|
||||||
-- argument = {
|
|
||||||
-- size = 200,
|
|
||||||
-- },
|
|
||||||
-- name = 'Text Input',
|
-- name = 'Text Input',
|
||||||
-- description = 'Short text input',
|
-- description = 'Short text input',
|
||||||
-- },
|
-- },
|
||||||
-- {
|
-- {
|
||||||
-- key = 'Key',
|
-- key = 'Flag',
|
||||||
-- saveOnly = false,
|
-- permanentStorage = false,
|
||||||
-- default = input.KEY.LeftAlt,
|
-- default = false,
|
||||||
-- renderer = 'keybind',
|
-- renderer = 'yeNo',
|
||||||
-- name = 'Key',
|
-- name = 'Flag',
|
||||||
-- description = 'Bind Key',
|
-- description = 'Flag toggle',
|
||||||
-- },
|
-- },
|
||||||
-- }
|
-- }
|
||||||
-- }
|
-- }
|
||||||
|
|
|
@ -3,6 +3,7 @@ local util = require('openmw.util')
|
||||||
local async = require('openmw.async')
|
local async = require('openmw.async')
|
||||||
local core = require('openmw.core')
|
local core = require('openmw.core')
|
||||||
local storage = require('openmw.storage')
|
local storage = require('openmw.storage')
|
||||||
|
local I = require('openmw.interfaces')
|
||||||
|
|
||||||
local common = require('scripts.omw.settings.common')
|
local common = require('scripts.omw.settings.common')
|
||||||
|
|
||||||
|
@ -15,34 +16,68 @@ local pages = {}
|
||||||
local groups = {}
|
local groups = {}
|
||||||
local pageOptions = {}
|
local pageOptions = {}
|
||||||
|
|
||||||
local padding = function(size)
|
local interval = { template = I.MWUI.templates.interval }
|
||||||
|
local growingIntreval = {
|
||||||
|
template = I.MWUI.templates.interval,
|
||||||
|
external = {
|
||||||
|
grow = 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
local spacer = {
|
||||||
|
props = {
|
||||||
|
size = util.vector2(0, 10),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
local bigSpacer = {
|
||||||
|
props = {
|
||||||
|
size = util.vector2(0, 50),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
local stretchingLine = {
|
||||||
|
template = I.MWUI.templates.horizontalLine,
|
||||||
|
external = {
|
||||||
|
stretch = 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
local spacedLines = function(count)
|
||||||
|
local content = {}
|
||||||
|
table.insert(content, spacer)
|
||||||
|
table.insert(content, stretchingLine)
|
||||||
|
for i = 2, count do
|
||||||
|
table.insert(content, interval)
|
||||||
|
table.insert(content, stretchingLine)
|
||||||
|
end
|
||||||
|
table.insert(content, spacer)
|
||||||
return {
|
return {
|
||||||
props = {
|
type = ui.TYPE.Flex,
|
||||||
size = util.vector2(size, size),
|
external = {
|
||||||
}
|
stretch = 1,
|
||||||
|
},
|
||||||
|
content = ui.content(content),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
local smallPadding = padding(10)
|
|
||||||
local bigPadding = padding(25)
|
|
||||||
|
|
||||||
local pageHeader = {
|
local function interlaceSeparator(layouts, separator)
|
||||||
props = {
|
local result = {}
|
||||||
textColor = util.color.rgb(1, 1, 1),
|
result[1] = layouts[1]
|
||||||
textSize = 30,
|
for i = 2, #layouts do
|
||||||
},
|
table.insert(result, separator)
|
||||||
}
|
table.insert(result, layouts[i])
|
||||||
local groupHeader = {
|
end
|
||||||
props = {
|
return result
|
||||||
textColor = util.color.rgb(1, 1, 1),
|
end
|
||||||
textSize = 25,
|
|
||||||
},
|
local function setSettingValue(global, groupKey, settingKey, value)
|
||||||
}
|
if global then
|
||||||
local normal = {
|
core.sendGlobalEvent(common.setGlobalEvent, {
|
||||||
props = {
|
groupKey = groupKey,
|
||||||
textColor = util.color.rgb(1, 1, 1),
|
settingKey = settingKey,
|
||||||
textSize = 20,
|
value = value,
|
||||||
},
|
})
|
||||||
}
|
else
|
||||||
|
storage.playerSection(groupKey):set(settingKey, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function renderSetting(group, setting, value, global)
|
local function renderSetting(group, setting, value, global)
|
||||||
local renderFunction = renderers[setting.renderer]
|
local renderFunction = renderers[setting.renderer]
|
||||||
|
@ -50,55 +85,47 @@ local function renderSetting(group, setting, value, global)
|
||||||
error(('Setting %s of %s has unknown renderer %s'):format(setting.key, group.key, setting.renderer))
|
error(('Setting %s of %s has unknown renderer %s'):format(setting.key, group.key, setting.renderer))
|
||||||
end
|
end
|
||||||
local set = function(value)
|
local set = function(value)
|
||||||
if global then
|
setSettingValue(global, group.key, setting.key, value)
|
||||||
core.sendGlobalEvent(common.setGlobalEvent, {
|
|
||||||
groupKey = group.key,
|
|
||||||
settingKey = setting.key,
|
|
||||||
value = value,
|
|
||||||
})
|
|
||||||
else
|
|
||||||
storage.playerSection(group.key):set(setting.key, value)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
local l10n = core.l10n(group.l10n)
|
local l10n = core.l10n(group.l10n)
|
||||||
return {
|
local titleLayout = {
|
||||||
name = setting.key,
|
|
||||||
type = ui.TYPE.Flex,
|
type = ui.TYPE.Flex,
|
||||||
content = ui.content {
|
content = ui.content {
|
||||||
{
|
{
|
||||||
type = ui.TYPE.Flex,
|
template = I.MWUI.templates.textNormal,
|
||||||
props = {
|
props = {
|
||||||
horizontal = true,
|
text = l10n(setting.name),
|
||||||
align = ui.ALIGNMENT.Start,
|
textSize = 18,
|
||||||
arrange = ui.ALIGNMENT.End,
|
|
||||||
},
|
|
||||||
content = ui.content {
|
|
||||||
{
|
|
||||||
type = ui.TYPE.Text,
|
|
||||||
template = normal,
|
|
||||||
props = {
|
|
||||||
text = l10n(setting.name),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
smallPadding,
|
|
||||||
renderFunction(value, set, setting.argument),
|
|
||||||
smallPadding,
|
|
||||||
{
|
|
||||||
type = ui.TYPE.Text,
|
|
||||||
template = normal,
|
|
||||||
props = {
|
|
||||||
text = 'Reset',
|
|
||||||
},
|
|
||||||
events = {
|
|
||||||
mouseClick = async:callback(function()
|
|
||||||
set(setting.default)
|
|
||||||
end),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if setting.description then
|
||||||
|
titleLayout.content:add(interval)
|
||||||
|
titleLayout.content:add {
|
||||||
|
template = I.MWUI.templates.textNormal,
|
||||||
|
props = {
|
||||||
|
text = l10n(setting.description),
|
||||||
|
textSize = 16,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
name = setting.key,
|
||||||
|
type = ui.TYPE.Flex,
|
||||||
|
props = {
|
||||||
|
horizontal = true,
|
||||||
|
arrange = ui.ALIGNMENT.Center,
|
||||||
|
},
|
||||||
|
external = {
|
||||||
|
stretch = 1,
|
||||||
|
},
|
||||||
|
content = ui.content {
|
||||||
|
titleLayout,
|
||||||
|
growingIntreval,
|
||||||
|
renderFunction(value, set, setting.argument),
|
||||||
|
},
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local groupLayoutName = function(key, global)
|
local groupLayoutName = function(key, global)
|
||||||
|
@ -107,52 +134,101 @@ end
|
||||||
|
|
||||||
local function renderGroup(group, global)
|
local function renderGroup(group, global)
|
||||||
local l10n = core.l10n(group.l10n)
|
local l10n = core.l10n(group.l10n)
|
||||||
local layout = {
|
|
||||||
|
local valueSection = common.getSection(global, group.key)
|
||||||
|
local settingLayouts = {}
|
||||||
|
local sortedSettings = {}
|
||||||
|
for _, setting in pairs(group.settings) do
|
||||||
|
sortedSettings[setting.order] = setting
|
||||||
|
end
|
||||||
|
for _, setting in ipairs(sortedSettings) do
|
||||||
|
table.insert(settingLayouts, renderSetting(group, setting, valueSection:get(setting.key), global))
|
||||||
|
end
|
||||||
|
local settingsContent = ui.content(interlaceSeparator(settingLayouts, spacedLines(1)))
|
||||||
|
|
||||||
|
local resetButtonLayout = {
|
||||||
|
template = I.MWUI.templates.box,
|
||||||
|
content = ui.content {
|
||||||
|
{
|
||||||
|
template = I.MWUI.templates.padding,
|
||||||
|
content = ui.content {
|
||||||
|
{
|
||||||
|
template = I.MWUI.templates.textNormal,
|
||||||
|
props = {
|
||||||
|
text = 'Reset',
|
||||||
|
},
|
||||||
|
events = {
|
||||||
|
mouseClick = async:callback(function()
|
||||||
|
for _, setting in pairs(group.settings) do
|
||||||
|
setSettingValue(global, group.key, setting.key, setting.default)
|
||||||
|
end
|
||||||
|
end),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local titleLayout = {
|
||||||
|
type = ui.TYPE.Flex,
|
||||||
|
external = {
|
||||||
|
stretch = 1,
|
||||||
|
},
|
||||||
|
content = ui.content {
|
||||||
|
{
|
||||||
|
template = I.MWUI.templates.textHeader,
|
||||||
|
props = {
|
||||||
|
text = l10n(group.name),
|
||||||
|
textSize = 20,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if group.description then
|
||||||
|
titleLayout.content:add(interval)
|
||||||
|
titleLayout.content:add {
|
||||||
|
template = I.MWUI.templates.textHeader,
|
||||||
|
props = {
|
||||||
|
text = l10n(group.description),
|
||||||
|
textSize = 18,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
name = groupLayoutName(group.key, global),
|
name = groupLayoutName(group.key, global),
|
||||||
type = ui.TYPE.Flex,
|
type = ui.TYPE.Flex,
|
||||||
|
external = {
|
||||||
|
stretch = 1,
|
||||||
|
},
|
||||||
content = ui.content {
|
content = ui.content {
|
||||||
{
|
{
|
||||||
type = ui.TYPE.Flex,
|
type = ui.TYPE.Flex,
|
||||||
props = {
|
props = {
|
||||||
horizontal = true,
|
horizontal = true,
|
||||||
align = ui.ALIGNMENT.Start,
|
arrange = ui.ALIGNMENT.Center,
|
||||||
arrange = ui.ALIGNMENT.End,
|
},
|
||||||
|
external = {
|
||||||
|
stretch = 1,
|
||||||
},
|
},
|
||||||
content = ui.content {
|
content = ui.content {
|
||||||
{
|
titleLayout,
|
||||||
name = 'name',
|
growingIntreval,
|
||||||
type = ui.TYPE.Text,
|
resetButtonLayout,
|
||||||
template = groupHeader,
|
|
||||||
props = {
|
|
||||||
text = l10n(group.name),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
smallPadding,
|
|
||||||
{
|
|
||||||
name = 'description',
|
|
||||||
type = ui.TYPE.Text,
|
|
||||||
template = normal,
|
|
||||||
props = {
|
|
||||||
text = l10n(group.description),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
smallPadding,
|
spacedLines(2),
|
||||||
{
|
{
|
||||||
name = 'settings',
|
name = 'settings',
|
||||||
type = ui.TYPE.Flex,
|
type = ui.TYPE.Flex,
|
||||||
content = ui.content{},
|
content = settingsContent,
|
||||||
|
external = {
|
||||||
|
stretch = 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
bigPadding,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
local settingsContent = layout.content.settings.content
|
|
||||||
local valueSection = common.getSection(global, group.key)
|
|
||||||
for _, setting in pairs(group.settings) do
|
|
||||||
settingsContent:add(renderSetting(group, setting, valueSection:get(setting.key), global))
|
|
||||||
end
|
|
||||||
return layout
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function pageGroupComparator(a, b)
|
local function pageGroupComparator(a, b)
|
||||||
|
@ -165,16 +241,22 @@ local function generateSearchHints(page)
|
||||||
local hints = {}
|
local hints = {}
|
||||||
local l10n = core.l10n(page.l10n)
|
local l10n = core.l10n(page.l10n)
|
||||||
table.insert(hints, l10n(page.name))
|
table.insert(hints, l10n(page.name))
|
||||||
table.insert(hints, l10n(page.description))
|
if page.description then
|
||||||
|
table.insert(hints, l10n(page.description))
|
||||||
|
end
|
||||||
local pageGroups = groups[page.key]
|
local pageGroups = groups[page.key]
|
||||||
for _, pageGroup in pairs(pageGroups) do
|
for _, pageGroup in pairs(pageGroups) do
|
||||||
local group = common.getSection(pageGroup.global, common.groupSectionKey):get(pageGroup.key)
|
local group = common.getSection(pageGroup.global, common.groupSectionKey):get(pageGroup.key)
|
||||||
local l10n = core.l10n(group.l10n)
|
local l10n = core.l10n(group.l10n)
|
||||||
table.insert(hints, l10n(group.name))
|
table.insert(hints, l10n(group.name))
|
||||||
table.insert(hints, l10n(group.description))
|
if group.description then
|
||||||
|
table.insert(hints, l10n(group.description))
|
||||||
|
end
|
||||||
for _, setting in pairs(group.settings) do
|
for _, setting in pairs(group.settings) do
|
||||||
table.insert(hints, l10n(setting.name))
|
table.insert(hints, l10n(setting.name))
|
||||||
table.insert(hints, l10n(setting.description))
|
if setting.description then
|
||||||
|
table.insert(hints, l10n(setting.description))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return table.concat(hints, ' ')
|
return table.concat(hints, ' ')
|
||||||
|
@ -182,55 +264,60 @@ end
|
||||||
|
|
||||||
local function renderPage(page)
|
local function renderPage(page)
|
||||||
local l10n = core.l10n(page.l10n)
|
local l10n = core.l10n(page.l10n)
|
||||||
|
local sortedGroups = {}
|
||||||
|
for i, v in ipairs(groups[page.key]) do sortedGroups[i] = v end
|
||||||
|
table.sort(sortedGroups, pageGroupComparator)
|
||||||
|
local groupLayouts = {}
|
||||||
|
for _, pageGroup in ipairs(sortedGroups) do
|
||||||
|
local group = common.getSection(pageGroup.global, common.groupSectionKey):get(pageGroup.key)
|
||||||
|
table.insert(groupLayouts, renderGroup(group, pageGroup.global))
|
||||||
|
end
|
||||||
|
local groupsLayout = {
|
||||||
|
name = 'groups',
|
||||||
|
type = ui.TYPE.Flex,
|
||||||
|
external = {
|
||||||
|
stretch = 1,
|
||||||
|
},
|
||||||
|
content = ui.content(interlaceSeparator(groupLayouts, bigSpacer)),
|
||||||
|
}
|
||||||
|
local titleLayout = {
|
||||||
|
type = ui.TYPE.Flex,
|
||||||
|
external = {
|
||||||
|
stretch = 1,
|
||||||
|
},
|
||||||
|
content = ui.content {
|
||||||
|
{
|
||||||
|
template = I.MWUI.templates.textHeader,
|
||||||
|
props = {
|
||||||
|
text = l10n(page.name),
|
||||||
|
textSize = 22,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spacedLines(3),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if page.description then
|
||||||
|
titleLayout.content:add {
|
||||||
|
template = I.MWUI.templates.textNormal,
|
||||||
|
props = {
|
||||||
|
text = l10n(page.description),
|
||||||
|
textSize = 20,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
local layout = {
|
local layout = {
|
||||||
name = page.key,
|
name = page.key,
|
||||||
type = ui.TYPE.Flex,
|
type = ui.TYPE.Flex,
|
||||||
|
props = {
|
||||||
|
position = util.vector2(10, 10),
|
||||||
|
},
|
||||||
content = ui.content {
|
content = ui.content {
|
||||||
smallPadding,
|
titleLayout,
|
||||||
{
|
bigSpacer,
|
||||||
type = ui.TYPE.Flex,
|
groupsLayout,
|
||||||
props = {
|
bigSpacer,
|
||||||
horizontal = true,
|
|
||||||
align = ui.ALIGNMENT.Start,
|
|
||||||
arrange = ui.ALIGNMENT.End,
|
|
||||||
},
|
|
||||||
content = ui.content {
|
|
||||||
{
|
|
||||||
name = 'name',
|
|
||||||
type = ui.TYPE.Text,
|
|
||||||
template = pageHeader,
|
|
||||||
props = {
|
|
||||||
text = l10n(page.name),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
smallPadding,
|
|
||||||
{
|
|
||||||
name = 'description',
|
|
||||||
type = ui.TYPE.Text,
|
|
||||||
template = normal,
|
|
||||||
props = {
|
|
||||||
text = l10n(page.description),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
bigPadding,
|
|
||||||
{
|
|
||||||
name = 'groups',
|
|
||||||
type = ui.TYPE.Flex,
|
|
||||||
content = ui.content {},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
local groupsContent = layout.content.groups.content
|
|
||||||
local pageGroups = groups[page.key]
|
|
||||||
local sortedGroups = {}
|
|
||||||
for i, v in ipairs(pageGroups) do sortedGroups[i] = v end
|
|
||||||
table.sort(sortedGroups, pageGroupComparator)
|
|
||||||
for _, pageGroup in ipairs(sortedGroups) do
|
|
||||||
local group = common.getSection(pageGroup.global, common.groupSectionKey):get(pageGroup.key)
|
|
||||||
groupsContent:add(renderGroup(group, pageGroup.global))
|
|
||||||
end
|
|
||||||
return {
|
return {
|
||||||
name = l10n(page.name),
|
name = l10n(page.name),
|
||||||
element = ui.create(layout),
|
element = ui.create(layout),
|
||||||
|
@ -241,13 +328,15 @@ end
|
||||||
local function onSettingChanged(global)
|
local function onSettingChanged(global)
|
||||||
return async:callback(function(groupKey, settingKey)
|
return async:callback(function(groupKey, settingKey)
|
||||||
local group = common.getSection(global, common.groupSectionKey):get(groupKey)
|
local group = common.getSection(global, common.groupSectionKey):get(groupKey)
|
||||||
if not pageOptions[group.page] then return end
|
if not group or not pageOptions[group.page] then return end
|
||||||
|
|
||||||
|
local value = common.getSection(global, group.key):get(settingKey)
|
||||||
|
|
||||||
local element = pageOptions[group.page].element
|
local element = pageOptions[group.page].element
|
||||||
local groupLayout = element.layout.content.groups.content[groupLayoutName(group.key, global)]
|
local groupsLayout = element.layout.content.groups
|
||||||
local settingsLayout = groupLayout.content.settings
|
local groupLayout = groupsLayout.content[groupLayoutName(group.key, global)]
|
||||||
local value = common.getSection(global, group.key):get(settingKey)
|
local settingsContent = groupLayout.content.settings.content
|
||||||
settingsLayout.content[settingKey] = renderSetting(group, group.settings[settingKey], value, global)
|
settingsContent[settingKey] = renderSetting(group, group.settings[settingKey], value, global)
|
||||||
element:update()
|
element:update()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -293,8 +382,8 @@ local function registerPage(options)
|
||||||
if type(options.name) ~= 'string' then
|
if type(options.name) ~= 'string' then
|
||||||
error('Page must have a name')
|
error('Page must have a name')
|
||||||
end
|
end
|
||||||
if type(options.description) ~= 'string' then
|
if options.description ~= nil and type(options.description) ~= 'string' then
|
||||||
error('Page must have a description')
|
error('Page description key must be a string')
|
||||||
end
|
end
|
||||||
local page = {
|
local page = {
|
||||||
key = options.key,
|
key = options.key,
|
||||||
|
|
39
files/builtin_scripts/scripts/omw/settings/renderers.lua
Normal file
39
files/builtin_scripts/scripts/omw/settings/renderers.lua
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
local ui = require('openmw.ui')
|
||||||
|
local async = require('openmw.async')
|
||||||
|
local I = require('openmw.interfaces')
|
||||||
|
|
||||||
|
return function(registerRenderer)
|
||||||
|
registerRenderer('textLine', function(value, set)
|
||||||
|
return {
|
||||||
|
template = I.MWUI.templates.textEditLine,
|
||||||
|
props = {
|
||||||
|
text = tostring(value),
|
||||||
|
},
|
||||||
|
events = {
|
||||||
|
textChanged = async:callback(function(s) set(s) end),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
registerRenderer('yesNo', function(value, set)
|
||||||
|
return {
|
||||||
|
template = I.MWUI.templates.box,
|
||||||
|
content = ui.content {
|
||||||
|
{
|
||||||
|
template = I.MWUI.templates.padding,
|
||||||
|
content = ui.content {
|
||||||
|
{
|
||||||
|
template = I.MWUI.templates.textNormal,
|
||||||
|
props = {
|
||||||
|
text = value and 'Yes' or 'No',
|
||||||
|
},
|
||||||
|
events = {
|
||||||
|
mouseClick = async:callback(function() set(not value) end),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
end
|
|
@ -12,7 +12,7 @@
|
||||||
</Resource>
|
</Resource>
|
||||||
|
|
||||||
<Resource type="ResourceSkin" name="LuaTextEditClient" size="16 16">
|
<Resource type="ResourceSkin" name="LuaTextEditClient" size="16 16">
|
||||||
<BasisSkin type="EditText" offset="0 0 16 16" align="Stretch" name="Client" />
|
<BasisSkin type="EditText" offset="0 0 16 16" align="Stretch" />
|
||||||
</Resource>
|
</Resource>
|
||||||
|
|
||||||
<Resource type="ResourceSkin" name="LuaTextEdit" size="16 16">
|
<Resource type="ResourceSkin" name="LuaTextEdit" size="16 16">
|
||||||
|
|
Loading…
Reference in a new issue