1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-12-18 07:43:07 +00:00

Merge branch 'lua_ui_flex' into 'master'

Lua UI Flex widget

Closes #6646

See merge request OpenMW/openmw!1743
This commit is contained in:
psi29a 2022-04-06 23:29:23 +00:00
commit f5bc78cac3
12 changed files with 235 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)

View file

@ -0,0 +1,88 @@
#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
{
int alignSize(int container, int content, Alignment alignment)
{
int alignedPosition = 0;
{
switch (alignment)
{
case Alignment::Start:
alignedPosition = 0;
break;
case Alignment::Center:
alignedPosition = (container - content) / 2;
break;
case Alignment::End:
alignedPosition = container - content;
break;
}
}
return alignedPosition;
}
float getGrow(WidgetExtension* w)
{
return std::max(0.0f, w->externalValue("grow", 0.0f));
}
}
void LuaFlex::updateChildren()
{
float totalGrow = 0;
MyGUI::IntSize childrenSize;
for (auto* w: children())
{
w->clearForced();
MyGUI::IntSize size = w->calculateSize();
primary(childrenSize) += primary(size);
secondary(childrenSize) = std::max(secondary(childrenSize), secondary(size));
totalGrow += getGrow(w);
}
mChildrenSize = childrenSize;
MyGUI::IntSize flexSize = calculateSize();
int growSize = 0;
float growFactor = 0;
if (totalGrow > 0)
{
growSize = primary(flexSize) - primary(childrenSize);
growFactor = growSize / totalGrow;
}
MyGUI::IntPoint childPosition;
primary(childPosition) = alignSize(primary(flexSize) - growSize, primary(childrenSize), mAlign);
secondary(childPosition) = alignSize(secondary(flexSize), secondary(childrenSize), mArrange);
for (auto* w : children())
{
w->forcePosition(childPosition);
MyGUI::IntSize size = w->widget()->getSize();
primary(size) += static_cast<int>(growFactor * getGrow(w));
w->forceSize(size);
primary(childPosition) += primary(size);
}
WidgetExtension::updateProperties();
}
MyGUI::IntSize LuaFlex::calculateSize()
{
MyGUI::IntSize size = WidgetExtension::calculateSize();
if (mAutoSized) {
primary(size) = primary(mChildrenSize);
secondary(size) = std::max(secondary(size), secondary(mChildrenSize));
}
return size;
}
}

View file

@ -0,0 +1,55 @@
#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;
MyGUI::IntSize childScalingSize() override
{
return MyGUI::IntSize();
}
private:
bool mHorizontal;
bool mAutoSized;
MyGUI::IntSize mChildrenSize;
Alignment mAlign;
Alignment mArrange;
template<typename T>
T& primary(MyGUI::types::TPoint<T>& point)
{
return mHorizontal ? point.left : point.top;
}
template<typename T>
T& secondary(MyGUI::types::TPoint<T>& point)
{
return mHorizontal ? point.top : point.left;
}
template<typename T>
T& primary(MyGUI::types::TSize<T>& size)
{
return mHorizontal ? size.width : size.height;
}
template<typename T>
T& secondary(MyGUI::types::TSize<T>& size)
{
return mHorizontal ? size.height : size.width;
}
};
}
#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;

View file

@ -81,6 +81,7 @@ Widget types
Text: Displays text. <widgets/text> Text: Displays text. <widgets/text>
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>
Example Example
------- -------

View file

@ -0,0 +1,43 @@
Flex Widget
===========
Aligns its children along either a column or a row, depending on the `horizontal` property.
Properties
----------
.. list-table::
:header-rows: 1
:widths: 20 20 60
* - name
- type (default value)
- description
* - horizontal
- bool (false)
- Flex aligns its children in a row if true, otherwise in a column.
* - autoSize
- bool (true)
- | If true, Flex will automatically resize to fit its contents.
| Children can't be relatively position/sized when true.
* - align
- ui.ALIGNMENT (Start)
- Where to align the children in the main axis.
* - arrange
- ui.ALIGNMETN (Start)
- How to arrange the children in the cross axis.
External
--------
.. list-table::
:header-rows: 1
:widths: 20 20 60
* - name
- type (default value)
- description
* - grow
- float (0)
- | Grow factor for the child. If there is unused space in the Flex,
| it will be split between widgets according to this value.
| Has no effect if `autoSize` is `true`.