Make coordinate calculation more robust, implement Flex widget type

This commit is contained in:
uramer 2022-04-04 23:10:03 +02:00
parent fbc84465c5
commit 788745e004
10 changed files with 181 additions and 25 deletions

View file

@ -256,7 +256,7 @@ add_component_dir (fallback
add_component_dir (lua_ui add_component_dir (lua_ui
registerscriptsettings scriptsettings registerscriptsettings scriptsettings
properties widget element util layers content alignment resources properties widget element util layers content alignment resources
adapter text textedit window image container adapter text textedit window image container flex
) )

View file

@ -9,9 +9,9 @@ namespace LuaUi
align |= MyGUI::Align::Left; align |= MyGUI::Align::Left;
if (horizontal == Alignment::End) if (horizontal == Alignment::End)
align |= MyGUI::Align::Right; align |= MyGUI::Align::Right;
if (horizontal == Alignment::Start) if (vertical == Alignment::Start)
align |= MyGUI::Align::Top; align |= MyGUI::Align::Top;
if (horizontal == Alignment::End) if (vertical == Alignment::End)
align |= MyGUI::Align::Bottom; align |= MyGUI::Align::Bottom;
return align; return align;
} }

View file

@ -29,7 +29,7 @@ namespace LuaUi
size.width = std::max(size.width, coord.left + coord.width); size.width = std::max(size.width, coord.left + coord.width);
size.height = std::max(size.height, coord.top + coord.height); size.height = std::max(size.height, coord.top + coord.height);
} }
setForcedSize(size); forceSize(size);
updateCoord(); updateCoord();
} }
} }

View file

@ -136,8 +136,8 @@ namespace LuaUi
setTemplate(ext, layout.get<sol::object>(LayoutKeys::templateLayout)); setTemplate(ext, layout.get<sol::object>(LayoutKeys::templateLayout));
ext->setProperties(layout.get<sol::object>(LayoutKeys::props)); ext->setProperties(layout.get<sol::object>(LayoutKeys::props));
setEventCallbacks(ext, layout.get<sol::object>(LayoutKeys::events)); setEventCallbacks(ext, layout.get<sol::object>(LayoutKeys::events));
ext->setChildren(updateContent(ext->children(), layout.get<sol::object>(LayoutKeys::content))); ext->setChildren(updateContent(ext->children(), layout.get<sol::object>(LayoutKeys::content)));
ext->updateCoord();
} }
std::string setLayer(WidgetExtension* ext, const sol::table& layout) std::string setLayer(WidgetExtension* ext, const sol::table& layout)

106
components/lua_ui/flex.cpp Normal file
View file

@ -0,0 +1,106 @@
#include "flex.hpp"
namespace LuaUi
{
void LuaFlex::updateProperties()
{
mHorizontal = propertyValue("horizontal", false);
mAutoSized = propertyValue("autoSize", true);
mAlign = propertyValue("align", Alignment::Start);
mArrange = propertyValue("arrange", Alignment::Start);
WidgetExtension::updateProperties();
}
namespace
{
MyGUI::IntPoint alignSize(const MyGUI::IntSize& container, const MyGUI::IntSize& content, Alignment alignment)
{
MyGUI::IntPoint alignedPosition;
{
MyGUI::IntSize alignSize = container;
switch (alignment)
{
case Alignment::Start:
alignedPosition = MyGUI::IntPoint(0, 0);
break;
case Alignment::Center:
alignSize -= content;
alignedPosition = { alignSize.width / 2, alignSize.height / 2 };
break;
case Alignment::End:
alignSize -= content;
alignedPosition = { alignSize.width, alignSize.height };
break;
}
}
return alignedPosition;
}
}
void LuaFlex::updateChildren()
{
float totalGrow = 0;
MyGUI::IntSize childrenSize;
for (auto* w: children())
{
w->clearForced();
childrenSize += w->calculateSize();
totalGrow += w->externalValue("grow", 0.0f);
}
mChildrenSize = childrenSize;
MyGUI::IntSize flexSize = calculateSize();
MyGUI::IntSize growSize;
MyGUI::FloatSize growFactor;
if (totalGrow > 0)
{
growSize = flexSize - childrenSize;
growFactor = { growSize.width / totalGrow, growSize.height / totalGrow };
}
if (mHorizontal)
flexSize.width -= growSize.width;
else
flexSize.height-= growSize.height;
MyGUI::IntPoint alignedPosition = alignSize(flexSize, childrenSize, mAlign);
MyGUI::IntPoint arrangedPosition = alignSize(flexSize, childrenSize, mArrange);
MyGUI::IntPoint childPosition;
if (mHorizontal)
childPosition = { alignedPosition.left, arrangedPosition.top };
else
childPosition = { arrangedPosition.left, alignedPosition.top };
for (auto* w : children())
{
w->forcePosition(childPosition);
float grow = w->externalValue("grow", 0);
MyGUI::IntSize growth(growFactor.width * grow, growFactor.height * grow);
if (mHorizontal)
{
int width = w->widget()->getWidth();
width += growth.width;
w->forceSize({width, w->widget()->getHeight()});
childPosition.left += width;
}
else
{
int height = w->widget()->getHeight();
height += growth.height;
w->forceSize({ w->widget()->getWidth(), height });
childPosition.top += height;
}
}
WidgetExtension::updateProperties();
}
MyGUI::IntSize LuaFlex::calculateSize()
{
MyGUI::IntSize size = WidgetExtension::calculateSize();
if (mAutoSized) {
if (mHorizontal)
size.width = mChildrenSize.width;
else
size.height = mChildrenSize.height;
}
return size;
}
}

