Refactor done
This commit is contained in:
parent
d6025bc4e0
commit
837d8dc507
25 changed files with 797 additions and 610 deletions
|
|
@ -36,8 +36,8 @@ namespace tp {
|
|||
mViewport(canvas, editor) {
|
||||
mEditor = editor;
|
||||
|
||||
mDockSpace.addSideWidget(&mNavigationMenu, DockLayoutWidget::RIGHT);
|
||||
mDockSpace.addSideWidget(&mRenderMenu, DockLayoutWidget::LEFT);
|
||||
mDockSpace.addSideWidget(&mNavigationMenu, DockWidget::RIGHT);
|
||||
mDockSpace.addSideWidget(&mRenderMenu, DockWidget::LEFT);
|
||||
mDockSpace.setCenterWidget(&mViewport);
|
||||
|
||||
// Render
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ namespace tp {
|
|||
mCurrentTrackInfo.mPlayer = mPlayer;
|
||||
|
||||
mDockSpace.setCenterWidget(&mSongList);
|
||||
mDockSpace.addSideWidget(&mCurrentTrackInfo, DockLayoutWidget::RIGHT);
|
||||
mDockSpace.addSideWidget(&mCurrentTrackInfo, DockWidget::RIGHT);
|
||||
|
||||
// this->mChildWidgets.pushBack(&mCurrentTrackInfo);
|
||||
// this->mChildWidgets.pushBack(&mCurrentTrack);
|
||||
|
|
|
|||
|
|
@ -97,6 +97,10 @@ namespace tp {
|
|||
}
|
||||
}
|
||||
|
||||
Rect relative() const {
|
||||
return { { 0, 0 }, size };
|
||||
}
|
||||
|
||||
// argument isInside
|
||||
bool isInside(const Vec2<Type>& p) const { return isInside(p.x, p.y); }
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ namespace tp {
|
|||
halnf mPadding = 0;
|
||||
};
|
||||
|
||||
class ChattingWidget : public DockLayoutWidget {
|
||||
class ChattingWidget : public DockWidget {
|
||||
public:
|
||||
ChattingWidget() {
|
||||
// todo : fetch code
|
||||
|
|
@ -205,7 +205,7 @@ namespace tp {
|
|||
mActive.mHistoryView.addWidget(&message.data());
|
||||
}
|
||||
|
||||
addSideWidget(&mSideView, DockLayoutWidget::RIGHT);
|
||||
addSideWidget(&mSideView, DockWidget::RIGHT);
|
||||
setCenterWidget(&mActive);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,19 +33,19 @@ namespace tp {
|
|||
public:
|
||||
SimpleWidget3() {
|
||||
|
||||
mDockSpace.addSideWidget(&mButtons[0], DockLayoutWidget::BOTTOM);
|
||||
mDockSpace.addSideWidget(&mButtons[1], DockLayoutWidget::RIGHT);
|
||||
mDockSpace.addSideWidget(&mButtons[0], DockWidget::BOTTOM);
|
||||
mDockSpace.addSideWidget(&mButtons[1], DockWidget::RIGHT);
|
||||
|
||||
mDockSpace.removeSideWidget(DockLayoutWidget::BOTTOM);
|
||||
mDockSpace.removeSideWidget(DockWidget::BOTTOM);
|
||||
|
||||
mDockSpace.addSideWidget(&mButtons[0], DockLayoutWidget::TOP);
|
||||
mDockSpace.addSideWidget(&mButtons[2], DockLayoutWidget::LEFT);
|
||||
mDockSpace.addSideWidget(&mButtons[0], DockWidget::TOP);
|
||||
mDockSpace.addSideWidget(&mButtons[2], DockWidget::LEFT);
|
||||
|
||||
mDockSpace.removeSideWidget(DockLayoutWidget::TOP);
|
||||
mDockSpace.removeSideWidget(DockWidget::TOP);
|
||||
|
||||
mDockSpace.addSideWidget(&mButtons[0], DockLayoutWidget::BOTTOM);
|
||||
mDockSpace.addSideWidget(&mButtons[0], DockWidget::BOTTOM);
|
||||
|
||||
mDockSpace.addSideWidget(&mButtons[3], DockLayoutWidget::TOP);
|
||||
mDockSpace.addSideWidget(&mButtons[3], DockWidget::TOP);
|
||||
mDockSpace.setCenterWidget(&mButtons[4]);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
using namespace tp;
|
||||
|
||||
DockLayoutWidget::DockLayoutWidget() {
|
||||
DockWidget::DockWidget() {
|
||||
mSideWidgets[0].side = LEFT;
|
||||
mSideWidgets[1].side = TOP;
|
||||
mSideWidgets[2].side = RIGHT;
|
||||
mSideWidgets[3].side = BOTTOM;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::addSideWidget(Widget* widget, Side side) {
|
||||
void DockWidget::addSideWidget(Widget* widget, Side side) {
|
||||
if (sideExists(side)) return;
|
||||
|
||||
auto& sideWidget = mSideWidgets[side];
|
||||
|
|
@ -27,7 +27,7 @@ void DockLayoutWidget::addSideWidget(Widget* widget, Side side) {
|
|||
widget->mIsDocked = true;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::removeSideWidget(Side side) {
|
||||
void DockWidget::removeSideWidget(Side side) {
|
||||
if (!sideExists(side)) return;
|
||||
|
||||
bool removed = false;
|
||||
|
|
@ -48,18 +48,18 @@ void DockLayoutWidget::removeSideWidget(Side side) {
|
|||
mSideWidgets[side].widget = nullptr;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::setCenterWidget(Widget* widget) {
|
||||
void DockWidget::setCenterWidget(Widget* widget) {
|
||||
mChildWidgets.removeNode(mChildWidgets.find(mCenterWidget));
|
||||
mCenterWidget = widget;
|
||||
mChildWidgets.pushBack(mCenterWidget);
|
||||
}
|
||||
|
||||
void DockLayoutWidget::toggleHiddenState(DockLayoutWidget::Side side) {
|
||||
void DockWidget::toggleHiddenState(DockWidget::Side side) {
|
||||
if (!sideExists(side)) return;
|
||||
mSideWidgets[side].hidden = !mSideWidgets[side].hidden;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::eventProcess(const tp::Events& events) {
|
||||
void DockWidget::eventProcess(const tp::Events& events) {
|
||||
calculateSideAreas();
|
||||
calculateResizeHandles();
|
||||
// calculateHeaderAreas();
|
||||
|
|
@ -70,7 +70,7 @@ void DockLayoutWidget::eventProcess(const tp::Events& events) {
|
|||
updateChildSideWidgets();
|
||||
}
|
||||
|
||||
void DockLayoutWidget::eventDraw(Canvas& canvas) {
|
||||
void DockWidget::eventDraw(Canvas& canvas) {
|
||||
canvas.rect(this->mArea, mBackgroundColor, 0);
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
|
|
@ -89,7 +89,7 @@ void DockLayoutWidget::eventDraw(Canvas& canvas) {
|
|||
}
|
||||
}
|
||||
|
||||
void DockLayoutWidget::eventDrawOver(Canvas& canvas) {
|
||||
void DockWidget::eventDrawOver(Canvas& canvas) {
|
||||
if (!mPreview) return;
|
||||
|
||||
if (mPreviewSide != NONE) canvas.rect(mPreviewArea.shrink(mPadding * 2), mPreviewColor, mRounding);
|
||||
|
|
@ -100,7 +100,7 @@ void DockLayoutWidget::eventDrawOver(Canvas& canvas) {
|
|||
}
|
||||
}
|
||||
|
||||
void DockLayoutWidget::calculateSideAreas() {
|
||||
void DockWidget::calculateSideAreas() {
|
||||
auto startArea = this->mArea;
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
const auto side = sideWidget.order;
|
||||
|
|
@ -135,7 +135,7 @@ void DockLayoutWidget::calculateSideAreas() {
|
|||
mCenterArea = startArea.shrink(mPadding);
|
||||
}
|
||||
|
||||
void DockLayoutWidget::calculateResizeHandles() {
|
||||
void DockWidget::calculateResizeHandles() {
|
||||
RectF rec;
|
||||
|
||||
if (isSideVisible(LEFT)) {
|
||||
|
|
@ -162,7 +162,7 @@ void DockLayoutWidget::calculateResizeHandles() {
|
|||
}
|
||||
}
|
||||
|
||||
void DockLayoutWidget::handleResizeEvents(const Events& events) {
|
||||
void DockWidget::handleResizeEvents(const Events& events) {
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
auto& sideSize = sideWidget.absoluteSize;
|
||||
auto& resizeHandle = sideWidget.resizeHandle;
|
||||
|
|
@ -225,7 +225,7 @@ void DockLayoutWidget::handleResizeEvents(const Events& events) {
|
|||
}
|
||||
}
|
||||
|
||||
void DockLayoutWidget::updateChildSideWidgets() {
|
||||
void DockWidget::updateChildSideWidgets() {
|
||||
// Update Child Widgets
|
||||
{
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
|
|
@ -261,7 +261,7 @@ void DockLayoutWidget::updateChildSideWidgets() {
|
|||
*/
|
||||
}
|
||||
|
||||
void DockLayoutWidget::calculateHeaderAreas() {
|
||||
void DockWidget::calculateHeaderAreas() {
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (!isSideVisible(Side(i))) continue;
|
||||
auto& area = mSideWidgets[i].area;
|
||||
|
|
@ -273,13 +273,13 @@ void DockLayoutWidget::calculateHeaderAreas() {
|
|||
}
|
||||
}
|
||||
|
||||
bool DockLayoutWidget::isSideVisible(DockLayoutWidget::Side side) {
|
||||
bool DockWidget::isSideVisible(DockWidget::Side side) {
|
||||
return sideExists(side) && !mSideWidgets[side].hidden;
|
||||
}
|
||||
|
||||
bool DockLayoutWidget::sideExists(DockLayoutWidget::Side side) { return mSideWidgets[side].widget; }
|
||||
bool DockWidget::sideExists(DockWidget::Side side) { return mSideWidgets[side].widget; }
|
||||
|
||||
ualni DockLayoutWidget::getVisibleSidesSize() {
|
||||
ualni DockWidget::getVisibleSidesSize() {
|
||||
ualni out = 0;
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (isSideVisible(Side(i))) out++;
|
||||
|
|
@ -287,9 +287,9 @@ ualni DockLayoutWidget::getVisibleSidesSize() {
|
|||
return out;
|
||||
}
|
||||
|
||||
DockLayoutWidget::Side DockLayoutWidget::getPreviewSide() { return mPreviewSide; }
|
||||
DockWidget::Side DockWidget::getPreviewSide() { return mPreviewSide; }
|
||||
|
||||
void DockLayoutWidget::handlePreview(const Events& events) {
|
||||
void DockWidget::handlePreview(const Events& events) {
|
||||
if (!mPreview) {
|
||||
mPreviewSide = NONE;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ void WorkspaceWidget::eventProcess(const Events& events) {
|
|||
|
||||
if (widget->mDropped) {
|
||||
auto side = mDockSpace.getPreviewSide();
|
||||
if (side != DockLayoutWidget::NONE) {
|
||||
if (side != DockWidget::NONE) {
|
||||
mFloatingLayer.mChildWidgets.removeNode(mFloatingLayer.mChildWidgets.find(widget));
|
||||
widget->setCollapsed(false);
|
||||
widget->stopFloating();
|
||||
|
|
@ -52,13 +52,13 @@ void WorkspaceWidget::eventProcess(const Events& events) {
|
|||
// toggle hide state
|
||||
if (events.isDown(InputID::LEFT_ALT)) {
|
||||
if (events.isPressed(InputID::N1)) {
|
||||
mDockSpace.toggleHiddenState(DockLayoutWidget::LEFT);
|
||||
mDockSpace.toggleHiddenState(DockWidget::LEFT);
|
||||
} else if (events.isPressed(InputID::N2)) {
|
||||
mDockSpace.toggleHiddenState(DockLayoutWidget::TOP);
|
||||
mDockSpace.toggleHiddenState(DockWidget::TOP);
|
||||
} else if (events.isPressed(InputID::N3)) {
|
||||
mDockSpace.toggleHiddenState(DockLayoutWidget::RIGHT);
|
||||
mDockSpace.toggleHiddenState(DockWidget::RIGHT);
|
||||
} else if (events.isPressed(InputID::N4)) {
|
||||
mDockSpace.toggleHiddenState(DockLayoutWidget::BOTTOM);
|
||||
mDockSpace.toggleHiddenState(DockWidget::BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "WidgetBase.hpp"
|
||||
|
||||
namespace tp {
|
||||
class DockLayoutWidget : public Widget {
|
||||
class DockWidget : public Widget {
|
||||
public:
|
||||
enum Side { LEFT, TOP, RIGHT, BOTTOM, NONE };
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ namespace tp {
|
|||
};
|
||||
|
||||
public:
|
||||
DockLayoutWidget();
|
||||
DockWidget();
|
||||
|
||||
void eventProcess(const Events& events) override;
|
||||
void eventDraw(Canvas& canvas) override;
|
||||
|
|
@ -54,7 +54,7 @@ namespace tp {
|
|||
void calculateHeaderAreas();
|
||||
|
||||
bool isSideVisible(Side side);
|
||||
bool sideExists(DockLayoutWidget::Side side);
|
||||
bool sideExists(DockWidget::Side side);
|
||||
ualni getVisibleSidesSize();
|
||||
void handlePreview(const Events& events);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace tp {
|
|||
void eventProcess(const Events& events) override;
|
||||
|
||||
protected:
|
||||
DockLayoutWidget mDockSpace;
|
||||
DockWidget mDockSpace;
|
||||
FloatingLayoutWidget mFloatingLayer;
|
||||
|
||||
// Parameters
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include "RootWidget.hpp"
|
||||
#include "AnimationTestWidget.hpp"
|
||||
#include "FloatingWidget.hpp"
|
||||
#include "DockLayoutWidget.hpp"
|
||||
#include "DockWidget.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ public:
|
|||
mDockLayout.addChild(&mFloatingMenu);
|
||||
|
||||
mDockLayout.setCenterWidget(&mButton5);
|
||||
mDockLayout.dockWidget(&mButton6, DockLayoutWidget::RIGHT);
|
||||
mDockLayout.dockWidget(&mButton6, DockLayout::RIGHT);
|
||||
|
||||
mFloatingMenu.addToMenu(&mButton);
|
||||
mFloatingMenu2.addToMenu(&mButton2);
|
||||
|
|
@ -42,8 +42,8 @@ public:
|
|||
mButton.setAction([this]() { mButton2.setColor(RGBA::random()); });
|
||||
mButton2.setAction([this]() { mButton.setColor(RGBA::random()); });
|
||||
|
||||
mButton5.setAction([this]() { mDockLayout.dockWidget(&mFloatingMenu, DockLayoutWidget::Side::LEFT); });
|
||||
mButton6.setAction([this]() { mDockLayout.undockWidget(DockLayoutWidget::Side::LEFT); });
|
||||
mButton5.setAction([this]() { mDockLayout.dockWidget(&mFloatingMenu, DockLayout::LEFT); });
|
||||
mButton6.setAction([this]() { mDockLayout.undockWidget(DockLayout::LEFT); });
|
||||
|
||||
mButton5.setText("dock");
|
||||
mButton6.setText("undock");
|
||||
|
|
@ -94,10 +94,10 @@ public:
|
|||
mButton3.setSizePolicy(SizePolicy::Expanding, SizePolicy::Minimal);
|
||||
|
||||
mWidget.setSizePolicy(SizePolicy::Minimal, SizePolicy::Minimal);
|
||||
mWidget.setLayoutPolicy(LayoutPolicy::Horizontal);
|
||||
// mWidget.setLayoutPolicy(LayoutPolicy::Horizontal);
|
||||
|
||||
mButton.setAction([this]() { mButton2.setMinSize(mButton2.getMinSize() + 10); });
|
||||
mButton2.setAction([this]() { mButton.setMinSize(mButton.getMinSize() + 10); } );
|
||||
// mButton.setAction([this]() { mButton2.setMinSize(mButton2.getMinSize() + 10); });
|
||||
// mButton2.setAction([this]() { mButton.setMinSize(mButton.getMinSize() + 10); } );
|
||||
|
||||
RootWidget::setWidgetArea(mWidget, { 400, 100, 150, 200 });
|
||||
}
|
||||
|
|
@ -135,7 +135,7 @@ private:
|
|||
FloatingWidget mWidgetFloating;
|
||||
AnimationTestWidget mAnimationTestWidget;
|
||||
|
||||
DockLayoutWidget mDockLayout;
|
||||
DockWidget mDockLayout;
|
||||
|
||||
RootWidget mRootWidget;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,99 +1,23 @@
|
|||
#include "DockLayoutWidget.hpp"
|
||||
#include "FloatingWidget.hpp"
|
||||
#include "DockLayout.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
DockLayoutWidget::DockLayoutWidget() {
|
||||
DockLayout::DockLayout(Widget* widget) :
|
||||
WidgetLayout(widget) {
|
||||
mSideWidgets[0].side = LEFT;
|
||||
mSideWidgets[1].side = TOP;
|
||||
mSideWidgets[2].side = RIGHT;
|
||||
mSideWidgets[3].side = BOTTOM;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::process(const EventHandler& events) {
|
||||
// calculateHeaderAreas();
|
||||
|
||||
Widget* floater = nullptr;
|
||||
for (auto child : mChildren) {
|
||||
if (auto iter = dynamic_cast<FloatingWidget*>(child)) {
|
||||
if (iter->isFloating()) {
|
||||
floater = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (floater) undockWidget(getSideFromWidget(floater), false);
|
||||
|
||||
if (floater) {
|
||||
handlePreview(events);
|
||||
}
|
||||
|
||||
if (mPreviewWidget && !floater) {
|
||||
dockWidget(mPreviewWidget, mPreviewSide);
|
||||
}
|
||||
|
||||
mPreviewWidget = floater;
|
||||
|
||||
if (!mPreviewWidget) {
|
||||
handleResizeEvents(events);
|
||||
}
|
||||
}
|
||||
|
||||
void DockLayoutWidget::draw(Canvas& canvas) {
|
||||
canvas.rect(getRelativeArea(), mBackgroundColor, 0);
|
||||
}
|
||||
|
||||
void DockLayoutWidget::drawOverlay(Canvas& canvas) {
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (!isSideVisible(sideWidget.side)) continue;
|
||||
auto& handle = sideWidget.resizeHandle;
|
||||
|
||||
if (handle.active) {
|
||||
canvas.rect(handle.area.shrink(mPadding / 1.5f), mResizeHandleColorActive, 0);
|
||||
} else if (handle.hover) {
|
||||
canvas.rect(handle.area.shrink(mPadding / 1.5f), mResizeHandleColorHovered, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (!isSideVisible(sideWidget.side)) continue;
|
||||
canvas.rect(sideWidget.headerArea, mResizeHandleColorActive, 0);
|
||||
}
|
||||
|
||||
if (mPreviewWidget) {
|
||||
if (mPreviewSide != NONE) canvas.rect(mPreviewArea.shrink(mPadding * 2), mPreviewColor, mRounding);
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (sideWidget.widget) continue;
|
||||
canvas.rect(sideWidget.previewHandleArea, mPreviewColor, mRounding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DockLayoutWidget::propagateEventsToChildren() const {
|
||||
return !mResizing;
|
||||
}
|
||||
|
||||
bool DockLayoutWidget::needsNextFrame() const {
|
||||
return Widget::needsNextFrame() || mResizing;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::setCenterWidget(Widget* widget) {
|
||||
bool DockLayout::setCenterWidget(Widget* widget) {
|
||||
if (mCenterWidget) return false;
|
||||
mCenterWidget = widget;
|
||||
addChild(widget);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::dockWidget(Widget* widget, Side side) {
|
||||
if (sideExists(side) || side == Side::NONE) return;
|
||||
|
||||
addChild(widget);
|
||||
|
||||
widget->bringToBack();
|
||||
if (mCenterWidget) mCenterWidget->bringToBack();
|
||||
for (auto& order : mSideWidgets) {
|
||||
if (order.widget) order.widget->bringToBack();
|
||||
}
|
||||
bool DockLayout::dockWidget(Widget* widget, Side side) {
|
||||
if (sideExists(side) || side == Side::NONE) return false;
|
||||
|
||||
auto& sideWidget = mSideWidgets[side];
|
||||
sideWidget.widget = widget;
|
||||
|
|
@ -107,20 +31,12 @@ void DockLayoutWidget::dockWidget(Widget* widget, Side side) {
|
|||
|
||||
sideWidget.hidden = false;
|
||||
sideWidget.areaBeforeDocking = widget->getArea();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::undockWidget(Side side, bool restoreArea) {
|
||||
if (!sideExists(side) || (side == Side::NONE)) return;
|
||||
|
||||
auto& sideWidget = mSideWidgets[side];
|
||||
|
||||
sideWidget.widget->bringToFront();
|
||||
|
||||
if (restoreArea) {
|
||||
sideWidget.widget->setArea(sideWidget.areaBeforeDocking);
|
||||
} else {
|
||||
sideWidget.widget->endAnimations();
|
||||
}
|
||||
bool DockLayout::undockWidget(Side side) {
|
||||
if (!sideExists(side) || (side == Side::NONE)) return false;
|
||||
|
||||
bool removed = false;
|
||||
for (ualni i = 0; i < 3; i++) {
|
||||
|
|
@ -132,17 +48,18 @@ void DockLayoutWidget::undockWidget(Side side, bool restoreArea) {
|
|||
}
|
||||
}
|
||||
mSideWidgets[3].order = -1;
|
||||
|
||||
mSideWidgets[side].widget = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::toggleWidgetVisibility(Side side) {
|
||||
void DockLayout::toggleWidgetVisibility(Side side) {
|
||||
DEBUG_ASSERT(sideExists(side))
|
||||
mSideWidgets[side].hidden = !mSideWidgets[side].hidden;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::calculateSideAreas() {
|
||||
auto startArea = getRelativeAreaCache();
|
||||
void DockLayout::calculateSideAreas() {
|
||||
auto startArea = getArea().relative();
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
const auto side = sideWidget.order;
|
||||
|
|
@ -177,9 +94,9 @@ void DockLayoutWidget::calculateSideAreas() {
|
|||
mCenterArea = startArea.shrink(mPadding);
|
||||
}
|
||||
|
||||
void DockLayoutWidget::calculateResizeHandles() {
|
||||
void DockLayout::calculateResizeHandles() {
|
||||
RectF rec;
|
||||
RectF area = getRelativeArea();
|
||||
RectF area = getArea().relative();
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
auto& sideSize = sideWidget.absoluteSize;
|
||||
|
|
@ -224,80 +141,23 @@ void DockLayoutWidget::calculateResizeHandles() {
|
|||
}
|
||||
}
|
||||
|
||||
void DockLayoutWidget::handleResizeEvents(const EventHandler& events) {
|
||||
auto pointer = events.getPointer();
|
||||
auto pointerDelta = events.getPointerDelta();
|
||||
void DockLayout::updateChildSideWidgets() {
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (!sideExists(Side(i))) continue;
|
||||
auto widget = mSideWidgets[i].widget;
|
||||
|
||||
// check triggers
|
||||
if (events.isReleased(InputID::MOUSE1)) {
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
sideWidget.resizeHandle.active = false;
|
||||
}
|
||||
|
||||
mResizing = false;
|
||||
} else {
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
sideWidget.resizeHandle.hover = sideWidget.resizeHandle.area.isInside(pointer);
|
||||
if (sideWidget.resizeHandle.hover && events.isPressed(InputID::MOUSE1)) {
|
||||
sideWidget.resizeHandle.active = true;
|
||||
|
||||
mResizing = true;
|
||||
triggerWidgetUpdate("new docked child");
|
||||
}
|
||||
if (!isSideVisible(Side(i))) {
|
||||
// FIXME : widget->mEnable = false;
|
||||
} else {
|
||||
widget->setAreaCache(mSideWidgets[i].area);
|
||||
// FIXME : widget->mEnable = true;
|
||||
}
|
||||
}
|
||||
|
||||
// do the resizing
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (!sideWidget.resizeHandle.active) continue;
|
||||
|
||||
halnf delta = pointerDelta[(sideWidget.side == TOP || sideWidget.side == BOTTOM)];
|
||||
|
||||
if (sideWidget.side == BOTTOM || sideWidget.side == RIGHT) {
|
||||
delta *= -1;
|
||||
}
|
||||
|
||||
sideWidget.absoluteSize += delta;
|
||||
}
|
||||
if (mCenterWidget) mCenterWidget->setAreaCache(mCenterArea);
|
||||
}
|
||||
|
||||
void DockLayoutWidget::updateChildSideWidgets() {
|
||||
// Update Child Widgets
|
||||
{
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (!sideExists(Side(i))) continue;
|
||||
auto widget = mSideWidgets[i].widget;
|
||||
|
||||
if (!isSideVisible(Side(i))) {
|
||||
// widget->mEnable = false;
|
||||
} else {
|
||||
widget->setAreaCache(mSideWidgets[i].area);
|
||||
// widget->mEnable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mCenterWidget) mCenterWidget->setAreaCache(mCenterArea);
|
||||
}
|
||||
|
||||
// update depth order
|
||||
/*
|
||||
if (mChildWidgets.size() > 1) {
|
||||
for (auto sideChild : mSideWidgets) {
|
||||
if (!sideChild) continue;
|
||||
|
||||
for (auto childNode = mChildWidgets.firstNode(); childNode; childNode = childNode->next) {
|
||||
if (childNode->data == sideChild) {
|
||||
mChildWidgets.detach(childNode);
|
||||
mChildWidgets.pushBack(childNode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void DockLayoutWidget::calculateHeaderAreas() {
|
||||
void DockLayout::calculateHeaderAreas() {
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (!isSideVisible(Side(i))) continue;
|
||||
auto& area = mSideWidgets[i].area;
|
||||
|
|
@ -309,15 +169,7 @@ void DockLayoutWidget::calculateHeaderAreas() {
|
|||
}
|
||||
}
|
||||
|
||||
bool DockLayoutWidget::isSideVisible(DockLayoutWidget::Side side) {
|
||||
return sideExists(side) && !mSideWidgets[side].hidden;
|
||||
}
|
||||
|
||||
bool DockLayoutWidget::sideExists(DockLayoutWidget::Side side) {
|
||||
return mSideWidgets[side].widget;
|
||||
}
|
||||
|
||||
ualni DockLayoutWidget::getVisibleSidesSize() {
|
||||
ualni DockLayout::getVisibleSidesSize() {
|
||||
ualni out = 0;
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (isSideVisible(Side(i))) out++;
|
||||
|
|
@ -325,20 +177,30 @@ ualni DockLayoutWidget::getVisibleSidesSize() {
|
|||
return out;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::handlePreview(const EventHandler& events) {
|
||||
const halnf factor = 0.3;
|
||||
const halnf handleFactor = 0.1;
|
||||
auto DockLayout::getSideFromWidget(Widget* widget) -> Side {
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (sideWidget.widget == widget) return sideWidget.side;
|
||||
}
|
||||
return DockLayout::NONE;
|
||||
}
|
||||
|
||||
const auto handleSize = min(mCenterArea.size.x, mCenterArea.size.y) * handleFactor;
|
||||
void DockLayout::adjustChildrenRect() {
|
||||
calculateSideAreas();
|
||||
calculateResizeHandles();
|
||||
updateChildSideWidgets();
|
||||
}
|
||||
|
||||
void DockLayout::updatePreviewSide(const Vec2F& pointer) {
|
||||
const auto handleSize = min(mCenterArea.size.x, mCenterArea.size.y) * mHandleFactor;
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (sideWidget.widget) continue;
|
||||
|
||||
switch (sideWidget.side) {
|
||||
case TOP: sideWidget.area = mCenterArea.splitByFactorVT(factor); break;
|
||||
case BOTTOM: sideWidget.area = mCenterArea.splitByFactorVB(1 - factor); break;
|
||||
case LEFT: sideWidget.area = mCenterArea.splitByFactorHL(factor); break;
|
||||
case RIGHT: sideWidget.area = mCenterArea.splitByFactorHR(1 - factor); break;
|
||||
case TOP: sideWidget.area = mCenterArea.splitByFactorVT(mHandleSplitFactor); break;
|
||||
case BOTTOM: sideWidget.area = mCenterArea.splitByFactorVB(1 - mHandleSplitFactor); break;
|
||||
case LEFT: sideWidget.area = mCenterArea.splitByFactorHL(mHandleSplitFactor); break;
|
||||
case RIGHT: sideWidget.area = mCenterArea.splitByFactorHR(1 - mHandleSplitFactor); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
|
@ -352,22 +214,68 @@ void DockLayoutWidget::handlePreview(const EventHandler& events) {
|
|||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (sideWidget.widget) continue;
|
||||
|
||||
if (sideWidget.previewHandleArea.isInside(events.getPointer())) {
|
||||
if (sideWidget.previewHandleArea.isInside(pointer)) {
|
||||
mPreviewArea = sideWidget.area;
|
||||
mPreviewSide = sideWidget.side;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto DockLayoutWidget::getSideFromWidget(Widget* widget) -> Side {
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (sideWidget.widget == widget) return sideWidget.side;
|
||||
}
|
||||
return DockLayoutWidget::NONE;
|
||||
DockLayout::Side DockLayout::getPreviewSide() {
|
||||
return mPreviewSide;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::adjustChildrenRect() {
|
||||
calculateSideAreas();
|
||||
calculateResizeHandles();
|
||||
updateChildSideWidgets();
|
||||
void DockLayout::updateResizeHover(const Vec2F& pointer) {
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
sideWidget.resizeHandle.hover = sideWidget.resizeHandle.area.isInside(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
void DockLayout::updateResize(const Vec2F& pointerDelta) {
|
||||
if (!mResizing) return;
|
||||
|
||||
// do the resizing
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (!sideWidget.resizeHandle.active) continue;
|
||||
halnf delta = pointerDelta[(sideWidget.side == TOP || sideWidget.side == BOTTOM)];
|
||||
if (sideWidget.side == BOTTOM || sideWidget.side == RIGHT) {
|
||||
delta *= -1;
|
||||
}
|
||||
sideWidget.absoluteSize += delta;
|
||||
}
|
||||
}
|
||||
|
||||
bool DockLayout::startResize(const Vec2F& pointer) {
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (sideWidget.resizeHandle.hover) {
|
||||
sideWidget.resizeHandle.active = true;
|
||||
mResizing = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DockLayout::endResize() {
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
sideWidget.resizeHandle.active = false;
|
||||
}
|
||||
mResizing = false;
|
||||
}
|
||||
|
||||
bool DockLayout::isSideVisible(DockLayout::Side side) const {
|
||||
return sideExists(side) && !mSideWidgets[side].hidden;
|
||||
}
|
||||
|
||||
bool DockLayout::sideExists(DockLayout::Side side) const {
|
||||
return mSideWidgets[side].widget;
|
||||
}
|
||||
|
||||
const std::vector<Widget*>& DockLayout::getDockedWidgets() {
|
||||
mDockedWidgets.resize(5);
|
||||
for (auto i = 0; i < 4; i++) {
|
||||
mDockedWidgets[i] = mSideWidgets[i].widget;
|
||||
}
|
||||
mDockedWidgets[4] = mCenterWidget;
|
||||
return mDockedWidgets;
|
||||
}
|
||||
131
WidgetsNew/private/DockWidget.cpp
Normal file
131
WidgetsNew/private/DockWidget.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#include "DockWidget.hpp"
|
||||
#include "FloatingWidget.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
DockWidget::DockWidget() {
|
||||
setLayout(new DockLayout(this));
|
||||
}
|
||||
|
||||
void DockWidget::dockWidget(Widget* widget, DockLayout::Side side) {
|
||||
if (layout()->dockWidget(widget, side)) {
|
||||
addChild(widget);
|
||||
|
||||
for (auto child : layout()->getDockedWidgets()) {
|
||||
if (child) child->bringToBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidget::undockWidget(DockLayout::Side side, bool restoreArea) {
|
||||
if (layout()->sideExists(side) && side != DockLayout::NONE) {
|
||||
auto widget = layout()->getSideWidget(side);
|
||||
|
||||
widget->bringToFront();
|
||||
if (restoreArea) {
|
||||
widget->setArea(layout()->getRectBeforeDocked(side));
|
||||
} else {
|
||||
// FIXME : widget->endAnimations();
|
||||
}
|
||||
|
||||
layout()->undockWidget(side);
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidget::setCenterWidget(Widget* widget) {
|
||||
if (layout()->setCenterWidget(widget)) {
|
||||
addChild(widget);
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidget::toggleWidgetVisibility(DockLayout::Side side) {
|
||||
layout()->toggleWidgetVisibility(side);
|
||||
}
|
||||
|
||||
void DockWidget::process(const EventHandler& events) {
|
||||
// calculateHeaderAreas();
|
||||
|
||||
Widget* floater = nullptr;
|
||||
for (auto child : mChildren) {
|
||||
if (auto iter = dynamic_cast<FloatingWidget*>(child)) {
|
||||
if (iter->isFloating()) {
|
||||
floater = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (floater) undockWidget(layout()->getSideFromWidget(floater), false);
|
||||
|
||||
if (floater) {
|
||||
layout()->updatePreviewSide(events.getPointer());
|
||||
}
|
||||
|
||||
if (mPreviewWidget && !floater) {
|
||||
dockWidget(mPreviewWidget, layout()->getPreviewSide());
|
||||
}
|
||||
|
||||
mPreviewWidget = floater;
|
||||
|
||||
if (!mPreviewWidget) {
|
||||
layout()->updateResizeHover(events.getPointer());
|
||||
|
||||
if (events.isPressed(InputID::MOUSE1)) {
|
||||
if (layout()->startResize(events.getPointer())) {
|
||||
triggerWidgetUpdate("dock layout resizing");
|
||||
}
|
||||
} else if (events.isReleased(InputID::MOUSE1)) {
|
||||
layout()->endResize();
|
||||
}
|
||||
|
||||
if (layout()->isResizing()) {
|
||||
layout()->updateResize(events.getPointerDelta());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DockWidget::propagateEventsToChildren() const {
|
||||
return !layout()->isResizing();
|
||||
}
|
||||
|
||||
bool DockWidget::needsNextFrame() const {
|
||||
return Widget::needsNextFrame() || layout()->isResizing();
|
||||
}
|
||||
|
||||
void DockWidget::draw(Canvas& canvas) {
|
||||
canvas.rect(getRelativeArea(), mBackgroundColor, 0);
|
||||
}
|
||||
|
||||
void DockWidget::drawSide(DockLayout::Side side, tp::Canvas& canvas) {
|
||||
auto lay = layout();
|
||||
|
||||
if (lay->isSideVisible(side)) {
|
||||
// header
|
||||
canvas.rect(lay->getHeaderArea(side), mResizeHandleColorActive, 0);
|
||||
|
||||
// resize
|
||||
if (lay->isResizing(side)) {
|
||||
canvas.rect(lay->getResizeHandleArea(side).shrink(mPadding / 1.5f), mResizeHandleColorActive, 0);
|
||||
} else if (lay->isResizeHandleHover(side)) {
|
||||
canvas.rect(lay->getResizeHandleArea(side).shrink(mPadding / 1.5f), mResizeHandleColorHovered, 0);
|
||||
}
|
||||
|
||||
} else {
|
||||
// preview handles
|
||||
if (mPreviewWidget) {
|
||||
// preview active
|
||||
if (lay->getPreviewSide() == side) {
|
||||
canvas.rect(lay->getPreviewArea().shrink(mPadding * 2), mPreviewColor, mRounding);
|
||||
} else {
|
||||
canvas.rect(lay->getPreviewHandleArea(side), mPreviewColor, mRounding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidget::drawOverlay(Canvas& canvas) {
|
||||
drawSide(DockLayout::Side::LEFT, canvas);
|
||||
drawSide(DockLayout::Side::RIGHT, canvas);
|
||||
drawSide(DockLayout::Side::TOP, canvas);
|
||||
drawSide(DockLayout::Side::BOTTOM, canvas);
|
||||
}
|
||||
52
WidgetsNew/private/FloatingLayout.cpp
Normal file
52
WidgetsNew/private/FloatingLayout.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#include "FloatingLayout.hpp"
|
||||
#include "Widget.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
void FloatingLayout::pickRect() {
|
||||
if (mIsFloating) {
|
||||
auto area = getArea();
|
||||
|
||||
if (mIsResizing) {
|
||||
mPointerCurrent.clamp(mMinSize, mMaxSize);
|
||||
|
||||
area.size = mPointerCurrent + mHandleSize / 2.f;
|
||||
|
||||
for (auto child : children()) {
|
||||
child->triggerWidgetUpdate("floating menu resized");
|
||||
}
|
||||
|
||||
} else if (mIsFloating) {
|
||||
area.pos += mPointerCurrent - mPointerStart;
|
||||
}
|
||||
|
||||
setArea(area);
|
||||
}
|
||||
|
||||
clampMinMaxSize();
|
||||
}
|
||||
|
||||
RectF FloatingLayout::resizeHandleRect() {
|
||||
auto area = getAnimatedArea().relative();
|
||||
area.pos = area.p3() - mHandleSize;
|
||||
area.size = mHandleSize;
|
||||
area.shrink(mHandlePadding);
|
||||
return area;
|
||||
}
|
||||
|
||||
void FloatingLayout::startAction(const Vec2F& pointer) {
|
||||
mPointerStart = pointer;
|
||||
|
||||
mIsFloating = true;
|
||||
if (resizeHandleRect().isInside(mPointerStart)) {
|
||||
mIsResizing = true;
|
||||
}
|
||||
}
|
||||
|
||||
void FloatingLayout::updateAction(const Vec2F& pointer) {
|
||||
mPointerCurrent = pointer;
|
||||
}
|
||||
|
||||
void FloatingLayout::endAction() {
|
||||
mIsResizing = mIsFloating = false;
|
||||
}
|
||||
|
|
@ -3,76 +3,39 @@
|
|||
using namespace tp;
|
||||
|
||||
void FloatingWidget::process(const EventHandler& events) {
|
||||
const auto relativePointer = events.getPointer();
|
||||
|
||||
bool inside = getRelativeAreaT().isInside(relativePointer);
|
||||
|
||||
if (inside && events.isPressed(InputID::MOUSE1)) {
|
||||
mPointerStart = relativePointer;
|
||||
mIsFloating = true;
|
||||
|
||||
if (resizeHandleRect().isInside(relativePointer)) {
|
||||
mIsResizing = true;
|
||||
}
|
||||
const auto pointer = events.getPointer();
|
||||
|
||||
if (getRelativeAreaT().isInside(pointer) && events.isPressed(InputID::MOUSE1)) {
|
||||
layout()->startAction(pointer);
|
||||
bringToFront();
|
||||
}
|
||||
|
||||
|
||||
if (mIsFloating && events.isReleased(InputID::MOUSE1)) {
|
||||
mIsFloating = false;
|
||||
mIsResizing = false;
|
||||
if (layout()->isFloating() && events.isReleased(InputID::MOUSE1)) {
|
||||
layout()->endAction();
|
||||
}
|
||||
|
||||
mPointerCurrent = relativePointer;
|
||||
|
||||
// triggerWidgetUpdate();
|
||||
}
|
||||
|
||||
void FloatingWidget::pickRect() {
|
||||
if (mIsFloating) {
|
||||
auto area = getAreaCache();
|
||||
|
||||
if (mIsResizing) {
|
||||
mPointerCurrent.clamp(mMinSize, mMaxSize);
|
||||
|
||||
area.size = mPointerCurrent + mHandleSize / 2.f;
|
||||
|
||||
for (auto child : mChildren) {
|
||||
child->triggerWidgetUpdate("floating menu resized");
|
||||
}
|
||||
|
||||
} else if (mIsFloating) {
|
||||
area.pos += mPointerCurrent - mPointerStart;
|
||||
}
|
||||
|
||||
setAreaCache(area);
|
||||
}
|
||||
|
||||
clampMinMaxSize();
|
||||
layout()->updateAction(pointer);
|
||||
}
|
||||
|
||||
void FloatingWidget::draw(Canvas& canvas) {
|
||||
canvas.rect(resizeHandleRect(), RGBA(0.7f), 2);
|
||||
canvas.rect(layout()->resizeHandleRect(), RGBA(0.7f), 2);
|
||||
canvas.rect(getRelativeArea(), RGBA(0.5f), 10);
|
||||
}
|
||||
|
||||
RectF FloatingWidget::resizeHandleRect() {
|
||||
auto area = getRelativeArea();
|
||||
area.pos = area.p3() - mHandleSize;
|
||||
area.size = mHandleSize;
|
||||
area.shrink(mHandlePadding);
|
||||
return area;
|
||||
}
|
||||
|
||||
bool FloatingWidget::propagateEventsToChildren() const {
|
||||
return !mIsFloating;
|
||||
return !layout()->isFloating();
|
||||
}
|
||||
|
||||
bool FloatingWidget::isFloating() const {
|
||||
return mIsFloating;
|
||||
return layout()->isFloating();
|
||||
}
|
||||
|
||||
bool FloatingWidget::needsNextFrame() const {
|
||||
return Widget::needsNextFrame() || isFloating();
|
||||
}
|
||||
|
||||
FloatingLayout* FloatingWidget::layout() { return dynamic_cast<FloatingLayout*>(Widget::getLayout()); }
|
||||
|
||||
const FloatingLayout* FloatingWidget::layout() const {
|
||||
return dynamic_cast<const FloatingLayout*>(Widget::getLayout());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
#include <algorithm>
|
||||
#include "LayoutPolicies.hpp"
|
||||
#include "LayoutManager.hpp"
|
||||
|
||||
#include "Widget.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
const RectF& WidgetLayout::getArea() const {
|
||||
return mWidget->getAreaCache();
|
||||
return mWidget->mAreaCache;
|
||||
}
|
||||
|
||||
RectF WidgetLayout::getAnimatedArea() const {
|
||||
return mWidget->getArea();
|
||||
}
|
||||
|
||||
void WidgetLayout::setArea(const RectF& area) {
|
||||
|
|
@ -17,9 +21,79 @@ Widget* WidgetLayout::parent() const { return mWidget->mParent; }
|
|||
|
||||
const std::vector<Widget*>& WidgetLayout::children() const { return mWidget->mChildren; }
|
||||
|
||||
const Vec2F& BasicLayout::getMinSize() { return mMinSize; }
|
||||
const Vec2F& WidgetLayout::getMinSize() { return mMinSize; }
|
||||
|
||||
void BasicLayout::setMinSize(const Vec2F& size) { mMinSize = size; }
|
||||
void WidgetLayout::setMinSize(const Vec2F& size) { mMinSize = size; }
|
||||
|
||||
const Vec2<SizePolicy>& WidgetLayout::getSizePolicy() const { return mSizePolicy; }
|
||||
|
||||
void WidgetLayout::setSizePolicy(SizePolicy x, SizePolicy y) { mSizePolicy = { x, y }; }
|
||||
|
||||
RangeF WidgetLayout::pickRange(const RangeF& current, const RangeF& children, const RangeF& parent, bool vertical) const {
|
||||
RangeF out;
|
||||
|
||||
switch (mSizePolicy[vertical]) {
|
||||
case SizePolicy::Fixed: out = current; break;
|
||||
case SizePolicy::Expanding: out = parent; break;
|
||||
case SizePolicy::Minimal: out = children; break;
|
||||
}
|
||||
|
||||
out = clampRange(out, children, parent, vertical);
|
||||
return out;
|
||||
}
|
||||
|
||||
void WidgetLayout::clampMinMaxSize() {
|
||||
auto current = getArea();
|
||||
current.size.clamp(mMinSize, mMaxSize);
|
||||
setArea(current);
|
||||
}
|
||||
|
||||
RangeF WidgetLayout::clampRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool vertical) const {
|
||||
auto out = current;
|
||||
|
||||
if (!children().empty()) {
|
||||
auto clampedChild = child;
|
||||
clampedChild.clamp(parent);
|
||||
out.clamp(clampedChild, parent);
|
||||
} else {
|
||||
out.clamp(parent);
|
||||
}
|
||||
|
||||
// clamp min max sizes
|
||||
auto len = clamp(current.size(), mMinSize[vertical], mMaxSize[vertical]);
|
||||
if (len != current.size()) {
|
||||
out.resizeFromCenter(len);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
RectF WidgetLayout::getChildrenEnclosure() const {
|
||||
RectF out;
|
||||
|
||||
if (children().empty()) {
|
||||
out = { getArea().center(), { 0, 0 } };
|
||||
} else {
|
||||
out = children().front()->getLayout()->getArea();
|
||||
for (auto child : children()) {
|
||||
out.expand(child->getLayout()->getArea());
|
||||
}
|
||||
out.pos += getArea().pos;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
RectF WidgetLayout::getAvailableChildArea() const {
|
||||
return getArea().relative();
|
||||
}
|
||||
|
||||
RectF WidgetLayout::getParentEnclosure() const {
|
||||
DEBUG_ASSERT(parent())
|
||||
if (!parent()) return { { 0, 0 }, mMaxSize };
|
||||
auto out = parent()->getLayout()->getAvailableChildArea();
|
||||
return out;
|
||||
}
|
||||
|
||||
void BasicLayout::pickRect() {
|
||||
auto current = getArea();
|
||||
|
|
@ -57,16 +131,15 @@ void BasicLayout::adjustChildrenRect() {
|
|||
|
||||
|
||||
halnf BasicLayout::changeChildSize(tp::Widget* widget, halnf diff, bool vertical) {
|
||||
auto prevSize = widget->getAreaCache().size[vertical];
|
||||
auto prevSize = widget->getLayout()->getArea().size[vertical];
|
||||
{
|
||||
auto area = widget->getAreaCache();
|
||||
auto area = widget->getLayout()->getArea();
|
||||
area.size[vertical] += diff;
|
||||
widget->setAreaCache(area);
|
||||
|
||||
// FIXME : widget->clampMinMaxSize();
|
||||
widget->getLayout()->clampMinMaxSize();
|
||||
}
|
||||
auto newSize = widget->getAreaCache().size[vertical];
|
||||
|
||||
auto newSize = widget->getLayout()->getArea().size[vertical];
|
||||
return newSize - prevSize;
|
||||
}
|
||||
|
||||
|
|
@ -76,22 +149,20 @@ void BasicLayout::adjustLayout(bool vertical) {
|
|||
Vec2F availableSize = getArea().size;
|
||||
|
||||
for (auto child : children()) {
|
||||
// FIXME :
|
||||
if (child->getLayout()->getSizePolicy()[!vertical] != SizePolicy::Minimal) {
|
||||
child->getLayout()->pickRect();
|
||||
}
|
||||
|
||||
// if (child->mSizePolicy[!vertical] != SizePolicy::Minimal) {
|
||||
// child->pickRect();
|
||||
// }
|
||||
|
||||
// if (child->mSizePolicy[vertical] == SizePolicy::Expanding) {
|
||||
if (child->getLayout()->getSizePolicy()[vertical] == SizePolicy::Expanding) {
|
||||
contributors.emplace_back( child, true );
|
||||
|
||||
auto area = child->getAreaCache();
|
||||
auto area = child->getLayout()->getArea();
|
||||
area.size[vertical] = 0;
|
||||
child->setAreaCache(area);
|
||||
// child->clampRect();
|
||||
child->getLayout()->clampRect();
|
||||
}
|
||||
|
||||
//}
|
||||
contentSize += child->getAreaCache().size;
|
||||
contentSize += child->getLayout()->getArea().size;
|
||||
}
|
||||
|
||||
availableSize -= mLayoutGap * ((halnf) children().size() - 1) + mLayoutMargin * 2;
|
||||
|
|
@ -124,7 +195,7 @@ void BasicLayout::adjustLayout(bool vertical) {
|
|||
// arrange
|
||||
halnf iterPos = mLayoutMargin;
|
||||
for (auto child : children()) {
|
||||
auto area = child->getAreaCache();
|
||||
auto area = child->getLayout()->getArea();
|
||||
area.pos[vertical] = iterPos;
|
||||
iterPos += area.size[vertical] + mLayoutGap;
|
||||
child->setAreaCache(area);
|
||||
|
|
@ -135,72 +206,19 @@ void BasicLayout::adjustLayout(bool vertical) {
|
|||
}
|
||||
}
|
||||
|
||||
RangeF BasicLayout::pickRange(const RangeF& current, const RangeF& children, const RangeF& parent, bool vertical) const {
|
||||
RangeF out;
|
||||
|
||||
switch (mSizePolicy[vertical]) {
|
||||
case SizePolicy::Fixed: out = current; break;
|
||||
case SizePolicy::Expanding: out = parent; break;
|
||||
case SizePolicy::Minimal: out = children; break;
|
||||
}
|
||||
|
||||
out = clampRange(out, children, parent, vertical);
|
||||
return out;
|
||||
RectF BasicLayout::getAvailableChildArea() const {
|
||||
auto out = WidgetLayout::getAvailableChildArea();
|
||||
return out.scaleFromCenter(mLayoutMargin, true);
|
||||
}
|
||||
|
||||
void BasicLayout::clampMinMaxSize() {
|
||||
auto current = getArea();
|
||||
current.size.clamp(mMinSize, mMaxSize);
|
||||
setArea(current);
|
||||
}
|
||||
|
||||
RangeF BasicLayout::clampRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool vertical) const {
|
||||
auto out = current;
|
||||
|
||||
if (!children().empty()) {
|
||||
auto clampedChild = child;
|
||||
clampedChild.clamp(parent);
|
||||
out.clamp(clampedChild, parent);
|
||||
} else {
|
||||
out.clamp(parent);
|
||||
}
|
||||
|
||||
// clamp min max sizes
|
||||
auto len = clamp(current.size(), mMinSize[vertical], mMaxSize[vertical]);
|
||||
if (len != current.size()) {
|
||||
out.resizeFromCenter(len);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
RectF BasicLayout::getChildrenEnclosure() const {
|
||||
RectF out;
|
||||
|
||||
if (children().empty()) {
|
||||
out = { getArea().center(), { 0, 0 } };
|
||||
} else {
|
||||
out = children().front()->getAreaCache();
|
||||
for (auto child : children()) {
|
||||
out.expand(child->getAreaCache());
|
||||
void LayoutManager::adjust(Widget* root) {
|
||||
Widget::dfs(
|
||||
root,
|
||||
[](Widget* widget) {
|
||||
widget->getLayout()->pickRect();
|
||||
},
|
||||
[](Widget* widget) {
|
||||
widget->getLayout()->adjustChildrenRect();
|
||||
}
|
||||
out.pos += getArea().pos;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
RectF BasicLayout::getParentEnclosure() const {
|
||||
DEBUG_ASSERT(parent())
|
||||
if (!parent()) return { { 0, 0 }, mMaxSize };
|
||||
|
||||
// FIXME :
|
||||
// auto out = parent()->getRelativeAreaT();
|
||||
|
||||
// if (parent()->mLayoutPolicy != LayoutPolicy::Passive) {
|
||||
// return out.scaleFromCenter(parent()->mLayoutMargin, true);
|
||||
// }
|
||||
|
||||
// return out;
|
||||
return {};
|
||||
);
|
||||
}
|
||||
|
|
@ -26,10 +26,8 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) {
|
|||
// construct hierarchy tree of widgets to process
|
||||
updateTreeToProcess();
|
||||
|
||||
auto root = mWidgetsToProcess.find(mRoot) == mWidgetsToProcess.end() ? nullptr : &mWidgetsToProcess[mRoot];
|
||||
|
||||
// update active tree animations
|
||||
updateAnimations(root);
|
||||
updateAnimations();
|
||||
updateAreaCache(mRoot, true);
|
||||
|
||||
// update all events and call all event processing callbacks
|
||||
events->setEnableKeyEvents(true);
|
||||
|
|
@ -38,14 +36,14 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) {
|
|||
|
||||
events->setEnableKeyEvents(false);
|
||||
events->setCursorOrigin({ 0, 0 });
|
||||
processActiveTree(root, *events, { 0, 0 });
|
||||
processActiveTree(mRoot, *events, { 0, 0 });
|
||||
|
||||
updateAreaCache(root, true);
|
||||
updateAreaCache(mRoot, true);
|
||||
|
||||
// update widget sizes base on individual size policies
|
||||
adjustSizes(root);
|
||||
processLayout();
|
||||
|
||||
updateAreaCache(root, false);
|
||||
updateAreaCache(mRoot, false);
|
||||
|
||||
// trigger some widgets by moise pointer
|
||||
handleFocusChanges(*events);
|
||||
|
|
@ -62,7 +60,7 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) {
|
|||
auto end = !widget->needsNextFrame();
|
||||
if (end) {
|
||||
widget->endAnimations();
|
||||
widget->mTriggerReason = "del";
|
||||
widget->mDebug.triggerReason = "del";
|
||||
}
|
||||
return end;
|
||||
});
|
||||
|
|
@ -73,33 +71,33 @@ bool RootWidget::needsUpdate() const { return !mTriggeredWidgets.empty() || mDeb
|
|||
void RootWidget::debugDrawWidget(Widget* widget) {
|
||||
|
||||
ImGui::PushID(widget);
|
||||
if (ImGui::CollapsingHeader(widget->mName.c_str())) {
|
||||
if (ImGui::CollapsingHeader(widget->mDebug.id.c_str())) {
|
||||
|
||||
ImGui::Text("trigger reason: %s", widget->mTriggerReason.c_str());
|
||||
ImGui::Text("trigger reason: %s", widget->mDebug.triggerReason.c_str());
|
||||
|
||||
auto area = widget->getAreaT();
|
||||
if (ImGui::InputFloat4("rect", &area.x)) {
|
||||
widget->setArea(area);
|
||||
}
|
||||
|
||||
ImGui::InputFloat2("min size", &widget->mMinSize.x);
|
||||
ImGui::InputFloat2("max size", &widget->mMaxSize.x);
|
||||
// ImGui::InputFloat2("min size", &widget->mMinSize.x);
|
||||
// ImGui::InputFloat2("max size", &widget->mMaxSize.x);
|
||||
|
||||
int sizePolicyX = int(widget->mSizePolicy.x);
|
||||
int sizePolicyY = int(widget->mSizePolicy.y);
|
||||
int layout = int(widget->mLayoutPolicy);
|
||||
// int sizePolicyX = int(widget->mSizePolicy.x);
|
||||
// int sizePolicyY = int(widget->mSizePolicy.y);
|
||||
// int layout = int(widget->mLayoutPolicy);
|
||||
|
||||
if (ImGui::Combo("Size Policy X", &sizePolicyX, "Fixed\0Expanding\0Minimal\0")) {
|
||||
widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY));
|
||||
}
|
||||
// if (ImGui::Combo("Size Policy X", &sizePolicyX, "Fixed\0Expanding\0Minimal\0")) {
|
||||
// widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY));
|
||||
// }
|
||||
|
||||
if (ImGui::Combo("Size Policy Y", &sizePolicyY, "Fixed\0Expanding\0Minimal\0")) {
|
||||
widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY));
|
||||
}
|
||||
// if (ImGui::Combo("Size Policy Y", &sizePolicyY, "Fixed\0Expanding\0Minimal\0")) {
|
||||
// widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY));
|
||||
// }
|
||||
|
||||
if (ImGui::Combo("Layout", &layout, "Passive\0Vertical\0Horizontal\0")) {
|
||||
widget->setLayoutPolicy(LayoutPolicy(layout));
|
||||
}
|
||||
// if (ImGui::Combo("Layout", &layout, "Passive\0Vertical\0Horizontal\0")) {
|
||||
// widget->setLayoutPolicy(LayoutPolicy(layout));
|
||||
// }
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
|
@ -117,7 +115,7 @@ void RootWidget::drawFrame(Canvas& canvas) {
|
|||
drawDebug(canvas, mRoot, { 0, 0 }, 0);
|
||||
|
||||
ImGui::Text("Triggered Widgets: %i", (int) mTriggeredWidgets.size());
|
||||
ImGui::Text("Widgets To Process: %i", (int) mWidgetsToProcess.size());
|
||||
ImGui::Text("Widgets To Process: %i", mDebugWidgetsToProcess);
|
||||
|
||||
ImGui::Text("To Toggle processing press k");
|
||||
ImGui::Checkbox("Stop processing", &mDebugStopProcessing);
|
||||
|
|
@ -147,17 +145,22 @@ void RootWidget::drawFrame(Canvas& canvas) {
|
|||
|
||||
|
||||
void RootWidget::updateTreeToProcess() {
|
||||
mWidgetsToProcess.clear();
|
||||
dfs(mRoot, [](Widget* widget) {
|
||||
widget->mNeedsProcessing = false;
|
||||
});
|
||||
|
||||
for (auto& [widget, flag] : mTriggeredWidgets) {
|
||||
flag = true;
|
||||
for (auto iter = widget; iter; iter = iter->mParent) {
|
||||
if (iter->mParent) {
|
||||
mWidgetsToProcess[iter->mParent].children.insert(&mWidgetsToProcess[iter]);
|
||||
mWidgetsToProcess[iter->mParent].widget= iter->mParent;
|
||||
mWidgetsToProcess[iter].widget= iter;
|
||||
}
|
||||
|
||||
for (auto iter = widget; iter && iter != this; iter = iter->mParent) {
|
||||
iter->mNeedsProcessing = true;
|
||||
}
|
||||
}
|
||||
|
||||
mDebugWidgetsToProcess = 0;
|
||||
dfs(mRoot, [this](Widget*) {
|
||||
mDebugWidgetsToProcess++;
|
||||
});
|
||||
}
|
||||
|
||||
void RootWidget::drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos) {
|
||||
|
|
@ -179,17 +182,15 @@ void RootWidget::drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos)
|
|||
void RootWidget::drawDebug(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder) {
|
||||
auto area = RectF{ pos, active->getAreaT().size };
|
||||
|
||||
auto processed = mWidgetsToProcess.find(active) != mWidgetsToProcess.end();
|
||||
|
||||
if (processed) {
|
||||
if (active->mNeedsProcessing) {
|
||||
RGBA color = { 1, 0, 0, 1};
|
||||
canvas.frame(area, color);
|
||||
canvas.text((active->mName + ":" + std::to_string(depthOrder)).c_str(), area, 22, Canvas::Align::LC, 2, color);
|
||||
canvas.text((active->mDebug.id + ":" + std::to_string(depthOrder)).c_str(), area, 22, Canvas::Align::LC, 2, color);
|
||||
}
|
||||
|
||||
if (processed || active->mInFocus) {
|
||||
canvas.circle(pos + active->mLocalPoint, 5, active->mDebugColor);
|
||||
canvas.circle(active->mGlobalPoint, 15, active->mDebugColor);
|
||||
if (active->mNeedsProcessing || active->mInFocus) {
|
||||
canvas.circle(pos + active->mDebug.pLocal, 5, active->mDebug.col);
|
||||
canvas.circle(active->mDebug.pGlobal, 15, active->mDebug.col);
|
||||
}
|
||||
|
||||
if (active->mInFocus) {
|
||||
|
|
@ -208,12 +209,10 @@ void RootWidget::setWidgetArea(Widget& widget, const RectF& rect) {
|
|||
widget.mArea.endAnimation();
|
||||
}
|
||||
|
||||
void RootWidget::updateAnimations(ActiveTreeNode* iter) {
|
||||
if (!iter) return;
|
||||
iter->widget->updateAnimations();
|
||||
for (auto child : iter->children) {
|
||||
updateAnimations(child);
|
||||
}
|
||||
void RootWidget::updateAnimations() {
|
||||
dfs(mRoot, [](Widget* widget) {
|
||||
widget->updateAnimations();
|
||||
});
|
||||
}
|
||||
|
||||
void RootWidget::getWidgetPath(Widget* widget, std::vector<Widget*>& out) {
|
||||
|
|
@ -289,21 +288,21 @@ void RootWidget::findFocusWidget(Widget* iter, Widget** focus, const Vec2F& poin
|
|||
|
||||
void RootWidget::updateWidget(Widget* widget, const char* reason) {
|
||||
DEBUG_ASSERT(reason)
|
||||
widget->mTriggerReason = reason;
|
||||
widget->mDebug.triggerReason = reason;
|
||||
mTriggeredWidgets.insert({ widget, false });
|
||||
}
|
||||
|
||||
void RootWidget::updateAreaCache(ActiveTreeNode* iter, bool read) {
|
||||
if (!iter) return;
|
||||
void RootWidget::updateAreaCache(Widget* iter, bool read) {
|
||||
if (!iter || !iter->mNeedsProcessing) return;
|
||||
|
||||
if (read) {
|
||||
iter->widget->mAreaCache = iter->widget->getAreaT();
|
||||
iter->mAreaCache = iter->getAreaT();
|
||||
} else {
|
||||
iter->widget->setArea(iter->widget->mAreaCache);
|
||||
iter->widget->mArea.updateCurrentRect();
|
||||
iter->setArea(iter->mAreaCache);
|
||||
iter->mArea.updateCurrentRect();
|
||||
}
|
||||
|
||||
for (auto child : iter->widget->mChildren) {
|
||||
for (auto child : iter->mChildren) {
|
||||
if (read) {
|
||||
child->mAreaCache = child->getAreaT();
|
||||
} else {
|
||||
|
|
@ -312,37 +311,29 @@ void RootWidget::updateAreaCache(ActiveTreeNode* iter, bool read) {
|
|||
}
|
||||
}
|
||||
|
||||
for (auto child : iter->children) {
|
||||
updateAreaCache(child, read);
|
||||
for (auto child : iter->mDepthOrder) {
|
||||
updateAreaCache(child.data(), read);
|
||||
}
|
||||
}
|
||||
|
||||
void RootWidget::adjustSizes(ActiveTreeNode* iter) {
|
||||
if (!iter) return;
|
||||
|
||||
iter->widget->pickRect();
|
||||
|
||||
for (auto child : iter->children) {
|
||||
adjustSizes(child);
|
||||
}
|
||||
|
||||
iter->widget->adjustChildrenRect();
|
||||
void RootWidget::processLayout() {
|
||||
mLayoutManager.adjust(mRoot);
|
||||
}
|
||||
|
||||
void RootWidget::processActiveTree(ActiveTreeNode* iter, EventHandler& events, Vec2F parent) {
|
||||
if (!iter) return;
|
||||
void RootWidget::processActiveTree(Widget* iter, EventHandler& events, Vec2F parent) {
|
||||
if (!iter || !iter->mNeedsProcessing) return;
|
||||
|
||||
auto current = parent + iter->widget->getAreaT().pos;
|
||||
auto current = parent + iter->getAreaT().pos;
|
||||
|
||||
if (!iter->widget->mInFocus) {
|
||||
iter->widget->mGlobalPoint = current;
|
||||
if (!iter->mInFocus) {
|
||||
iter->mDebug.pGlobal = current;
|
||||
|
||||
events.setCursorOrigin(current);
|
||||
iter->widget->process(events);
|
||||
iter->process(events);
|
||||
}
|
||||
|
||||
for (auto child : iter->children) {
|
||||
processActiveTree(child, events, current);
|
||||
for (auto child : iter->mDepthOrder) {
|
||||
processActiveTree(child.data(), events, current);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -377,7 +368,7 @@ void RootWidget::processFocusItems(EventHandler& events) {
|
|||
|
||||
events.setCursorOrigin(widgetGlobalPos[iter]);
|
||||
|
||||
widget->mGlobalPoint = widgetGlobalPos[iter];
|
||||
widget->mDebug.pGlobal = widgetGlobalPos[iter];
|
||||
|
||||
if (!eventsProcessed && widget->processesEvents()) {
|
||||
events.setEnableKeyEvents(true);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Widget::~Widget() {
|
|||
delete mLayout;
|
||||
}
|
||||
|
||||
void Widget::addChild(Widget* child) {
|
||||
void Widget::addChild(Widget* child, bool front) {
|
||||
if (auto node = mDepthOrder.find(child)) {
|
||||
node->data->bringToFront();
|
||||
return;
|
||||
|
|
@ -25,7 +25,12 @@ void Widget::addChild(Widget* child) {
|
|||
}
|
||||
|
||||
mChildren.push_back(child);
|
||||
mDepthOrder.pushBack(child);
|
||||
|
||||
if (front) {
|
||||
mDepthOrder.pushFront(child);
|
||||
} else {
|
||||
mDepthOrder.pushBack(child);
|
||||
}
|
||||
|
||||
child->mParent = this;
|
||||
|
||||
|
|
@ -78,6 +83,8 @@ void Widget::setLayout(tp::WidgetLayout* layout) {
|
|||
|
||||
WidgetLayout* Widget::getLayout() { return mLayout; }
|
||||
|
||||
const WidgetLayout* Widget::getLayout() const { return mLayout; }
|
||||
|
||||
WidgetManagerInterface* Widget::getRoot() {
|
||||
Widget* iter = mParent;
|
||||
while (iter && iter->mParent) {
|
||||
|
|
@ -105,13 +112,13 @@ RectF Widget::getArea() const { return mArea.getCurrentRect(); }
|
|||
|
||||
RectF Widget::getAreaT() const { return mArea.getTargetRect(); }
|
||||
|
||||
const RectF& Widget::getAreaCache() const { return mAreaCache; }
|
||||
// const RectF& Widget::getAreaCache() const { return mAreaCache; }
|
||||
|
||||
RectF Widget::getRelativeArea() const { return { {}, mArea.getCurrentRect().size }; }
|
||||
|
||||
RectF Widget::getRelativeAreaT() const { return { {}, mArea.getTargetRect().size }; }
|
||||
|
||||
RectF Widget::getRelativeAreaCache() const { return { {}, mAreaCache.size }; }
|
||||
// RectF Widget::getRelativeAreaCache() const { return { {}, mAreaCache.size }; }
|
||||
|
||||
void Widget::setDebug(const char* name, RGBA col) {
|
||||
mDebug.id = name;
|
||||
|
|
|
|||
108
WidgetsNew/public/DockLayout.hpp
Normal file
108
WidgetsNew/public/DockLayout.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
41
WidgetsNew/public/DockWidget.hpp
Normal file
41
WidgetsNew/public/DockWidget.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
34
WidgetsNew/public/FloatingLayout.hpp
Normal file
34
WidgetsNew/public/FloatingLayout.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue