Improved dragging of widgets into AutoHideArea

This commit is contained in:
Uwe Kindler 2023-06-28 14:01:08 +02:00
parent f6ccaba6aa
commit b801f0655d
7 changed files with 127 additions and 38 deletions

View File

@ -437,8 +437,8 @@ void MainWindowPrivate::createContent()
// For this Special Dock Area we want to avoid dropping on the center of it (i.e. we don't want this widget to be ever tabbified):
{
SpecialDockArea->setAllowedAreas(ads::OuterDockAreas);
//SpecialDockArea->setAllowedAreas({ads::LeftDockWidgetArea, ads::RightDockWidgetArea}); // just for testing
//SpecialDockArea->setAllowedAreas(ads::OuterDockAreas);
SpecialDockArea->setAllowedAreas({ads::LeftDockWidgetArea, ads::RightDockWidgetArea, ads::TopDockWidgetArea}); // just for testing
}
DockWidget = createLongTextLabelDockWidget();
@ -506,7 +506,9 @@ void MainWindowPrivate::createContent()
// Test dock area docking
auto RighDockArea = DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(), TopDockArea);
DockManager->addDockWidget(ads::TopDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
DockWidget = createLongTextLabelDockWidget();
DockWidget->setFeature(ads::CDockWidget::DockWidgetPinnable, false);
DockManager->addDockWidget(ads::TopDockWidgetArea, DockWidget, RighDockArea);
auto BottomDockArea = DockManager->addDockWidget(ads::BottomDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
auto LabelDockWidget = createLongTextLabelDockWidget();

View File

@ -186,6 +186,12 @@ public:
*/
void dropIntoAutoHideSideBar(CFloatingDockContainer* FloatingWidget, DockWidgetArea area);
/**
* Creates a new tab for a widget dropped into the center of a section
*/
void dropIntoCenterOfSection(CFloatingDockContainer* FloatingWidget,
CDockAreaWidget* TargetArea);
/**
* Drop floating widget into dock area
*/
@ -207,13 +213,13 @@ public:
/**
* Creates a new tab for a widget dropped into the center of a section
*/
void dropIntoCenterOfSection(CFloatingDockContainer* FloatingWidget,
CDockAreaWidget* TargetArea);
void moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea);
/**
* Creates a new tab for a widget dropped into the center of a section
* Moves the dock widget or dock area given in Widget parameter to
* a auto hide sidebar area
*/
void moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea);
void moveToAutoHideSideBar(QWidget* Widget, DockWidgetArea area);
/**
@ -760,6 +766,33 @@ void DockContainerWidgetPrivate::moveToNewSection(QWidget* Widget, CDockAreaWidg
}
//============================================================================
void DockContainerWidgetPrivate::moveToAutoHideSideBar(QWidget* Widget, DockWidgetArea area)
{
std::cout << "DockContainerWidgetPrivate::moveToAutoHideSideBar " << area << std::endl;
CDockWidget* DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
CDockAreaWidget* DroppedDockArea = qobject_cast<CDockAreaWidget*>(Widget);
auto SideBarLocation = internal::toSideBarLocation(area);
if (DroppedDockWidget)
{
_this->createAndSetupAutoHideContainer(SideBarLocation, DroppedDockWidget);
}
else
{
for (const auto DockWidget : DroppedDockArea->openedDockWidgets())
{
if (!DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable))
{
continue;
}
_this->createAndSetupAutoHideContainer(SideBarLocation, DockWidget);
}
}
}
//============================================================================
void DockContainerWidgetPrivate::updateSplitterHandles( QSplitter* splitter )
{
@ -1724,24 +1757,6 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
d->DockManager->notifyFloatingWidgetDrop(FloatingWidget);
}
/*
* else if (internal::isSideBarArea(ContainerDropArea))
{
// Drop into AutoHideArea
auto DockWidget = qobject_cast<CDockWidget*>(d->Content);
auto DockArea = qobject_cast<CDockAreaWidget*>(d->Content);
auto SideBarLocation = internal::toSideBarLocation(ContainerDropArea);
if (DockWidget)
{
DockWidget->toggleAutoHide(SideBarLocation);
}
else if (DockArea)
{
DockArea->toggleAutoHide(SideBarLocation);
}
}
*/
//============================================================================
void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget)
@ -1752,6 +1767,10 @@ void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea,
{
d->moveToNewSection(Widget, TargetAreaWidget, DropArea);
}
else if (internal::isSideBarArea(DropArea))
{
d->moveToAutoHideSideBar(Widget, DropArea);
}
else
{
d->moveToContainer(Widget, DropArea);

View File

@ -103,6 +103,13 @@ protected:
*/
CAutoHideDockContainer* createAndSetupAutoHideContainer(SideBarLocation area, CDockWidget* DockWidget);
/**
* The funtion does the same like createAndSetupAutoHideContainer() but checks
* if the given DockWidget is pinnable. If it is not pinnable, the
* function returns a nullptr.
*/
CAutoHideDockContainer* createAutoHideContainerIfPinnable(SideBarLocation area, CDockWidget* DockWidget);
/**
* Helper function for creation of the root splitter
*/

View File

@ -209,6 +209,11 @@ struct DockOverlayCrossPrivate
CDockOverlay::eMode Mode)
{
QColor borderColor = iconColor(CDockOverlayCross::FrameColor);
// TODO: remove, this is just for debugging
if (Mode == CDockOverlay::ModeContainerOverlay)
{
borderColor = Qt::red;
}
QColor backgroundColor = iconColor(CDockOverlayCross::WindowBackgroundColor);
QColor overlayColor = iconColor(CDockOverlayCross::OverlayColor);
if (overlayColor.alpha() == 255)
@ -426,12 +431,26 @@ CDockOverlay::~CDockOverlay()
void CDockOverlay::setAllowedAreas(DockWidgetAreas areas)
{
if (areas == d->AllowedAreas)
{
return;
}
d->AllowedAreas = areas;
d->Cross->reset();
}
//============================================================================
void CDockOverlay::setAllowedArea(DockWidgetArea area, bool Enable)
{
auto AreasOld = d->AllowedAreas;
d->AllowedAreas.setFlag(area, Enable);
if (AreasOld != d->AllowedAreas)
{
d->Cross->reset();
}
}
//============================================================================
DockWidgetAreas CDockOverlay::allowedAreas() const
{
@ -456,6 +475,7 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
auto DockArea = qobject_cast<CDockAreaWidget*>(d->TargetWidget.data());
if (!DockArea && CDockManager::autoHideConfigFlags().testFlag(CDockManager::AutoHideFeatureEnabled))
{
std::cout << d->Mode << " Find out side bar area " << std::endl;
auto Rect = rect();
const QPoint pos = mapFromGlobal(QCursor::pos());
if (pos.x() < d->sideBarMouseZone(SideBarLeft))
@ -468,6 +488,7 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
}
else if (pos.y() < d->sideBarMouseZone(SideBarTop))
{
std::cout << d->Mode << " TopAutoHideArea " << std::endl;
return TopAutoHideArea;
}
else if (pos.y() > (Rect.height() - d->sideBarMouseZone(SideBarBottom)))
@ -513,12 +534,14 @@ DockWidgetArea CDockOverlay::visibleDropAreaUnderCursor() const
//============================================================================
DockWidgetArea CDockOverlay::showOverlay(QWidget* target)
{
std::cout << d->Mode << " CDockOverlay::showOverlay()" << target << " " << target->objectName().toStdString() << std::endl;
if (d->TargetWidget == target)
{
// Hint: We could update geometry of overlay here.
DockWidgetArea da = dropAreaUnderCursor();
if (da != d->LastLocation)
{
std::cout << d->Mode << " repaint()" << std::endl;
repaint();
d->LastLocation = da;
}
@ -543,6 +566,7 @@ DockWidgetArea CDockOverlay::showOverlay(QWidget* target)
//============================================================================
void CDockOverlay::hideOverlay()
{
std::cout << d->Mode << " CDockOverlay::hideOverlay()" << std::endl;
hide();
d->TargetWidget.clear();
d->LastLocation = InvalidDockWidgetArea;
@ -554,6 +578,7 @@ void CDockOverlay::hideOverlay()
void CDockOverlay::enableDropPreview(bool Enable)
{
d->DropPreviewEnabled = Enable;
std::cout << d->Mode << " update() " << Enable << std::endl;
update();
}
@ -581,6 +606,7 @@ void CDockOverlay::paintEvent(QPaintEvent* event)
double Factor = (CDockOverlay::ModeContainerOverlay == d->Mode) ?
3 : 2;
std::cout << "CDockOverlay::paintEvent da: " << da << std::endl;
switch (da)
{
case TopDockWidgetArea: r.setHeight(r.height() / Factor); break;
@ -596,6 +622,11 @@ void CDockOverlay::paintEvent(QPaintEvent* event)
}
QPainter painter(this);
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
// TODO: This is just for debugging - remove later
if (d->Mode == CDockOverlay::ModeContainerOverlay)
{
Color = Qt::red;
}
QPen Pen = painter.pen();
Pen.setColor(Color.darker(120));
Pen.setStyle(Qt::SolidLine);

View File

@ -72,6 +72,11 @@ public:
*/
void setAllowedAreas(DockWidgetAreas areas);
/**
* Enable / disable a certain area
*/
void setAllowedArea(DockWidgetArea area, bool Enable);
/**
* Returns flags with all allowed drop areas
*/

View File

@ -585,11 +585,19 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &GlobalPos)
}
int VisibleDockAreas = TopContainer->visibleDockAreaCount();
ContainerOverlay->setAllowedAreas(
VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
DockWidgetAreas AllowedAreas = (VisibleDockAreas > 1) ? OuterDockAreas : AllDockAreas;
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
// If the dock container contains only one single DockArea, then we need
// to respect the allowed areas - only the center area is relevant here because
// all other allowed areas are from the container
if (VisibleDockAreas == 1 && DockArea)
{
AllowedAreas.setFlag(CenterDockWidgetArea, DockArea->allowedAreas().testFlag(CenterDockWidgetArea));
}
ContainerOverlay->setAllowedAreas(AllowedAreas);
DockWidgetArea ContainerArea = ContainerOverlay->showOverlay(TopContainer);
ContainerOverlay->enableDropPreview(ContainerArea != InvalidDockWidgetArea);
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0)
{
DockAreaOverlay->enableDropPreview(true);

View File

@ -101,6 +101,7 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
{
if (!_this->isVisible() || !DockManager)
{
std::cout << "return 1" << std::endl;
return;
}
@ -126,20 +127,24 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
DropContainer = TopContainer;
auto ContainerOverlay = DockManager->containerOverlay();
auto DockAreaOverlay = DockManager->dockAreaOverlay();
auto DockDropArea = DockAreaOverlay->dropAreaUnderCursor();
auto ContainerDropArea = ContainerOverlay->dropAreaUnderCursor();
if (!TopContainer)
{
std::cout << "ContainerOverlay->hideOverlay() 1" << std::endl;
ContainerOverlay->hideOverlay();
std::cout << "DockAreaOverlay->hideOverlay() 1" << std::endl;
DockAreaOverlay->hideOverlay();
if (CDockManager::testConfigFlag(CDockManager::DragPreviewIsDynamic))
{
std::cout << "return 2" << std::endl;
setHidden(false);
}
return;
}
auto DockDropArea = DockAreaOverlay->dropAreaUnderCursor();
auto ContainerDropArea = ContainerOverlay->dropAreaUnderCursor();
int VisibleDockAreas = TopContainer->visibleDockAreaCount();
// Include the overlay widget we're dragging as a visible widget
@ -148,15 +153,25 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
{
VisibleDockAreas++;
}
std::cout << "VisibleDockAreas " << VisibleDockAreas << std::endl;
ContainerOverlay->setAllowedAreas( VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
DockWidgetAreas AllowedAreas = (VisibleDockAreas > 1) ? OuterDockAreas : AllDockAreas;
//ContainerOverlay->enableDropPreview(ContainerDropArea != InvalidDockWidgetArea);
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
// If the dock container contains only one single DockArea, then we need
// to respect the allowed areas - only the center area is relevant here because
// all other allowed areas are from the container
if (VisibleDockAreas == 1 && DockArea)
{
AllowedAreas.setFlag(CenterDockWidgetArea, DockArea->allowedAreas().testFlag(CenterDockWidgetArea));
}
ContainerOverlay->setAllowedAreas(AllowedAreas);
if (DockArea && DockArea->isVisible() && VisibleDockAreas >= 0 && DockArea != ContentSourceArea)
{
DockAreaOverlay->enableDropPreview(true);
DockAreaOverlay->setAllowedAreas( (VisibleDockAreas == 1) ? NoDockWidgetArea : DockArea->allowedAreas());
DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea);
std::cout << "DockWidgetArea " << Area << std::endl;
// A CenterDockWidgetArea for the dockAreaOverlay() indicates that
// the mouse is in the title bar. If the ContainerArea is valid
@ -165,28 +180,30 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
if ((Area == CenterDockWidgetArea) && (ContainerDropArea != InvalidDockWidgetArea))
{
DockAreaOverlay->enableDropPreview(false);
std::cout << "ContainerOverlay->enableDropPreview(true) 1" << std::endl;
ContainerOverlay->enableDropPreview(true);
}
else
{
std::cout << "ContainerOverlay->enableDropPreview 2" << std::endl;
ContainerOverlay->enableDropPreview(InvalidDockWidgetArea == Area);
}
ContainerOverlay->showOverlay(TopContainer);
}
else
{
std::cout << "DockAreaOverlay->hideOverlay() 2" << std::endl;
DockAreaOverlay->hideOverlay();
// If there is only one single visible dock area in a container, then
// it does not make sense to show a dock overlay because the dock area
// would be removed and inserted at the same position
// would be removed and inserted at the same position. Only auto hide
// area is allowed
if (VisibleDockAreas == 1)
{
ContainerOverlay->hideOverlay();
}
else
{
ContainerOverlay->showOverlay(TopContainer);
ContainerOverlay->setAllowedAreas(AutoHideDockAreas);
}
ContainerOverlay->showOverlay(TopContainer);
if (DockArea == ContentSourceArea && InvalidDockWidgetArea == ContainerDropArea)