View file

@ -0,0 +1,27 @@
#ifndef OPENMW_LUAUI_FLEX
#define OPENMW_LUAUI_FLEX
#include "widget.hpp"
#include "alignment.hpp"
namespace LuaUi
{
class LuaFlex : public MyGUI::Widget, public WidgetExtension
{
MYGUI_RTTI_DERIVED(LuaFlex)
protected:
MyGUI::IntSize calculateSize() override;
void updateProperties() override;
void updateChildren() override;
private:
bool mHorizontal;
bool mAutoSized;
MyGUI::IntSize mChildrenSize;
Alignment mAlign;
Alignment mArrange;
};
}
#endif // OPENMW_LUAUI_FLEX

View file

@ -9,6 +9,7 @@
#include "window.hpp" #include "window.hpp"
#include "image.hpp" #include "image.hpp"
#include "container.hpp" #include "container.hpp"
#include "flex.hpp"
#include "element.hpp" #include "element.hpp"
#include "registerscriptsettings.hpp" #include "registerscriptsettings.hpp"
@ -24,8 +25,9 @@ namespace LuaUi
MyGUI::FactoryManager::getInstance().registerFactory<LuaTextEdit>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<LuaTextEdit>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<LuaWindow>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<LuaWindow>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<LuaImage>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<LuaImage>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<LuaContainer>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<LuaTileRect>("BasisSkin"); MyGUI::FactoryManager::getInstance().registerFactory<LuaTileRect>("BasisSkin");
MyGUI::FactoryManager::getInstance().registerFactory<LuaContainer>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<LuaFlex>("Widget");
} }
const std::unordered_map<std::string, std::string>& widgetTypeToName() const std::unordered_map<std::string, std::string>& widgetTypeToName()
@ -36,6 +38,7 @@ namespace LuaUi
{ "LuaTextEdit", "TextEdit" }, { "LuaTextEdit", "TextEdit" },
{ "LuaWindow", "Window" }, { "LuaWindow", "Window" },
{ "LuaImage", "Image" }, { "LuaImage", "Image" },
{ "LuaFlex", "Flex" },
}; };
return types; return types;
} }

View file

