diff --git a/src/app/ui/main_window.cpp b/src/app/ui/main_window.cpp index 547e2a855..22a9740f4 100644 --- a/src/app/ui/main_window.cpp +++ b/src/app/ui/main_window.cpp @@ -298,9 +298,9 @@ void MainWindow::onMouseOverTab(Tabs* tabs, TabView* tabView) } } -void MainWindow::onFloatingTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) +DropViewPreviewResult MainWindow::onFloatingTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) { - m_workspace->setDropViewPreview(pos, + return m_workspace->setDropViewPreview(pos, dynamic_cast(tabView), static_cast(tabs)); } diff --git a/src/app/ui/main_window.h b/src/app/ui/main_window.h index 5fab9d60b..fff63ef38 100644 --- a/src/app/ui/main_window.h +++ b/src/app/ui/main_window.h @@ -79,7 +79,7 @@ namespace app { void onCloseTab(Tabs* tabs, TabView* tabView) override; void onContextMenuTab(Tabs* tabs, TabView* tabView) override; void onMouseOverTab(Tabs* tabs, TabView* tabView) override; - void onFloatingTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) override; + DropViewPreviewResult onFloatingTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) override; void onDockingTab(Tabs* tabs, TabView* tabView) override; DropTabResult onDropTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) override; diff --git a/src/app/ui/tabs.cpp b/src/app/ui/tabs.cpp index c3c7b6291..964f0280d 100644 --- a/src/app/ui/tabs.cpp +++ b/src/app/ui/tabs.cpp @@ -240,15 +240,19 @@ void Tabs::setDropViewPreview(const gfx::Point& pos, TabView* view) else newIndex = 0; - if (m_dropNewIndex == newIndex && m_dropNewTab == view) - return; + bool startAni = (m_dropNewIndex != newIndex || m_dropNewTab != view); m_dropNewIndex = newIndex; + m_dropNewPosX = (pos.x - getBounds().x); m_dropNewTab = view; - resetOldPositions(animationTime()); - updateTabs(); - startAnimation(ANI_REORDER_TABS, ANI_REORDER_TABS_TICKS); + if (startAni) { + resetOldPositions(animationTime()); + updateTabs(); + startAnimation(ANI_REORDER_TABS, ANI_REORDER_TABS_TICKS); + } + else + invalidate(); } void Tabs::removeDropViewPreview() @@ -286,19 +290,27 @@ bool Tabs::onProcessMessage(Message* msg) // We are drag a tab... else { TabPtr justDocked(nullptr); + bool dockedInThisTabs = true; // Floating tab (to create a new window) if (!getBounds().contains(mousePos) && (ABS(delta.y) > 16*guiscale() || mousePos.x < getBounds().x-16*guiscale() || mousePos.x > getBounds().x2()+16*guiscale())) { - if (!m_floatingOverlay) - createFloatingTab(m_selected); - - m_floatingOverlay->moveOverlay(mousePos - m_dragOffset); + DropViewPreviewResult result = DropViewPreviewResult::FLOATING; if (m_delegate) - m_delegate->onFloatingTab(this, m_selected->view, mousePos); + result = m_delegate->onFloatingTab(this, m_selected->view, mousePos); + + if (result != DropViewPreviewResult::DROP_IN_TABS) { + if (!m_floatingOverlay) + createFloatingTab(m_selected); + m_floatingOverlay->moveOverlay(mousePos - m_dragOffset); + dockedInThisTabs = false; + } + else { + destroyFloatingOverlay(); + } } else { justDocked = m_floatingTab; @@ -309,7 +321,7 @@ bool Tabs::onProcessMessage(Message* msg) } // Docked tab - if (!m_floatingOverlay) { + if (dockedInThisTabs) { m_selected->x = m_dragTabX + delta.x; int i = (mousePos.x - m_border*guiscale() - getBounds().x) / m_selected->width; @@ -474,6 +486,19 @@ void Tabs::onPaint(PaintEvent& ev) drawTab(g, box, m_selected.get(), dy, (tab == m_hot), true); } + + // New tab from other Tab that want to be dropped here. + if (m_dropNewTab) { + SkinTheme* theme = static_cast(this->getTheme()); + Tab newTab(m_dropNewTab); + newTab.text = m_dropNewTab->getTabText(); + newTab.icon = m_dropNewTab->getTabIcon(); + newTab.width = (!m_list.empty() ? m_list[0]->width: + theme->dimensions.tabsWidth()); + newTab.x = m_dropNewPosX - newTab.width/2; + box = getTabBounds(&newTab); + drawTab(g, box, &newTab, 0, true, true); + } } void Tabs::onResize(ResizeEvent& ev) @@ -830,10 +855,7 @@ void Tabs::createFloatingTab(TabPtr& tab) void Tabs::destroyFloatingTab() { - if (m_floatingOverlay) { - OverlayManager::instance()->removeOverlay(m_floatingOverlay.get()); - m_floatingOverlay.reset(); - } + destroyFloatingOverlay(); if (m_floatingTab) { TabPtr tab(m_floatingTab); @@ -848,4 +870,12 @@ void Tabs::destroyFloatingTab() } } +void Tabs::destroyFloatingOverlay() +{ + if (m_floatingOverlay) { + OverlayManager::instance()->removeOverlay(m_floatingOverlay.get()); + m_floatingOverlay.reset(); + } +} + } // namespace app diff --git a/src/app/ui/tabs.h b/src/app/ui/tabs.h index a279bb6eb..d97d521b1 100644 --- a/src/app/ui/tabs.h +++ b/src/app/ui/tabs.h @@ -49,6 +49,12 @@ namespace app { DOCKED_IN_OTHER_PLACE, }; + enum class DropViewPreviewResult { + DROP_IN_PANEL, + DROP_IN_TABS, + FLOATING, + }; + // Interface used to control notifications from the Tabs widget. class TabsDelegate { public: @@ -71,9 +77,13 @@ namespace app { // mouse just leave all tabs) virtual void onMouseOverTab(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; + // Called when the user is dragging a tab outside the Tabs + // bar. + virtual DropViewPreviewResult onFloatingTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) = 0; + + // Called when the user is dragging a tab inside the Tabs bar. virtual void onDockingTab(Tabs* tabs, TabView* tabView) = 0; + virtual DropTabResult onDropTab(Tabs* tabs, TabView* tabView, const gfx::Point& pos) = 0; }; @@ -154,6 +164,7 @@ namespace app { gfx::Rect getTabBounds(Tab* tab); void createFloatingTab(TabPtr& tab); void destroyFloatingTab(); + void destroyFloatingOverlay(); int m_border; TabsList m_list; @@ -185,6 +196,7 @@ namespace app { // Drop new tabs TabView* m_dropNewTab; int m_dropNewIndex; + int m_dropNewPosX; }; } // namespace app diff --git a/src/app/ui/workspace.cpp b/src/app/ui/workspace.cpp index 325274c24..6b13b09de 100644 --- a/src/app/ui/workspace.cpp +++ b/src/app/ui/workspace.cpp @@ -130,7 +130,7 @@ void Workspace::onResize(ui::ResizeEvent& ev) child->setBounds(rc); } -void Workspace::setDropViewPreview(const gfx::Point& pos, +DropViewPreviewResult Workspace::setDropViewPreview(const gfx::Point& pos, WorkspaceView* view, WorkspaceTabs* tabs) { TabView* tabView = dynamic_cast(view); @@ -155,6 +155,13 @@ void Workspace::setDropViewPreview(const gfx::Point& pos, m_dropPreviewPanel->setDropViewPreview(pos, view); if (m_dropPreviewTabs) m_dropPreviewTabs->setDropViewPreview(pos, tabView); + + if (panel) + return DropViewPreviewResult::DROP_IN_PANEL; + else if (newTabs) + return DropViewPreviewResult::DROP_IN_TABS; + else + return DropViewPreviewResult::FLOATING; } void Workspace::removeDropViewPreview() diff --git a/src/app/ui/workspace.h b/src/app/ui/workspace.h index 5d8b240ea..761c06fb2 100644 --- a/src/app/ui/workspace.h +++ b/src/app/ui/workspace.h @@ -9,6 +9,7 @@ #define APP_UI_WORKSPACE_H_INCLUDED #pragma once +#include "app/ui/tabs.h" #include "app/ui/workspace_panel.h" #include "base/signal.h" #include "ui/widget.h" @@ -43,8 +44,9 @@ namespace app { void selectNextTab(); void selectPreviousTab(); - // Drop views into workspace - void setDropViewPreview(const gfx::Point& pos, + // Set the preview of what could happen if we drop the given + // "view" at the "pos"? + DropViewPreviewResult setDropViewPreview(const gfx::Point& pos, WorkspaceView* view, WorkspaceTabs* tabs); void removeDropViewPreview();