diff --git a/specter/include/Specter/RootView.hpp b/specter/include/Specter/RootView.hpp index e64aecc1f..5e982f2e5 100644 --- a/specter/include/Specter/RootView.hpp +++ b/specter/include/Specter/RootView.hpp @@ -50,9 +50,9 @@ class RootView : public View InteractiveSplit, InteractiveJoin, } m_phase = Phase::Inactive; - bool m_draw = false; int m_interactiveSlot = 0; float m_interactiveSplit = 0.5; + bool m_interactiveDown = false; VertexBufferBinding m_vertsBinding; ViewBlock m_viewBlock; @@ -84,10 +84,6 @@ class RootView : public View bool m_deferredSplit = false; bool m_deferredJoin = false; - void beginSplit(); - void beginJoin(); - void cancelAction(); - struct SplitActionNode : IMenuNode { SplitMenuSystem& m_smn; @@ -174,6 +170,11 @@ public: { m_activeDragView = dragView; } + void unsetActiveDragView(View* dragView) + { + if (dragView == m_activeDragView) + m_activeDragView = nullptr; + } void setActiveMenuButton(Button* button) { m_activeMenuButton = button; @@ -219,6 +220,13 @@ public: void resetTooltip(ViewResources& res); void displayTooltip(const std::string& name, const std::string& help); + void beginInteractiveJoin(SplitView* sv, const boo::SWindowCoord& coord) + { + m_splitMenuSystem.m_phase = SplitMenuSystem::Phase::InteractiveJoin; + m_splitMenuSystem.m_splitView = sv; + m_splitMenuSystem.mouseMove(coord); + } + private: void _updateCursor() { diff --git a/specter/include/Specter/Space.hpp b/specter/include/Specter/Space.hpp index 0fab6ef87..2f87fc27c 100644 --- a/specter/include/Specter/Space.hpp +++ b/specter/include/Specter/Space.hpp @@ -14,17 +14,18 @@ struct ISpaceController { virtual bool spaceSplitAllowed() const {return false;} virtual ISplitSpaceController* spaceSplit(SplitView::Axis axis, int thisSlot) {return nullptr;} - virtual ISpaceController* spaceJoin(int keepSlot) {return nullptr;} }; struct ISplitSpaceController { virtual SplitView* splitView()=0; virtual void updateSplit(float split)=0; + virtual void joinViews(SplitView* thisSplit, int thisSlot, SplitView* otherSplit, int otherSlot)=0; }; class Space : public View { + friend class RootView; ISpaceController& m_controller; Toolbar::Position m_tbPos; ViewChild> m_toolbar; @@ -62,6 +63,8 @@ public: void resized(const boo::SWindowRect& rootView, const boo::SWindowRect& sub); void draw(boo::IGraphicsCommandQueue* gfxQ); + SplitView* findSplitViewOnSide(SplitView::Axis axis, int side); + void setMultiplyColor(const Zeus::CColor& color) { View::setMultiplyColor(color); diff --git a/specter/include/Specter/SplitView.hpp b/specter/include/Specter/SplitView.hpp index db03f8bdc..2bc987e06 100644 --- a/specter/include/Specter/SplitView.hpp +++ b/specter/include/Specter/SplitView.hpp @@ -10,6 +10,7 @@ struct ISplitSpaceController; class SplitView : public View { friend class RootView; + friend class Space; public: class Resources { @@ -82,7 +83,9 @@ public: Axis axis() const {return m_axis;} float split() const {return m_slide;} bool testSplitHover(const boo::SWindowCoord& coord); - bool testJoinArrowHover(const boo::SWindowCoord& coord, int& slotOut, boo::SWindowRect& rectOut, ArrowDir& dirOut); + bool testJoinArrowHover(const boo::SWindowCoord& coord, int& origSlotOut, + SplitView*& splitOut, int& slotOut, + boo::SWindowRect& rectOut, ArrowDir& dirOut, int forceSlot=-1); void getJoinArrowHover(int slot, boo::SWindowRect& rectOut, ArrowDir& dirOut); bool testSplitLineHover(const boo::SWindowCoord& coord, int& slotOut, boo::SWindowRect& rectOut, float& splitOut, Axis& axisOut); void getSplitLineHover(int slot, boo::SWindowRect& rectOut, Axis& axisOut); diff --git a/specter/lib/RootView.cpp b/specter/lib/RootView.cpp index b35443988..5623a021b 100644 --- a/specter/lib/RootView.cpp +++ b/specter/lib/RootView.cpp @@ -128,24 +128,6 @@ void RootView::SplitMenuSystem::setLineVerts(const boo::SWindowRect& rect, float m_viewVertBlockBuf->load(&m_viewBlock, sizeof(m_viewBlock)); } -void RootView::SplitMenuSystem::beginSplit() -{ - m_phase = Phase::InteractiveSplit; - m_draw = true; -} - -void RootView::SplitMenuSystem::beginJoin() -{ - m_phase = Phase::InteractiveJoin; - m_draw = true; -} - -void RootView::SplitMenuSystem::cancelAction() -{ - m_phase = Phase::Inactive; - m_draw = false; -} - void RootView::destroyed() { m_destroyed = true; @@ -239,7 +221,28 @@ void RootView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton butto void RootView::SplitMenuSystem::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods) { - + if (m_phase == Phase::InteractiveJoin) + { + int origDummy; + SplitView* selSplit; + boo::SWindowRect rect; + SplitView::ArrowDir arrow; + if (m_splitView->testJoinArrowHover(coord, origDummy, selSplit, m_interactiveSlot, rect, arrow)) + { + setArrowVerts(rect, arrow); + m_interactiveDown = true; + } + } + else if (m_phase == Phase::InteractiveSplit) + { + boo::SWindowRect rect; + SplitView::Axis axis; + if (m_splitView->testSplitLineHover(coord, m_interactiveSlot, rect, m_interactiveSplit, axis)) + { + setLineVerts(rect, m_interactiveSplit, axis); + m_interactiveDown = true; + } + } } void RootView::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods) @@ -279,7 +282,43 @@ void RootView::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, void RootView::SplitMenuSystem::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods) { - + if (m_phase == Phase::InteractiveJoin) + { + int origSlot; + SplitView* selSplit; + boo::SWindowRect rect; + SplitView::ArrowDir arrow; + if (m_splitView->testJoinArrowHover(coord, origSlot, selSplit, m_interactiveSlot, rect, arrow)) + { + setArrowVerts(rect, arrow); + if (m_interactiveDown) + { + m_interactiveDown = false; + m_phase = Phase::Inactive; + m_splitView->m_controller->joinViews(m_splitView, origSlot, selSplit, m_interactiveSlot); + } + } + } + else if (m_phase == Phase::InteractiveSplit) + { + boo::SWindowRect rect; + SplitView::Axis axis; + if (m_splitView->testSplitLineHover(coord, m_interactiveSlot, rect, m_interactiveSplit, axis)) + { + setLineVerts(rect, m_interactiveSplit, axis); + if (m_interactiveDown) + { + m_interactiveDown = false; + m_phase = Phase::Inactive; + Space* space = dynamic_cast(m_splitView->m_views[m_interactiveSlot].m_view); + if (space && space->m_controller.spaceSplitAllowed()) + { + ISplitSpaceController* ss = space->m_controller.spaceSplit(axis, 0); + ss->splitView()->setSplit(m_interactiveSplit); + } + } + } + } } SplitView* RootView::recursiveTestSplitHover(SplitView* sv, const boo::SWindowCoord& coord) const @@ -347,10 +386,6 @@ void RootView::mouseMove(const boo::SWindowCoord& coord) sv = recursiveTestSplitHover(sv, coord); if (sv) { - if (sv->axis() == SplitView::Axis::Horizontal) - setHorizontalSplitHover(true); - else - setVerticalSplitHover(true); m_hoverSplitDragView = sv; break; } @@ -371,6 +406,14 @@ void RootView::mouseMove(const boo::SWindowCoord& coord) v->mouseMove(coord); } + if (m_hoverSplitDragView) + { + if (m_hoverSplitDragView->axis() == SplitView::Axis::Horizontal) + setHorizontalSplitHover(true); + else + setVerticalSplitHover(true); + } + boo::SWindowRect ttrect = m_rootRect; ttrect.location[0] = coord.pixel[0]; ttrect.location[1] = coord.pixel[1]; @@ -388,9 +431,11 @@ void RootView::SplitMenuSystem::mouseMove(const boo::SWindowCoord& coord) { if (m_phase == Phase::InteractiveJoin) { + int origDummy; + SplitView* selSplit; boo::SWindowRect rect; SplitView::ArrowDir arrow; - if (m_splitView->testJoinArrowHover(coord, m_interactiveSlot, rect, arrow)) + if (m_splitView->testJoinArrowHover(coord, origDummy, selSplit, m_interactiveSlot, rect, arrow)) setArrowVerts(rect, arrow); } else if (m_phase == Phase::InteractiveSplit) @@ -499,7 +544,7 @@ void RootView::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool return; } if (key == boo::ESpecialKey::Esc && m_splitMenuSystem.m_phase != SplitMenuSystem::Phase::Inactive) - m_splitMenuSystem.cancelAction(); + m_splitMenuSystem.m_phase = SplitMenuSystem::Phase::Inactive; for (View* v : m_views) v->specialKeyDown(key, mods, isRepeat); if (m_activeTextView) @@ -545,7 +590,7 @@ void RootView::internalThink() { m_splitMenuSystem.m_deferredSplit = false; m_rightClickMenu.m_view.reset(); - m_splitMenuSystem.beginSplit(); + m_splitMenuSystem.m_phase = SplitMenuSystem::Phase::InteractiveSplit; m_splitMenuSystem.mouseMove(m_splitMenuSystem.m_deferredCoord); } @@ -553,7 +598,7 @@ void RootView::internalThink() { m_splitMenuSystem.m_deferredJoin = false; m_rightClickMenu.m_view.reset(); - m_splitMenuSystem.beginJoin(); + m_splitMenuSystem.m_phase = SplitMenuSystem::Phase::InteractiveJoin; m_splitMenuSystem.mouseMove(m_splitMenuSystem.m_deferredCoord); } @@ -585,7 +630,7 @@ void RootView::draw(boo::IGraphicsCommandQueue* gfxQ) void RootView::SplitMenuSystem::draw(boo::IGraphicsCommandQueue* gfxQ) { - if (m_phase == Phase::Inactive || !m_draw) + if (m_phase == Phase::Inactive) return; gfxQ->setShaderDataBinding(m_vertsBinding); gfxQ->setDrawPrimitive(boo::Primitive::TriStrips); diff --git a/specter/lib/Space.cpp b/specter/lib/Space.cpp index 2e0afe1fa..8320532b1 100644 --- a/specter/lib/Space.cpp +++ b/specter/lib/Space.cpp @@ -129,6 +129,7 @@ void Space::CornerView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseBut m_space.m_cornerDrag = true; m_space.m_cornerDragPoint[0] = coord.pixel[0]; m_space.m_cornerDragPoint[1] = coord.pixel[1]; + rootView().setActiveDragView(&m_space); } } @@ -142,7 +143,10 @@ void Space::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, bo void Space::CornerView::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) { if (button == boo::EMouseButton::Primary) + { m_space.m_cornerDrag = false; + rootView().unsetActiveDragView(&m_space); + } } void Space::mouseMove(const boo::SWindowCoord& coord) @@ -150,19 +154,81 @@ void Space::mouseMove(const boo::SWindowCoord& coord) if (m_cornerDrag) { float pf = rootView().viewRes().pixelFactor(); - if (m_cornerView.m_view->m_flip) + if (coord.pixel[0] < m_cornerDragPoint[0] - CORNER_DRAG_THRESHOLD * pf) { - if (coord.pixel[0] < m_cornerDragPoint[0] - CORNER_DRAG_THRESHOLD * pf) + if (m_cornerView.m_view->m_flip) + { + m_cornerDrag = false; + rootView().unsetActiveDragView(this); rootView().viewManager().deferSpaceSplit(&m_controller, SplitView::Axis::Vertical, 1, coord); - else if (coord.pixel[1] < m_cornerDragPoint[1] - CORNER_DRAG_THRESHOLD * pf) - rootView().viewManager().deferSpaceSplit(&m_controller, SplitView::Axis::Horizontal, 1, coord); + } + else + { + SplitView* sv = findSplitViewOnSide(SplitView::Axis::Vertical, 0); + if (sv) + { + m_cornerDrag = false; + rootView().unsetActiveDragView(this); + rootView().beginInteractiveJoin(sv, coord); + } + } } - else + else if (coord.pixel[1] < m_cornerDragPoint[1] - CORNER_DRAG_THRESHOLD * pf) { - if (coord.pixel[0] > m_cornerDragPoint[0] + CORNER_DRAG_THRESHOLD * pf) + if (m_cornerView.m_view->m_flip) + { + m_cornerDrag = false; + rootView().unsetActiveDragView(this); + rootView().viewManager().deferSpaceSplit(&m_controller, SplitView::Axis::Horizontal, 1, coord); + } + else + { + SplitView* sv = findSplitViewOnSide(SplitView::Axis::Horizontal, 0); + if (sv) + { + m_cornerDrag = false; + rootView().unsetActiveDragView(this); + rootView().beginInteractiveJoin(sv, coord); + } + } + } + else if (coord.pixel[0] > m_cornerDragPoint[0] + CORNER_DRAG_THRESHOLD * pf) + { + if (!m_cornerView.m_view->m_flip) + { + m_cornerDrag = false; + rootView().unsetActiveDragView(this); rootView().viewManager().deferSpaceSplit(&m_controller, SplitView::Axis::Vertical, 0, coord); - else if (coord.pixel[1] > m_cornerDragPoint[1] + CORNER_DRAG_THRESHOLD * pf) + } + else + { + SplitView* sv = findSplitViewOnSide(SplitView::Axis::Vertical, 1); + if (sv) + { + m_cornerDrag = false; + rootView().unsetActiveDragView(this); + rootView().beginInteractiveJoin(sv, coord); + } + } + } + else if (coord.pixel[1] > m_cornerDragPoint[1] + CORNER_DRAG_THRESHOLD * pf) + { + if (!m_cornerView.m_view->m_flip) + { + m_cornerDrag = false; + rootView().unsetActiveDragView(this); rootView().viewManager().deferSpaceSplit(&m_controller, SplitView::Axis::Horizontal, 0, coord); + } + else + { + SplitView* sv = findSplitViewOnSide(SplitView::Axis::Horizontal, 1); + if (sv) + { + m_cornerDrag = false; + rootView().unsetActiveDragView(this); + rootView().beginInteractiveJoin(sv, coord); + } + } } } else @@ -197,6 +263,20 @@ void Space::CornerView::mouseLeave(const boo::SWindowCoord& coord) rootView().setSpaceCornerHover(false); } +SplitView* Space::findSplitViewOnSide(SplitView::Axis axis, int side) +{ + SplitView* ret = dynamic_cast(&parentView()); + while (ret) + { + if (ret->axis() != axis) + return nullptr; + if (ret->m_views[side ^ 1].m_view == this) + return ret; + ret = dynamic_cast(&ret->parentView()); + } + return nullptr; +} + void Space::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) { View::resized(root, sub); diff --git a/specter/lib/SplitView.cpp b/specter/lib/SplitView.cpp index 704f96843..716dd00bf 100644 --- a/specter/lib/SplitView.cpp +++ b/specter/lib/SplitView.cpp @@ -99,74 +99,87 @@ bool SplitView::testSplitHover(const boo::SWindowCoord& coord) return false; } -bool SplitView::testJoinArrowHover(const boo::SWindowCoord& coord, int& slotOut, boo::SWindowRect& rectOut, ArrowDir& dirOut) +bool SplitView::testJoinArrowHover(const boo::SWindowCoord& coord, int& origSlotOut, + SplitView*& splitOut, int& slotOut, + boo::SWindowRect& rectOut, ArrowDir& dirOut, int forceSlot) { if (!subRect().coordInRect(coord)) return false; + int origDummy; + ArrowDir dirDummy; + if (m_axis == Axis::Horizontal) { int slidePx = subRect().size[1] * m_slide; - if (coord.pixel[1] - subRect().location[1] - slidePx >= 0) + if ((forceSlot == -1 && coord.pixel[1] - subRect().location[1] - slidePx >= 0) || forceSlot == 1) { + origSlotOut = 0; + dirOut = ArrowDir::Up; if (m_views[1].m_view) { SplitView* chSplit = dynamic_cast(m_views[1].m_view); if (chSplit && chSplit->m_axis == Axis::Horizontal) - return chSplit->testJoinArrowHover(coord, slotOut, rectOut, dirOut); + return chSplit->testJoinArrowHover(coord, origDummy, splitOut, slotOut, rectOut, dirDummy, 0); } + splitOut = this; slotOut = 1; rectOut = subRect(); rectOut.location[1] += slidePx; rectOut.size[1] -= slidePx; - dirOut = ArrowDir::Up; return true; } else { + origSlotOut = 1; + dirOut = ArrowDir::Down; if (m_views[0].m_view) { SplitView* chSplit = dynamic_cast(m_views[0].m_view); if (chSplit && chSplit->m_axis == Axis::Horizontal) - return chSplit->testJoinArrowHover(coord, slotOut, rectOut, dirOut); + return chSplit->testJoinArrowHover(coord, origDummy, splitOut, slotOut, rectOut, dirDummy, 1); } + splitOut = this; slotOut = 0; rectOut = subRect(); rectOut.size[1] = slidePx; - dirOut = ArrowDir::Down; return true; } } else { int slidePx = subRect().size[0] * m_slide; - if (coord.pixel[0] - subRect().location[0] - slidePx >= 0) + if ((forceSlot == -1 && coord.pixel[0] - subRect().location[0] - slidePx >= 0) || forceSlot == 1) { + origSlotOut = 0; + dirOut = ArrowDir::Right; if (m_views[1].m_view) { SplitView* chSplit = dynamic_cast(m_views[1].m_view); if (chSplit && chSplit->m_axis == Axis::Vertical) - return chSplit->testJoinArrowHover(coord, slotOut, rectOut, dirOut); + return chSplit->testJoinArrowHover(coord, origDummy, splitOut, slotOut, rectOut, dirDummy, 0); } + splitOut = this; slotOut = 1; rectOut = subRect(); rectOut.location[0] += slidePx; rectOut.size[0] -= slidePx; - dirOut = ArrowDir::Right; return true; } else { + origSlotOut = 1; + dirOut = ArrowDir::Left; if (m_views[0].m_view) { SplitView* chSplit = dynamic_cast(m_views[0].m_view); if (chSplit && chSplit->m_axis == Axis::Vertical) - return chSplit->testJoinArrowHover(coord, slotOut, rectOut, dirOut); + return chSplit->testJoinArrowHover(coord, origDummy, splitOut, slotOut, rectOut, dirDummy, 1); } + splitOut = this; slotOut = 0; rectOut = subRect(); rectOut.size[0] = slidePx; - dirOut = ArrowDir::Left; return true; } }