You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/components/fx/widgets.hpp

293 lines
9.1 KiB
C++

#ifndef OPENMW_COMPONENTS_FX_WIDGETS_H
#define OPENMW_COMPONENTS_FX_WIDGETS_H
#include <MyGUI_Button.h>
#include <MyGUI_Delegate.h>
#include <MyGUI_InputManager.h>
#include <MyGUI_MouseButton.h>
#include <MyGUI_RTTI.h>
#include <MyGUI_TextBox.h>
#include <MyGUI_Widget.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include <osg/Vec2f>
#include <osg/Vec3f>
#include <osg/Vec4f>
#include <components/misc/strings/format.hpp>
#include "types.hpp"
namespace Gui
{
class AutoSizedTextBox;
class AutoSizedButton;
}
namespace fx
{
namespace Widgets
{
enum Index
{
None = -1,
Zero = 0,
One = 1,
Two = 2,
Three = 3
};
class EditBase
{
public:
virtual ~EditBase() = default;
void setData(const std::shared_ptr<fx::Types::UniformBase>& uniform, Index index = None)
{
mUniform = uniform;
mIndex = index;
}
virtual void setValueFromUniform() = 0;
virtual void toDefault() = 0;
protected:
std::shared_ptr<fx::Types::UniformBase> mUniform;
Index mIndex;
};
class EditBool : public EditBase, public MyGUI::Widget
{
MYGUI_RTTI_DERIVED(EditBool)
public:
void setValue(bool value);
void setValueFromUniform() override;
void toDefault() override;
private:
void initialiseOverride() override;
void notifyMouseButtonClick(MyGUI::Widget* sender);
MyGUI::Button* mCheckbutton{ nullptr };
MyGUI::Widget* mFill{ nullptr };
};
template <class T, class UType>
class EditNumber : public EditBase, public MyGUI::Widget
{
MYGUI_RTTI_DERIVED(EditNumber)
public:
void setValue(T value)
{
mValue = value;
if constexpr (std::is_floating_point_v<T>)
mValueLabel->setCaption(Misc::StringUtils::format("%.3f", mValue));
else
mValueLabel->setCaption(std::to_string(mValue));
float range = 0.f;
float min = 0.f;
if constexpr (std::is_fundamental_v<UType>)
{
mUniform->template setValue<UType>(mValue);
range = mUniform->template getMax<UType>() - mUniform->template getMin<UType>();
min = mUniform->template getMin<UType>();
}
else
{
UType uvalue = mUniform->template getValue<UType>();
uvalue[mIndex] = mValue;
mUniform->template setValue<UType>(uvalue);
range = mUniform->template getMax<UType>()[mIndex] - mUniform->template getMin<UType>()[mIndex];
min = mUniform->template getMin<UType>()[mIndex];
}
float fill = (range == 0.f) ? 1.f : (mValue - min) / range;
mFill->setRealSize(fill, 1.0);
}
void setValueFromUniform() override
{
T value;
if constexpr (std::is_fundamental_v<UType>)
value = mUniform->template getValue<UType>();
else
value = mUniform->template getValue<UType>()[mIndex];
setValue(value);
}
void toDefault() override
{
if constexpr (std::is_fundamental_v<UType>)
setValue(mUniform->template getDefault<UType>());
else
setValue(mUniform->template getDefault<UType>()[mIndex]);
}
private:
void initialiseOverride() override
{
Base::initialiseOverride();
assignWidget(mDragger, "Dragger");
assignWidget(mValueLabel, "Value");
assignWidget(mButtonIncrease, "ButtonIncrease");
assignWidget(mButtonDecrease, "ButtonDecrease");
assignWidget(mFill, "Fill");
mButtonIncrease->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNumber::notifyButtonClicked);
mButtonDecrease->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNumber::notifyButtonClicked);
mDragger->eventMouseButtonPressed += MyGUI::newDelegate(this, &EditNumber::notifyMouseButtonPressed);
mDragger->eventMouseDrag += MyGUI::newDelegate(this, &EditNumber::notifyMouseButtonDragged);
mDragger->eventMouseWheel += MyGUI::newDelegate(this, &EditNumber::notifyMouseWheel);
}
void notifyMouseWheel(MyGUI::Widget* sender, int rel)
{
if (rel > 0)
increment(mUniform->mStep);
else
increment(-mUniform->mStep);
}
void notifyMouseButtonDragged(MyGUI::Widget* sender, int left, int top, MyGUI::MouseButton id)
{
if (id != MyGUI::MouseButton::Left)
return;
int delta = left - mLastPointerX;
// allow finer tuning when shift is pressed
constexpr double scaling = 20.0;
T step
= MyGUI::InputManager::getInstance().isShiftPressed() ? mUniform->mStep / scaling : mUniform->mStep;
if (step == 0)
{
if constexpr (std::is_integral_v<T>)
step = 1;
else
step = mUniform->mStep;
}
if (delta > 0)
increment(step);
else if (delta < 0)
increment(-step);
mLastPointerX = left;
}
void notifyMouseButtonPressed(MyGUI::Widget* sender, int left, int top, MyGUI::MouseButton id)
{
if (id != MyGUI::MouseButton::Left)
return;
mLastPointerX = left;
}
void increment(T step)
{
if constexpr (std::is_fundamental_v<UType>)
setValue(std::clamp<T>(mUniform->template getValue<UType>() + step,
mUniform->template getMin<UType>(), mUniform->template getMax<T>()));
else
setValue(std::clamp<T>(mUniform->template getValue<UType>()[mIndex] + step,
mUniform->template getMin<UType>()[mIndex], mUniform->template getMax<UType>()[mIndex]));
}
void notifyButtonClicked(MyGUI::Widget* sender)
{
if (sender == mButtonDecrease)
increment(-mUniform->mStep);
else if (sender == mButtonIncrease)
increment(mUniform->mStep);
}
MyGUI::Button* mButtonDecrease{ nullptr };
MyGUI::Button* mButtonIncrease{ nullptr };
MyGUI::Widget* mDragger{ nullptr };
MyGUI::Widget* mFill{ nullptr };
MyGUI::TextBox* mValueLabel{ nullptr };
T mValue{};
int mLastPointerX{ 0 };
};
class EditNumberFloat4 : public EditNumber<float, osg::Vec4f>
{
MYGUI_RTTI_DERIVED(EditNumberFloat4)
};
class EditNumberFloat3 : public EditNumber<float, osg::Vec3f>
{
MYGUI_RTTI_DERIVED(EditNumberFloat3)
};
class EditNumberFloat2 : public EditNumber<float, osg::Vec2f>
{
MYGUI_RTTI_DERIVED(EditNumberFloat2)
};
class EditNumberFloat : public EditNumber<float, float>
{
MYGUI_RTTI_DERIVED(EditNumberFloat)
};
class EditNumberInt : public EditNumber<int, int>
{
MYGUI_RTTI_DERIVED(EditNumberInt)
};
class EditChoice : public EditBase, public MyGUI::Widget
{
MYGUI_RTTI_DERIVED(EditChoice)
public:
template <class T>
void setValue(const T& value);
void setValueFromUniform() override;
void toDefault() override;
private:
void initialiseOverride() override;
void notifyComboBoxChanged(MyGUI::ComboBox* sender, size_t pos);
MyGUI::ComboBox* mChoices{ nullptr };
};
class UniformBase final : public MyGUI::Widget
{
MYGUI_RTTI_DERIVED(UniformBase)
public:
void init(const std::shared_ptr<fx::Types::UniformBase>& uniform);
void toDefault();
void addItem(EditBase* item);
Gui::AutoSizedTextBox* getLabel() { return mLabel; }
private:
void notifyResetClicked(MyGUI::Widget* sender);
void initialiseOverride() override;
Gui::AutoSizedButton* mReset{ nullptr };
Gui::AutoSizedTextBox* mLabel{ nullptr };
MyGUI::Widget* mClient{ nullptr };
std::vector<EditBase*> mBases;
};
}
}
#endif