KDDockWidgets API Documentation 2.1
Loading...
Searching...
No Matches
core/MainWindow.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5 Author: Sérgio Martins <sergio.martins@kdab.com>
6
7 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
8
9 Contact KDAB at <info@kdab.com> for commercial licensing options.
10*/
11
12
20#include "MainWindow.h"
21#include "MainWindow_p.h"
22#include "kddockwidgets/KDDockWidgets.h"
23#include "DockRegistry.h"
24#include "Layout_p.h"
25#include "core/MDILayout.h"
26#include "core/DropArea.h"
27#include "core/Utils_p.h"
28#include "core/Logging_p.h"
29#include "core/ScopedValueRollback_p.h"
30#include "core/WidgetResizeHandler_p.h"
31#include "core/ViewFactory.h"
32#include "core/LayoutSaver_p.h"
33#include "core/layouting/Item_p.h"
34#include "Platform.h"
35#include "core/DockWidget_p.h"
36#include "core/Group.h"
37#include "core/SideBar.h"
38#include "kddockwidgets/core/views/MainWindowViewInterface.h"
39
40#include <unordered_map>
41#include <algorithm>
42
43using namespace KDDockWidgets;
44using namespace KDDockWidgets::Core;
45
46static Layout *createLayout(MainWindow *mainWindow, MainWindowOptions options)
47{
48 if (options & MainWindowOption_MDI)
49 return new MDILayout(mainWindow->view());
50
51 return new DropArea(mainWindow->view(), options);
52}
53
54MainWindow::MainWindow(View *view, const QString &uniqueName, MainWindowOptions options)
56 , d(new Private(this, uniqueName, options))
57{
58}
59
60void MainWindow::init(const QString &name)
61{
62 d->init();
63 d->m_layout = createLayout(this, d->m_options);
64
65 d->m_persistentCentralDockWidget = d->createPersistentCentralDockWidget(d->name);
66
67 setUniqueName(name);
68
69 d->m_visibleWidgetCountConnection =
70 d->m_layout->d_ptr()->visibleWidgetCountChanged.connect([this](int count) { d->groupCountChanged.emit(count); });
71 view()->d->closeRequested.connect([this](CloseEvent *ev) { d->m_layout->onCloseEvent(ev); });
72
73 d->m_resizeConnection = view()->d->resized.connect([this](Size size) {
74 d->onResized(size);
75 });
76}
77
79{
81 delete d;
82}
83
85{
86 assert(widget);
87 KDDW_DEBUG("dock={}", ( void * )widget);
88
89 if (!DockRegistry::self()->affinitiesMatch(d->affinities, widget->affinities())) {
90 KDDW_ERROR("Refusing to dock widget with incompatible affinity. {} {}", widget->affinities(), affinities());
91 return;
92 }
93
94 if (widget->options() & DockWidgetOption_NotDockable) {
95 KDDW_ERROR("Refusing to dock non-dockable widget {}", ( void * )widget);
96 return;
97 }
98
99 if (isMDI()) {
100 // Not applicable to MDI
101 return;
102 }
103
104 if (d->supportsPersistentCentralWidget()) {
105 KDDW_ERROR("Not supported with MainWindowOption_HasCentralWidget."
106 "MainWindowOption_HasCentralWidget can only have 1 widget in the center.",
107 "Use MainWindowOption_HasCentralFrame instead, which is similar but supports "
108 "tabbing");
109 } else if (d->supportsCentralFrame()) {
110 dropArea()->centralGroup()->addTab(widget);
111 } else {
112 KDDW_ERROR("Not supported without MainWindowOption_HasCentralFrame");
113 }
114}
115
117 Core::DockWidget *relativeTo, const InitialOption &option)
118{
120 KDDW_ERROR("Refusing to dock non-dockable widget dw={}", ( void * )dw);
121 return;
122 }
123
124 if (isMDI()) {
125 // Not applicable to MDI
126 return;
127 }
128
129 dropArea()->addDockWidget(dw, location, relativeTo, option);
130}
131
133 KDDockWidgets::Location location, const KDDockWidgets::InitialOption &initialOption)
134{
135 if (!dockWidget || location == Location_None || isMDI())
136 return;
137
138 if (!(d->m_options & MainWindowOption_HasCentralFrame)) {
139 KDDW_ERROR("MainWindow::addDockWidgetToSide: A central group is required. Either MainWindowOption_HasCentralFrame or MainWindowOption_HasCentralWidget");
140 return;
141 }
142
143 Group *group = dropArea()->centralGroup();
144 if (!group || !group->layoutItem()) {
145 // Doesn't happen
146 KDDW_ERROR("MainWindow::addDockWidgetToSide: no group");
147 return;
148 }
149
150 auto locToUse = [](Location loc) {
151 switch (loc) {
152 case Location_None:
153 return Location_None;
154 case Location_OnLeft:
155 return Location_OnBottom;
156 case Location_OnTop:
157 return Location_OnRight;
158 case Location_OnRight:
159 return Location_OnBottom;
161 return Location_OnRight;
162 }
163
164 return Location_None;
165 };
166
167 Core::Item *neighbor = group->layoutItem()->outermostNeighbor(location, /*visibleOnly=*/false);
168 if (neighbor) {
169 if (neighbor->isContainer()) {
170 auto container = object_cast<ItemBoxContainer *>(neighbor);
171 const auto children = container->childItems();
172 if (children.isEmpty()) {
173 // Doesn't happen
174 KDDW_ERROR("MainWindow::addDockWidgetToSide: no children");
175 } else {
176 // There's an existing container with opposite orientation, add there but to end
177 dropArea()->_addDockWidget(dockWidget, locToUse(location), children.last(), initialOption);
178 }
179 } else {
180 dropArea()->_addDockWidget(dockWidget, locToUse(location), neighbor, initialOption);
181 }
182 } else {
183 addDockWidget(dockWidget, location, nullptr, initialOption);
184 }
185}
186
188{
189 return d->name;
190}
191
192MainWindowOptions MainWindow::options() const
193{
194 return d->m_options;
195}
196
198{
199 return d->m_layout->asDropArea();
200}
201
203{
204 return dropArea();
205}
206
208{
209 return d->m_layout;
210}
211
213{
214 return d->m_layout->asMDILayout();
215}
216
217void MainWindow::setAffinities(const Vector<QString> &affinityNames)
218{
219 Vector<QString> affinities = affinityNames;
221
222 if (d->affinities == affinities)
223 return;
224
225 if (!d->affinities.isEmpty()) {
226 KDDW_ERROR("Affinity is already set, refusing to change."
227 "Submit a feature request with a good justification.");
228 return;
229 }
230
231 d->affinities = affinities;
232}
233
235{
236 return d->affinities;
237}
238
240{
242}
243
245{
247}
248
249CursorPositions MainWindow::Private::allowedResizeSides(SideBarLocation loc) const
250{
251 // When a sidebar is on top, you can only resize its bottom.
252 // and so forth...
253
254 switch (loc) {
258 return CursorPosition_Left;
262 return CursorPosition_Top;
266 }
267
269}
270
271Rect MainWindow::Private::rectForOverlay(Core::Group *group, SideBarLocation location) const
272{
273 Core::SideBar *sb = q->sideBar(location);
274 if (!sb)
275 return {};
276
277 const Rect centralAreaGeo = q->centralAreaGeometry();
278 const Margins centerWidgetMargins = q->centerWidgetMargins();
279
280 Rect rect;
281 const int margin = m_overlayMargin;
282 switch (location) {
285
286 Core::SideBar *leftSideBar = q->sideBar(SideBarLocation::West);
287 Core::SideBar *rightSideBar = q->sideBar(SideBarLocation::East);
288 const int leftSideBarWidth =
289 (leftSideBar && leftSideBar->isVisible()) ? leftSideBar->width() : 0;
290 const int rightSideBarWidth =
291 (rightSideBar && rightSideBar->isVisible()) ? rightSideBar->width() : 0;
292 rect.setHeight(std::max(300, group->view()->minSize().height()));
293 rect.setWidth(centralAreaGeo.width() - margin * 2 - leftSideBarWidth - rightSideBarWidth);
294 rect.moveLeft(margin + leftSideBarWidth);
295 if (location == SideBarLocation::South) {
296 rect.moveTop(centralAreaGeo.bottom() - centerWidgetMargins.bottom() - rect.height()
297 - sb->height());
298 } else {
299 rect.moveTop(centralAreaGeo.y() + sb->height() + centerWidgetMargins.top());
300 }
301 break;
302 }
305 Core::SideBar *topSideBar = q->sideBar(SideBarLocation::North);
306 Core::SideBar *bottomSideBar = q->sideBar(SideBarLocation::South);
307 const int topSideBarHeight =
308 (topSideBar && topSideBar->isVisible()) ? topSideBar->height() : 0;
309 const int bottomSideBarHeight =
310 (bottomSideBar && bottomSideBar->isVisible()) ? bottomSideBar->height() : 0;
311 rect.setWidth(std::max(300, group->view()->minSize().width()));
312 rect.setHeight(centralAreaGeo.height() - topSideBarHeight - bottomSideBarHeight
313 - centerWidgetMargins.top() - centerWidgetMargins.bottom());
314 rect.moveTop(sb->view()->mapTo(q->view(), Point(0, 0)).y() + topSideBarHeight - 1);
315 if (location == SideBarLocation::East) {
316 rect.moveLeft(centralAreaGeo.x() + centralAreaGeo.width() - rect.width() - sb->width()
317 - centerWidgetMargins.right() - margin);
318 } else {
319 rect.moveLeft(margin + centralAreaGeo.x() + centerWidgetMargins.left() + sb->width());
320 }
321
322 break;
323 }
326 break;
327 }
328
329 return rect;
330}
331
332static SideBarLocation opposedSideBarLocationForBorder(Core::LayoutBorderLocation loc)
333{
334 switch (loc) {
335 case Core::LayoutBorderLocation_North:
337 case Core::LayoutBorderLocation_East:
339 case Core::LayoutBorderLocation_West:
341 case Core::LayoutBorderLocation_South:
343 case Core::LayoutBorderLocation_All:
344 case Core::LayoutBorderLocation_Verticals:
345 case Core::LayoutBorderLocation_Horizontals:
346 case Core::LayoutBorderLocation_None:
347 break;
348 }
349
350 KDDW_ERROR("Unknown loc={}", loc);
352}
353
354static SideBarLocation sideBarLocationForBorder(Core::LayoutBorderLocations loc)
355{
356 switch (loc) {
357 case Core::LayoutBorderLocation_North:
359 case Core::LayoutBorderLocation_East:
361 case Core::LayoutBorderLocation_West:
363 case Core::LayoutBorderLocation_South:
365 case Core::LayoutBorderLocation_All:
366 case Core::LayoutBorderLocation_Verticals:
367 case Core::LayoutBorderLocation_Horizontals:
368 case Core::LayoutBorderLocation_None:
369 break;
370 }
371
373}
374
375SideBarLocation MainWindow::Private::preferredSideBar(Core::DockWidget *dw) const
376{
377 Group *group = dw->d->group();
378 Core::Item *item = q->layout()->itemForGroup(group);
379 if (!item) {
380 KDDW_ERROR("No item for dock widget");
382 }
383
384 const Core::LayoutBorderLocations borders = item->adjacentLayoutBorders();
385 const double aspectRatio = group->width() / (std::max(1, group->height()) * 1.0);
386
388 if (borders == Core::LayoutBorderLocation_All) {
389 return aspectRatio > 1.0 ? SideBarLocation::South : SideBarLocation::East;
390 }
391
393 for (auto borderLoc :
394 { Core::LayoutBorderLocation_North, Core::LayoutBorderLocation_East,
395 Core::LayoutBorderLocation_West, Core::LayoutBorderLocation_South }) {
396 if (borders == (Core::LayoutBorderLocation_All & ~borderLoc))
397 return opposedSideBarLocationForBorder(borderLoc);
398 }
399
401 if ((borders & Core::LayoutBorderLocation_Verticals)
402 == Core::LayoutBorderLocation_Verticals) {
403
404 const int distanceToTop = group->geometry().y();
405 const int distanceToBottom = q->layout()->layoutHeight() - group->geometry().bottom();
406 return distanceToTop > distanceToBottom ? SideBarLocation::South : SideBarLocation::North;
407 }
408
410 if ((borders & Core::LayoutBorderLocation_Horizontals)
411 == Core::LayoutBorderLocation_Horizontals) {
412
413 const int distanceToLeft = group->geometry().x();
414 const int distanceToRight = q->layout()->layoutWidth() - group->geometry().right();
415 return distanceToLeft > distanceToRight ? SideBarLocation::East : SideBarLocation::West;
416 }
417
418 // 5. It's in a corner
419 if (borders == (Core::LayoutBorderLocation_West | Core::LayoutBorderLocation_South)) {
420 return aspectRatio > 1.0 ? SideBarLocation::South : SideBarLocation::West;
421 } else if (borders
422 == (Core::LayoutBorderLocation_East | Core::LayoutBorderLocation_South)) {
423 return aspectRatio > 1.0 ? SideBarLocation::South : SideBarLocation::East;
424 } else if (borders
425 == (Core::LayoutBorderLocation_West | Core::LayoutBorderLocation_North)) {
426 return aspectRatio > 1.0 ? SideBarLocation::North : SideBarLocation::West;
427 } else if (borders
428 == (Core::LayoutBorderLocation_East | Core::LayoutBorderLocation_North)) {
429 return aspectRatio > 1.0 ? SideBarLocation::North : SideBarLocation::East;
430 }
431
432
433 {
434 // 6. It's only touching 1 border
436 if (loc != SideBarLocation::None)
437 return loc;
438 }
439
440 // It's not touching any border, use aspect ratio.
441 return aspectRatio > 1.0 ? SideBarLocation::South : SideBarLocation::West;
442}
443
444void MainWindow::Private::updateOverlayGeometry(Size suggestedSize)
445{
446 if (!m_overlayedDockWidget)
447 return;
448
449 Core::SideBar *sb = q->sideBarForDockWidget(m_overlayedDockWidget);
450 if (!sb) {
451 KDDW_ERROR("Expected a sidebar");
452 return;
453 }
454
455 const Rect defaultGeometry = rectForOverlay(m_overlayedDockWidget->d->group(), sb->location());
456 Rect newGeometry = defaultGeometry;
457
458 Core::Group *group = m_overlayedDockWidget->d->group();
459
460 if (suggestedSize.isValid() && !suggestedSize.isEmpty()) {
461 // Let's try to honour the suggested overlay size
462 switch (sb->location()) {
464 const int maxHeight = q->height() - group->pos().y() - 10; // gap
465 newGeometry.setHeight(std::min(suggestedSize.height(), maxHeight));
466 break;
467 }
469 const int maxHeight = sb->pos().y() - m_layout->view()->pos().y() - 10; // gap
470 const int bottom = newGeometry.bottom();
471 newGeometry.setHeight(std::min(suggestedSize.height(), maxHeight));
472 newGeometry.moveBottom(bottom);
473 break;
474 }
476 const int maxWidth = sb->pos().x() - m_layout->view()->pos().x() - 10; // gap
477 const int right = newGeometry.right();
478 newGeometry.setWidth(std::min(suggestedSize.width(), maxWidth));
479 newGeometry.moveRight(right);
480 break;
481 }
483 const int maxWidth = q->width() - group->pos().x() - 10; // gap
484 newGeometry.setWidth(std::min(suggestedSize.width(), maxWidth));
485 break;
486 }
489 KDDW_ERROR("Unexpected sidebar value");
490 break;
491 }
492 }
493
494 m_overlayedDockWidget->d->group()->view()->setGeometry(newGeometry);
495}
496
497void MainWindow::Private::clearSideBars()
498{
501 if (Core::SideBar *sb = q->sideBar(loc))
502 sb->clear();
503 }
504}
505
506Rect MainWindow::Private::windowGeometry() const
507{
513
514 if (Core::Window::Ptr window = q->view()->window())
515 return window->geometry();
516
517 return q->window()->geometry();
518}
519
521{
522 moveToSideBar(dw, d->preferredSideBar(dw));
523}
524
526{
528 return;
529
530 if (Core::SideBar *sb = sideBar(location)) {
531 ScopedValueRollback rollback(dw->d->m_isMovingToSideBar, true);
533 dw->forceClose();
534 sb->addDockWidget(dw);
535 } else {
536 // Shouldn't happen
537 KDDW_ERROR("Minimization supported, probably disabled in Config::self().flags()");
538 }
539}
540
542{
543 if (!dw)
544 return;
545
546 DockWidget::Private::UpdateActions updateActions(dw);
547
548 // First un-overlay it, if it's overlayed
549 if (dw == d->m_overlayedDockWidget)
551
553 if (!sb) {
554 // Doesn't happen
555 KDDW_ERROR("Dock widget isn't in any sidebar");
556 return;
557 }
558
559 sb->removeDockWidget(dw);
560 dw->setFloating(false); // dock it
561}
562
564{
565 if (!dw || dw->isPersistentCentralDockWidget())
566 return;
567
568 const Core::SideBar *sb = sideBarForDockWidget(dw);
569 if (!sb) {
570 KDDW_ERROR("You need to add the dock widget to the sidebar before you can overlay it");
571 return;
572 }
573
574 if (d->m_overlayedDockWidget == dw) {
575 // Already overlayed
576 return;
577 }
578
579 // We only support one overlay at a time, remove any existing overlay
581
582 auto group = new Core::Group(nullptr, FrameOption_IsOverlayed);
583 group->setParentView(view());
584 d->m_overlayedDockWidget = dw;
585 group->addTab(dw);
586 d->updateOverlayGeometry(dw->d->lastPosition()->lastOverlayedGeometry(sb->location()).size());
587
588 group->setAllowedResizeSides(d->allowedResizeSides(sb->location()));
589 group->view()->show();
590
591 dw->d->isOverlayedChanged.emit(true);
592}
593
595{
596 const bool wasOverlayed = d->m_overlayedDockWidget == dw;
597 clearSideBarOverlay(); // Because only 1 dock widget can be overlayed each time
598 if (!wasOverlayed) {
600 }
601}
602
603void MainWindow::clearSideBarOverlay(bool deleteGroup)
604{
605 if (!d->m_overlayedDockWidget)
606 return;
607
608 auto overlayedDockWidget = d->m_overlayedDockWidget;
609 d->m_overlayedDockWidget = nullptr;
610
611 Core::Group *group = overlayedDockWidget->d->group();
612 if (!group) { // prophylactic check
613 return;
614 }
615
617 overlayedDockWidget->d->lastPosition()->setLastOverlayedGeometry(loc, group->geometry());
618
620 group->unoverlay();
621
622 if (deleteGroup) {
623 // only update actions at the end
624 DockWidget::Private::UpdateActions updateActions(overlayedDockWidget);
625
626 overlayedDockWidget->setParent(nullptr);
627
628 {
629 ScopedValueRollback guard(overlayedDockWidget->d->m_removingFromOverlay, true);
631 overlayedDockWidget->dptr()->setIsOpen(false);
632 }
633
634 overlayedDockWidget->d->isOverlayedChanged.emit(false);
635 overlayedDockWidget = nullptr;
636 delete group;
637 } else {
638 // No cleanup, just unset. When we drag the overlay it becomes a normal floating window
639 // meaning we reuse Frame. Don't delete it.
640 overlayedDockWidget->d->isOverlayedChanged.emit(false);
641 overlayedDockWidget = nullptr;
642 }
643}
644
646{
649
650 if (Core::SideBar *sb = sideBar(loc)) {
651 if (sb->containsDockWidget(const_cast<Core::DockWidget *>(dw)))
652 return sb;
653 }
654 }
655
656 return nullptr;
657}
658
660{
661 return d->m_overlayedDockWidget;
662}
663
665{
666 if (Core::SideBar *sb = sideBar(loc)) {
667 return !sb->isEmpty(); // isVisible() is always true, but its height is 0 when empty.
668 }
669
670 return false;
671}
672
674{
677 if (sideBarIsVisible(loc))
678 return true;
679 }
680
681 return false;
682}
683
684bool MainWindow::isMDI() const
685{
686 return d->m_options & MainWindowOption_MDI;
687}
688
689bool MainWindow::closeDockWidgets(bool force)
690{
691 bool allClosed = true;
692
693 const auto dockWidgets = d->m_layout->dockWidgets();
694 for (Core::DockWidget *dw : dockWidgets) {
695 Core::Group *group = dw->d->group();
696
697 if (force) {
698 dw->forceClose();
699 } else {
700 const bool closed = dw->view()->close();
701 allClosed = allClosed && closed;
702 }
703
704 if (group->beingDeletedLater()) {
705 // The dock widget was closed and this group is empty, delete immediately instead of
706 // waiting. I'm not a big fan of deleting stuff later, as state becomes inconsistent
707
708 // Empty groups are historically deleted later since they are triggered by mouse click
709 // on the title bar, and the title bar is inside the group.
710 // When doing it programmatically we can delete immediately.
711
712 delete group;
713 }
714 }
715
716 return allClosed;
717}
718
719void MainWindow::setUniqueName(const QString &uniqueName)
720{
721 if (uniqueName.isEmpty())
722 return;
723
724 if (d->name.isEmpty()) {
725 d->name = uniqueName;
726 d->uniqueNameChanged.emit();
728 } else {
729 KDDW_ERROR("Already has a name. {} {}", this->uniqueName(), uniqueName);
730 }
731}
732
733bool MainWindow::deserialize(const LayoutSaver::MainWindow &mw)
734{
735 if (mw.options != options()) {
736 KDDW_ERROR("Refusing to restore MainWindow with different options ; expected={}, has={}", int(mw.options), int(options()));
737 return false;
738 }
739
740 if (d->affinities != mw.affinities) {
741 KDDW_ERROR("Affinity name changed from {} to {}", d->affinities, mw.affinities);
742
743 d->affinities = mw.affinities;
744 }
745
746 // Restore the SideBars
747 d->clearSideBars();
750 Core::SideBar *sb = sideBar(loc);
751 if (!sb)
752 continue;
753
754 const Vector<QString> dockWidgets = mw.dockWidgetsForSideBar(loc);
755 for (const QString &uniqueName : dockWidgets) {
756
759 if (!dw) {
760 KDDW_ERROR("Could not find dock widget {} . Won't restore it to sidebar", uniqueName);
761 continue;
762 }
763
764 sb->addDockWidget(dw);
765 }
766 }
767
768 const bool success = layout()->deserialize(mw.multiSplitterLayout);
769
770 // Commented-out for now, we don't want to restore the popup/overlay. popups are perishable
771 // if (!mw.overlayedDockWidget.isEmpty())
772 // overlayOnSideBar(DockRegistry::self()->dockByName(mw.overlayedDockWidget));
773
774 return success;
775}
776
777LayoutSaver::MainWindow MainWindow::serialize() const
778{
779 LayoutSaver::MainWindow m;
780
781 Window::Ptr window = view()->window();
782
783 m.options = options();
784 m.geometry = d->windowGeometry();
785 m.normalGeometry = view()->normalGeometry();
786 m.isVisible = isVisible();
787 m.uniqueName = uniqueName();
788 m.screenIndex = Platform::instance()->screenNumberForView(view());
789 m.screenSize = Platform::instance()->screenSizeFor(view());
790 m.multiSplitterLayout = layout()->serialize();
791 m.affinities = d->affinities;
792 m.windowState = window ? window->windowState() : WindowState::None;
793
796 if (Core::SideBar *sb = sideBar(loc)) {
797 const Vector<QString> dockwidgets = sb->serialize();
798 if (!dockwidgets.isEmpty())
799 m.dockWidgetsPerSideBar[loc] = dockwidgets;
800 }
801 }
802
803 return m;
804}
805
806void MainWindow::setPersistentCentralView(std::shared_ptr<View> widget)
807{
808 if (!d->supportsPersistentCentralWidget()) {
809 KDDW_ERROR("MainWindow::setPersistentCentralWidget() requires "
810 "MainWindowOption_HasCentralWidget");
811 return;
812 }
813
814 if (auto dw = d->m_persistentCentralDockWidget) {
815 dw->setGuestView(widget);
816 } else {
817 KDDW_ERROR("Unexpected null central dock widget");
818 }
819}
820
821std::shared_ptr<View> MainWindow::persistentCentralView() const
822{
823 if (auto dw = d->m_persistentCentralDockWidget)
824 return dw->guestView();
825
826 return {};
827}
828
829void MainWindow::setContentsMargins(int left, int top, int right, int bottom)
830{
831 auto v = dynamic_cast<Core::MainWindowViewInterface *>(view());
832 v->setContentsMargins(left, top, right, bottom);
833}
834
836{
837 auto v = dynamic_cast<Core::MainWindowViewInterface *>(view());
838 return v->centerWidgetMargins();
839}
840
842{
843 auto it = d->m_sideBars.find(loc);
844 return it == d->m_sideBars.cend() ? nullptr : it->second;
845}
846
848{
849 auto v = dynamic_cast<Core::MainWindowViewInterface *>(view());
850 return v->centralAreaGeometry();
851}
852
854{
855 return d->m_overlayMargin;
856}
857
858void MainWindow::setOverlayMargin(int margin)
859{
860 if (margin == d->m_overlayMargin)
861 return;
862
863 d->m_overlayMargin = margin;
864 d->overlayMarginChanged.emit(margin);
865}
void setParentView(View *parent)
View * view() const
Returns the view associated with this controller, if any.
std::shared_ptr< View > window() const
The DockWidget base-class. DockWidget and Core::DockWidget are only split in two so we can share some...
bool setFloating(bool floats)
setter to make the dock widget float or dock.
SideBarLocation sideBarLocation() const
Returns whether this dock widget is in a side bar, and which. SideBarLocation::None is returned if it...
Vector< QString > affinities() const
Returns the affinity name. Empty by default.
std::shared_ptr< View > guestView() const
Like widget() but returns a view.
void setGuestView(std::shared_ptr< View > guest)
sets the widget which this dock widget hosts.
bool isPersistentCentralDockWidget() const
Returns whether this dock widget is the main window persistent central widget This only applies when ...
DockWidgetOptions options() const
Returns the dock widget's options which control behaviour.
void forceClose()
Like QWidget::close() but the hosted widget won't be asked if we should close.
void layoutParentContainerEqually(DockWidget *)
void _addDockWidget(DockWidget *dw, KDDockWidgets::Location location, Item *relativeTo, const InitialOption &initialOption)
void addDockWidget(DockWidget *dw, KDDockWidgets::Location location, DockWidget *relativeTo, const InitialOption &initialOption={})
void layoutEqually()
See docs for MainWindowBase::layoutEqually()
void unoverlay()
clears the FrameOption_IsOverlayed flag. For example, if you drag a side-bar overlay,...
void setAllowedResizeSides(CursorPositions sides)
To allow resizing the overlayed dock widget (auto-hide feature)
Core::Item * layoutItem() const
returns the layout item that either contains this Frame in the layout or is a placeholder
void addTab(DockWidget *, const InitialOption &={})
Adds a widget into the Group's Stack.
bool beingDeletedLater() const
Returns whether a deleteLater has already been issued.
The widget (QWidget or QQuickItem) which holds a layout of dock widgets.
Definition Layout.h:57
virtual bool deserialize(const LayoutSaver::MultiSplitter &)
Definition Layout.cpp:285
LayoutSaver::MultiSplitter serialize() const
Definition Layout.cpp:320
The MDILayout class implements a layout suitable for MDI style docking. Where dock widgets are free t...
The interface that MainWindow views should implement.
virtual Margins centerWidgetMargins() const =0
virtual void setContentsMargins(int left, int top, int right, int bottom)=0
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
bool sideBarIsVisible(KDDockWidgets::SideBarLocation location) const
Returns whether the specified sidebar is visible.
void setAffinities(const Vector< QString > &names)
Sets the affinities names. Dock widgets can only dock into main windows of the same affinity.
QString uniqueName() const
Returns the unique name that was passed via constructor. Used internally by the save/restore mechanis...
void setOverlayMargin(int margin)
Sets the margin used by overlay docks. Does not modify currently overlayed docks.
void addDockWidgetAsTab(KDDockWidgets::Core::DockWidget *dockwidget)
Docks a DockWidget into the central group, tabbed.
void overlayOnSideBar(KDDockWidgets::Core::DockWidget *dw)
Shows the dock widget overlayed on top of the main window, placed next to the sidebar.
friend class KDDockWidgets::QtWidgets::MainWindow
std::shared_ptr< View > persistentCentralView() const
KDDockWidgets::Core::SideBar * sideBarForDockWidget(const KDDockWidgets::Core::DockWidget *dw) const
Returns the sidebar this dockwidget is in. nullptr if not in any.
void toggleOverlayOnSideBar(KDDockWidgets::Core::DockWidget *dw)
Shows or hides an overlay. It's assumed the dock widget is already in a side-bar.
void layoutParentContainerEqually(KDDockWidgets::Core::DockWidget *dockWidget)
like layoutEqually() but starts with the container that has dockWidget. While layoutEqually() starts ...
Margins centerWidgetMargins() const
bool anySideBarIsVisible() const
Returns whether any side bar is visible.
int overlayMargin() const
Returns the margin used by overlay docks. Default: 1.
void setContentsMargins(int l, int t, int r, int b)
Sets the content's margins.
void setPersistentCentralView(std::shared_ptr< View > widget)
Sets a persistent central widget. It can't be detached.
MDILayout * mdiLayout() const
void layoutEqually()
layouts all the widgets so they have an equal size within their parent container
DropArea * multiSplitter() const
void clearSideBarOverlay(bool deleteGroup=true)
closes any overlayed dock widget. The sidebar still displays them as button.
MainWindowOptions options() const
Returns the main window options that were passed via constructor.
Core::DockWidget * overlayedDockWidget() const
returns the dock widget which is currently overlayed. nullptr if none. This is only relevant when usi...
void moveToSideBar(KDDockWidgets::Core::DockWidget *dw)
Moves the dock widget into one of the MainWindow's sidebar. Means the dock widget is removed from the...
bool closeDockWidgets(bool force=false)
Closes all dock widgets which are docked into this main window This is convenience to calling DockWid...
void init(const QString &name)
bool isMDI() const
Returns whether this main window is using an MDI layout. In other words, returns true if MainWindowOp...
Vector< QString > affinities() const
Returns the list of affinity names. Empty by default.
void addDockWidgetToSide(KDDockWidgets::Core::DockWidget *dockWidget, KDDockWidgets::Location location, const KDDockWidgets::InitialOption &initialOption={})
void restoreFromSideBar(KDDockWidgets::Core::DockWidget *dw)
Removes the dock widget from the sidebar and docks it into the main window again.
Core::SideBar * sideBar(SideBarLocation location) const
Returns the side bar at the specified location.
void addDockWidget(KDDockWidgets::Core::DockWidget *dockWidget, KDDockWidgets::Location location, KDDockWidgets::Core::DockWidget *relativeTo=nullptr, const KDDockWidgets::InitialOption &initialOption={})
Docks a DockWidget into this main window.
void setUniqueName(const QString &uniqueName)
static Platform * instance()
Returns the platform singleton.
virtual int screenNumberForView(View *) const =0
Returns the screen index for the specified view or window. It's up to the platform to decide how scre...
virtual Size screenSizeFor(View *) const =0
Returns the size of the screen where this view is in.
Vector< QString > serialize() const
returns a serialization of this sidebar's state Currently it's just a list of dock widget ids
void clear()
clears the sidebar (removes all dock widgets from it)
void removeDockWidget(DockWidget *dw)
SideBarLocation location() const
returns the sidebar's location in the main window
bool containsDockWidget(DockWidget *) const
void addDockWidget(DockWidget *dw)
bool isEmpty() const
returns whether there's no dock widgets
virtual void show()=0
virtual Size minSize() const =0
virtual Rect normalGeometry() const =0
virtual std::shared_ptr< Core::Window > window() const =0
Returns the window this view is inside For the Qt frontend, this wraps a QWindow. Like QWidget::windo...
virtual bool close()=0
virtual Point mapTo(View *, Point) const =0
@ CreateIfNotFound
Creates the dock widget via the user's widget factory in case it doesn't exist.
Q_INVOKABLE KDDockWidgets::Core::DockWidget * dockByName(const QString &, KDDockWidgets::DockRegistry::DockByNameFlags={}) const
void registerMainWindow(Core::MainWindow *)
static DockRegistry * self()
void unregisterMainWindow(Core::MainWindow *)
A MultiSplitter with support for drop indicators when hovering over.
static Layout * createLayout(MainWindow *mainWindow, MainWindowOptions options)
static SideBarLocation opposedSideBarLocationForBorder(Core::LayoutBorderLocation loc)
static SideBarLocation sideBarLocationForBorder(Core::LayoutBorderLocations loc)
ViewType
Each View type also has a specific Controller associated with, except for ViewType::None.
Definition Controller.h:26
Class to abstract QAction, so code still works with QtQuick and Flutter.
@ MainWindowOption_MDI
‍Makes the MainWindow always have a central group, for tabbing documents
@ MainWindowOption_HasCentralFrame
‍No option set
@ Location_OnTop
‍Left docking location
@ Location_OnRight
‍Top docking location
@ Location_OnBottom
‍Right docking location
SideBarLocation
Each main window supports 4 sidebars.
@ DockWidgetOption_NotDockable
The DockWidget can't be docked, it's always floating.
@ OverlayCollapse
User clicked the pin-button (or programmatically) (auto-hide/sidebar/pin-unpin functionality)
@ MovedToSideBar
User clicked menu with QAction.
bool isEmpty() const const
QTextStream & right(QTextStream &stream)
QMainWindow sub-class to enable KDDockWidgets support.
Struct describing the preferred dock widget size and visibility when adding it to a layout.

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated by doxygen 1.9.8