@ -10,7 +10,9 @@
namespace LuaUi namespace LuaUi
{ {
WidgetExtension::WidgetExtension() WidgetExtension::WidgetExtension()
: mPropagateEvents(true) : mForcePosition(false)
, mForceSize(false)
, mPropagateEvents(true)
, mLua(nullptr) , mLua(nullptr)
, mWidget(nullptr) , mWidget(nullptr)
, mSlot(this) , mSlot(this)
@ -85,7 +87,6 @@ namespace LuaUi
ext->mParent = this; ext->mParent = this;
ext->mTemplateChild = false; ext->mTemplateChild = false;
ext->widget()->attachToWidget(mSlot->widget()); ext->widget()->attachToWidget(mSlot->widget());
ext->updateCoord();
} }
void WidgetExtension::attachTemplate(WidgetExtension* ext) void WidgetExtension::attachTemplate(WidgetExtension* ext)
@ -93,7 +94,6 @@ namespace LuaUi
ext->mParent = this; ext->mParent = this;
ext->mTemplateChild = true; ext->mTemplateChild = true;
ext->widget()->attachToWidget(widget()); ext->widget()->attachToWidget(widget());
ext->updateCoord();
} }
WidgetExtension* WidgetExtension::findDeep(std::string_view flagName) WidgetExtension* WidgetExtension::findDeep(std::string_view flagName)
@ -219,16 +219,30 @@ namespace LuaUi
return mForcedCoord; return mForcedCoord;
} }
void WidgetExtension::setForcedCoord(const MyGUI::IntCoord& offset) void WidgetExtension::forceCoord(const MyGUI::IntCoord& offset)
{ {
mForcePosition = true;
mForceSize = true;
mForcedCoord = offset; mForcedCoord = offset;
} }
void WidgetExtension::setForcedSize(const MyGUI::IntSize& size) void WidgetExtension::forcePosition(const MyGUI::IntPoint& pos)
{ {
mForcePosition = true;
mForcedCoord = pos;
}
void WidgetExtension::forceSize(const MyGUI::IntSize& size)
{
mForceSize = true;
mForcedCoord = size; mForcedCoord = size;
} }
void WidgetExtension::clearForced() {
mForcePosition = false;
mForceSize = false;
}
void WidgetExtension::updateCoord() void WidgetExtension::updateCoord()
{ {
MyGUI::IntCoord oldCoord = mWidget->getCoord(); MyGUI::IntCoord oldCoord = mWidget->getCoord();
@ -246,7 +260,6 @@ namespace LuaUi
{ {
mProperties = props; mProperties = props;
updateProperties(); updateProperties();
updateCoord();
} }
void WidgetExtension::updateProperties() void WidgetExtension::updateProperties()
@ -281,9 +294,12 @@ namespace LuaUi
MyGUI::IntSize WidgetExtension::calculateSize() MyGUI::IntSize WidgetExtension::calculateSize()
{ {
if (mForceSize)
return mForcedCoord.size();
MyGUI::IntSize pSize = parentSize(); MyGUI::IntSize pSize = parentSize();
MyGUI::IntSize newSize; MyGUI::IntSize newSize;
newSize = mAbsoluteCoord.size() + mForcedCoord.size(); newSize = mAbsoluteCoord.size();
newSize.width += mRelativeCoord.width * pSize.width; newSize.width += mRelativeCoord.width * pSize.width;
newSize.height += mRelativeCoord.height * pSize.height; newSize.height += mRelativeCoord.height * pSize.height;
return newSize; return newSize;
@ -291,9 +307,11 @@ namespace LuaUi
MyGUI::IntPoint WidgetExtension::calculatePosition(const MyGUI::IntSize& size) MyGUI::IntPoint WidgetExtension::calculatePosition(const MyGUI::IntSize& size)
{ {
if (mForcePosition)
return mForcedCoord.point();
MyGUI::IntSize pSize = parentSize(); MyGUI::IntSize pSize = parentSize();
MyGUI::IntPoint newPosition; MyGUI::IntPoint newPosition;
newPosition = mAbsoluteCoord.point() + mForcedCoord.point(); newPosition = mAbsoluteCoord.point();
newPosition.left += mRelativeCoord.left * pSize.width - mAnchor.width * size.width; newPosition.left += mRelativeCoord.left * pSize.width - mAnchor.width * size.width;
newPosition.top += mRelativeCoord.top * pSize.height - mAnchor.height * size.height; newPosition.top += mRelativeCoord.top * pSize.height - mAnchor.height * size.height;
return newPosition; return newPosition;

View file

@ -47,8 +47,11 @@ namespace LuaUi
void setExternal(sol::object external) { mExternal = external; } void setExternal(sol::object external) { mExternal = external; }
MyGUI::IntCoord forcedCoord(); MyGUI::IntCoord forcedCoord();
void setForcedCoord(const MyGUI::IntCoord& offset); void forceCoord(const MyGUI::IntCoord& offset);
void setForcedSize(const MyGUI::IntSize& size); void forceSize(const MyGUI::IntSize& size);
void forcePosition(const MyGUI::IntPoint& pos);
void clearForced();
void updateCoord(); void updateCoord();
const sol::table& getLayout() { return mLayout; } const sol::table& getLayout() { return mLayout; }
@ -65,6 +68,9 @@ namespace LuaUi
mOnCoordChange = callback; mOnCoordChange = callback;
} }
virtual MyGUI::IntSize calculateSize();
virtual MyGUI::IntPoint calculatePosition(const MyGUI::IntSize& size);
protected: protected:
virtual void initialize(); virtual void initialize();
sol::table makeTable() const; sol::table makeTable() const;
@ -72,8 +78,6 @@ namespace LuaUi
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();
virtual MyGUI::IntSize calculateSize();
virtual MyGUI::IntPoint calculatePosition(const MyGUI::IntSize& size);
MyGUI::IntCoord calculateCoord(); MyGUI::IntCoord calculateCoord();
virtual MyGUI::IntSize childScalingSize(); virtual MyGUI::IntSize childScalingSize();
@ -113,6 +117,8 @@ namespace LuaUi
} }
} }
bool mForcePosition;
bool mForceSize;
// offsets the position and size, used only in C++ widget code // offsets the position and size, used only in C++ widget code
MyGUI::IntCoord mForcedCoord; MyGUI::IntCoord mForcedCoord;
// position and size in pixels // position and size in pixels

View file

@ -39,8 +39,7 @@ namespace LuaUi
if (mCaption) if (mCaption)
mCaption->setCaption(propertyValue("caption", std::string())); mCaption->setCaption(propertyValue("caption", std::string()));
mMoveResize = MyGUI::IntCoord(); mMoveResize = MyGUI::IntCoord();
setForcedCoord(mMoveResize); clearForced();
WidgetExtension::updateProperties(); WidgetExtension::updateProperties();
} }
@ -70,11 +69,8 @@ namespace LuaUi
change.width *= (left - mPreviousMouse.left); change.width *= (left - mPreviousMouse.left);
change.height *= (top - mPreviousMouse.top); change.height *= (top - mPreviousMouse.top);
mMoveResize = mMoveResize + change.size(); mMoveResize = mMoveResize + change;
setForcedCoord(mMoveResize); forceCoord(mMoveResize);
// position can change based on size changes
mMoveResize = mMoveResize + change.point() + getPosition() - calculateCoord().point();
setForcedCoord(mMoveResize);
updateCoord(); updateCoord();
mPreviousMouse.left = left; mPreviousMouse.left = left;