35 #include <QGridLayout>
39 #include <QXmlStreamWriter>
40 #include <QAbstractButton>
54 #if QT_VERSION < 0x050900
58 return "0123456789abcdef"[value & 0xF];
66 const int length = separator ? (src.size() * 3 - 1) : (src.size() * 2);
67 QByteArray hex(length, Qt::Uninitialized);
68 char *hexData = hex.data();
70 for (
int i = 0, o = 0; i < src.size(); ++i) {
74 if ((separator) && (o < length))
75 hexData[o++] = separator;
116 Splitter->addWidget(widget);
120 Splitter->insertWidget(0, widget);
303 s->setChildrenCollapsible(
false);
313 int AreaSize = (Splitter->orientation() == Qt::Horizontal) ? Splitter->width() : Splitter->height();
314 auto SplitterSizes = Splitter->sizes();
316 qreal TotRatio = SplitterSizes.size() - 1.0 + LastRatio;
317 for(
int i = 0; i < SplitterSizes.size() -1; i++)
319 SplitterSizes[i] = AreaSize / TotRatio;
321 SplitterSizes.back() = AreaSize * LastRatio / TotRatio;
322 Splitter->setSizes(SplitterSizes);
362 auto ContainerDropArea =
DockManager->containerOverlay()->dropAreaUnderCursor();
368 dropArea = dropOverlay->showOverlay(DockArea);
370 ContainerDropArea != dropArea)
377 ADS_PRINT(
"Dock Area Drop Content: " << dropArea);
385 dropArea = ContainerDropArea;
386 ADS_PRINT(
"Container Drop Content: " << dropArea);
423 auto NewDockAreas = FloatingDockContainer->findChildren<
CDockAreaWidget*>(
424 QString(), Qt::FindChildrenRecursively);
429 Splitter->setOrientation(InsertParam.orientation());
431 else if (Splitter->orientation() != InsertParam.orientation())
433 QSplitter* NewSplitter =
newSplitter(InsertParam.orientation());
434 QLayoutItem* li =
Layout->replaceWidget(Splitter, NewSplitter);
435 NewSplitter->addWidget(Splitter);
437 Splitter = NewSplitter;
442 auto FloatingSplitter = FloatingDockContainer->
rootSplitter();
443 if (FloatingSplitter->count() == 1)
448 else if (FloatingSplitter->orientation() == InsertParam.orientation())
450 int InsertIndex = InsertParam.append() ? Splitter->count() : 0;
451 while (FloatingSplitter->count())
453 Splitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0));
468 if (!Splitter->isVisible())
481 auto NewDockWidgets = FloatingContainer->
dockWidgets();
483 int NewCurrentIndex = -1;
493 for (
int i = 0; i < NewDockWidgets.count(); ++i)
500 if (NewCurrentIndex < 0 && !DockWidget->isClosed())
525 QString(), Qt::FindChildrenRecursively);
526 QSplitter* TargetAreaSplitter = internal::findParent<QSplitter*>(TargetArea);
528 if (!TargetAreaSplitter)
530 QSplitter* Splitter =
newSplitter(InsertParam.orientation());
531 Layout->replaceWidget(TargetArea, Splitter);
532 Splitter->addWidget(TargetArea);
534 TargetAreaSplitter = Splitter;
536 int AreaIndex = TargetAreaSplitter->indexOf(TargetArea);
537 auto Widget = FloatingWidget->
dockContainer()->findChild<QWidget*>(QString(), Qt::FindDirectChildrenOnly);
538 auto FloatingSplitter = qobject_cast<QSplitter*>(Widget);
540 if (TargetAreaSplitter->orientation() == InsertParam.orientation())
542 auto Sizes = TargetAreaSplitter->sizes();
543 int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
544 bool AdjustSplitterSizes =
true;
545 if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1)
547 TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), Widget);
552 AdjustSplitterSizes = (FloatingSplitter->count() == 1);
553 int InsertIndex = AreaIndex + InsertParam.insertOffset();
554 while (FloatingSplitter->count())
556 TargetAreaSplitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0));
561 if (AdjustSplitterSizes)
563 int Size = (TargetAreaSize - TargetAreaSplitter->handleWidth()) / 2;
564 Sizes[AreaIndex] = Size;
565 Sizes.insert(AreaIndex, Size);
566 TargetAreaSplitter->setSizes(Sizes);
572 QSplitter* NewSplitter =
newSplitter(InsertParam.orientation());
573 int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
574 bool AdjustSplitterSizes =
true;
575 if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1)
577 NewSplitter->addWidget(Widget);
582 AdjustSplitterSizes = (FloatingSplitter->count() == 1);
583 while (FloatingSplitter->count())
585 NewSplitter->addWidget(FloatingSplitter->widget(0));
592 auto Sizes = TargetAreaSplitter->sizes();
595 if (AdjustSplitterSizes)
597 int Size = TargetAreaSize / 2;
598 NewSplitter->setSizes({Size, Size});
600 TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter);
601 TargetAreaSplitter->setSizes(Sizes);
613 auto DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
614 auto DroppedArea = qobject_cast<CDockAreaWidget*>(Widget);
616 if (DroppedDockWidget)
619 if (OldDockArea == TargetArea)
633 int NewCurrentIndex = DroppedArea->currentIndex();
634 for (
int i = 0; i < NewDockWidgets.count(); ++i)
640 DroppedArea->dockContainer()->removeDockArea(DroppedArea);
641 DroppedArea->deleteLater();
661 CDockWidget* DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
662 CDockAreaWidget* DroppedDockArea = qobject_cast<CDockAreaWidget*>(Widget);
664 if (DroppedDockWidget)
677 NewDockArea = DroppedDockArea;
681 QSplitter* TargetAreaSplitter = internal::findParent<QSplitter*>(TargetArea);
682 int AreaIndex = TargetAreaSplitter->indexOf(TargetArea);
683 auto Sizes = TargetAreaSplitter->sizes();
684 if (TargetAreaSplitter->orientation() == InsertParam.orientation())
686 int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
687 TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), NewDockArea);
689 int Size = (TargetAreaSize - TargetAreaSplitter->handleWidth()) / 2;
690 Sizes[AreaIndex] = Size;
691 Sizes.insert(AreaIndex, Size);
695 auto Sizes = TargetAreaSplitter->sizes();
696 int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
697 QSplitter* NewSplitter =
newSplitter(InsertParam.orientation());
698 NewSplitter->addWidget(TargetArea);
701 int Size = TargetAreaSize / 2;
702 NewSplitter->setSizes({Size, Size});
703 TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter);
706 TargetAreaSplitter->setSizes(Sizes);
720 for (
int i = 0; i < splitter->count(); ++i)
735 auto Area = qobject_cast<CDockAreaWidget*>(widget);
738 return Area->isCentralWidgetArea();
741 auto innerSplitter = qobject_cast<CDockSplitter*>(widget);
744 return innerSplitter->isResizingWithContainer();
755 CDockWidget* DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
756 CDockAreaWidget* DroppedDockArea = qobject_cast<CDockAreaWidget*>(Widget);
759 if (DroppedDockWidget)
775 auto Splitter = internal::findParent<CDockSplitter*>(DroppedDockArea);
777 if (Splitter ==
RootSplitter && InsertParam.orientation() == Splitter->orientation())
779 if (InsertParam.append() && Splitter->lastWidget() == DroppedDockArea)
783 else if (!InsertParam.append() && Splitter->firstWidget() == DroppedDockArea)
789 NewDockArea = DroppedDockArea;
801 int NewAreaCount = NewDockAreas.count();
806 for (
auto DockArea : NewDockAreas)
814 if (1 == CountBefore)
816 DockAreas.at(0)->updateTitleBarVisibility();
819 if (1 == NewAreaCount)
821 DockAreas.last()->updateTitleBarVisibility();
832 for (
auto DockArea : NewDockAreas)
834 QObject::connect(DockArea,
845 QSplitter* Splitter = qobject_cast<QSplitter*>(Widget);
848 s.writeStartElement(
"Splitter");
849 s.writeAttribute(
"Orientation", (Splitter->orientation() == Qt::Horizontal) ?
"|" :
"-");
850 s.writeAttribute(
"Count", QString::number(Splitter->count()));
851 ADS_PRINT(
"NodeSplitter orient: " << Splitter->orientation()
852 <<
" WidgetCont: " << Splitter->count());
853 for (
int i = 0; i < Splitter->count(); ++i)
858 s.writeStartElement(
"Sizes");
859 for (
auto Size : Splitter->sizes())
861 s.writeCharacters(QString::number(Size) +
" ");
879 QWidget*& CreatedWidget,
bool Testing)
882 QString OrientationStr =
s.attributes().value(
"Orientation").toString();
885 if (!OrientationStr.startsWith(
"|") && !OrientationStr.startsWith(
"-"))
892 bool HorizontalSplitter = OrientationStr.startsWith(
"|");
896 if (
s.fileVersion() == 0)
898 HorizontalSplitter = !HorizontalSplitter;
901 int Orientation = HorizontalSplitter ? Qt::Horizontal : Qt::Vertical;
902 int WidgetCount =
s.attributes().value(
"Count").toInt(&Ok);
907 ADS_PRINT(
"Restore NodeSplitter Orientation: " << Orientation <<
908 " WidgetCount: " << WidgetCount);
909 QSplitter* Splitter =
nullptr;
912 Splitter =
newSplitter(
static_cast<Qt::Orientation
>(Orientation));
914 bool Visible =
false;
916 while (
s.readNextStartElement())
918 QWidget* ChildNode =
nullptr;
920 if (
s.name() ==
"Splitter")
924 else if (
s.name() ==
"Area")
928 else if (
s.name() ==
"Sizes")
930 QString sSizes =
s.readElementText().trimmed();
932 QTextStream TextStream(&sSizes);
933 while (!TextStream.atEnd())
942 s.skipCurrentElement();
950 if (Testing || !ChildNode)
955 ADS_PRINT(
"ChildNode isVisible " << ChildNode->isVisible()
956 <<
" isVisibleTo " << ChildNode->isVisibleTo(Splitter));
957 Splitter->addWidget(ChildNode);
958 Visible |= ChildNode->isVisibleTo(Splitter);
965 if (Sizes.count() != WidgetCount)
972 if (!Splitter->count())
979 Splitter->setSizes(Sizes);
980 Splitter->setVisible(Visible);
982 CreatedWidget = Splitter;
986 CreatedWidget =
nullptr;
995 QWidget*& CreatedWidget,
bool Testing)
998 #ifdef ADS_DEBUG_PRINT
999 int Tabs =
s.attributes().value(
"Tabs").toInt(&Ok);
1006 QString CurrentDockWidget =
s.attributes().value(
"Current").toString();
1007 ADS_PRINT(
"Restore NodeDockArea Tabs: " << Tabs <<
" Current: "
1008 << CurrentDockWidget);
1014 const auto AllowedAreasAttribute =
s.attributes().value(
"AllowedAreas");
1015 if (!AllowedAreasAttribute.isEmpty())
1020 const auto FlagsAttribute =
s.attributes().value(
"Flags");
1021 if (!FlagsAttribute.isEmpty())
1023 DockArea->
setDockAreaFlags((CDockAreaWidget::DockAreaFlags)FlagsAttribute.toInt(
nullptr, 16));
1027 while (
s.readNextStartElement())
1029 if (
s.name() !=
"Widget")
1034 auto ObjectName =
s.attributes().value(
"Name");
1035 if (ObjectName.isEmpty())
1040 bool Closed =
s.attributes().value(
"Closed").toInt(&Ok);
1046 s.skipCurrentElement();
1076 DockArea->setProperty(
"currentDockWidget", CurrentDockWidget);
1080 CreatedWidget = DockArea;
1087 QWidget*& CreatedWidget,
bool Testing)
1090 while (
s.readNextStartElement())
1092 if (
s.name() ==
"Splitter")
1097 else if (
s.name() ==
"Area")
1104 s.skipCurrentElement();
1134 RootSplitter->setOrientation(InsertParam.orientation());
1138 if (Splitter->orientation() == InsertParam.orientation())
1142 if (Splitter->isHidden())
1149 QSplitter* NewSplitter =
newSplitter(InsertParam.orientation());
1150 if (InsertParam.append())
1152 QLayoutItem* li =
Layout->replaceWidget(Splitter, NewSplitter);
1153 NewSplitter->addWidget(Splitter);
1154 NewSplitter->addWidget(NewDockArea);
1160 NewSplitter->addWidget(NewDockArea);
1161 QLayoutItem* li =
Layout->replaceWidget(Splitter, NewSplitter);
1162 NewSplitter->addWidget(Splitter);
1176 #if defined(QT_DEBUG)
1177 QSplitter* Splitter = qobject_cast<QSplitter*>(widget);
1179 buf.fill(
' ', level * 4);
1182 #ifdef ADS_DEBUG_PRINT
1183 qDebug(
"%sSplitter %s v: %s c: %s",
1185 (Splitter->orientation() == Qt::Vertical) ?
"--" :
"|",
1186 Splitter->isHidden() ?
" " :
"v",
1187 QString::number(Splitter->count()).toStdString().c_str());
1188 std::cout << (
const char*)buf <<
"Splitter "
1189 << ((Splitter->orientation() == Qt::Vertical) ?
"--" :
"|") <<
" "
1190 << (Splitter->isHidden() ?
" " :
"v") <<
" "
1191 << QString::number(Splitter->count()).toStdString() << std::endl;
1193 for (
int i = 0; i < Splitter->count(); ++i)
1205 #ifdef ADS_DEBUG_PRINT
1206 qDebug(
"%sDockArea", (
const char*)buf);
1207 std::cout << (
const char*)buf
1208 << (DockArea->isHidden() ?
" " :
"v")
1210 <<
" DockArea " <<
"[hs: " << DockArea->sizePolicy().horizontalStretch() <<
", vs: " << DockArea->sizePolicy().verticalStretch() <<
"]" << std::endl;
1211 buf.fill(
' ', (level + 1) * 4);
1214 std::cout << (
const char*)buf << (i == DockArea->
currentIndex() ?
"*" :
" ");
1216 std::cout << (
DockWidget->isHidden() ?
" " :
"v");
1218 std::cout <<
DockWidget->windowTitle().toStdString() << std::endl;
1237 return TargetDockArea;
1244 QSplitter* TargetAreaSplitter = internal::findParent<QSplitter*>(TargetDockArea);
1245 int index = TargetAreaSplitter ->indexOf(TargetDockArea);
1246 if (TargetAreaSplitter->orientation() == InsertParam.orientation())
1248 ADS_PRINT(
"TargetAreaSplitter->orientation() == InsertParam.orientation()");
1249 TargetAreaSplitter->insertWidget(index + InsertParam.insertOffset(), NewDockArea);
1259 ADS_PRINT(
"TargetAreaSplitter->orientation() != InsertParam.orientation()");
1260 auto TargetAreaSizes = TargetAreaSplitter->sizes();
1261 QSplitter* NewSplitter =
newSplitter(InsertParam.orientation());
1262 NewSplitter->addWidget(TargetDockArea);
1266 TargetAreaSplitter->insertWidget(index, NewSplitter);
1270 TargetAreaSplitter->setSizes(TargetAreaSizes);
1288 d->
Layout =
new QGridLayout();
1289 d->
Layout->setContentsMargins(0, 1, 0, 1);
1298 if (DockManager !=
this)
1364 bool Result = QWidget::event(e);
1365 if (e->type() == QEvent::WindowActivate)
1383 if (Container && Container !=
this)
1395 ADS_PRINT(
"CDockContainerWidget::removeDockArea");
1396 area->disconnect(
this);
1398 CDockSplitter* Splitter = internal::findParent<CDockSplitter*>(area);
1402 area->setParent(
nullptr);
1412 if (Splitter->count() > 1)
1423 if (!Splitter->count())
1429 QWidget* widget = Splitter->widget(0);
1430 QSplitter* ChildSplitter = qobject_cast<QSplitter*>(widget);
1439 ChildSplitter->setParent(
nullptr);
1440 QLayoutItem* li =
d->
Layout->replaceWidget(Splitter, ChildSplitter);
1443 ADS_PRINT(
"RootSplitter replaced by child splitter");
1445 else if (Splitter->count() == 1)
1447 ADS_PRINT(
"Replacing splitter with content");
1448 QSplitter* ParentSplitter = internal::findParent<QSplitter*>(Splitter);
1449 auto Sizes = ParentSplitter->sizes();
1450 QWidget* widget = Splitter->widget(0);
1451 widget->setParent(
this);
1453 ParentSplitter->setSizes(Sizes);
1476 if (DockArea->isVisible() && DockArea->rect().contains(DockArea->mapFromGlobal(GlobalPos)))
1513 Result += DockArea->isHidden() ? 0 : 1;
1526 const QPoint& TargetPos)
1528 ADS_PRINT(
"CDockContainerWidget::dropFloatingWidget");
1533 auto ContainerDropArea =
d->
DockManager->containerOverlay()->dropAreaUnderCursor();
1534 bool Dropped =
false;
1539 dropOverlay->setAllowedAreas(DockArea->
allowedAreas());
1540 dropArea = dropOverlay->showOverlay(DockArea);
1542 ContainerDropArea != dropArea)
1549 ADS_PRINT(
"Dock Area Drop Content: " << dropArea);
1558 dropArea = ContainerDropArea;
1559 ADS_PRINT(
"Container Drop Content: " << dropArea);
1569 FloatingWidget->deleteLater();
1580 window()->activateWindow();
1581 if (SingleDroppedDockWidget)
1583 d->
DockManager->notifyWidgetOrAreaRelocation(SingleDroppedDockWidget);
1585 d->
DockManager->notifyFloatingWidgetDrop(FloatingWidget);
1593 if (TargetAreaWidget)
1606 window()->activateWindow();
1617 if (!DockArea->isHidden())
1619 Result.append(DockArea);
1630 ADS_PRINT(
"CDockContainerWidget::saveState isFloating "
1633 s.writeStartElement(
"Container");
1634 s.writeAttribute(
"Floating", QString::number(
isFloating() ? 1 : 0));
1638 QByteArray Geometry = FloatingWidget->saveGeometry();
1639 #if QT_VERSION < 0x050900
1642 s.writeTextElement(
"Geometry", Geometry.toHex(
' '));
1646 s.writeEndElement();
1653 bool IsFloating =
s.attributes().value(
"Floating").toInt();
1654 ADS_PRINT(
"Restore CDockContainerWidget Floating" << IsFloating);
1656 QWidget*NewRootSplitter {};
1667 if (!
s.readNextStartElement() ||
s.name() !=
"Geometry")
1672 QByteArray GeometryString =
s.readElementText(CDockingStateReader::ErrorOnUnexpectedElement).toLocal8Bit();
1673 QByteArray Geometry = QByteArray::fromHex(GeometryString);
1674 if (Geometry.isEmpty())
1682 FloatingWidget->restoreGeometry(Geometry);
1698 if (!NewRootSplitter)
1705 d->
RootSplitter = qobject_cast<QSplitter*>(NewRootSplitter);
1706 OldRoot->deleteLater();
1734 #if (ADS_DEBUG_LEVEL > 0)
1735 qDebug(
"\n\nDumping layout --------------------------");
1736 std::cout <<
"\n\nDumping layout --------------------------" << std::endl;
1738 qDebug(
"--------------------------\n\n");
1739 std::cout <<
"--------------------------\n\n" << std::endl;
1755 if (DockAreas.count() != 1)
1760 return DockAreas[0]->openDockWidgetsCount() == 1;
1768 if (!TopLevelDockArea)
1773 auto DockWidgets = TopLevelDockArea->openedDockWidgets();
1774 if (DockWidgets.count() != 1)
1779 return DockWidgets[0];
1788 if (DockAreas.count() != 1)
1793 return DockAreas[0];
1803 Result.append(DockArea->dockWidgets());
1823 Features &= DockArea->features();
1833 return internal::findParent<CFloatingDockContainer*>(
this);
1842 if (DockArea == KeepOpenArea)
1858 DockArea->closeArea();