transferred the docking implementation to DropController

This commit is contained in:
Roman Pudashkin 2021-11-09 18:09:49 +02:00
parent 7d7e770df5
commit 4e835dd2eb
10 changed files with 482 additions and 466 deletions

View file

@ -22,7 +22,7 @@
#include "docksetup.h"
#include "internal/dragcontroller.h"
#include "internal/dropcontroller.h"
#include "internal/dockseparator.h"
#include "internal/dockframemodel.h"
#include "internal/dockwindowactionscontroller.h"
@ -51,7 +51,7 @@ class DockWidgetFactory : public KDDockWidgets::DefaultWidgetFactory
public:
KDDockWidgets::DropIndicatorOverlayInterface* createDropIndicatorOverlay(KDDockWidgets::DropArea* dropArea) const override
{
return new DragController(dropArea);
return new DropController(dropArea);
}
Layouting::Separator* createSeparator(Layouting::Widget* parent = nullptr) const override

View file

@ -44,8 +44,8 @@ set (DOCKWINDOW_SRC
${CMAKE_CURRENT_LIST_DIR}/dockcentralview.h
${CMAKE_CURRENT_LIST_DIR}/internal/dockbase.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/dockbase.h
${CMAKE_CURRENT_LIST_DIR}/internal/dragcontroller.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/dragcontroller.h
${CMAKE_CURRENT_LIST_DIR}/internal/dropcontroller.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/dropcontroller.h
${CMAKE_CURRENT_LIST_DIR}/internal/dockseparator.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/dockseparator.h
${CMAKE_CURRENT_LIST_DIR}/internal/dockframemodel.cpp

View file

@ -40,35 +40,6 @@
using namespace mu::dock;
using namespace mu::async;
static constexpr double MAX_DISTANCE_TO_HOLDER = 50;
static bool isPointAllowedForDrop(const QPoint& point, const DropDestination& dropDestination)
{
QRect dropRect = dropDestination.dock->frameGeometry();
if (!dropRect.contains(point)) {
return false;
}
if (dropDestination.dropDistance == 0) {
return true;
}
if (dropDestination.dropLocation == Location::Left) {
if (std::abs(dropRect.left() - point.x()) <= dropDestination.dropDistance) {
return true;
}
}
if (dropDestination.dropLocation == Location::Right) {
if (std::abs(dropRect.right() - point.x()) <= dropDestination.dropDistance) {
return true;
}
}
return false;
}
DockWindow::DockWindow(QQuickItem* parent)
: QQuickItem(parent),
m_toolBars(this),
@ -231,39 +202,14 @@ void DockWindow::toggleDockFloating(const QString& dockName)
}
}
DropDestination DockWindow::hover(const QString& draggedDockName, const QPoint& globalPos)
DockPageView* DockWindow::currentPage() const
{
DockBase* draggedDock = m_currentPage ? m_currentPage->dockByName(draggedDockName) : nullptr;
if (!draggedDock) {
return DropDestination();
}
QPoint hoveredLocalPos = m_mainWindow->mapFromGlobal(globalPos);
DropDestination dropDestination = resolveDropDestination(draggedDock, hoveredLocalPos);
if (auto toolBar = dynamic_cast<DockToolBarView*>(draggedDock)) {
updateToolBarOrientation(toolBar, dropDestination);
}
setCurrentDropDestination(draggedDock, dropDestination);
return m_currentDropDestination;
return m_currentPage;
}
void DockWindow::endHover()
QQuickItem& DockWindow::asItem() const
{
if (!m_currentDropDestination.isValid()) {
return;
}
m_currentDropDestination.dock->hideHighlighting();
if (m_currentDropDestination.dock->type() == DockType::DockingHolder) {
m_currentDropDestination.dock->close();
}
m_currentDropDestination.clear();
return *m_mainWindow;
}
DockingHolderView* DockWindow::mainToolBarDockingHolder() const
@ -555,237 +501,3 @@ QList<DockToolBarView*> DockWindow::topLevelToolBars(const DockPageView* page) c
return toolBars;
}
bool DockWindow::isMouseOverDock(const QPoint& mouseLocalPos, const DockBase* dock) const
{
QRect geometry = dock ? dock->frameGeometry() : QRect();
return geometry.contains(mouseLocalPos);
}
void DockWindow::updateToolBarOrientation(DockToolBarView* draggedToolBar, const DropDestination& dropDestination)
{
IF_ASSERT_FAILED(draggedToolBar) {
return;
}
framework::Orientation orientation = framework::Orientation::Horizontal;
if (!dropDestination.isValid()) {
draggedToolBar->setOrientation(static_cast<Qt::Orientation>(orientation));
return;
}
switch (dropDestination.dock->location()) {
case Location::Left:
case Location::Right:
orientation = framework::Orientation::Vertical;
break;
case Location::Top:
case Location::Bottom:
orientation = framework::Orientation::Horizontal;
break;
case Location::Center:
case Location::Undefined:
break;
}
draggedToolBar->setOrientation(static_cast<Qt::Orientation>(orientation));
}
void DockWindow::setCurrentDropDestination(const DockBase* draggedDock, const DropDestination& dropDestination)
{
if (m_currentDropDestination == dropDestination) {
return;
}
endHover();
m_currentDropDestination = dropDestination;
if (!m_currentDropDestination.isValid()) {
return;
}
auto showHighlighting = [this, draggedDock]() {
QRect highlightingRect = resolveHighlightingRect(draggedDock, m_currentDropDestination);
m_currentDropDestination.dock->showHighlighting(highlightingRect);
};
if (m_currentDropDestination.dock->type() != DockType::DockingHolder) {
showHighlighting();
return;
}
switch (m_currentDropDestination.dock->location()) {
case Location::Left:
case Location::Right:
m_currentDropDestination.dock->setMinimumWidth(draggedDock->minimumWidth());
break;
case Location::Top:
case Location::Bottom:
m_currentDropDestination.dock->setMinimumHeight(draggedDock->minimumHeight());
break;
case Location::Center:
case Location::Undefined:
break;
}
m_currentDropDestination.dock->open();
showHighlighting();
m_currentDropDestination.dock->init();
}
DropDestination DockWindow::resolveDropDestination(const DockBase* draggedDock, const QPoint& localPos) const
{
if (draggedDock->type() == DockType::Panel) {
DropDestination destination;
destination.dock = resolveTabifyPanel(dynamic_cast<const DockPanelView*>(draggedDock), localPos);
destination.dropLocation = resolveDropLocation(destination.dock, localPos);
if (destination.isValid()) {
return destination;
}
}
const DockingHolderView* holder = resolveDockingHolder(draggedDock->type(), localPos);
QList<DropDestination> destinations = draggedDock->dropDestinations();
for (const DropDestination& destination : destinations) {
if (holder == destination.dock) {
return destination;
}
if (isPointAllowedForDrop(localPos, destination)) {
return destination;
}
}
return DropDestination();
}
DockingHolderView* DockWindow::resolveDockingHolder(DockType draggedDockType, const QPoint& localPos) const
{
if (!m_currentPage) {
return nullptr;
}
if (!m_mainWindow->contains(localPos)) {
return nullptr;
}
QRect centralGeometry = m_currentPage->centralDock()->frameGeometry();
// TODO: Need to take any panels docked at top into account
if (localPos.y() <= centralGeometry.top() + MAX_DISTANCE_TO_HOLDER) {
return m_currentPage->holder(draggedDockType, Location::Top);
}
if (localPos.y() >= centralGeometry.bottom() - MAX_DISTANCE_TO_HOLDER) {
return m_currentPage->holder(draggedDockType, Location::Bottom);
}
if (localPos.x() <= MAX_DISTANCE_TO_HOLDER) {
return m_currentPage->holder(draggedDockType, Location::Left);
}
if (localPos.x() >= m_mainWindow->rect().right() - MAX_DISTANCE_TO_HOLDER) {
return m_currentPage->holder(draggedDockType, Location::Right);
}
return nullptr;
}
DockPanelView* DockWindow::resolveTabifyPanel(const DockPanelView* panel, const QPoint& localPos) const
{
QList<DockPanelView*> tabs = m_currentPage->possibleTabs(panel);
for (DockPanelView* tab : tabs) {
if (isMouseOverDock(localPos, tab)) {
return tab;
}
}
return nullptr;
}
Location DockWindow::resolveDropLocation(const DockBase* hoveredDock, const QPoint& localPos) const
{
if (!hoveredDock) {
return Location::Undefined;
}
QRect geometry = hoveredDock->frameGeometry();
Location dockLocation = hoveredDock->location();
qreal frameEnd = geometry.bottom();
qreal mousePos = localPos.y();
Location beginDropLocation = Location::Top;
Location endDropLocation = Location::Bottom;
if (dockLocation == Location::Top || dockLocation == Location::Bottom) {
mousePos = localPos.x();
frameEnd = geometry.right();
beginDropLocation = Location::Left;
endDropLocation = Location::Right;
}
if (mousePos <= frameEnd / 3) {
return beginDropLocation;
}
if (mousePos <= frameEnd / 1.5) {
return Location::Center;
}
if (mousePos <= frameEnd) {
return endDropLocation;
}
return Location::Undefined;
}
QRect DockWindow::resolveHighlightingRect(const DockBase* draggedDock, const DropDestination& destination) const
{
if (!destination.isValid()) {
return QRect();
}
QRect frameGeometry = destination.dock->frameGeometry();
int frameWidth = frameGeometry.width();
int frameHeight = frameGeometry.height();
QRect fullFrameHighlightingRect = QRect(0, 0, frameWidth, frameHeight);
if (destination.dock->type() == DockType::DockingHolder) {
return fullFrameHighlightingRect;
}
if (destination.dock->type() == DockType::Central) {
int draggedDockWidth = draggedDock->frameGeometry().width();
if (destination.dropLocation == Location::Left) {
return QRect(0, 0, draggedDockWidth, frameHeight);
}
if (destination.dropLocation == Location::Right) {
return QRect(frameWidth - draggedDockWidth, 0, draggedDockWidth, frameHeight);
}
}
switch (destination.dropLocation) {
case Location::Top:
return QRect(0, 0, frameWidth, frameHeight / 2);
case Location::Bottom:
return QRect(0, frameHeight / 2, frameWidth, frameHeight / 2);
case Location::Left:
return QRect(0, 0, frameWidth / 2, frameHeight);
case Location::Right:
return QRect(frameWidth / 2, 0, frameWidth / 2, frameHeight);
case Location::Center:
return fullFrameHighlightingRect;
case Location::Undefined:
break;
}
return QRect();
}

