Cleanup widgets
This commit is contained in:
parent
9e7704a446
commit
15127c5122
19 changed files with 455 additions and 221 deletions
|
|
@ -9,28 +9,7 @@ using namespace tp;
|
|||
class SimpleGUI : public Application {
|
||||
public:
|
||||
SimpleGUI() {
|
||||
|
||||
// debug
|
||||
|
||||
mGui.addSideWidget(&mButtons[0], DockSpaceWidget::BOTTOM);
|
||||
mGui.addSideWidget(&mButtons[1], DockSpaceWidget::RIGHT);
|
||||
|
||||
mGui.removeSideWidget(DockSpaceWidget::BOTTOM);
|
||||
|
||||
mGui.addSideWidget(&mButtons[0], DockSpaceWidget::TOP);
|
||||
mGui.addSideWidget(&mButtons[2], DockSpaceWidget::LEFT);
|
||||
|
||||
mGui.removeSideWidget(DockSpaceWidget::TOP);
|
||||
|
||||
mGui.addSideWidget(&mButtons[0], DockSpaceWidget::BOTTOM);
|
||||
|
||||
mGui.addSideWidget(&mButtons[3], DockSpaceWidget::TOP);
|
||||
mGui.setCenterWidget(&mButtons[4]);
|
||||
|
||||
mButtons[4].mCallback = [&]() { mGui.toggleHiddenState(DockSpaceWidget::BOTTOM); };
|
||||
mButtons[0].mCallback = [&]() { mGui.toggleHiddenState(DockSpaceWidget::TOP); };
|
||||
mButtons[2].mCallback = [&]() { mGui.toggleHiddenState(DockSpaceWidget::RIGHT); };
|
||||
mButtons[3].mCallback = [&]() { mGui.toggleHiddenState(DockSpaceWidget::LEFT); };
|
||||
// mGui.mPreview = true;
|
||||
}
|
||||
|
||||
void processFrame(EventHandler* eventHandler) override {
|
||||
|
|
@ -49,9 +28,8 @@ public:
|
|||
private:
|
||||
WidgetManager mWidgetManager;
|
||||
|
||||
DockSpaceWidget mGui;
|
||||
|
||||
ButtonWidget mButtons[5];
|
||||
// DockSpaceWidget mGui;
|
||||
SimpleWidget3 mGui;
|
||||
};
|
||||
|
||||
int main() {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ namespace tp {
|
|||
this->addWidgetToMenu(&mSlider);
|
||||
|
||||
mInMenuButton1.mLabel.mLabel = "Button1";
|
||||
|
||||
mInMenuButton1.mCallback = []() {
|
||||
printf("asd\n");
|
||||
};
|
||||
|
||||
mInMenuButton2.mLabel.mLabel = "Button2";
|
||||
}
|
||||
|
||||
|
|
@ -23,31 +28,41 @@ namespace tp {
|
|||
NamedSliderWidget mSlider;
|
||||
};
|
||||
|
||||
class SimpleWidget2 : public DockSpaceWidget {
|
||||
class SimpleWidget3 : public WorkspaceWidget {
|
||||
public:
|
||||
SimpleWidget2() {
|
||||
this->mChildWidgets.pushBack(&mFloating);
|
||||
mFloating.addWidgetToMenu(&mWidget);
|
||||
SimpleWidget3() {
|
||||
|
||||
this->mChildWidgets.pushBack(&mFloating2);
|
||||
mFloating2.addWidgetToMenu(&mWidget2);
|
||||
mDockSpace.addSideWidget(&mButtons[0], DockSpaceWidget::BOTTOM);
|
||||
mDockSpace.addSideWidget(&mButtons[1], DockSpaceWidget::RIGHT);
|
||||
|
||||
mFloating2.mArea = { 200, 100, 100, 100 };
|
||||
mDockSpace.removeSideWidget(DockSpaceWidget::BOTTOM);
|
||||
|
||||
this->mChildWidgets.pushBack(&mFloating3);
|
||||
mFloating3.addWidgetToMenu(&mWidget3);
|
||||
mDockSpace.addSideWidget(&mButtons[0], DockSpaceWidget::TOP);
|
||||
mDockSpace.addSideWidget(&mButtons[2], DockSpaceWidget::LEFT);
|
||||
|
||||
mFloating3.mArea = { 400, 100, 100, 100 };
|
||||
mDockSpace.removeSideWidget(DockSpaceWidget::TOP);
|
||||
|
||||
mDockSpace.addSideWidget(&mButtons[0], DockSpaceWidget::BOTTOM);
|
||||
|
||||
mDockSpace.addSideWidget(&mButtons[3], DockSpaceWidget::TOP);
|
||||
mDockSpace.setCenterWidget(&mButtons[4]);
|
||||
|
||||
/*
|
||||
mButtons[4].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::BOTTOM); };
|
||||
mButtons[0].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::TOP); };
|
||||
mButtons[2].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::RIGHT); };
|
||||
mButtons[3].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::LEFT); };
|
||||
*/
|
||||
|
||||
mButtons[0].addWidgetToMenu(&mWidget);
|
||||
mButtons[1].addWidgetToMenu(&mWidget2);
|
||||
}
|
||||
|
||||
private:
|
||||
FloatingWidget mFloating;
|
||||
FloatingWidget mButtons[5];
|
||||
|
||||
SimpleWidget mWidget;
|
||||
|
||||
FloatingWidget mFloating2;
|
||||
SimpleWidget mWidget2;
|
||||
|
||||
FloatingWidget mFloating3;
|
||||
SimpleWidget mWidget3;
|
||||
};
|
||||
}
|
||||
|
|
@ -2,41 +2,50 @@
|
|||
|
||||
using namespace tp;
|
||||
|
||||
DockSpaceWidget::DockSpaceWidget() = default;
|
||||
DockSpaceWidget::DockSpaceWidget() {
|
||||
mSideWidgets[0].side = LEFT;
|
||||
mSideWidgets[1].side = TOP;
|
||||
mSideWidgets[2].side = RIGHT;
|
||||
mSideWidgets[3].side = BOTTOM;
|
||||
}
|
||||
|
||||
void DockSpaceWidget::addSideWidget(Widget* widget, Side side) {
|
||||
if (mSideWidgets[side]) return;
|
||||
mSideWidgets[side] = widget;
|
||||
for (auto& order : mSideSplitOrder) {
|
||||
if (order == -1) {
|
||||
order = side;
|
||||
if (isSideExists(side)) return;
|
||||
|
||||
auto& sideWidget = mSideWidgets[side];
|
||||
sideWidget.widget = widget;
|
||||
for (auto& order : mSideWidgets) {
|
||||
if (order.order == -1) {
|
||||
order.order = side;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sideWidget.hidden = false;
|
||||
|
||||
mChildWidgets.pushBack(widget);
|
||||
widget->mIsDocked = true;
|
||||
mSideHidden[side] = false;
|
||||
}
|
||||
|
||||
void DockSpaceWidget::removeSideWidget(Side side) {
|
||||
if (!mSideWidgets[side]) return;
|
||||
if (!isSideExists(side)) return;
|
||||
|
||||
bool removed = false;
|
||||
for (ualni i = 0; i < 3; i++) {
|
||||
if (mSideSplitOrder[i] == side) {
|
||||
if (mSideWidgets[i].order == side) {
|
||||
removed = true;
|
||||
}
|
||||
if (removed) {
|
||||
mSideSplitOrder[i] = mSideSplitOrder[i + 1];
|
||||
swap(mSideWidgets[i].order, mSideWidgets[i + 1].order);
|
||||
}
|
||||
}
|
||||
mSideSplitOrder[3] = -1;
|
||||
mSideWidgets[3].order = -1;
|
||||
|
||||
auto widget = mSideWidgets[side];
|
||||
mSideWidgets[side] = nullptr;
|
||||
auto widget = mSideWidgets[side].widget;
|
||||
widget->mIsDocked = false;
|
||||
|
||||
mChildWidgets.removeNode(mChildWidgets.find(widget));
|
||||
|
||||
mSideWidgets[side].widget = nullptr;
|
||||
}
|
||||
|
||||
void DockSpaceWidget::setCenterWidget(Widget* widget) {
|
||||
|
|
@ -47,15 +56,15 @@ void DockSpaceWidget::setCenterWidget(Widget* widget) {
|
|||
|
||||
void DockSpaceWidget::toggleHiddenState(DockSpaceWidget::Side side) {
|
||||
if (!isSideExists(side)) return;
|
||||
mSideHidden[side] = !mSideHidden[side];
|
||||
mSideWidgets[side].hidden = !mSideWidgets[side].hidden;
|
||||
}
|
||||
|
||||
void DockSpaceWidget::eventProcess(const tp::Events& events) {
|
||||
updateActiveWindow(events);
|
||||
|
||||
calculateSideAreas();
|
||||
calculateResizeHandles();
|
||||
// calculateHeaderAreas();
|
||||
|
||||
handlePreview(events);
|
||||
handleResizeEvents(events);
|
||||
|
||||
updateChildSideWidgets();
|
||||
|
|
@ -64,129 +73,156 @@ void DockSpaceWidget::eventProcess(const tp::Events& events) {
|
|||
void DockSpaceWidget::eventDraw(Canvas& canvas) {
|
||||
canvas.rect(this->mArea, mBackgroundColor, 0);
|
||||
|
||||
for (auto sizeHandle : mResizeHandles) {
|
||||
if (sizeHandle->active) {
|
||||
canvas.rect(sizeHandle->area.shrink(mPadding / 1.5f), mResizeHandleColorActive, 0);
|
||||
} else if (sizeHandle->hover) {
|
||||
canvas.rect(sizeHandle->area.shrink(mPadding / 1.5f), mResizeHandleColorHovered, 0);
|
||||
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& header : mSideHeaderAreas) {
|
||||
canvas.rect(header, mResizeHandleColorActive, 0);
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (!isSideVisible(sideWidget.side)) continue;
|
||||
canvas.rect(sideWidget.headerArea, mResizeHandleColorActive, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DockSpaceWidget::updateActiveWindow(const tp::Events& events) {
|
||||
if (this->mChildWidgets.size() > 1 && events.isPressed(InputID::MOUSE1)) {
|
||||
void DockSpaceWidget::eventDrawOver(Canvas& canvas) {
|
||||
if (!mPreview) return;
|
||||
|
||||
Widget* activeChild = nullptr;
|
||||
if (mPreviewSide != NONE) canvas.rect(mPreviewArea.shrink(mPadding * 2), mPreviewColor, mRounding);
|
||||
|
||||
for (auto childNode = this->mChildWidgets.firstNode(); childNode; childNode = childNode->next) {
|
||||
auto child = childNode->data;
|
||||
|
||||
if (child->mIsDocked) continue;
|
||||
if (child->mArea.isInside(events.getPointer())) {
|
||||
|
||||
mChildWidgets.detach(childNode);
|
||||
mChildWidgets.pushFront(childNode);
|
||||
|
||||
child->mHandlesEvents = true;
|
||||
activeChild = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (activeChild) {
|
||||
for (auto child : this->mChildWidgets) {
|
||||
if (activeChild != child.data() && !child->mIsDocked) child->mHandlesEvents = false;
|
||||
}
|
||||
}
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (sideWidget.widget) continue;
|
||||
canvas.rect(sideWidget.previewHandleArea, mPreviewColor, mRounding);
|
||||
}
|
||||
}
|
||||
|
||||
void DockSpaceWidget::calculateSideAreas() {
|
||||
auto startArea = this->mArea;
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
const auto side = mSideSplitOrder[i];
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
const auto side = sideWidget.order;
|
||||
|
||||
if (side == -1) break;
|
||||
if (mSideHidden[side]) continue;
|
||||
if (!isSideVisible(Side(side))) continue;
|
||||
|
||||
bool vertical = side == TOP || side == BOTTOM;
|
||||
bool opposite = side == BOTTOM || side == RIGHT;
|
||||
|
||||
const auto maxAbsoluteSize = startArea.size[vertical];
|
||||
const auto paddingFactor = mSideSizePadding / maxAbsoluteSize;
|
||||
auto& sideSize = mSideWidgets[side].absoluteSize;
|
||||
|
||||
mSideAbsoluteSize[side] =
|
||||
clamp(mSideAbsoluteSize[side], maxAbsoluteSize * paddingFactor, maxAbsoluteSize * (1.f - paddingFactor));
|
||||
|
||||
auto factor = mSideAbsoluteSize[side] / startArea.size[vertical];
|
||||
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);
|
||||
mSideAreas[side] = side == LEFT ? first : second;
|
||||
area = side == LEFT ? first : second;
|
||||
startArea = side == LEFT ? second : first;
|
||||
} else {
|
||||
const auto first = startArea.splitByFactorVT(factor);
|
||||
const auto second = startArea.splitByFactorVB(factor);
|
||||
mSideAreas[side] = side == TOP ? first : second;
|
||||
area = side == TOP ? first : second;
|
||||
startArea = side == TOP ? second : first;
|
||||
}
|
||||
|
||||
mSideAreas[side] = mSideAreas[side].shrink(mPadding);
|
||||
area = area.shrink(mPadding);
|
||||
}
|
||||
|
||||
mCenterArea = startArea.shrink(mPadding);
|
||||
}
|
||||
|
||||
void DockSpaceWidget::calculateResizeHandles() {
|
||||
mResizeHandles.clear();
|
||||
RectF rec;
|
||||
|
||||
if (isSideVisible(LEFT)) {
|
||||
rec = { mSideAreas[LEFT].p4(), { mPadding * 2, mSideAreas[LEFT].size.y } };
|
||||
mResizeHandles.append({ rec, LEFT, 0, mCenterArea.p3().x });
|
||||
auto& side = mSideWidgets[LEFT];
|
||||
rec = { side.area.p4(), { mPadding * 2, side.area.size.y } };
|
||||
side.resizeHandle = { rec, 0, mCenterArea.p3().x };
|
||||
}
|
||||
if (isSideVisible(RIGHT)) {
|
||||
rec = { mSideAreas[RIGHT].p1(), { mPadding * 2, mSideAreas[RIGHT].size.y } };
|
||||
auto& side = mSideWidgets[RIGHT];
|
||||
rec = { side.area.p1(), { mPadding * 2, side.area.size.y } };
|
||||
rec.x -= mPadding * 2;
|
||||
mResizeHandles.append({ rec, RIGHT, mCenterArea.p1().x, rec.p3().x });
|
||||
side.resizeHandle = { rec, 0, (this->mArea.p3() - mCenterArea.p1()).x };
|
||||
}
|
||||
if (isSideVisible(TOP)) {
|
||||
rec = { mSideAreas[TOP].p2(), { mSideAreas[TOP].size.x, mPadding * 2 } };
|
||||
mResizeHandles.append({ rec, TOP, 0, mCenterArea.p2().y });
|
||||
auto& side = mSideWidgets[TOP];
|
||||
rec = { side.area.p2(), { side.area.size.x, mPadding * 2 } };
|
||||
side.resizeHandle = { rec, 0, mCenterArea.p2().y };
|
||||
}
|
||||
if (isSideVisible(BOTTOM)) {
|
||||
rec = { mSideAreas[BOTTOM].p1(), { mSideAreas[BOTTOM].size.x, mPadding * 2 } };
|
||||
auto& side = mSideWidgets[BOTTOM];
|
||||
rec = { side.area.p1(), { side.area.size.x, mPadding * 2 } };
|
||||
rec.y -= mPadding * 2;
|
||||
mResizeHandles.append({ rec, BOTTOM, mCenterArea.p1().y, rec.p2().y });
|
||||
side.resizeHandle = { rec, 0, (this->mArea.p3() - mCenterArea.p1()).y };
|
||||
}
|
||||
}
|
||||
|
||||
void DockSpaceWidget::handleResizeEvents(const Events& events) {
|
||||
for (auto resizeHandle : mResizeHandles) {
|
||||
resizeHandle->hover = false;
|
||||
if (resizeHandle->area.isInside(events.getPointerPrev())) {
|
||||
resizeHandle->hover = true;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
sideWidget.resizeHandle.hover = false;
|
||||
if (sideWidget.resizeHandle.area.isInside(events.getPointerPrev())) {
|
||||
sideWidget.resizeHandle.hover = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
sideWidget.resizeHandle.active = false;
|
||||
}
|
||||
|
||||
if (mPreview) return;
|
||||
|
||||
auto resizeSideWidget = [&events](SideWidgetData& sideWidget, Vec2F deltaVec) {
|
||||
halnf delta = deltaVec[(sideWidget.side == TOP || sideWidget.side == BOTTOM)];
|
||||
if (sideWidget.side == BOTTOM || sideWidget.side == RIGHT) delta *= -1;
|
||||
sideWidget.absoluteSize += delta;
|
||||
sideWidget.resizeHandle.active = true;
|
||||
};
|
||||
|
||||
if (events.isDown(InputID::MOUSE1)) {
|
||||
for (auto resizeHandle : mResizeHandles) {
|
||||
resizeHandle->active = false;
|
||||
if (resizeHandle->area.isInside(events.getPointerPrev())) {
|
||||
auto factorDeltaVec = events.getPointerDelta();
|
||||
halnf factorDelta = factorDeltaVec[(resizeHandle->side == TOP || resizeHandle->side == BOTTOM)];
|
||||
if (resizeHandle->side == BOTTOM || resizeHandle->side == RIGHT) factorDelta *= -1;
|
||||
mSideAbsoluteSize[resizeHandle->side] += factorDelta;
|
||||
resizeHandle->active = true;
|
||||
for (auto& sideWidget : mSideWidgets) {
|
||||
if (sideWidget.resizeHandle.area.isInside(events.getPointerPrev())) {
|
||||
resizeSideWidget(sideWidget, events.getPointerDelta());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (events.isDown(InputID::LEFT_ALT)) {
|
||||
const auto pointer = events.getPointerPrev();
|
||||
if (!mCenterArea.isInside(pointer)) return;
|
||||
|
||||
if (events.isPressed(InputID::MOUSE1)) {
|
||||
for (auto i : { 0, 1 }) {
|
||||
const auto step = mCenterArea.size[i] / 3.f;
|
||||
const auto rec1 = mCenterArea.pos[i];
|
||||
const auto pos = pointer[i];
|
||||
if (pos > rec1 && pos < rec1 + step) resizeType[i] = 0;
|
||||
if (pos > rec1 + step && pos < rec1 + step * 2) resizeType[i] = 1;
|
||||
if (pos > rec1 + step * 2) resizeType[i] = 2;
|
||||
}
|
||||
} else if (events.isDown(InputID::MOUSE1)) {
|
||||
const auto deltaVec = events.getPointerDelta();
|
||||
|
||||
if (resizeType[0] == 0) resizeSideWidget(mSideWidgets[LEFT], deltaVec);
|
||||
if (resizeType[1] == 0) resizeSideWidget(mSideWidgets[TOP], deltaVec);
|
||||
if (resizeType[0] == 2) resizeSideWidget(mSideWidgets[RIGHT], deltaVec);
|
||||
if (resizeType[1] == 2) resizeSideWidget(mSideWidgets[BOTTOM], deltaVec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DockSpaceWidget::updateChildSideWidgets() {
|
||||
|
|
@ -194,12 +230,13 @@ void DockSpaceWidget::updateChildSideWidgets() {
|
|||
{
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (!isSideExists(Side(i))) continue;
|
||||
auto widget = mSideWidgets[i].widget;
|
||||
|
||||
if (!isSideVisible(Side(i))) {
|
||||
mSideWidgets[i]->mEnable = false;
|
||||
widget->mEnable = false;
|
||||
} else {
|
||||
mSideWidgets[i]->setArea(mSideAreas[i]);
|
||||
mSideWidgets[i]->mEnable = true;
|
||||
widget->setArea(mSideWidgets[i].area);
|
||||
widget->mEnable = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -227,18 +264,20 @@ void DockSpaceWidget::updateChildSideWidgets() {
|
|||
void DockSpaceWidget::calculateHeaderAreas() {
|
||||
for (ualni i = 0; i < 4; i++) {
|
||||
if (!isSideVisible(Side(i))) continue;
|
||||
const auto factor = mHeaderSize / mSideAreas[i].size.y;
|
||||
mSideHeaderAreas[i] = mSideAreas[i].splitByFactorVT(factor);
|
||||
mSideAreas[i] = mSideAreas[i].splitByFactorVB(factor);
|
||||
auto& area = mSideWidgets[i].area;
|
||||
const auto factor = mHeaderSize / area.size.y;
|
||||
mSideWidgets[i].headerArea = area.splitByFactorVT(factor);
|
||||
area = area.splitByFactorVB(factor);
|
||||
|
||||
mSideHeaderAreas[i].size.y -= mPadding;
|
||||
mSideWidgets[i].headerArea.size.y -= mPadding;
|
||||
}
|
||||
}
|
||||
|
||||
bool DockSpaceWidget::isSideVisible(DockSpaceWidget::Side side) { return mSideWidgets[side] && !mSideHidden[side]; }
|
||||
|
||||
bool DockSpaceWidget::isSideExists(DockSpaceWidget::Side side) { return mSideWidgets[side]; }
|
||||
bool DockSpaceWidget::isSideVisible(DockSpaceWidget::Side side) {
|
||||
return isSideExists(side) && !mSideWidgets[side].hidden;
|
||||
}
|
||||
|
||||
bool DockSpaceWidget::isSideExists(DockSpaceWidget::Side side) { return mSideWidgets[side].widget; }
|
||||
|
||||
ualni DockSpaceWidget::getVisibleSidesSize() {
|
||||
ualni out = 0;
|
||||
|
|
@ -247,3 +286,41 @@ ualni DockSpaceWidget::getVisibleSidesSize() {
|
|||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
DockSpaceWidget::Side DockSpaceWidget::getPreviewSide() { return mPreviewSide; }
|
||||
|
||||
void DockSpaceWidget::handlePreview(const Events& 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.previewHandleArea.isInside(events.getPointer())) {
|
||||
mPreviewArea = sideWidget.area;
|
||||
mPreviewSide = sideWidget.side;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Widgets/private/FloatSpaceWidget.cpp
Normal file
47
Widgets/private/FloatSpaceWidget.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#include "FloatSpaceWidget.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
FloatSpaceWidget::FloatSpaceWidget() = default;
|
||||
|
||||
void FloatSpaceWidget::eventProcess(const tp::Events& events) {
|
||||
updateActiveWindow(events);
|
||||
}
|
||||
|
||||
void FloatSpaceWidget::updateActiveWindow(const tp::Events& events) {
|
||||
mIsPassThrough = true;
|
||||
for (auto childNode = this->mChildWidgets.firstNode(); childNode; childNode = childNode->next) {
|
||||
auto child = childNode->data;
|
||||
if (child->mArea.isInside(events.getPointer())) {
|
||||
mIsPassThrough = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (events.isPressed(InputID::MOUSE1)) {
|
||||
|
||||
Widget* activeChild = nullptr;
|
||||
|
||||
for (auto childNode = this->mChildWidgets.firstNode(); childNode; childNode = childNode->next) {
|
||||
auto child = childNode->data;
|
||||
|
||||
if (child->mArea.isInside(events.getPointer())) {
|
||||
|
||||
mChildWidgets.detach(childNode);
|
||||
mChildWidgets.pushFront(childNode);
|
||||
|
||||
child->mHandlesEvents = true;
|
||||
activeChild = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (activeChild) {
|
||||
for (auto child : this->mChildWidgets) {
|
||||
if (activeChild != child.data() && !child->mIsDocked) child->mHandlesEvents = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool FloatSpaceWidget::handlesEvent() const { return !mIsPassThrough; }
|
||||
|
|
@ -78,3 +78,9 @@ RectF FloatingWidget::getResizeHandle() {
|
|||
auto pos = this->mArea.pos + this->mArea.size - size;
|
||||
return { pos, size };
|
||||
}
|
||||
|
||||
bool FloatingWidget::isFloating() const { return mFloating; }
|
||||
|
||||
void FloatingWidget::stopFloating() {
|
||||
mFloating = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ void ScrollBarWidget::eventProcess(const Events& events) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (events.getScrollY() != 0) {
|
||||
if (events.getScrollY() != 0 && mArea.isInside(events.getPointer())) {
|
||||
auto offset = events.getScrollY() < 0 ? 1.0f : -1.0f;
|
||||
mPositionFraction += mSizeFraction * offset * 0.3f;
|
||||
mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ void Widget::drawWrapper(Canvas& canvas) {
|
|||
child->data->drawWrapper(canvas);
|
||||
}
|
||||
canvas.popClamp();
|
||||
|
||||
eventDrawOver(canvas);
|
||||
}
|
||||
|
||||
void Widget::updateConfigWrapper(WidgetManager& wm) {
|
||||
|
|
@ -52,6 +54,7 @@ void Widget::updateConfigWrapper(WidgetManager& wm) {
|
|||
|
||||
void Widget::eventProcess(const Events& events) {}
|
||||
void Widget::eventDraw(Canvas& canvas) {}
|
||||
void Widget::eventDrawOver(Canvas& canvas) {}
|
||||
void Widget::eventUpdateConfiguration(WidgetManager& wm) {}
|
||||
|
||||
void Widget::eventVisible(const Events& events) {}
|
||||
|
|
|
|||
66
Widgets/private/WorkspaceWidget.cpp
Normal file
66
Widgets/private/WorkspaceWidget.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#include "WorkspaceWidget.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
WorkspaceWidget::WorkspaceWidget() {
|
||||
this->mChildWidgets.pushBack(&mFloatingLayer);
|
||||
this->mChildWidgets.pushBack(&mDockSpace);
|
||||
}
|
||||
|
||||
void WorkspaceWidget::eventProcess(const Events& events) {
|
||||
mDockSpace.setArea(this->mArea);
|
||||
mFloatingLayer.setArea(this->mArea);
|
||||
|
||||
mDockSpace.mPreview = false;
|
||||
mDockSpace.mHandlesEvents = !mFloatingLayer.handlesEvent();
|
||||
|
||||
for (auto floatingChild : mFloatingLayer.mChildWidgets) {
|
||||
auto widget = dynamic_cast<FloatingWidget*>(floatingChild.data());
|
||||
if (!widget) continue;
|
||||
if (widget->isFloating()) {
|
||||
if (widget->isReleased()) {
|
||||
auto side = mDockSpace.getPreviewSide();
|
||||
if (side != DockSpaceWidget::NONE) {
|
||||
mFloatingLayer.mChildWidgets.removeNode(mFloatingLayer.mChildWidgets.find(widget));
|
||||
widget->setCollapsed(true);
|
||||
widget->stopFloating();
|
||||
mDockSpace.addSideWidget(widget, side);
|
||||
}
|
||||
} else {
|
||||
mDockSpace.mHandlesEvents = true;
|
||||
mDockSpace.mPreview = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& dockedChild : mDockSpace.mSideWidgets) {
|
||||
auto widget = dynamic_cast<FloatingWidget*>(dockedChild.widget);
|
||||
if (!widget) continue;
|
||||
|
||||
if (widget->isFloating()) {
|
||||
mDockSpace.removeSideWidget(dockedChild.side);
|
||||
mFloatingLayer.mChildWidgets.pushBack(widget);
|
||||
widget->mArea.pos = events.getPointer() - 20;
|
||||
widget->mArea.size = mDefaultFloatSize;
|
||||
}
|
||||
}
|
||||
|
||||
// toggle hide state
|
||||
if (events.isDown(InputID::LEFT_ALT)) {
|
||||
if (events.isPressed(InputID::N1)) {
|
||||
mDockSpace.toggleHiddenState(DockSpaceWidget::LEFT);
|
||||
} else if (events.isPressed(InputID::N2)) {
|
||||
mDockSpace.toggleHiddenState(DockSpaceWidget::TOP);
|
||||
} else if (events.isPressed(InputID::N3)) {
|
||||
mDockSpace.toggleHiddenState(DockSpaceWidget::RIGHT);
|
||||
} else if (events.isPressed(InputID::N4)) {
|
||||
mDockSpace.toggleHiddenState(DockSpaceWidget::BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& dockedChild : mDockSpace.mSideWidgets) {
|
||||
auto widget = dynamic_cast<FloatingWidget*>(dockedChild.widget);
|
||||
if (!widget) continue;
|
||||
widget->setCollapsed(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,23 +3,49 @@
|
|||
namespace tp {
|
||||
class DockSpaceWidget : public Widget {
|
||||
public:
|
||||
enum Side { LEFT, TOP, RIGHT, BOTTOM };
|
||||
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:
|
||||
DockSpaceWidget();
|
||||
|
||||
void eventProcess(const Events& events) override;
|
||||
void eventDraw(Canvas& canvas) override;
|
||||
void eventDrawOver(Canvas& canvas) override;
|
||||
|
||||
void addSideWidget(Widget* widget, Side side);
|
||||
void removeSideWidget(Side side);
|
||||
|
||||
void toggleHiddenState(DockSpaceWidget::Side side);
|
||||
void toggleHiddenState(Side side);
|
||||
|
||||
void setCenterWidget(Widget* widget);
|
||||
|
||||
Side getPreviewSide();
|
||||
|
||||
private:
|
||||
void updateActiveWindow(const tp::Events& events);
|
||||
void calculateSideAreas();
|
||||
void calculateResizeHandles();
|
||||
void handleResizeEvents(const Events& events);
|
||||
|
|
@ -27,43 +53,36 @@ namespace tp {
|
|||
|
||||
void calculateHeaderAreas();
|
||||
|
||||
|
||||
bool isSideVisible(Side side);
|
||||
bool isSideExists(Side side);
|
||||
ualni getVisibleSidesSize();
|
||||
void handlePreview(const Events& events);
|
||||
|
||||
private:
|
||||
// todo : make better grouping into structs
|
||||
RectF mPreviewArea = {};
|
||||
Side mPreviewSide = NONE;
|
||||
int resizeType[2] = { 0, 0 };
|
||||
|
||||
Widget* mSideWidgets[4] { nullptr, nullptr, nullptr, nullptr };
|
||||
public:
|
||||
SideWidgetData mSideWidgets[4];
|
||||
|
||||
private:
|
||||
Widget* mCenterWidget = nullptr;
|
||||
|
||||
alni mSideSplitOrder[4] = { -1, -1, -1, -1 };
|
||||
halnf mSideAbsoluteSize[4] { 200, 100, 200, 100 };
|
||||
bool mSideHidden[4] { true, false, false, false };
|
||||
halnf mSideSizePadding = 50.f;
|
||||
|
||||
// Geometry cache
|
||||
struct ResizeHandle {
|
||||
RectF area{ 0, 0, 0, 0 };
|
||||
Side side{ TOP };
|
||||
halnf start{ 0 };
|
||||
halnf end{ 0 };
|
||||
bool active = false;
|
||||
bool hover = false;
|
||||
};
|
||||
|
||||
Buffer<ResizeHandle> mResizeHandles;
|
||||
RectF mSideAreas[4];
|
||||
RectF mSideHeaderAreas[4];
|
||||
RectF mCenterArea {};
|
||||
|
||||
// View Parameters
|
||||
// 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
Widgets/public/FloatSpaceWidget.hpp
Normal file
18
Widgets/public/FloatSpaceWidget.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include "FloatingWidget.hpp"
|
||||
|
||||
namespace tp {
|
||||
class FloatSpaceWidget : public Widget {
|
||||
public:
|
||||
FloatSpaceWidget();
|
||||
|
||||
void eventProcess(const Events& events) override;
|
||||
|
||||
[[nodiscard]] bool handlesEvent() const;
|
||||
|
||||
private:
|
||||
void updateActiveWindow(const tp::Events& events);
|
||||
|
||||
private:
|
||||
bool mIsPassThrough = false;
|
||||
};
|
||||
}
|
||||
|
|
@ -11,6 +11,9 @@ namespace tp {
|
|||
void eventDraw(Canvas& canvas) override;
|
||||
void eventUpdateConfiguration(WidgetManager& wm) override;
|
||||
|
||||
[[nodiscard]] bool isFloating() const;
|
||||
void stopFloating();
|
||||
|
||||
private:
|
||||
void checkFloating(const Events& events);
|
||||
void checkResizing(const Events& events);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,13 @@ namespace tp {
|
|||
void updateConfigWrapper(WidgetManager& wm);
|
||||
|
||||
virtual void eventProcess(const Events& events);
|
||||
|
||||
// draws before child widgets
|
||||
virtual void eventDraw(Canvas& canvas);
|
||||
|
||||
// draws overlay after child widgets
|
||||
virtual void eventDrawOver(Canvas& canvas);
|
||||
|
||||
virtual void eventUpdateConfiguration(WidgetManager& wm);
|
||||
|
||||
virtual void eventVisible(const Events& events);
|
||||
|
|
|
|||
|
|
@ -9,4 +9,6 @@
|
|||
#include "CollapsableMenu.hpp"
|
||||
#include "FloatingWidget.hpp"
|
||||
#include "Animations.hpp"
|
||||
#include "FloatSpaceWidget.hpp"
|
||||
#include "DockspaceWidget.hpp"
|
||||
#include "WorkspaceWidget.hpp"
|
||||
|
|
|
|||
19
Widgets/public/WorkspaceWidget.hpp
Normal file
19
Widgets/public/WorkspaceWidget.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widgets.hpp"
|
||||
|
||||
namespace tp {
|
||||
class WorkspaceWidget : public Widget {
|
||||
public:
|
||||
WorkspaceWidget();
|
||||
|
||||
void eventProcess(const Events& events) override;
|
||||
|
||||
protected:
|
||||
DockSpaceWidget mDockSpace;
|
||||
FloatSpaceWidget mFloatingLayer;
|
||||
|
||||
// Parameters
|
||||
Vec2F mDefaultFloatSize = { 200, 200 };
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue