diff --git a/src/app/ui/main_window.cpp b/src/app/ui/main_window.cpp index 5653e4cb9..86e54f6ba 100644 --- a/src/app/ui/main_window.cpp +++ b/src/app/ui/main_window.cpp @@ -247,6 +247,17 @@ void MainWindow::onActiveViewChange() configureWorkspaceLayout(); } +bool MainWindow::onIsModified(Tabs* tabs, TabView* tabView) +{ + if (DocumentView* docView = dynamic_cast(tabView)) { + Document* document = docView->getDocument(); + return document->isModified(); + } + else { + return false; + } +} + void MainWindow::onSelectTab(Tabs* tabs, TabView* tabView) { if (!tabView) @@ -286,15 +297,16 @@ void MainWindow::onMouseOverTab(Tabs* tabs, TabView* tabView) } } -bool MainWindow::onIsModified(Tabs* tabs, TabView* tabView) +void MainWindow::onFloatingTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) { - if (DocumentView* docView = dynamic_cast(tabView)) { - Document* document = docView->getDocument(); - return document->isModified(); - } - else { - return false; - } + m_workspace->setDropViewPreview(pos); +} + +DropTabResult MainWindow::onDropTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) +{ + m_workspace->removeDropViewPreview(pos); + m_workspace->dropViewAt(pos, dynamic_cast(tabView)); + return DropTabResult::IGNORE; } void MainWindow::configureWorkspaceLayout() diff --git a/src/app/ui/main_window.h b/src/app/ui/main_window.h index 740990b7d..92b53c529 100644 --- a/src/app/ui/main_window.h +++ b/src/app/ui/main_window.h @@ -74,11 +74,13 @@ namespace app { void popTimeline(); // TabsDelegate implementation. + bool onIsModified(Tabs* tabs, TabView* tabView) override; void onSelectTab(Tabs* tabs, TabView* tabView) override; void onCloseTab(Tabs* tabs, TabView* tabView) override; void onContextMenuTab(Tabs* tabs, TabView* tabView) override; void onMouseOverTab(Tabs* tabs, TabView* tabView) override; - bool onIsModified(Tabs* tabs, TabView* tabView) override; + void onFloatingTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) override; + DropTabResult onDropTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) override; protected: bool onProcessMessage(ui::Message* msg) override; diff --git a/src/app/ui/tabs.cpp b/src/app/ui/tabs.cpp index 94865162b..4dd6f4e0b 100644 --- a/src/app/ui/tabs.cpp +++ b/src/app/ui/tabs.cpp @@ -250,6 +250,9 @@ bool Tabs::onProcessMessage(Message* msg) createFloatingTab(m_selected); m_floatingOverlay->moveOverlay(mousePos - m_dragOffset); + + if (m_delegate) + m_delegate->onFloatingTab(this, m_selected->view, mousePos); } else { justDocked = m_floatingTab; @@ -332,8 +335,13 @@ bool Tabs::onProcessMessage(Message* msg) releaseMouse(); - if (m_isDragging) + if (m_isDragging) { + if (m_delegate) + m_delegate->onDropTab(this, m_selected->view, + mouseMsg->position()); + stopDrag(); + } if (m_clickedCloseButton) { m_clickedCloseButton = false; diff --git a/src/app/ui/tabs.h b/src/app/ui/tabs.h index 28e1939c1..696e30d51 100644 --- a/src/app/ui/tabs.h +++ b/src/app/ui/tabs.h @@ -41,11 +41,20 @@ namespace app { virtual TabIcon getTabIcon() = 0; }; + enum class DropTabResult { + IGNORE, + DOCKED_IN_OTHER_PLACE, + }; + // Interface used to control notifications from the Tabs widget. class TabsDelegate { public: + virtual ~TabsDelegate() { } + // Returns true if the tab represent a modified document. + virtual bool onIsModified(Tabs* tabs, TabView* tabView) = 0; + // Called when the user selected the tab with the left mouse button. virtual void onSelectTab(Tabs* tabs, TabView* tabView) = 0; @@ -59,7 +68,9 @@ namespace app { // mouse just leave all tabs) virtual void onMouseOverTab(Tabs* tabs, TabView* tabView) = 0; - virtual bool onIsModified(Tabs* tabs, TabView* tabView) = 0; + // Called when the user is dragging a tab outside the Tabs bar. + virtual void onFloatingTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) = 0; + virtual DropTabResult onDropTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) = 0; }; // Tabs control. Used to show opened documents. diff --git a/src/app/ui/workspace.cpp b/src/app/ui/workspace.cpp index 44ea6f418..959e30284 100644 --- a/src/app/ui/workspace.cpp +++ b/src/app/ui/workspace.cpp @@ -30,6 +30,7 @@ Workspace::Workspace() : Widget(kGenericWidget) , m_tabsBar(nullptr) , m_activeView(nullptr) + , m_dropPreview(false) { SkinTheme* theme = static_cast(getTheme()); setBgColor(theme->colors.workspace()); @@ -100,4 +101,58 @@ void Workspace::onPaint(PaintEvent& ev) ev.getGraphics()->fillRect(getBgColor(), getClientBounds()); } +void Workspace::onResize(ui::ResizeEvent& ev) +{ + setBoundsQuietly(ev.getBounds()); + + gfx::Rect cpos = getChildrenBounds(); + + // Preview to drop tabs in workspace + if (m_dropPreview && cpos.contains(m_dropPos)) { + int left = ABS(cpos.x - m_dropPos.x); + int top = ABS(cpos.y - m_dropPos.y); + int right = ABS(cpos.x + cpos.w - m_dropPos.x); + int bottom = ABS(cpos.y + cpos.h - m_dropPos.y); + int threshold = 32*guiscale(); + if (threshold > cpos.w/2) threshold = cpos.w/2; + if (threshold > cpos.h/2) threshold = cpos.h/2; + + if (left < threshold && left < right && left < top && left < bottom) { + cpos.x += threshold; + cpos.w -= threshold; + } + else if (top < threshold && top < left && top < right && top < bottom) { + cpos.y += threshold; + cpos.h -= threshold; + } + else if (right < threshold && right < left && right < top && right < bottom) { + cpos.w -= threshold; + } + else if (bottom < threshold && bottom < left && bottom < top && bottom < right) { + cpos.h -= threshold; + } + } + + for (Widget* child : getChildren()) + child->setBounds(cpos); +} + +void Workspace::setDropViewPreview(const gfx::Point& pos) +{ + m_dropPos = pos; + m_dropPreview = true; + + layout(); +} + +void Workspace::removeDropViewPreview(const gfx::Point& pos) +{ + m_dropPreview = false; + layout(); +} + +void Workspace::dropViewAt(const gfx::Point& pos, WorkspaceView* view) +{ +} + } // namespace app diff --git a/src/app/ui/workspace.h b/src/app/ui/workspace.h index a2f7c1f32..92e37b23c 100644 --- a/src/app/ui/workspace.h +++ b/src/app/ui/workspace.h @@ -40,15 +40,23 @@ namespace app { WorkspaceView* activeView(); void setActiveView(WorkspaceView* view); + // Drop views into workspace + void setDropViewPreview(const gfx::Point& pos); + void removeDropViewPreview(const gfx::Point& pos); + void dropViewAt(const gfx::Point& pos, WorkspaceView* view); + Signal0 ActiveViewChanged; protected: void onPaint(ui::PaintEvent& ev) override; + void onResize(ui::ResizeEvent& ev) override; private: Tabs* m_tabsBar; WorkspaceViews m_views; WorkspaceView* m_activeView; + bool m_dropPreview; + gfx::Point m_dropPos; }; } // namespace app