Refactor done

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

View file

@ -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;
}
@ -351,23 +213,69 @@ 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;
}

View 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);
}

View 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;
}

View file

@ -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());
}

View file

@ -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 {};
);
}

View file

@ -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);

View file

@ -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;