This commit is contained in:
IlyaShurupov 2024-10-08 14:23:49 +03:00
parent 49cfe70c0d
commit 72c4740f82
18 changed files with 592 additions and 203 deletions

View file

@ -12,9 +12,9 @@ namespace tp {
void draw(Canvas& canvas) override;
void process(const EventHandler& events) override;
[[nodiscard]] bool needUpdate() const override;
[[nodiscard]] bool needsNextFrame() const override;
private:
SpringRect mTestSpring;
mutable SpringRect mTestSpring;
};
}

View file

@ -1,22 +1,61 @@
#pragma once
#include "Widget.hpp"
#include "SimpleWidgets.hpp"
#include "LayoutWidget.hpp"
namespace tp {
class FloatingWidget : public Widget {
public:
FloatingWidget() = default;
FloatingWidget() {
setDebug("float", { 0.0, 0.9, 0.1, 0.7 });
}
void process(const EventHandler& events) override;
void updateArea(RectF& area) const override;
void adjustRect() override;
void draw(Canvas& canvas) override;
RectF resizeHandleRect();
bool propagateEventsToChildren() const override;
private:
bool mIsFloating = false;
bool mIsResizing = false;
halnf mHandleSize = 10;
halnf mHandlePadding = 2;
Vec2F mPointerStart;
Vec2F mPointerCurrent;
};
class FloatingMenu : public FloatingWidget {
public:
FloatingMenu() {
setDebug("float menu", { 0.0, 0.9, 0.1, 0.7 });
addChild(&mMenuLayout);
mMenuLayout.addChild(&mHeader);
mMenuLayout.addChild(&mBodyLayout);
addToMenu(&mTestButton);
mHeader.setText("Menu");
}
public:
void addToMenu(Widget* widget) {
mBodyLayout.addChild(widget);
}
private:
VerticalLayout mMenuLayout;
VerticalLayout mBodyLayout;
LabelWidget mHeader;
ButtonWidget mTestButton;
};
}

View file

@ -0,0 +1,56 @@
#pragma once
#include "Widget.hpp"
namespace tp {
class DesktopLayout : public Widget {
public:
DesktopLayout() { setDebug("desktop layout", { 0, 0, 0.9, 0.9 }); }
void draw(Canvas& canvas) override {
// canvas.rect(getRelativeArea(), RGBA(0, 0, 0, 1));
}
void adjustRect() override {
// do nothing
}
void adjustChildrenRect() override {
// todo : adjust by viewport pos
}
[[nodiscard]] bool processesEvents() const override { return false; }
};
class VerticalLayout : public Widget {
public:
VerticalLayout() {
setDebug("vertical", { 0.8, 0.1, 0.1, 0.9 });
}
void draw(Canvas& canvas) override {
// canvas.frame(getRelativeArea(), RGBA(1));
}
void adjustChildrenRect() override {
auto content = &mChildren;
auto area = getRelativeArea();
auto iterRect = area.shrink(mPadding);
iterRect.height = ((iterRect.height + mGap) / (float) content->size()) - mGap;
for (auto widget :(*content)) {
widget->setArea(iterRect);
iterRect.y += iterRect.height + mGap;
}
}
[[nodiscard]] bool processesEvents() const override { return false; }
private:
halnf mGap = 10;
halnf mPadding = 10;
};
}

View file

@ -2,46 +2,54 @@
#include "Widget.hpp"
#include <map>
#include <vector>
#include <set>
namespace tp {
class RootWidget {
class RootWidget : public WidgetManagerInterface {
// path from leaf to root of widgets that need to be updated
struct ActivePath {
struct ActiveNode {
Widget* widget = nullptr;
Vec2F globalPos;
};
Buffer<ActiveNode> path;
struct ActiveTreeNode {
ActiveTreeNode* parent = nullptr;
std::set<ActiveTreeNode*> children;
Widget* widget = nullptr;
};
public:
RootWidget() = default;
RootWidget() { setDebug("root", RGBA(1)); }
void setRootWidget(Widget* widget);
void updateWidget(Widget*);
static void setWidgetArea(Widget& widget, const RectF& rect);
public:
void processFrame(EventHandler* events, const RectF& screenArea);
void drawFrame(Canvas& canvas);
[[nodiscard]] bool needsUpdate() const;
static void setWidgetArea(Widget& widget, const RectF& rect);
private:
void updateActivePaths(Buffer<ActivePath>* activePaths, const Vec2F& pointer);
void updateTreeToProcess();
void updateAnimations(ActiveTreeNode* iter);
void drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos);
void processPaths(const Buffer<ActivePath>& path, EventHandler& events);
void clearProcessedFlag(const Buffer<ActivePath>& paths);
void drawDebug(Canvas& canvas, Widget* active, const Vec2F& pos);
void findFocusWidget(Widget* iter, Widget** focus, const Vec2F& pointer);
void handleFocusChanges(EventHandler& events);
void getWidgetPath(Widget* widget, std::vector<Widget*>& out);
void processActiveTree(ActiveTreeNode* iter, EventHandler& events);
void processFocusItems(EventHandler& events);
void adjustSizes(ActiveTreeNode* iter);
private:
RectF mScreenArea;
Widget* mRoot = nullptr;
Buffer<Widget*> mActiveWidgets;
Buffer<ActivePath> mActivePaths[2]; // current and prev
bool mFlipFlop = false;
// frame to frame changes
std::set<Widget*> mTriggeredWidgets;
std::map<Widget*, ActiveTreeNode> mWidgetsToProcess;
Widget* mInFocusWidget = nullptr;
bool mNeedUpdate = false;
bool mDebug = false;
};
}

View file

@ -7,14 +7,17 @@
namespace tp {
class LabelWidget : public Widget {
public:
LabelWidget() = default;
LabelWidget() {
setDebug("label", { 0.1, 0.1, 0.1, 0.1 });
}
void setText(const std::string& text);
[[nodiscard]] const std::string& getText() const;
void draw(Canvas& canvas) override;
[[nodiscard]] bool isPassThroughEvents() const override { return true; }
[[nodiscard]] bool processesEvents() const override { return false; }
private:
std::string mText = "Text";
@ -33,11 +36,14 @@ namespace tp {
void process(const EventHandler& eventHandler) override;
void draw(Canvas& canvas) override;
[[nodiscard]] bool isPassThroughEvents() const override { return false; }
void mouseEnter() override;
void mouseLeave() override;
[[nodiscard]] bool needUpdate() const override;
[[nodiscard]] bool processesEvents() const override { return true; }
[[nodiscard]] bool needsNextFrame() const override;
void finishAnimations() override;
void endAnimations() override;
void updateAnimations() override;
private:
std::function<void()> mAction;
@ -45,7 +51,7 @@ namespace tp {
SpringRect mColorAnimated;
halnf mRounding = 5;
RGBA mColor = { 1.0f, 0.0f, 0.0f, 1.f };
RGBA mColorHovered = { 0.0f, 0.0f, 0.0f, 1.f };
RGBA mColorHovered = { 0.0f, 0.4f, 0.4f, 1.f };
RGBA mColor = { 0.0f, 0.0f, 0.0f, 1.f };
};
}

View file

@ -139,7 +139,7 @@ namespace tp {
mEndPos.updateCurrentPosition();
}
[[nodiscard]] bool checkAnimationShouldEnd() const {
[[nodiscard]] bool shouldEndTransition() const {
return mStartPos.checkAnimationShouldEnd() && mEndPos.checkAnimationShouldEnd();
}

View file

@ -5,7 +5,11 @@
#include "EventHandler.hpp"
#include "Graphics.hpp"
#include <vector>
namespace tp {
class WidgetManagerInterface;
class Widget {
friend class RootWidget;
@ -13,41 +17,68 @@ namespace tp {
Widget();
virtual ~Widget() = default;
virtual void process(const EventHandler& events) {}
virtual void updateArea(RectF& area) const {}
void setDebug(const char* name, RGBA col) {
mName = name;
mDebugColor = col;
}
virtual void draw(Canvas& canvas);
virtual void drawOverlay(Canvas& canvas) {}
void addChild(Widget* child) {
mChildren.push_back(child);
child->mParent = this;
virtual bool isPassThroughEvents() const { return false; }
triggerWidgetUpdate();
child->triggerWidgetUpdate();
}
[[nodiscard]] virtual bool needUpdate() const;
WidgetManagerInterface* getRoot();
virtual void finishAnimations();
void triggerWidgetUpdate();
public:
[[nodiscard]] RectF getRelativeArea() const;
void setActive(bool active);
virtual void process(const EventHandler& events) {}
virtual void draw(Canvas& canvas) { canvas.rect(mArea.getCurrentRect(), RGBA(1.f), 10); }
virtual void drawOverlay(Canvas& canvas) {}
void addChild(Widget* widget);
virtual void mouseEnter();
virtual void mouseLeave();
private:
// size policies
virtual void adjustRect();
virtual void adjustChildrenRect();
[[nodiscard]] virtual bool processesEvents() const;
[[nodiscard]] virtual bool propagateEventsToChildren() const;
[[nodiscard]] virtual bool needsNextFrame() const;
virtual void endAnimations();
virtual void updateAnimations();
public:
[[nodiscard]] RectF getArea() const;
[[nodiscard]] RectF getRelativeArea() const;
void setArea(const RectF& area);
void removeChild(Widget* widget);
private:
protected:
Widget* mParent = nullptr;
std::vector<Widget*> mChildren;
// relative to the parent
SpringRect mArea;
// tree structure of widgets
List<Widget*> mChildWidgets;
ualni mZValue = 0;
// if needed updates even though pointer is not in area
bool mIsActive = false;
bool mInFocus = false;
Widget* mParent = nullptr;
// debug
std::string mName = "widget base";
Vec2F mLocalPoint;
Vec2F mGlobalPoint;
RGBA mDebugColor = { 1, 1, 1, 0.3 };
};
bool mProcessedFlag = false;
struct WidgetManagerInterface : public Widget {
virtual void updateWidget(Widget*) = 0;
};
}