Files
KDDockWidgets/src/private/indicators/ClassicIndicators.cpp
2021-04-29 21:50:17 +02:00

208 lines
6.8 KiB
C++

/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "ClassicIndicators_p.h"
#include "DropArea_p.h"
#include "DragController_p.h"
#include "Frame_p.h"
#include "Logging_p.h"
#include "Config.h"
#include "DockRegistry_p.h"
#include "FrameworkWidgetFactory.h"
#include "ClassicIndicatorsWindow_p.h"
#include "Utils_p.h"
using namespace KDDockWidgets;
static IndicatorWindow* createIndicatorWindow(ClassicIndicators *classicIndicators)
{
auto window = new IndicatorWindow(classicIndicators);
window->setObjectName(QStringLiteral("_docks_IndicatorWindow_Overlay"));
return window;
}
ClassicIndicators::ClassicIndicators(DropArea *dropArea)
: DropIndicatorOverlayInterface(dropArea) // Is parented on the drop-area, not a toplevel.
, m_rubberBand(Config::self().frameworkWidgetFactory()->createRubberBand(dropArea))
, m_indicatorWindow(createIndicatorWindow(this))
{
}
ClassicIndicators::~ClassicIndicators()
{
delete m_indicatorWindow;
}
DropIndicatorOverlayInterface::DropLocation ClassicIndicators::hover_impl(QPoint globalPos)
{
return m_indicatorWindow->hover(globalPos);
}
QPoint ClassicIndicators::posForIndicator(DropIndicatorOverlayInterface::DropLocation loc) const
{
return m_indicatorWindow->posForIndicator(loc);
}
bool ClassicIndicators::innerIndicatorsVisible() const
{
return m_innerIndicatorsVisible;
}
bool ClassicIndicators::outterIndicatorsVisible() const
{
return m_outterIndicatorsVisible;
}
bool ClassicIndicators::tabIndicatorVisible() const
{
return m_tabIndicatorVisible;
}
bool ClassicIndicators::onResize(QSize)
{
m_indicatorWindow->resize(window()->size());
return false;
}
void ClassicIndicators::updateVisibility()
{
if (isHovered()) {
m_indicatorWindow->updatePositions();
m_indicatorWindow->setVisible(true);
updateWindowPosition();
updateIndicatorsVisibility(true);
raiseIndicators();
} else {
m_rubberBand->setVisible(false);
m_indicatorWindow->setVisible(false);
updateIndicatorsVisibility(false);
}
}
void ClassicIndicators::updateIndicatorsVisibility(bool visible)
{
const bool isTheOnlyFrame = m_hoveredFrame && m_hoveredFrame->isTheOnlyFrame();
m_innerIndicatorsVisible = visible && m_hoveredFrame;
WindowBeingDragged *windowBeingDragged = DragController::instance()->windowBeingDragged();
// If there's only 1 frame in the layout, the outter indicators are redundant, as they do the same thing as the internal ones.
// But there might be another window obscuring our target, so it's useful to show the outter indicators in this case
m_outterIndicatorsVisible = visible && (!isTheOnlyFrame ||
DockRegistry::self()->isProbablyObscured(m_hoveredFrame->window()->windowHandle(), windowBeingDragged));
// Only allow to dock to center if the affinities match
auto tabbingAllowedFunc = Config::self().tabbingAllowedFunc();
m_tabIndicatorVisible = m_innerIndicatorsVisible && windowBeingDragged &&
DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), windowBeingDragged->affinities());
if (m_tabIndicatorVisible && tabbingAllowedFunc) {
const DockWidgetBase::List source = windowBeingDragged->dockWidgets();
const DockWidgetBase::List target = m_hoveredFrame->dockWidgets();
m_tabIndicatorVisible = tabbingAllowedFunc(source, target);
}
Q_EMIT innerIndicatorsVisibleChanged();
Q_EMIT outterIndicatorsVisibleChanged();
Q_EMIT tabIndicatorVisibleChanged();
}
void ClassicIndicators::raiseIndicators()
{
m_indicatorWindow->raise();
}
KDDockWidgets::Location locationToMultisplitterLocation(ClassicIndicators::DropLocation location)
{
switch (location) {
case DropIndicatorOverlayInterface::DropLocation_Left:
return KDDockWidgets::Location_OnLeft;
case DropIndicatorOverlayInterface::DropLocation_Top:
return KDDockWidgets::Location_OnTop;
case DropIndicatorOverlayInterface::DropLocation_Right:
return KDDockWidgets::Location_OnRight;
case DropIndicatorOverlayInterface::DropLocation_Bottom:
return KDDockWidgets::Location_OnBottom;
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
return KDDockWidgets::Location_OnLeft;
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
return KDDockWidgets::Location_OnTop;
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
return KDDockWidgets::Location_OnRight;
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
return KDDockWidgets::Location_OnBottom;
default:
return KDDockWidgets::Location_None;
}
}
void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location)
{
setCurrentDropLocation(location);
if (location == DropLocation_None) {
m_rubberBand->setVisible(false);
return;
}
if (location == DropLocation_Center) {
m_rubberBand->setGeometry(m_hoveredFrame ? m_hoveredFrame->QWidgetAdapter::geometry() : rect());
m_rubberBand->setVisible(true);
return;
}
KDDockWidgets::Location multisplitterLocation = locationToMultisplitterLocation(location);
Frame *relativeToFrame = nullptr;
switch (location) {
case DropLocation_Left:
case DropLocation_Top:
case DropLocation_Right:
case DropLocation_Bottom:
if (!m_hoveredFrame) {
qWarning() << "ClassicIndicators::setCurrentDropLocation: frame is null. location=" << location
<< "; isHovered=" << isHovered()
<< "; dropArea->widgets=" << m_dropArea->items();
Q_ASSERT(false);
return;
}
relativeToFrame = m_hoveredFrame;
break;
case DropLocation_OutterLeft:
case DropLocation_OutterTop:
case DropLocation_OutterRight:
case DropLocation_OutterBottom:
break;
default:
break;
}
auto windowBeingDragged = DragController::instance()->windowBeingDragged();
QRect rect = m_dropArea->rectForDrop(windowBeingDragged, multisplitterLocation,
m_dropArea->itemForFrame(relativeToFrame));
m_rubberBand->setGeometry(rect);
m_rubberBand->setVisible(true);
}
void ClassicIndicators::updateWindowPosition()
{
QRect rect = this->rect();
if (KDDockWidgets::isWindow(m_indicatorWindow)) {
// On all non-wayland platforms it's a top-level.
QPoint pos = mapToGlobal(QPoint(0, 0));
rect.moveTo(pos);
}
m_indicatorWindow->setGeometry(rect);
}