#pragma once #include #include #include #include #include #include "specter/IMenuNode.hpp" #include "specter/SplitView.hpp" #include "specter/View.hpp" #include #include #include #include #include namespace specter { class Button; class ITextInputView; class Tooltip; class ViewResources; struct IViewManager; class RootView : public View { boo::IWindow* m_window = nullptr; boo::ObjToken m_renderTex; boo::SWindowRect m_rootRect = {}; bool m_resizeRTDirty = false; bool m_destroyed = false; IViewManager& m_viewMan; ViewResources* m_viewRes; ITextInputView* m_activeTextView = nullptr; View* m_activeDragView = nullptr; Button* m_activeMenuButton = nullptr; ViewChild> m_rightClickMenu; boo::SWindowRect m_rightClickMenuRootAndLoc; SplitView* m_hoverSplitDragView = nullptr; bool m_activeSplitDragView = false; SplitView* recursiveTestSplitHover(SplitView* sv, const boo::SWindowCoord& coord) const; boo::DeferredWindowEvents m_events; struct SplitMenuSystem : IMenuNode { RootView& m_rv; std::string m_text; SplitView* m_splitView = nullptr; enum class Phase { Inactive, InteractiveSplit, InteractiveJoin, } m_phase = Phase::Inactive; int m_interactiveSlot = 0; float m_interactiveSplit = 0.5; bool m_interactiveDown = false; VertexBufferBindingSolid m_vertsBinding; ViewBlock m_viewBlock; hecl::UniformBufferPool::Token m_viewVertBlockBuf; SolidShaderVert m_verts[32]; void setArrowVerts(const boo::SWindowRect& rect, SplitView::ArrowDir dir); void setLineVerts(const boo::SWindowRect& rect, float split, SplitView::Axis axis); void mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods); void mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods); void mouseMove(const boo::SWindowCoord& coord); void mouseLeave(const boo::SWindowCoord& coord); void resized(); void draw(boo::IGraphicsCommandQueue* gfxQ); SplitMenuSystem(RootView& rv, boo::IGraphicsDataFactory::Context& ctx); const std::string* text() const override { return &m_text; } size_t subNodeCount() const override { return 2; } IMenuNode* subNode(size_t idx) override { if (idx) return &m_joinActionNode; else return &m_splitActionNode; } boo::SWindowCoord m_deferredCoord; bool m_deferredSplit = false; bool m_deferredJoin = false; struct SplitActionNode : IMenuNode { SplitMenuSystem& m_smn; std::string m_text; SplitActionNode(SplitMenuSystem& smn); const std::string* text() const override { return &m_text; } void activated(const boo::SWindowCoord& coord) override { m_smn.m_deferredSplit = true; m_smn.m_deferredCoord = coord; } } m_splitActionNode; struct JoinActionNode : IMenuNode { SplitMenuSystem& m_smn; std::string m_text; JoinActionNode(SplitMenuSystem& smn); const std::string* text() const override { return &m_text; } void activated(const boo::SWindowCoord& coord) override { m_smn.m_deferredJoin = true; m_smn.m_deferredCoord = coord; } } m_joinActionNode; }; std::optional m_splitMenuSystem; public: RootView(IViewManager& viewMan, ViewResources& res, boo::IWindow* window); ~RootView() override; void destroyed(); bool isDestroyed() const { return m_destroyed; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverloaded-virtual" void resized(const boo::SWindowRect& rect, bool) { resized(rect, rect); } #pragma GCC diagnostic pop void resized(const boo::SWindowRect& rootView, const boo::SWindowRect& sub) override; void mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods) override; void mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods) override; void mouseMove(const boo::SWindowCoord& coord) override; void mouseEnter(const boo::SWindowCoord& coord) override; void mouseLeave(const boo::SWindowCoord& coord) override; void scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll) override; void touchDown(const boo::STouchCoord& coord, uintptr_t tid) override; void touchUp(const boo::STouchCoord& coord, uintptr_t tid) override; void touchMove(const boo::STouchCoord& coord, uintptr_t tid) override; void charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat) override; void charKeyUp(unsigned long charCode, boo::EModifierKey mods) override; void specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat) override; void specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods) override; void modKeyDown(boo::EModifierKey mod, bool isRepeat) override; void modKeyUp(boo::EModifierKey mod) override; boo::ITextInputCallback* getTextInputCallback(); void internalThink(); void dispatchEvents() { m_events.dispatchEvents(); } void draw(boo::IGraphicsCommandQueue* gfxQ) override; const boo::SWindowRect& rootRect() const { return m_rootRect; } boo::IWindow* window() const { return m_window; } IViewManager& viewManager() const { return m_viewMan; } ViewResources& viewRes() const { return *m_viewRes; } const IThemeData& themeData() const; const boo::ObjToken& renderTex() const { return m_renderTex; } std::vector& accessContentViews() { return m_views; } void adoptRightClickMenu(std::unique_ptr&& menu, const boo::SWindowCoord& coord) { m_rightClickMenu.m_view = std::move(menu); m_rightClickMenuRootAndLoc = subRect(); m_rightClickMenuRootAndLoc.location[0] = coord.pixel[0]; m_rightClickMenuRootAndLoc.location[1] = coord.pixel[1]; updateSize(); } View* getRightClickMenu() { return m_rightClickMenu.m_view.get(); } void setActiveTextView(ITextInputView* textView); void setActiveDragView(View* dragView) { m_activeDragView = dragView; } void unsetActiveDragView(View* dragView) { if (dragView == m_activeDragView) m_activeDragView = nullptr; } void setActiveMenuButton(Button* button) { m_activeMenuButton = button; } void unsetActiveMenuButton(Button* button) { if (button == m_activeMenuButton) m_activeMenuButton = nullptr; } void startSplitDrag(SplitView* sv, const boo::SWindowCoord& coord) { m_hoverSplitDragView = sv; m_activeSplitDragView = true; sv->startDragSplit(coord); } bool m_hSplitHover = false; void setHorizontalSplitHover(bool hover) { m_hSplitHover = hover; _updateCursor(); } bool m_vSplitHover = false; void setVerticalSplitHover(bool hover) { m_vSplitHover = hover; _updateCursor(); } bool m_textFieldHover = false; void setTextFieldHover(bool hover) { m_textFieldHover = hover; _updateCursor(); } bool m_spaceCornerHover = false; void setSpaceCornerHover(bool hover) { m_spaceCornerHover = hover; _updateCursor(); } void resetTooltip(ViewResources& res); void displayTooltip(std::string_view name, std::string_view 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() { if (m_spaceCornerHover) m_window->setCursor(boo::EMouseCursor::Crosshairs); else if (m_vSplitHover) m_window->setCursor(boo::EMouseCursor::HorizontalArrow); else if (m_hSplitHover) m_window->setCursor(boo::EMouseCursor::VerticalArrow); else if (m_textFieldHover) m_window->setCursor(boo::EMouseCursor::IBeam); else m_window->setCursor(boo::EMouseCursor::Pointer); } std::vector m_views; std::unique_ptr m_tooltip; }; } // namespace specter