Reorganize code in widgets
This commit is contained in:
parent
837d8dc507
commit
e00dec67ba
31 changed files with 652 additions and 481 deletions
|
|
@ -26,18 +26,18 @@ namespace tp {
|
|||
virtual void pickRect() = 0;
|
||||
virtual void clampRect() = 0;
|
||||
virtual void adjustChildrenRect() = 0;
|
||||
virtual RectF getAvailableChildArea() const;
|
||||
[[nodiscard]] virtual RectF getAvailableChildArea() const;
|
||||
|
||||
public:
|
||||
const Vec2F& getMinSize();
|
||||
void setMinSize(const Vec2F& size);
|
||||
|
||||
const Vec2<SizePolicy>& getSizePolicy() const;
|
||||
[[nodiscard]] const Vec2<SizePolicy>& getSizePolicy() const;
|
||||
void setSizePolicy(SizePolicy x, SizePolicy y);
|
||||
|
||||
public:
|
||||
[[nodiscard]] const RectF& getArea() const;
|
||||
RectF getAnimatedArea() const;
|
||||
[[nodiscard]] RectF getAnimatedArea() const;
|
||||
|
||||
void setArea(const RectF& area);
|
||||
[[nodiscard]] Widget* parent() const;
|
||||
|
|
@ -60,30 +60,4 @@ namespace tp {
|
|||
Vec2F mMinSize = { 50, 50 };
|
||||
Vec2F mMaxSize = { FLT_MAX / 2, FLT_MAX / 2 };
|
||||
};
|
||||
|
||||
class BasicLayout : public WidgetLayout {
|
||||
public:
|
||||
explicit BasicLayout(Widget* widget) : WidgetLayout(widget) {}
|
||||
|
||||
void pickRect() override;
|
||||
void clampRect() override;
|
||||
void adjustChildrenRect() override;
|
||||
RectF getAvailableChildArea() const override;
|
||||
|
||||
private:
|
||||
void adjustLayout(bool vertical);
|
||||
static halnf changeChildSize(Widget*, halnf diff, bool vertical);
|
||||
|
||||
private:
|
||||
LayoutPolicy mLayoutPolicy = LayoutPolicy::Vertical;
|
||||
halnf mLayoutGap = 5;
|
||||
halnf mLayoutMargin = 10;
|
||||
};
|
||||
|
||||
class LayoutManager {
|
||||
public:
|
||||
LayoutManager() = default;
|
||||
|
||||
void adjust(Widget* root);
|
||||
};
|
||||
}
|
||||
|
|
@ -2,54 +2,41 @@
|
|||
|
||||
#include "Widget.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "UpdateManager.hpp"
|
||||
#include "LayoutManager.hpp"
|
||||
#include "DebugManager.hpp"
|
||||
|
||||
namespace tp {
|
||||
class RootWidget : public WidgetManagerInterface {
|
||||
friend DebugManager;
|
||||
|
||||
public:
|
||||
RootWidget() { setDebug("root", RGBA(1)); }
|
||||
RootWidget();
|
||||
|
||||
// User Interface
|
||||
public:
|
||||
void setRootWidget(Widget* widget);
|
||||
void updateWidget(Widget*, const char* reason = nullptr) override;
|
||||
|
||||
static void setWidgetArea(Widget& widget, const RectF& rect);
|
||||
|
||||
// Graphic Application Interface
|
||||
public:
|
||||
void processFrame(EventHandler* events, const RectF& screenArea);
|
||||
void drawFrame(Canvas& canvas);
|
||||
|
||||
[[nodiscard]] bool needsUpdate() const;
|
||||
|
||||
// Internals
|
||||
private:
|
||||
void updateTreeToProcess();
|
||||
void updateAnimations();
|
||||
void processLayout();
|
||||
void drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos);
|
||||
void drawDebug(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder);
|
||||
void findFocusWidget(Widget* iter, Widget** focus, const Vec2F& pointer);
|
||||
void handleFocusChanges(EventHandler& events);
|
||||
void getWidgetPath(Widget* widget, std::vector<Widget*>& out);
|
||||
void processActiveTree(Widget* iter, EventHandler& events, Vec2F pos);
|
||||
void processFocusItems(EventHandler& events);
|
||||
|
||||
void updateWidget(Widget*, const char* reason = nullptr) override;
|
||||
void updateAnimations();
|
||||
void updateAreaCache(Widget* iter, bool read);
|
||||
static void debugDrawWidget(Widget* widget);
|
||||
|
||||
private:
|
||||
LayoutManager mLayoutManager;
|
||||
|
||||
RectF mScreenArea;
|
||||
Widget* mRoot = nullptr;
|
||||
|
||||
// frame to frame changes
|
||||
std::map<Widget*, bool> mTriggeredWidgets;
|
||||
Widget* mInFocusWidget = nullptr;
|
||||
|
||||
bool mDebug = true;
|
||||
bool mDebugStopProcessing = false;
|
||||
bool mDebugRedrawAlways = false;
|
||||
int mDebugWidgetsToProcess = 0;
|
||||
LayoutManager mLayoutManager;
|
||||
UpdateManager mUpdateManager;
|
||||
DebugManager mDebugManager;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "Color.hpp"
|
||||
#include "Rect.hpp"
|
||||
#include "Timing.hpp"
|
||||
|
||||
namespace tp {
|
||||
class SpringValue {
|
||||
public:
|
||||
SpringValue() = default;
|
||||
|
||||
void updateCurrentPosition() {
|
||||
const auto deltaTime = halnf(gCurrentTime - mPrevTime);
|
||||
const auto deltaPos = mTargetPosition - mCurrentPosition;
|
||||
|
||||
auto deltaVelocity = deltaPos * mSpringStiffness;
|
||||
deltaVelocity -= mVelocity * (mVelocityDamping);
|
||||
|
||||
mVelocity += deltaVelocity;
|
||||
mCurrentPosition += mVelocity * deltaTime;
|
||||
mPrevTime = gCurrentTime;
|
||||
}
|
||||
|
||||
void setTargetPosition(halnf pos) {
|
||||
mTargetPosition = pos;
|
||||
if (mVelocity == 0) mPrevTime = gCurrentTime;
|
||||
}
|
||||
|
||||
[[nodiscard]] halnf getCurrentPos() const { return mCurrentPosition; }
|
||||
[[nodiscard]] halnf getTargetPos() const { return mTargetPosition; }
|
||||
[[nodiscard]] halnf getVelocity() const { return mVelocity; }
|
||||
[[nodiscard]] halnf getDeltaPos() const { return mTargetPosition - mCurrentPosition; }
|
||||
|
||||
void endAnimation() {
|
||||
mCurrentPosition = mTargetPosition;
|
||||
mVelocity = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
time_ms mPrevTime = 0;
|
||||
|
||||
halnf mTargetPosition = 0;
|
||||
halnf mCurrentPosition = 0;
|
||||
|
||||
halnf mVelocity = 0;
|
||||
|
||||
halnf mSpringStiffness = 0.0041;
|
||||
halnf mVelocityDamping = 0.25f;
|
||||
};
|
||||
|
||||
class SpringVec {
|
||||
public:
|
||||
SpringVec() = default;
|
||||
|
||||
void updateCurrentPosition() {
|
||||
mPosX.updateCurrentPosition();
|
||||
mPosY.updateCurrentPosition();
|
||||
}
|
||||
|
||||
void setTargetPosition(Vec2F pos) {
|
||||
mPosX.setTargetPosition(pos.x);
|
||||
mPosY.setTargetPosition(pos.y);
|
||||
}
|
||||
|
||||
[[nodiscard]] Vec2F getCurrentPos() const {
|
||||
return { mPosX.getCurrentPos(), mPosY.getCurrentPos() };
|
||||
}
|
||||
|
||||
[[nodiscard]] Vec2F getTargetPos() const {
|
||||
return { mPosX.getTargetPos(), mPosY.getTargetPos() };
|
||||
}
|
||||
|
||||
[[nodiscard]] Vec2F getVelocity() const {
|
||||
return { mPosX.getVelocity(), mPosY.getVelocity() };
|
||||
}
|
||||
|
||||
[[nodiscard]] bool checkAnimationShouldEnd() const {
|
||||
halnf velocityEpsilon = 0.0001f;
|
||||
halnf positionEpsilon = 1;
|
||||
|
||||
const auto vel = abs(mPosY.getVelocity()) > velocityEpsilon || abs(mPosX.getVelocity()) > velocityEpsilon;
|
||||
const auto pos = abs(mPosY.getDeltaPos()) > positionEpsilon || abs(mPosX.getDeltaPos()) > positionEpsilon;
|
||||
|
||||
return !(pos || vel);
|
||||
}
|
||||
|
||||
void endAnimation() {
|
||||
mPosX.endAnimation();
|
||||
mPosY.endAnimation();
|
||||
}
|
||||
|
||||
private:
|
||||
SpringValue mPosY;
|
||||
SpringValue mPosX;
|
||||
};
|
||||
|
||||
class SpringRect {
|
||||
public:
|
||||
SpringRect() = default;
|
||||
|
||||
[[nodiscard]] RectF getTargetRect() const {
|
||||
const auto start = mStartPos.getTargetPos();
|
||||
const auto end = mEndPos.getTargetPos();
|
||||
return { start, end - start };
|
||||
}
|
||||
|
||||
[[nodiscard]] RectF getCurrentRect() const {
|
||||
const auto start = mStartPos.getCurrentPos();
|
||||
const auto end = mEndPos.getCurrentPos();
|
||||
return { start, end - start };
|
||||
}
|
||||
|
||||
[[nodiscard]] RGBA getCurrentColor() const {
|
||||
const auto start = mStartPos.getCurrentPos();
|
||||
const auto end = mEndPos.getCurrentPos();
|
||||
return { start.x, start.y, end.x, end.y };
|
||||
}
|
||||
|
||||
void setTargetRect(const RectF& rect) {
|
||||
mStartPos.setTargetPosition(rect.p1());
|
||||
mEndPos.setTargetPosition(rect.p3());
|
||||
}
|
||||
|
||||
void setTargetColor(const RGBA& color) {
|
||||
mStartPos.setTargetPosition({ color.r, color.g });
|
||||
mEndPos.setTargetPosition({ color.b, color.a });
|
||||
}
|
||||
|
||||
SpringVec& getStart() {
|
||||
return mStartPos;
|
||||
}
|
||||
|
||||
SpringVec& getEnd() {
|
||||
return mEndPos;
|
||||
}
|
||||
|
||||
void updateCurrentRect() {
|
||||
mStartPos.updateCurrentPosition();
|
||||
mEndPos.updateCurrentPosition();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool shouldEndTransition() const {
|
||||
return mStartPos.checkAnimationShouldEnd() && mEndPos.checkAnimationShouldEnd();
|
||||
}
|
||||
|
||||
void endAnimation() {
|
||||
mStartPos.endAnimation();
|
||||
mEndPos.endAnimation();
|
||||
}
|
||||
|
||||
private:
|
||||
SpringVec mStartPos;
|
||||
SpringVec mEndPos;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "SpringAnimations.hpp"
|
||||
#include "LayoutManager.hpp"
|
||||
|
||||
#include "Layout.hpp"
|
||||
|
||||
#include "EventHandler.hpp"
|
||||
#include "Graphics.hpp"
|
||||
|
|
@ -10,14 +11,32 @@
|
|||
#include <functional>
|
||||
|
||||
namespace tp {
|
||||
class WidgetManagerInterface;
|
||||
class WidgetLayout;
|
||||
|
||||
class LayoutManager;
|
||||
class UpdateManager;
|
||||
class DebugManager;
|
||||
|
||||
class WidgetManagerInterface;
|
||||
class RootWidget;
|
||||
|
||||
class Widget {
|
||||
friend RootWidget;
|
||||
|
||||
friend LayoutManager;
|
||||
friend UpdateManager;
|
||||
friend DebugManager;
|
||||
|
||||
using BitField = Bits<ualni>;
|
||||
|
||||
using DFSAction = std::function<void(Widget*)>;
|
||||
|
||||
enum Flags : int1 {
|
||||
ENABLED = 0,
|
||||
NEEDS_UPDATE,
|
||||
IN_FOCUS,
|
||||
TRIGGERED,
|
||||
};
|
||||
|
||||
public:
|
||||
Widget();
|
||||
|
|
@ -30,10 +49,12 @@ namespace tp {
|
|||
void bringToBack();
|
||||
|
||||
void setLayout(WidgetLayout* layout);
|
||||
void setSizePolicy(SizePolicy x, SizePolicy y) { getLayout()->setSizePolicy(x, y); }
|
||||
void setSizePolicy(SizePolicy x, SizePolicy y);
|
||||
|
||||
void setEnabled(bool val) { mFlags.set(ENABLED, val); }
|
||||
|
||||
WidgetLayout* getLayout();
|
||||
const WidgetLayout* getLayout() const;
|
||||
[[nodiscard]] const WidgetLayout* getLayout() const;
|
||||
|
||||
void triggerWidgetUpdate(const char* reason = nullptr);
|
||||
|
||||
|
|
@ -58,20 +79,19 @@ namespace tp {
|
|||
public:
|
||||
[[nodiscard]] RectF getArea() const;
|
||||
[[nodiscard]] RectF getAreaT() const;
|
||||
// [[nodiscard]] const RectF& getAreaCache() const;
|
||||
|
||||
[[nodiscard]] RectF getRelativeArea() const;
|
||||
[[nodiscard]] RectF getRelativeAreaT() const;
|
||||
// [[nodiscard]] RectF getRelativeAreaCache() const;
|
||||
|
||||
void setArea(const RectF& area);
|
||||
void setAreaCache(const RectF& area);
|
||||
|
||||
private:
|
||||
using DFSAction = std::function<void(Widget*)>;
|
||||
[[nodiscard]] bool isUpdate() const { return mFlags.get(ENABLED) && mFlags.get(NEEDS_UPDATE); }
|
||||
[[nodiscard]] bool isDraw() const { return mFlags.get(ENABLED); }
|
||||
|
||||
static void dfs(Widget* iter, const DFSAction& before, const DFSAction& after = [](auto){}) {
|
||||
if (!iter->mNeedsProcessing) return;
|
||||
if (!iter->isUpdate()) return;
|
||||
|
||||
before(iter);
|
||||
|
||||
|
|
@ -96,10 +116,7 @@ namespace tp {
|
|||
|
||||
WidgetLayout* mLayout = nullptr;
|
||||
|
||||
// TODO : make bitfield processing flags
|
||||
bool mInFocus = false;
|
||||
bool mNeedsProcessing = false;
|
||||
bool mTriggered = false;
|
||||
BitField mFlags;
|
||||
|
||||
// debug
|
||||
struct {
|
||||
|
|
@ -113,5 +130,6 @@ namespace tp {
|
|||
|
||||
struct WidgetManagerInterface : public Widget {
|
||||
virtual void updateWidget(Widget*, const char* reason) = 0;
|
||||
static WidgetLayout* defaultLayout(Widget* widget);
|
||||
};
|
||||
}
|
||||
25
WidgetsNew/public/layouts/BasicLayout.hpp
Normal file
25
WidgetsNew/public/layouts/BasicLayout.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "Layout.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
class BasicLayout : public WidgetLayout {
|
||||
public:
|
||||
explicit BasicLayout(Widget* widget) : WidgetLayout(widget) {}
|
||||
|
||||
void pickRect() override;
|
||||
void clampRect() override;
|
||||
void adjustChildrenRect() override;
|
||||
[[nodiscard]] RectF getAvailableChildArea() const override;
|
||||
|
||||
private:
|
||||
void adjustLayout(bool vertical);
|
||||
static halnf changeChildSize(Widget*, halnf diff, bool vertical);
|
||||
|
||||
private:
|
||||
LayoutPolicy mLayoutPolicy = LayoutPolicy::Vertical;
|
||||
halnf mLayoutGap = 5;
|
||||
halnf mLayoutMargin = 10;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "LayoutManager.hpp"
|
||||
#include "BasicLayout.hpp"
|
||||
|
||||
namespace tp {
|
||||
class FloatingLayout : public BasicLayout {
|
||||
public:
|
||||
FloatingLayout(Widget* widget) :
|
||||
explicit FloatingLayout(Widget* widget) :
|
||||
BasicLayout(widget) {}
|
||||
|
||||
public:
|
||||
25
WidgetsNew/public/mangers/DebugManager.hpp
Normal file
25
WidgetsNew/public/mangers/DebugManager.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.hpp"
|
||||
|
||||
namespace tp {
|
||||
class DebugManager {
|
||||
public:
|
||||
DebugManager() = default;
|
||||
|
||||
bool isRedrawAlways() const { return mDebugRedrawAlways; }
|
||||
bool update(RootWidget* rootWidget, EventHandler& events);
|
||||
void drawDebug(RootWidget* rootWidget, Canvas& canvas);
|
||||
|
||||
private:
|
||||
void recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder);
|
||||
|
||||
static void widgetMenu(Widget*);
|
||||
|
||||
private:
|
||||
// debug
|
||||
bool mDebug = true;
|
||||
bool mDebugStopProcessing = false;
|
||||
bool mDebugRedrawAlways = false;
|
||||
};
|
||||
}
|
||||
11
WidgetsNew/public/mangers/LayoutManager.hpp
Normal file
11
WidgetsNew/public/mangers/LayoutManager.hpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "Layout.hpp"
|
||||
|
||||
namespace tp {
|
||||
class LayoutManager {
|
||||
public:
|
||||
LayoutManager() = default;
|
||||
void adjust(Widget* root);
|
||||
};
|
||||
}
|
||||
38
WidgetsNew/public/mangers/UpdateManager.hpp
Normal file
38
WidgetsNew/public/mangers/UpdateManager.hpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace tp {
|
||||
class UpdateManager {
|
||||
friend DebugManager;
|
||||
|
||||
public:
|
||||
UpdateManager() = default;
|
||||
|
||||
void scheduleUpdate(Widget* widget, const char* reason);
|
||||
|
||||
[[nodiscard]] bool isPendingUpdates() const {
|
||||
return !mTriggeredWidgets.empty();
|
||||
}
|
||||
|
||||
void processWidgets(Widget* root, EventHandler& eventHandler);
|
||||
void clean();
|
||||
|
||||
void updateTreeToProcess(Widget* root);
|
||||
void handleFocusChanges(Widget* root, EventHandler& events);
|
||||
|
||||
void findFocusWidget(Widget* iter, Widget** focus, const Vec2F& pointer);
|
||||
static void getWidgetPath(Widget* widget, std::vector<Widget*>& out);
|
||||
void processActiveTree(Widget* iter, EventHandler& events, Vec2F pos);
|
||||
void processFocusItems(EventHandler& events);
|
||||
|
||||
private:
|
||||
std::map<Widget*, bool> mTriggeredWidgets;
|
||||
Widget* mInFocusWidget = nullptr;
|
||||
|
||||
private:
|
||||
int mDebugWidgetsToProcess = 0;
|
||||
};
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
namespace tp {
|
||||
class FloatingWidget : public Widget {
|
||||
public:
|
||||
FloatingWidget() {
|
||||
FloatingWidget() : Widget() {
|
||||
setDebug("float", { 0.0, 0.9, 0.1, 1 });
|
||||
setLayout(new FloatingLayout(this));
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ namespace tp {
|
|||
|
||||
class FloatingMenu : public FloatingWidget {
|
||||
public:
|
||||
FloatingMenu() {
|
||||
FloatingMenu() : FloatingWidget() {
|
||||
setDebug("float menu", { 0.0, 0.9, 0.1, 0.7 });
|
||||
|
||||
// addChild(&mMenuLayout);
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
namespace tp {
|
||||
class LabelWidget : public Widget {
|
||||
public:
|
||||
LabelWidget() {
|
||||
LabelWidget() : Widget() {
|
||||
setDebug("label", { 0.1, 0.1, 0.1, 0.1 });
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue