Refactor done

This commit is contained in:
IlyaShurupov 2024-10-14 10:17:00 +03:00
parent 3e37f0cd3d
commit 1508a51cde
25 changed files with 797 additions and 610 deletions

View file

@ -0,0 +1,108 @@
#include "Widget.hpp"
namespace tp {
class DockLayout : public WidgetLayout {
public:
enum Side { LEFT, TOP, RIGHT, BOTTOM, NONE };
private:
struct ResizeHandle {
RectF area{ 0, 0, 0, 0 };
halnf start{ 0 };
halnf end{ 0 };
bool active = false;
bool hover = false;
};
struct SideWidgetData {
Widget* widget = nullptr;
bool hidden = false;
halnf absoluteSize = 200;
alni order = -1;
Side side = { TOP };
RectF area = {};
RectF headerArea = {};
RectF previewHandleArea = {};
ResizeHandle resizeHandle;
RectF areaBeforeDocking = {};
};
public:
explicit DockLayout(Widget* widget);
void updateResizeHover(const Vec2F& pointer);
bool startResize(const Vec2F& pointer);
void updateResize(const Vec2F& pointerDelta);
void endResize();
void updatePreviewSide(const Vec2F& pointer);
public:
void pickRect() override {}
void adjustChildrenRect() override;
void clampRect() override {};
public:
bool setCenterWidget(Widget* widget);
bool dockWidget(Widget* widget, Side side);
bool undockWidget(Side side);
void toggleWidgetVisibility(Side side);
public:
[[nodiscard]] bool isSideVisible(Side side) const;
[[nodiscard]] bool sideExists(Side side) const;
[[nodiscard]] bool isResizing() const { return mResizing; }
[[nodiscard]] bool isResizing(Side side) const { return mSideWidgets[side].resizeHandle.active; }
[[nodiscard]] bool isResizeHandleHover(Side side) const { return mSideWidgets[side].resizeHandle.hover; }
Side getSideFromWidget(Widget*);
Side getPreviewSide();
[[nodiscard]] RectF getRectBeforeDocked(Side side) const { return mSideWidgets[side].areaBeforeDocking; }
[[nodiscard]] RectF getResizeHandleArea(Side side) const { return mSideWidgets[side].resizeHandle.area; }
[[nodiscard]] RectF getHeaderArea(Side side) const { return mSideWidgets[side].headerArea; }
[[nodiscard]] RectF getPreviewHandleArea(Side side) const { return mSideWidgets[side].previewHandleArea; }
[[nodiscard]] RectF getPreviewArea() const { return mPreviewArea; }
Widget* getSideWidget(Side side) { return mSideWidgets[side].widget; }
const std::vector<Widget*>& getDockedWidgets();
private:
ualni getVisibleSidesSize();
void calculateSideAreas();
void calculateResizeHandles();
void updateChildSideWidgets();
void calculateHeaderAreas();
private:
RectF mPreviewArea = {};
Side mPreviewSide = NONE;
int resizeType[2] = { 0, 0 };
SideWidgetData mSideWidgets[4];
std::vector<Widget*> mDockedWidgets;
private:
bool mResizing = false;
Widget* mCenterWidget = nullptr;
RectF mCenterArea {};
// Parameters
const halnf mHandleSplitFactor = 0.3;
const halnf mHandleFactor = 0.1;
halnf mSideSizePadding = 150.f;
halnf mPadding = 4;
halnf mHeaderSize = 27;
};
}

View file

@ -1,97 +0,0 @@
#include "Widget.hpp"
namespace tp {
class DockLayoutWidget : public Widget {
public:
enum Side { LEFT, TOP, RIGHT, BOTTOM, NONE };
private:
struct ResizeHandle {
RectF area{ 0, 0, 0, 0 };
halnf start{ 0 };
halnf end{ 0 };
bool active = false;
bool hover = false;
};
struct SideWidgetData {
Widget* widget = nullptr;
bool hidden = false;
halnf absoluteSize = 200;
alni order = -1;
Side side = { TOP };
RectF area = {};
RectF headerArea = {};
RectF previewHandleArea = {};
ResizeHandle resizeHandle;
RectF areaBeforeDocking = {};
};
public:
DockLayoutWidget();
public:
void pickRect() override {}
void adjustChildrenRect() override;
void process(const EventHandler& events) override;
void draw(Canvas& canvas) override;
void drawOverlay(Canvas& canvas) override;
[[nodiscard]] bool propagateEventsToChildren() const override;
[[nodiscard]] bool needsNextFrame() const override;
public:
void setCenterWidget(Widget* widget);
void dockWidget(Widget* widget, Side side);
void undockWidget(Side side, bool restoreArea = true);
void toggleWidgetVisibility(Side side);
private:
Side getSideFromWidget(Widget*);
void calculateSideAreas();
void calculateResizeHandles();
void handleResizeEvents(const EventHandler& events);
void updateChildSideWidgets();
void calculateHeaderAreas();
bool isSideVisible(Side side);
bool sideExists(DockLayoutWidget::Side side);
ualni getVisibleSidesSize();
void handlePreview(const EventHandler& events);
private:
RectF mPreviewArea = {};
Side mPreviewSide = NONE;
int resizeType[2] = { 0, 0 };
SideWidgetData mSideWidgets[4];
private:
bool mResizing = false;
Widget* mCenterWidget = nullptr;
RectF mCenterArea {};
// Parameters
halnf mSideSizePadding = 150.f;
halnf mPadding = 4;
halnf mHeaderSize = 27;
halnf mRounding = 10;
Vec2F mPreviewHandleSize = { 50, 50 };
RGBA mResizeHandleColorHovered = RGBA(0.3, 0.3, 0.3, 1);
RGBA mResizeHandleColorActive = RGBA(0.6, 0.6, 0.6, 1);
RGBA mBackgroundColor = RGBA(0, 0, 0, 1);
RGBA mPreviewColor = RGBA(0.6, 0.6, 0.6, 0.2);
public:
Widget* mPreviewWidget = nullptr;
};
}

View file

@ -0,0 +1,41 @@
#include "DockLayout.hpp"
namespace tp {
class DockWidget : public Widget {
public:
DockWidget();
public:
void process(const EventHandler& events) override;
void draw(Canvas& canvas) override;
void drawOverlay(Canvas& canvas) override;
[[nodiscard]] bool propagateEventsToChildren() const override;
[[nodiscard]] bool needsNextFrame() const override;
void drawSide(DockLayout::Side side, Canvas& canvas);
public:
void setCenterWidget(Widget* widget);
void dockWidget(Widget* widget, DockLayout::Side side);
void undockWidget(DockLayout::Side side, bool restoreArea = true);
void toggleWidgetVisibility(DockLayout::Side side);
private:
DockLayout* layout() { return dynamic_cast<DockLayout*>(mLayout); }
const DockLayout* layout() const { return dynamic_cast<const DockLayout*>(mLayout); }
private:
Widget* mPreviewWidget = nullptr;
private:
halnf mRounding = 10;
halnf mPadding = 4;
RGBA mResizeHandleColorHovered = RGBA(0.3, 0.3, 0.3, 1);
RGBA mResizeHandleColorActive = RGBA(0.6, 0.6, 0.6, 1);
RGBA mBackgroundColor = RGBA(0, 0, 0, 1);
RGBA mPreviewColor = RGBA(0.6, 0.6, 0.6, 0.2);
};
}

View file

@ -0,0 +1,34 @@
#pragma once
#include "LayoutManager.hpp"
namespace tp {
class FloatingLayout : public BasicLayout {
public:
FloatingLayout(Widget* widget) :
BasicLayout(widget) {}
public:
void startAction(const Vec2F& pointer);
void updateAction(const Vec2F& pointer);
void endAction();
bool isFloating() const { return mIsFloating; }
RectF resizeHandleRect();
public:
void pickRect() override;
private:
bool mIsFloating = false;
bool mIsResizing = false;
Vec2F mPointerStart;
Vec2F mPointerCurrent;
// TODO : remove?
halnf mHandleSize = 10;
halnf mHandlePadding = 2;
};
}

View file

@ -1,24 +1,20 @@
#pragma once
#include "SimpleWidgets.hpp"
#include "FloatingLayout.hpp"
namespace tp {
class FloatingWidget : public Widget {
public:
FloatingWidget() {
setDebug("float", { 0.0, 0.9, 0.1, 1 });
mSizePolicy = { SizePolicy::Fixed, SizePolicy::Fixed };
mLayoutPolicy = LayoutPolicy::Horizontal;
setLayout(new FloatingLayout(this));
}
void process(const EventHandler& events) override;
void pickRect() override;
void draw(Canvas& canvas) override;
RectF resizeHandleRect();
[[nodiscard]] bool needsNextFrame() const override;
@ -28,14 +24,8 @@ namespace tp {
[[nodiscard]] bool isFloating() const;
private:
bool mIsFloating = false;
bool mIsResizing = false;
halnf mHandleSize = 10;
halnf mHandlePadding = 2;
Vec2F mPointerStart;
Vec2F mPointerCurrent;
FloatingLayout* layout();
[[nodiscard]] const FloatingLayout* layout() const;
};
class FloatingMenu : public FloatingWidget {
@ -53,8 +43,8 @@ namespace tp {
mHeader.setSizePolicy(SizePolicy::Expanding, SizePolicy::Minimal);
mBodyLayout.setSizePolicy(SizePolicy::Expanding, SizePolicy::Expanding);
setLayoutPolicy(LayoutPolicy::Vertical);
mBodyLayout.setLayoutPolicy(LayoutPolicy::Vertical);
// getLayout()->setLayoutPolicy(LayoutPolicy::Vertical);
// mBodyLayout.getLayout()->setLayoutPolicy(LayoutPolicy::Vertical);
}
public:

View file

@ -26,15 +26,39 @@ namespace tp {
virtual void pickRect() = 0;
virtual void clampRect() = 0;
virtual void adjustChildrenRect() = 0;
virtual RectF getAvailableChildArea() const;
protected:
public:
const Vec2F& getMinSize();
void setMinSize(const Vec2F& size);
const Vec2<SizePolicy>& getSizePolicy() const;
void setSizePolicy(SizePolicy x, SizePolicy y);
public:
[[nodiscard]] const RectF& getArea() const;
RectF getAnimatedArea() const;
void setArea(const RectF& area);
[[nodiscard]] Widget* parent() const;
[[nodiscard]] const std::vector<Widget*>& children() const;
public:
void clampMinMaxSize();
[[nodiscard]] RangeF pickRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool v) const;
[[nodiscard]] RangeF clampRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool v) const;
[[nodiscard]] RectF getChildrenEnclosure() const;
[[nodiscard]] RectF getParentEnclosure() const;
private:
Widget* mWidget = nullptr;
protected:
Vec2<SizePolicy> mSizePolicy = { SizePolicy::Fixed, SizePolicy::Fixed };
Vec2F mMinSize = { 50, 50 };
Vec2F mMaxSize = { FLT_MAX / 2, FLT_MAX / 2 };
};
class BasicLayout : public WidgetLayout {
@ -44,31 +68,22 @@ namespace tp {
void pickRect() override;
void clampRect() override;
void adjustChildrenRect() override;
public:
const Vec2F& getMinSize();
void setMinSize(const Vec2F& size);
RectF getAvailableChildArea() const override;
private:
void adjustLayout(bool vertical);
static halnf changeChildSize(Widget*, halnf diff, bool vertical);
[[nodiscard]] RangeF pickRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool v) const;
[[nodiscard]] RangeF clampRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool v) const;
void clampMinMaxSize();
[[nodiscard]] RectF getChildrenEnclosure() const;
[[nodiscard]] RectF getParentEnclosure() const;
private:
LayoutPolicy mLayoutPolicy = LayoutPolicy::Vertical;
Vec2<SizePolicy> mSizePolicy = { SizePolicy::Fixed, SizePolicy::Fixed };
Vec2F mMinSize = { 50, 50 };
Vec2F mMaxSize = { FLT_MAX / 2, FLT_MAX / 2 };
halnf mLayoutGap = 5;
halnf mLayoutMargin = 10;
};
class LayoutManager {
public:
LayoutManager() = default;
void adjust(Widget* root);
};
}

View file

@ -8,13 +8,6 @@
namespace tp {
class RootWidget : public WidgetManagerInterface {
struct ActiveTreeNode {
ActiveTreeNode* parent = nullptr;
std::set<ActiveTreeNode*> children;
Widget* widget = nullptr;
};
public:
RootWidget() { setDebug("root", RGBA(1)); }
@ -31,29 +24,32 @@ namespace tp {
private:
void updateTreeToProcess();
void updateAnimations(ActiveTreeNode* iter);
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(ActiveTreeNode* iter, EventHandler& events, Vec2F pos);
void processActiveTree(Widget* iter, EventHandler& events, Vec2F pos);
void processFocusItems(EventHandler& events);
void adjustSizes(ActiveTreeNode* iter);
void updateAreaCache(ActiveTreeNode* iter, bool read);
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;
std::map<Widget*, ActiveTreeNode> mWidgetsToProcess;
Widget* mInFocusWidget = nullptr;
bool mDebug = true;
bool mDebugStopProcessing = false;
bool mDebugRedrawAlways = false;
int mDebugWidgetsToProcess = 0;
};
}

View file

@ -1,32 +1,41 @@
#pragma once
#include "SpringAnimations.hpp"
#include "LayoutPolicies.hpp"
#include "LayoutManager.hpp"
#include "EventHandler.hpp"
#include "Graphics.hpp"
#include <vector>
#include <functional>
namespace tp {
class WidgetManagerInterface;
class WidgetLayout;
class LayoutManager;
class RootWidget;
class Widget {
friend class RootWidget;
friend RootWidget;
friend LayoutManager;
public:
Widget();
virtual ~Widget();
void addChild(Widget* child);
void addChild(Widget* child, bool front = false);
void removeChild(Widget* child);
void bringToFront();
void bringToBack();
void setLayout(WidgetLayout* layout);
void setSizePolicy(SizePolicy x, SizePolicy y) { getLayout()->setSizePolicy(x, y); }
WidgetLayout* getLayout();
const WidgetLayout* getLayout() const;
void triggerWidgetUpdate(const char* reason = nullptr);
protected:
virtual void process(const EventHandler& events) {}
@ -45,20 +54,34 @@ namespace tp {
protected:
void setDebug(const char* name, RGBA col);
WidgetManagerInterface* getRoot();
void triggerWidgetUpdate(const char* reason = nullptr);
public:
[[nodiscard]] RectF getArea() const;
[[nodiscard]] RectF getAreaT() const;
[[nodiscard]] const RectF& getAreaCache() const;
// [[nodiscard]] const RectF& getAreaCache() const;
[[nodiscard]] RectF getRelativeArea() const;
[[nodiscard]] RectF getRelativeAreaT() const;
[[nodiscard]] RectF getRelativeAreaCache() const;
// [[nodiscard]] RectF getRelativeAreaCache() const;
void setArea(const RectF& area);
void setAreaCache(const RectF& area);
private:
using DFSAction = std::function<void(Widget*)>;
static void dfs(Widget* iter, const DFSAction& before, const DFSAction& after = [](auto){}) {
if (!iter->mNeedsProcessing) return;
before(iter);
for (auto child : iter->mDepthOrder) {
dfs(child.data(), before, after);
}
after(iter);
}
protected:
friend WidgetLayout;
@ -73,7 +96,10 @@ namespace tp {
WidgetLayout* mLayout = nullptr;
// TODO : make bitfield processing flags
bool mInFocus = false;
bool mNeedsProcessing = false;
bool mTriggered = false;
// debug
struct {