View file

@ -47,7 +47,6 @@ namespace mu::dock {
class DockToolBarView;
class DockingHolderView;
class DockPageView;
class DockPanelView;
class DockWindow : public QQuickItem, public IDockWindow, public async::Asyncable
{
Q_OBJECT
@ -86,8 +85,8 @@ public:
bool isDockFloating(const QString& dockName) const override;
void toggleDockFloating(const QString& dockName) override;
DropDestination hover(const QString& draggedDockName, const QPoint& globalPos) override;
void endHover() override;
DockPageView* currentPage() const override;
QQuickItem& asItem() const override;
public slots:
void setMainToolBarDockingHolder(DockingHolderView* mainToolBarDockingHolder);
@ -129,22 +128,11 @@ private:
QList<DockToolBarView*> topLevelToolBars(const DockPageView* page) const;
bool isMouseOverDock(const QPoint& mouseLocalPos, const DockBase* dock) const;
void updateToolBarOrientation(DockToolBarView* draggedToolBar, const DropDestination& dropDestination = DropDestination());
void setCurrentDropDestination(const DockBase* draggedDock, const DropDestination& dropDestination);
DropDestination resolveDropDestination(const DockBase* draggedDock, const QPoint& localPos) const;
DockingHolderView* resolveDockingHolder(DockType draggedDockType, const QPoint& localPos) const;
DockPanelView* resolveTabifyPanel(const DockPanelView* panel, const QPoint& localPos) const;
Location resolveDropLocation(const DockBase* hoveredDock, const QPoint& localPos) const;
QRect resolveHighlightingRect(const DockBase* draggedDock, const DropDestination& destination) const;
KDDockWidgets::MainWindowBase* m_mainWindow = nullptr;
DockPageView* m_currentPage = nullptr;
uicomponents::QmlListProperty<DockToolBarView> m_toolBars;
DockingHolderView* m_mainToolBarDockingHolder = nullptr;
uicomponents::QmlListProperty<DockPageView> m_pages;
DropDestination m_currentDropDestination;
async::Channel<QStringList> m_docksOpenStatusChanged;
bool m_quiting = false;

View file

@ -30,6 +30,7 @@
class QPoint;
namespace mu::dock {
class DockPageView;
class IDockWindow
{
public:
@ -44,8 +45,8 @@ public:
virtual bool isDockFloating(const QString& dockName) const = 0;
virtual void toggleDockFloating(const QString& dockName) = 0;
virtual DropDestination hover(const QString& draggedDockName, const QPoint& globalPos) = 0;
virtual void endHover() = 0;
virtual DockPageView* currentPage() const = 0;
virtual QQuickItem& asItem() const = 0;
};
}

View file

@ -128,7 +128,7 @@ signals:
protected:
friend class DockWindow;
friend class DragController;
friend class DropController;
virtual DockType type() const = 0;

View file

@ -1,104 +0,0 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "dragcontroller.h"
#include "../idockwindow.h"
#include "../docktypes.h"
using namespace mu::dock;
using DockWidget = KDDockWidgets::DockWidgetBase;
using KDDropLocation = KDDockWidgets::DropIndicatorOverlayInterface::DropLocation;
namespace mu::dock {
static const DockWidget* draggedDock()
{
auto windowBeingDragged = KDDockWidgets::DragController::instance()->windowBeingDragged();
if (!windowBeingDragged || windowBeingDragged->dockWidgets().isEmpty()) {
return nullptr;
}
return windowBeingDragged->dockWidgets().first();
}
static KDDropLocation dropLocationToKDDockLocation(Location location)
{
switch (location) {
case Location::Undefined: return KDDropLocation::DropLocation_None;
case Location::Left: return KDDropLocation::DropLocation_Left;
case Location::Right: return KDDropLocation::DropLocation_Right;
case Location::Center: return KDDropLocation::DropLocation_Center;
case Location::Top: return KDDropLocation::DropLocation_Top;
case Location::Bottom: return KDDropLocation::DropLocation_Bottom;
}
return KDDropLocation::DropLocation_None;
}
}
DragController::DragController(KDDockWidgets::DropArea* dropArea)
: KDDockWidgets::DropIndicatorOverlayInterface(dropArea)
{
}
KDDropLocation DragController::hover_impl(QPoint globalPos)
{
IDockWindow* window = dockWindow();
const DockWidget* dock = draggedDock();
if (!window || !dock) {
return DropLocation_None;
}
DropDestination destination = window->hover(dock->uniqueName(), globalPos);
setCurrentDropLocation(dropLocationToKDDockLocation(destination.dropLocation));
if (destination.isValid()) {
setHoveredFrame(destination.dock->dockWidget()->frame());
}
return currentDropLocation();
}
void DragController::updateVisibility()
{
if (draggedDock()) {
return;
}
setCurrentDropLocation(DropLocation_None);
if (auto window = dockWindow()) {
window->endHover();
}
}
QPoint DragController::posForIndicator(KDDropLocation) const
{
return QPoint();
}
IDockWindow* DragController::dockWindow() const
{
return dockWindowProvider()->window();
}

View file

@ -1,49 +0,0 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MU_DOCK_DRAGCONTROLLER_H
#define MU_DOCK_DRAGCONTROLLER_H
#include "modularity/ioc.h"
#include "../idockwindowprovider.h"
#include "thirdparty/KDDockWidgets/src/private/DropIndicatorOverlayInterface_p.h"
namespace mu::dock {
class DragController : public KDDockWidgets::DropIndicatorOverlayInterface
{
INJECT(dock, IDockWindowProvider, dockWindowProvider)
public:
explicit DragController(KDDockWidgets::DropArea* dropArea);
DropLocation hover_impl(QPoint globalPos) override;
QPoint posForIndicator(DropLocation) const override;
private:
void updateVisibility() override;
IDockWindow* dockWindow() const;
};
}
#endif // MU_DOCK_DRAGCONTROLLER_H

View file

@ -0,0 +1,398 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "dropcontroller.h"
#include "../idockwindow.h"
#include "../dockpanelview.h"
#include "../dockpageview.h"
#include "../docktoolbarview.h"
#include "globaltypes.h"
#include "log.h"
using namespace mu::dock;
static constexpr double MAX_DISTANCE_TO_HOLDER = 50;
using DockWidget = KDDockWidgets::DockWidgetBase;
using KDDropLocation = KDDockWidgets::DropIndicatorOverlayInterface::DropLocation;
namespace mu::dock {
static const DockWidget* draggedDock()
{
auto windowBeingDragged = KDDockWidgets::DragController::instance()->windowBeingDragged();
if (!windowBeingDragged || windowBeingDragged->dockWidgets().isEmpty()) {
return nullptr;
}
return windowBeingDragged->dockWidgets().first();
}
static KDDropLocation dropLocationToKDDockLocation(Location location)
{
switch (location) {
case Location::Undefined: return KDDropLocation::DropLocation_None;
case Location::Left: return KDDropLocation::DropLocation_Left;
case Location::Right: return KDDropLocation::DropLocation_Right;
case Location::Center: return KDDropLocation::DropLocation_Center;
case Location::Top: return KDDropLocation::DropLocation_Top;
case Location::Bottom: return KDDropLocation::DropLocation_Bottom;
}
return KDDropLocation::DropLocation_None;
}
static bool isPointAllowedForDrop(const QPoint& point, const DropDestination& dropDestination)
{
QRect dropRect = dropDestination.dock->frameGeometry();
if (!dropRect.contains(point)) {
return false;
}
if (dropDestination.dropDistance == 0) {
return true;
}
if (dropDestination.dropLocation == Location::Left) {
if (std::abs(dropRect.left() - point.x()) <= dropDestination.dropDistance) {
return true;
}
}
if (dropDestination.dropLocation == Location::Right) {
if (std::abs(dropRect.right() - point.x()) <= dropDestination.dropDistance) {
return true;
}
}
return false;
}
}
DropController::DropController(KDDockWidgets::DropArea* dropArea)
: KDDockWidgets::DropIndicatorOverlayInterface(dropArea)
{
}
KDDropLocation DropController::hover_impl(QPoint globalPos)
{
const DockWidget* dock = draggedDock();
const DockPageView* page = currentPage();
if (!page || !dock) {
return DropLocation_None;
}
DockBase* draggedDock = page->dockByName(dock->uniqueName());
if (!draggedDock) {
return DropLocation_None;
}
QPoint hoveredLocalPos = dockWindow()->asItem().mapFromGlobal(globalPos).toPoint();
DropDestination dropDestination = resolveDropDestination(draggedDock, hoveredLocalPos);
if (auto toolBar = dynamic_cast<DockToolBarView*>(draggedDock)) {
updateToolBarOrientation(toolBar, dropDestination);
}
setCurrentDropDestination(draggedDock, dropDestination);
setCurrentDropLocation(dropLocationToKDDockLocation(m_currentDropDestination.dropLocation));
if (m_currentDropDestination.isValid()) {
setHoveredFrame(m_currentDropDestination.dock->dockWidget()->frame());
}
return currentDropLocation();
}
void DropController::updateVisibility()
{
if (draggedDock()) {
return;
}
setCurrentDropLocation(DropLocation_None);
endHover();
}
QPoint DropController::posForIndicator(KDDropLocation) const
{
return QPoint();
}
void DropController::endHover()
{
if (!m_currentDropDestination.isValid()) {
return;
}
m_currentDropDestination.dock->hideHighlighting();
if (m_currentDropDestination.dock->type() == DockType::DockingHolder) {
m_currentDropDestination.dock->close();
}
m_currentDropDestination.clear();
}
bool DropController::isMouseOverDock(const QPoint& mouseLocalPos, const DockBase* dock) const
{
QRect geometry = dock ? dock->frameGeometry() : QRect();
return geometry.contains(mouseLocalPos);
}
void DropController::updateToolBarOrientation(DockToolBarView* draggedToolBar, const DropDestination& dropDestination)
{
IF_ASSERT_FAILED(draggedToolBar) {
return;
}
framework::Orientation orientation = framework::Orientation::Horizontal;
if (!dropDestination.isValid()) {
draggedToolBar->setOrientation(static_cast<Qt::Orientation>(orientation));
return;
}
switch (dropDestination.dock->location()) {
case Location::Left:
case Location::Right:
orientation = framework::Orientation::Vertical;
break;
case Location::Top:
case Location::Bottom:
orientation = framework::Orientation::Horizontal;
break;
case Location::Center:
case Location::Undefined:
break;
}
draggedToolBar->setOrientation(static_cast<Qt::Orientation>(orientation));
}
void DropController::setCurrentDropDestination(const DockBase* draggedDock, const DropDestination& dropDestination)
{
if (m_currentDropDestination == dropDestination) {
return;
}
endHover();
m_currentDropDestination = dropDestination;
if (!m_currentDropDestination.isValid()) {
return;
}
auto showHighlighting = [this, draggedDock]() {
QRect highlightingRect = resolveHighlightingRect(draggedDock, m_currentDropDestination);
m_currentDropDestination.dock->showHighlighting(highlightingRect);
};
if (m_currentDropDestination.dock->type() != DockType::DockingHolder) {
showHighlighting();
return;
}
switch (m_currentDropDestination.dock->location()) {
case Location::Left:
case Location::Right:
m_currentDropDestination.dock->setMinimumWidth(draggedDock->minimumWidth());
break;
case Location::Top:
case Location::Bottom:
m_currentDropDestination.dock->setMinimumHeight(draggedDock->minimumHeight());
break;
case Location::Center:
case Location::Undefined:
break;
}
m_currentDropDestination.dock->open();
showHighlighting();
m_currentDropDestination.dock->init();
}
DropDestination DropController::resolveDropDestination(const DockBase* draggedDock, const QPoint& localPos) const
{
if (draggedDock->type() == DockType::Panel) {
DropDestination destination;
destination.dock = resolveTabifyPanel(dynamic_cast<const DockPanelView*>(draggedDock), localPos);
destination.dropLocation = resolveDropLocation(destination.dock, localPos);
if (destination.isValid()) {
return destination;
}
}
const DockingHolderView* holder = resolveDockingHolder(draggedDock->type(), localPos);
QList<DropDestination> destinations = draggedDock->dropDestinations();
for (const DropDestination& destination : destinations) {
if (holder == destination.dock) {
return destination;
}
if (isPointAllowedForDrop(localPos, destination)) {
return destination;
}
}
return DropDestination();
}
DockingHolderView* DropController::resolveDockingHolder(DockType draggedDockType, const QPoint& localPos) const
{
if (!dockWindow()->asItem().contains(localPos)) {
return nullptr;
}
QRect centralGeometry = currentPage()->centralDock()->frameGeometry();
// TODO: Need to take any panels docked at top into account
if (localPos.y() <= centralGeometry.top() + MAX_DISTANCE_TO_HOLDER) {
return currentPage()->holder(draggedDockType, Location::Top);
}
if (localPos.y() >= centralGeometry.bottom() - MAX_DISTANCE_TO_HOLDER) {
return currentPage()->holder(draggedDockType, Location::Bottom);
}
if (localPos.x() <= MAX_DISTANCE_TO_HOLDER) {
return currentPage()->holder(draggedDockType, Location::Left);
}
if (localPos.x() >= dockWindow()->asItem().boundingRect().right() - MAX_DISTANCE_TO_HOLDER) {
return currentPage()->holder(draggedDockType, Location::Right);
}
return nullptr;
}
DockPanelView* DropController::resolveTabifyPanel(const DockPanelView* panel, const QPoint& localPos) const
{
QList<DockPanelView*> tabs = currentPage()->possibleTabs(panel);
for (DockPanelView* tab : tabs) {
if (isMouseOverDock(localPos, tab)) {
return tab;
}
}
return nullptr;
}
Location DropController::resolveDropLocation(const DockBase* hoveredDock, const QPoint& localPos) const
{
if (!hoveredDock) {
return Location::Undefined;
}
QRect geometry = hoveredDock->frameGeometry();
Location dockLocation = hoveredDock->location();
qreal frameEnd = geometry.bottom();
qreal mousePos = localPos.y();
Location beginDropLocation = Location::Top;
Location endDropLocation = Location::Bottom;
if (dockLocation == Location::Top || dockLocation == Location::Bottom) {
mousePos = localPos.x();
frameEnd = geometry.right();
beginDropLocation = Location::Left;
endDropLocation = Location::Right;
}
if (mousePos <= frameEnd / 3) {
return beginDropLocation;
}
if (mousePos <= frameEnd / 1.5) {
return Location::Center;
}
if (mousePos <= frameEnd) {
return endDropLocation;
}
return Location::Undefined;
}
QRect DropController::resolveHighlightingRect(const DockBase* draggedDock, const DropDestination& destination) const
{
if (!destination.isValid()) {
return QRect();
}
QRect frameGeometry = destination.dock->frameGeometry();
int frameWidth = frameGeometry.width();
int frameHeight = frameGeometry.height();
QRect fullFrameHighlightingRect = QRect(0, 0, frameWidth, frameHeight);
if (destination.dock->type() == DockType::DockingHolder) {
return fullFrameHighlightingRect;
}
if (destination.dock->type() == DockType::Central) {
int draggedDockWidth = draggedDock->frameGeometry().width();
if (destination.dropLocation == Location::Left) {
return QRect(0, 0, draggedDockWidth, frameHeight);
}
if (destination.dropLocation == Location::Right) {
return QRect(frameWidth - draggedDockWidth, 0, draggedDockWidth, frameHeight);
}
}
switch (destination.dropLocation) {
case Location::Top:
return QRect(0, 0, frameWidth, frameHeight / 2);
case Location::Bottom:
return QRect(0, frameHeight / 2, frameWidth, frameHeight / 2);
case Location::Left:
return QRect(0, 0, frameWidth / 2, frameHeight);
case Location::Right:
return QRect(frameWidth / 2, 0, frameWidth / 2, frameHeight);
case Location::Center:
return fullFrameHighlightingRect;
case Location::Undefined:
break;
}
return QRect();
}
IDockWindow* DropController::dockWindow() const
{
return dockWindowProvider()->window();
}
DockPageView* DropController::currentPage() const
{
return dockWindow() ? dockWindow()->currentPage() : nullptr;
}

View file

@ -0,0 +1,70 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MU_DOCK_DROPCONTROLLER_H
#define MU_DOCK_DROPCONTROLLER_H
#include "modularity/ioc.h"
#include "../idockwindowprovider.h"
#include "dockbase.h"
#include "thirdparty/KDDockWidgets/src/private/DropIndicatorOverlayInterface_p.h"
namespace mu::dock {
class DockPanelView;
class DockingHolderView;
class DockToolBarView;
class DockPageView;
class DropController : public KDDockWidgets::DropIndicatorOverlayInterface
{
INJECT(dock, IDockWindowProvider, dockWindowProvider)
public:
explicit DropController(KDDockWidgets::DropArea* dropArea);
DropLocation hover_impl(QPoint globalPos) override;
QPoint posForIndicator(DropLocation) const override;
private:
void updateVisibility() override;
void endHover();
bool isMouseOverDock(const QPoint& mouseLocalPos, const DockBase* dock) const;
void updateToolBarOrientation(DockToolBarView* draggedToolBar, const DropDestination& dropDestination = DropDestination());
void setCurrentDropDestination(const DockBase* draggedDock, const DropDestination& dropDestination);
DropDestination resolveDropDestination(const DockBase* draggedDock, const QPoint& localPos) const;
DockingHolderView* resolveDockingHolder(DockType draggedDockType, const QPoint& localPos) const;
DockPanelView* resolveTabifyPanel(const DockPanelView* panel, const QPoint& localPos) const;
Location resolveDropLocation(const DockBase* hoveredDock, const QPoint& localPos) const;
QRect resolveHighlightingRect(const DockBase* draggedDock, const DropDestination& destination) const;
IDockWindow* dockWindow() const;
DockPageView* currentPage() const;
DropDestination m_currentDropDestination;
};
}
#endif // MU_DOCK_DROPCONTROLLER_H