Refactor in a good state
This commit is contained in:
parent
4b6e7da994
commit
164359f6aa
21 changed files with 606 additions and 105 deletions
|
|
@ -4,17 +4,27 @@
|
|||
#include "RootWidget.hpp"
|
||||
#include "AnimationTestWidget.hpp"
|
||||
#include "FloatingWidget.hpp"
|
||||
#include "SimpleWidgets.hpp"
|
||||
#include "LayoutWidget.hpp"
|
||||
#include "DockLayoutWidget.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
class WidgetApplication : public Application {
|
||||
public:
|
||||
WidgetApplication() {
|
||||
mRootWidget.setRootWidget(&mLayoutWidget);
|
||||
mRootWidget.setRootWidget(&mDockLayout);
|
||||
|
||||
mDockLayout.addChild(&mFloatingMenu);
|
||||
mDockLayout.addChild(&mFloatingMenu2);
|
||||
|
||||
mDockLayout.setCenterWidget(&mButton3);
|
||||
mDockLayout.dockWidget(&mButton4, DockLayoutWidget::RIGHT);
|
||||
|
||||
mFloatingMenu.addToMenu(&mButton);
|
||||
mFloatingMenu2.addToMenu(&mButton2);
|
||||
|
||||
mButton.setAction([this]() { mButton2.setColor(RGBA::random()); });
|
||||
mButton2.setAction([this]() { mButton.setColor(RGBA::random()); });
|
||||
|
||||
mLayoutWidget.addChild(&mFloatingMenu);
|
||||
// mLayoutWidget.addChild(&mButton2);
|
||||
|
||||
// mWidgetFloating.addChild(&mButton);
|
||||
|
|
@ -24,8 +34,7 @@ public:
|
|||
// mAnimationTestWidget.addChild(&mWidgetFloating);
|
||||
// mAnimationTestWidget.addChild(&mLayoutWidget);
|
||||
|
||||
// RootWidget::setWidgetArea(mButton, { 100, 100, 150, 200 });
|
||||
|
||||
RootWidget::setWidgetArea(mFloatingMenu2, { 300, 100, 150, 200 });
|
||||
RootWidget::setWidgetArea(mFloatingMenu, { 100, 100, 150, 200 });
|
||||
|
||||
// mWidgetFloating.addChild(&mLayoutWidget);
|
||||
|
|
@ -50,13 +59,20 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
LabelWidget mLabel;
|
||||
ButtonWidget mButton;
|
||||
ButtonWidget mButton2;
|
||||
ButtonWidget mButton3;
|
||||
ButtonWidget mButton4;
|
||||
|
||||
FloatingMenu mFloatingMenu;
|
||||
FloatingMenu mFloatingMenu2;
|
||||
|
||||
LabelWidget mLabel;
|
||||
FloatingWidget mWidgetFloating;
|
||||
AnimationTestWidget mAnimationTestWidget;
|
||||
DesktopLayout mLayoutWidget;
|
||||
FloatingMenu mFloatingMenu;
|
||||
|
||||
DockLayoutWidget mDockLayout;
|
||||
|
||||
RootWidget mRootWidget;
|
||||
};
|
||||
|
|
|
|||
324
WidgetsNew/private/DockLayoutWidget.cpp
Normal file
324
WidgetsNew/private/DockLayoutWidget.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
#include "DockLayoutWidget.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
DockLayoutWidget::DockLayoutWidget() {
|
||||
mSideWidgets[0].side = LEFT;
|
||||
mSideWidgets[1].side = TOP;
|
||||
mSideWidgets[2].side = RIGHT;
|
||||
mSideWidgets[3].side = BOTTOM;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::process(const EventHandler& events) {
|
||||
// calculateHeaderAreas();
|
||||
// handlePreview(events);
|
||||
|
||||
handleResizeEvents(events);
|
||||
calculateSideAreas();
|
||||
calculateResizeHandles();
|
||||
updateChildSideWidgets();
|
||||
}
|
||||
|
||||
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 (mPreview) {
|
||||
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) {
|
||||
mCenterWidget = widget;
|
||||
addChild(widget);
|
||||
}
|
||||
|
||||
void DockLayoutWidget::dockWidget(Widget* widget, Side side) {
|
||||
DEBUG_ASSERT(!sideExists(side))
|
||||
|
||||
addChild(widget);
|
||||
|
||||
auto& sideWidget = mSideWidgets[side];
|
||||
sideWidget.widget = widget;
|
||||
|
||||
for (auto& order : mSideWidgets) {
|
||||
if (order.order == -1) {
|
||||
order.order = side;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sideWidget.hidden = false;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::undockWidget(Side side) {
|
||||
DEBUG_ASSERT(sideExists(side))
|
||||
|
||||
bool removed = false;
|
||||
for (ualni i = 0; i < 3; i++) {
|
||||
if (mSideWidgets[i].order == side) {
|
||||
removed = true;
|
||||
}
|
||||
if (removed) {
|
||||
swap(mSideWidgets[i].order, mSideWidgets[i + 1].order);
|
||||
}
|
||||
}
|
||||
mSideWidgets[3].order = -1;
|
||||
|
||||
mSideWidgets[side].widget = nullptr;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::toggleWidgetVisibility(Side side) {
|
||||
DEBUG_ASSERT(sideExists(side))
|
||||
mSideWidgets[side].hidden = !mSideWidgets[side].hidden;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::calculateSideAreas() {
|
||||
auto startArea = getRelativeArea();
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
const auto side = sideWidget.order;
|
||||
|
||||
if (side == -1) break;
|
||||
if (!isSideVisible(Side(side))) continue;
|
||||
|
||||
bool vertical = side == TOP || side == BOTTOM;
|
||||
bool opposite = side == BOTTOM || side == RIGHT;
|
||||
|
||||
auto& sideSize = mSideWidgets[side].absoluteSize;
|
||||
|
||||
auto factor = sideSize / startArea.size[vertical];
|
||||
if (opposite) factor = factor * -1 + 1;
|
||||
auto& area = mSideWidgets[side].area;
|
||||
|
||||
if (!vertical) {
|
||||
const auto first = startArea.splitByFactorHL(factor);
|
||||
const auto second = startArea.splitByFactorHR(factor);
|
||||
area = side == LEFT ? first : second;
|
||||
startArea = side == LEFT ? second : first;
|
||||
} else {
|
||||
const auto first = startArea.splitByFactorVT(factor);
|
||||
const auto second = startArea.splitByFactorVB(factor);
|
||||
area = side == TOP ? first : second;
|
||||
startArea = side == TOP ? second : first;
|
||||
}
|
||||
|
||||
area = area.shrink(mPadding);
|
||||
}
|
||||
|
||||
mCenterArea = startArea.shrink(mPadding);
|
||||
}
|
||||
|
||||
void DockLayoutWidget::calculateResizeHandles() {
|
||||
RectF rec;
|
||||
RectF area = getRelativeArea();
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
auto& sideSize = sideWidget.absoluteSize;
|
||||
auto& resizeHandle = sideWidget.resizeHandle;
|
||||
|
||||
if (resizeHandle.end < mSideSizePadding * 2) {
|
||||
sideSize = resizeHandle.end / 2.f;
|
||||
} else {
|
||||
sideSize = clamp(sideSize, resizeHandle.start + mSideSizePadding, resizeHandle.end - mSideSizePadding);
|
||||
}
|
||||
}
|
||||
|
||||
if (isSideVisible(LEFT)) {
|
||||
auto& side = mSideWidgets[LEFT];
|
||||
rec = { side.area.p4(), { mPadding * 2, side.area.size.y } };
|
||||
side.resizeHandle.area = rec;
|
||||
side.resizeHandle.start = 0;
|
||||
side.resizeHandle.end = mCenterArea.p3().x;
|
||||
}
|
||||
if (isSideVisible(RIGHT)) {
|
||||
auto& side = mSideWidgets[RIGHT];
|
||||
rec = { side.area.p1(), { mPadding * 2, side.area.size.y } };
|
||||
rec.x -= mPadding * 2;
|
||||
side.resizeHandle.area = rec;
|
||||
side.resizeHandle.start = 0;
|
||||
side.resizeHandle.end = (area.p3() - mCenterArea.p1()).x;
|
||||
}
|
||||
if (isSideVisible(TOP)) {
|
||||
auto& side = mSideWidgets[TOP];
|
||||
rec = { side.area.p2(), { side.area.size.x, mPadding * 2 } };
|
||||
side.resizeHandle.area = rec;
|
||||
side.resizeHandle.start = 0;
|
||||
side.resizeHandle.end = mCenterArea.p2().y;
|
||||
}
|
||||
if (isSideVisible(BOTTOM)) {
|
||||
auto& side = mSideWidgets[BOTTOM];
|
||||
rec = { side.area.p1(), { side.area.size.x, mPadding * 2 } };
|
||||
rec.y -= mPadding * 2;
|
||||
side.resizeHandle.area = rec;
|
||||
side.resizeHandle.start = 0;
|
||||
side.resizeHandle.end = (area.p3() - mCenterArea.p1()).y;
|
||||
}
|
||||
}
|
||||
|
||||
void DockLayoutWidget::handleResizeEvents(const EventHandler& events) {
|
||||
auto pointer = events.getPointer();
|
||||
auto pointerDelta = events.getPointerDelta();
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
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->setArea(mSideWidgets[i].area);
|
||||
// widget->mEnable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mCenterWidget) mCenterWidget->setArea(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() {
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (!isSideVisible(Side(i))) continue;
|
||||
auto& area = mSideWidgets[i].area;
|
||||
const auto factor = mHeaderSize / area.size.y;
|
||||
mSideWidgets[i].headerArea = area.splitByFactorVT(factor);
|
||||
area = area.splitByFactorVB(factor);
|
||||
|
||||
mSideWidgets[i].headerArea.size.y -= mPadding;
|
||||
}
|
||||
}
|
||||
|
||||
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 out = 0;
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (isSideVisible(Side(i))) out++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void DockLayoutWidget::handlePreview(const EventHandler& events) {
|
||||
if (!mPreview) {
|
||||
mPreviewSide = NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
const halnf factor = 0.3;
|
||||
const halnf handleFactor = 0.1;
|
||||
|
||||
const auto handleSize = min(mCenterArea.size.x, mCenterArea.size.y) * handleFactor;
|
||||
|
||||
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;
|
||||
default: break;
|
||||
}
|
||||
|
||||
sideWidget.area = sideWidget.area.shrink(mPadding * 2);
|
||||
sideWidget.previewHandleArea = sideWidget.area.getSizedFromCenter({ handleSize, handleSize });
|
||||
}
|
||||
|
||||
mPreviewArea = {};
|
||||
mPreviewSide = NONE;
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (sideWidget.widget) continue;
|
||||
|
||||
if (sideWidget.previewHandleArea.isInside(events.getPointer())) {
|
||||
mPreviewArea = sideWidget.area;
|
||||
mPreviewSide = sideWidget.side;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,8 @@ void FloatingWidget::process(const EventHandler& events) {
|
|||
if (inside && events.isPressed(InputID::MOUSE1)) {
|
||||
mPointerStart = relativePointer;
|
||||
mIsFloating = true;
|
||||
|
||||
bringToFront();
|
||||
}
|
||||
|
||||
if (mIsFloating && resizeHandleRect().isInside(relativePointer)) {
|
||||
|
|
|
|||
|
|
@ -19,23 +19,26 @@ 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(&mWidgetsToProcess[mRoot]);
|
||||
updateAnimations(root);
|
||||
|
||||
// update all events and call all event processing callbacks
|
||||
EventHandler dummyEvents;
|
||||
|
||||
processFocusItems(*events);
|
||||
processActiveTree(&mWidgetsToProcess[mRoot], dummyEvents);
|
||||
processActiveTree(root, dummyEvents);
|
||||
|
||||
// update widget sizes base on individual size policies
|
||||
adjustSizes(&mWidgetsToProcess[mRoot]);
|
||||
adjustSizes(root);
|
||||
|
||||
// trigger some widgets by moise pointer
|
||||
handleFocusChanges(*events);
|
||||
|
||||
// check triggered widgets for removal
|
||||
erase_if(mTriggeredWidgets, [](auto widget) {
|
||||
// check triggered widgets for removal
|
||||
erase_if(mTriggeredWidgets, [this](auto widget) {
|
||||
if (mWidgetsToProcess.find(widget) == mWidgetsToProcess.end()) return false;
|
||||
auto end = !widget->needsNextFrame();
|
||||
if (end) {
|
||||
widget->endAnimations();
|
||||
|
|
@ -53,8 +56,10 @@ void RootWidget::drawFrame(Canvas& canvas) {
|
|||
// draw all tree from top to bottom
|
||||
drawRecursion(canvas, mRoot, { 0, 0 });
|
||||
|
||||
ImGui::Checkbox("Draw debug", &mDebug);
|
||||
|
||||
if (mDebug) {
|
||||
drawDebug(canvas, mRoot, { 0, 0 });
|
||||
drawDebug(canvas, mRoot, { 0, 0 }, 0);
|
||||
ImGui::Text("Triggered Widgets: %i", (int) mTriggeredWidgets.size());
|
||||
ImGui::Text("Widgets To Process: %i", (int) mWidgetsToProcess.size());
|
||||
}
|
||||
|
|
@ -80,8 +85,8 @@ void RootWidget::drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos)
|
|||
|
||||
active->draw(canvas);
|
||||
|
||||
for (auto child : active->mChildren) {
|
||||
drawRecursion(canvas, child, pos + child->getArea().pos);
|
||||
for (auto child = active->mDepthOrder.lastNode(); child; child = child->prev) {
|
||||
drawRecursion(canvas, child->data, pos + child->data->getArea().pos);
|
||||
}
|
||||
|
||||
canvas.setOrigin(pos);
|
||||
|
|
@ -90,14 +95,13 @@ void RootWidget::drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos)
|
|||
active->drawOverlay(canvas);
|
||||
}
|
||||
|
||||
void RootWidget::drawDebug(Canvas& canvas, Widget* active, const Vec2F& pos) {
|
||||
void RootWidget::drawDebug(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder) {
|
||||
auto area = RectF{ pos, active->getArea().size };
|
||||
|
||||
|
||||
if (mWidgetsToProcess.find(active) != mWidgetsToProcess.end()) {
|
||||
RGBA color = { 1, 0, 0, 1};
|
||||
canvas.frame(area, color);
|
||||
canvas.text(active->mName.c_str(), area, 12, Canvas::Align::LC, 2, color);
|
||||
canvas.text((active->mName + ":" + std::to_string(depthOrder)).c_str(), area, 22, Canvas::Align::LC, 2, color);
|
||||
}
|
||||
|
||||
if (active->mInFocus) {
|
||||
|
|
@ -107,8 +111,9 @@ void RootWidget::drawDebug(Canvas& canvas, Widget* active, const Vec2F& pos) {
|
|||
canvas.circle(active->mGlobalPoint, 10, active->mDebugColor);
|
||||
}
|
||||
|
||||
for (auto child : active->mChildren) {
|
||||
drawDebug(canvas, child, pos + child->getArea().pos);
|
||||
int orderIdx = 0;
|
||||
for (auto child = active->mDepthOrder.lastNode(); child; child = child->prev) {
|
||||
drawDebug(canvas, child->data, pos + child->data->getArea().pos, orderIdx++);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,40 +131,61 @@ void RootWidget::updateAnimations(ActiveTreeNode* iter) {
|
|||
}
|
||||
|
||||
void RootWidget::getWidgetPath(Widget* widget, std::vector<Widget*>& out) {
|
||||
if (!widget) return;
|
||||
|
||||
for (auto iter = widget; iter && iter != this; iter = iter->mParent) {
|
||||
out.push_back(iter);
|
||||
}
|
||||
|
||||
for (auto i = 0; i < out.size() / 2; i++) {
|
||||
swap(out[i], out[out.size() - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
void RootWidget::handleFocusChanges(EventHandler& events) {
|
||||
auto prevFocus = mInFocusWidget;
|
||||
|
||||
findFocusWidget(mRoot, &mInFocusWidget, events.getPointer());
|
||||
|
||||
if (prevFocus) {
|
||||
std::vector<Widget*> path1;
|
||||
std::vector<Widget*> path2;
|
||||
if (mInFocusWidget) updateWidget(mInFocusWidget);
|
||||
|
||||
getWidgetPath(prevFocus, path1);
|
||||
getWidgetPath(mInFocusWidget, path2);
|
||||
|
||||
size_t iter = 0;
|
||||
while (path1[iter] == path2[iter]) {
|
||||
iter++;
|
||||
std::vector<Widget*> path2;
|
||||
getWidgetPath(mInFocusWidget, path2);
|
||||
size_t propLen2 = path2.size();
|
||||
for (auto i = 0; i < path2.size(); i++) {
|
||||
if (!path2[i]->propagateEventsToChildren()) {
|
||||
propLen2 = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = iter; i < path1.size(); i++) {
|
||||
path1[i]->mouseLeave();
|
||||
std::vector<Widget*> path1;
|
||||
getWidgetPath(prevFocus, path1);
|
||||
size_t propLen1 = path1.size();
|
||||
for (auto i = 0; i < path1.size(); i++) {
|
||||
if (!path1[i]->propagateEventsToChildren()) {
|
||||
propLen1 = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = iter; i < path2.size(); i++) {
|
||||
path2[i]->mouseEnter();
|
||||
}
|
||||
size_t mostCommonIdx = 0;
|
||||
|
||||
} else {
|
||||
for (auto iter = mInFocusWidget; iter; iter = iter->mParent) {
|
||||
iter->mouseEnter();
|
||||
if (!(path1.empty() || path2.empty())) {
|
||||
while (path1[mostCommonIdx] == path2[mostCommonIdx]) {
|
||||
mostCommonIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = 0; i < path1.size(); i++) {
|
||||
path1[i]->mInFocus = false;
|
||||
if (i >= mostCommonIdx && i < propLen1) path1[i]->mouseLeave();
|
||||
}
|
||||
|
||||
for (auto i = 0; i < path2.size(); i++) {
|
||||
path2[i]->mInFocus = true;
|
||||
if (i >= mostCommonIdx && i < propLen2) path2[i]->mouseEnter();
|
||||
}
|
||||
}
|
||||
|
||||
void RootWidget::findFocusWidget(Widget* iter, Widget** focus, const Vec2F& pointer) {
|
||||
|
|
@ -167,8 +193,8 @@ void RootWidget::findFocusWidget(Widget* iter, Widget** focus, const Vec2F& poin
|
|||
|
||||
*focus = iter;
|
||||
|
||||
for (auto child : iter->mChildren) {
|
||||
findFocusWidget(child, focus, pointer - iter->mArea.getTargetRect().pos);
|
||||
for (auto child = iter->mDepthOrder.lastNode(); child; child = child->prev) {
|
||||
findFocusWidget(child->data, focus, pointer - iter->mArea.getTargetRect().pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,10 +234,6 @@ void RootWidget::processFocusItems(EventHandler& events) {
|
|||
std::vector<Widget*> path;
|
||||
getWidgetPath(mInFocusWidget, path);
|
||||
|
||||
for (auto i = 0; i < path.size() / 2; i++) {
|
||||
swap(path[i], path[path.size() - i - 1]);
|
||||
}
|
||||
|
||||
size_t len = path.size();
|
||||
for (auto i = 0; i < len; i++) {
|
||||
if (!path[i]->propagateEventsToChildren()) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,12 @@ void ButtonWidget::setAction(const std::function<void()>& action) {
|
|||
mAction = action;
|
||||
}
|
||||
|
||||
void ButtonWidget::setColor(const RGBA& in) {
|
||||
mColor = in;
|
||||
mColorAnimated.setTargetColor(mColor);
|
||||
triggerWidgetUpdate();
|
||||
}
|
||||
|
||||
void ButtonWidget::process(const EventHandler& eventHandler) {
|
||||
if (getArea().isInside(eventHandler.getPointer())) {
|
||||
if (eventHandler.isPressed(InputID::MOUSE1)) {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,24 @@ void Widget::adjustRect() {
|
|||
}
|
||||
}
|
||||
|
||||
void Widget::bringToFront() {
|
||||
if (!mParent) return;
|
||||
auto& order = mParent->mDepthOrder;
|
||||
auto node = order.find(this);
|
||||
DEBUG_ASSERT(node);
|
||||
order.detach(node);
|
||||
order.pushFront(node);
|
||||
}
|
||||
|
||||
void Widget::bringToBack() {
|
||||
if (!mParent) return;
|
||||
auto& order = mParent->mDepthOrder;
|
||||
auto node = order.find(this);
|
||||
DEBUG_ASSERT(node);
|
||||
order.detach(node);
|
||||
order.pushBack(node);
|
||||
}
|
||||
|
||||
void Widget::adjustChildrenRect() {
|
||||
auto area = RectF({}, getArea().size);
|
||||
for (auto widget : mChildren) {
|
||||
|
|
@ -71,7 +89,6 @@ void Widget::adjustChildrenRect() {
|
|||
|
||||
void Widget::mouseEnter() {
|
||||
mInFocus = true;
|
||||
triggerWidgetUpdate();
|
||||
}
|
||||
|
||||
void Widget::mouseLeave() {
|
||||
|
|
@ -80,4 +97,14 @@ void Widget::mouseLeave() {
|
|||
|
||||
bool Widget::propagateEventsToChildren() const {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::addChild(Widget* child) {
|
||||
mChildren.push_back(child);
|
||||
mDepthOrder.pushBack(child);
|
||||
|
||||
child->mParent = this;
|
||||
|
||||
triggerWidgetUpdate();
|
||||
child->triggerWidgetUpdate();
|
||||
}
|
||||
|
|
|
|||
94
WidgetsNew/public/DockLayoutWidget.hpp
Normal file
94
WidgetsNew/public/DockLayoutWidget.hpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#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;
|
||||
};
|
||||
|
||||
public:
|
||||
DockLayoutWidget();
|
||||
|
||||
public:
|
||||
void adjustRect() 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);
|
||||
void toggleWidgetVisibility(Side side);
|
||||
|
||||
private:
|
||||
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, 1);
|
||||
|
||||
public:
|
||||
bool mPreview = false;
|
||||
};
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ namespace tp {
|
|||
|
||||
RectF resizeHandleRect();
|
||||
|
||||
bool propagateEventsToChildren() const override;
|
||||
[[nodiscard]] bool propagateEventsToChildren() const override;
|
||||
|
||||
private:
|
||||
bool mIsFloating = false;
|
||||
|
|
@ -41,8 +41,6 @@ namespace tp {
|
|||
mMenuLayout.addChild(&mHeader);
|
||||
mMenuLayout.addChild(&mBodyLayout);
|
||||
|
||||
addToMenu(&mTestButton);
|
||||
|
||||
mHeader.setText("Menu");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace tp {
|
|||
void updateTreeToProcess();
|
||||
void updateAnimations(ActiveTreeNode* iter);
|
||||
void drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos);
|
||||
void drawDebug(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);
|
||||
|
|
@ -50,6 +50,6 @@ namespace tp {
|
|||
std::map<Widget*, ActiveTreeNode> mWidgetsToProcess;
|
||||
Widget* mInFocusWidget = nullptr;
|
||||
|
||||
bool mDebug = false;
|
||||
bool mDebug = true;
|
||||
};
|
||||
}
|
||||
|
|
@ -45,6 +45,8 @@ namespace tp {
|
|||
void endAnimations() override;
|
||||
void updateAnimations() override;
|
||||
|
||||
void setColor(const RGBA& in);
|
||||
|
||||
private:
|
||||
std::function<void()> mAction;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,18 +22,15 @@ namespace tp {
|
|||
mDebugColor = col;
|
||||
}
|
||||
|
||||
void addChild(Widget* child) {
|
||||
mChildren.push_back(child);
|
||||
child->mParent = this;
|
||||
|
||||
triggerWidgetUpdate();
|
||||
child->triggerWidgetUpdate();
|
||||
}
|
||||
void addChild(Widget* child);
|
||||
|
||||
WidgetManagerInterface* getRoot();
|
||||
|
||||
void triggerWidgetUpdate();
|
||||
|
||||
void bringToFront();
|
||||
void bringToBack();
|
||||
|
||||
public:
|
||||
virtual void process(const EventHandler& events) {}
|
||||
virtual void draw(Canvas& canvas) { canvas.rect(mArea.getCurrentRect(), RGBA(1.f), 10); }
|
||||
|
|
@ -63,12 +60,11 @@ namespace tp {
|
|||
Widget* mParent = nullptr;
|
||||
|
||||
std::vector<Widget*> mChildren;
|
||||
List<Widget*> mDepthOrder;
|
||||
|
||||
// relative to the parent
|
||||
SpringRect mArea;
|
||||
|
||||
ualni mZValue = 0;
|
||||
|
||||
bool mInFocus = false;
|
||||
|
||||
// debug
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue