21#include "MainWindow_p.h"
22#include "kddockwidgets/KDDockWidgets.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"
32#include "core/LayoutSaver_p.h"
33#include "core/layouting/Item_p.h"
35#include "core/DockWidget_p.h"
38#include "kddockwidgets/core/views/MainWindowViewInterface.h"
40#include <unordered_map>
56 , d(new Private(this, uniqueName, options))
65 d->m_persistentCentralDockWidget = d->createPersistentCentralDockWidget(d->name);
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); });
83 KDDW_DEBUG(
"dock={}", (
void * )widget);
86 KDDW_ERROR(
"Refusing to dock widget with incompatible affinity. {} {}", widget->
affinities(),
affinities());
91 KDDW_ERROR(
"Refusing to dock non-dockable widget {}", (
void * )widget);
100 if (d->supportsPersistentCentralWidget()) {
101 KDDW_ERROR(
"Not supported with MainWindowOption_HasCentralWidget."
102 "MainWindowOption_HasCentralWidget can only have 1 widget in the center.",
103 "Use MainWindowOption_HasCentralFrame instead, which is similar but supports "
105 }
else if (d->supportsCentralFrame()) {
108 KDDW_ERROR(
"Not supported without MainWindowOption_HasCentralFrame");
116 KDDW_ERROR(
"Refusing to dock non-dockable widget dw={}", (
void * )dw);
140 return d->m_layout->asDropArea();
155 return d->m_layout->asMDILayout();
166 if (!d->affinities.isEmpty()) {
167 KDDW_ERROR(
"Affinity is already set, refusing to change."
168 "Submit a feature request with a good justification.");
177 return d->affinities;
190CursorPositions MainWindow::Private::allowedResizeSides(
SideBarLocation loc)
const
218 const Rect centralAreaGeo = q->centralAreaGeometry();
219 const Margins centerWidgetMargins = q->centerWidgetMargins();
222 const int margin = m_overlayMargin;
229 const int leftSideBarWidth =
230 (leftSideBar && leftSideBar->
isVisible()) ? leftSideBar->
width() : 0;
231 const int rightSideBarWidth =
232 (rightSideBar && rightSideBar->
isVisible()) ? rightSideBar->
width() : 0;
233 rect.setHeight(std::max(300, group->
view()->
minSize().height()));
234 rect.setWidth(centralAreaGeo.width() - margin * 2 - leftSideBarWidth - rightSideBarWidth);
235 rect.moveLeft(margin + leftSideBarWidth);
237 rect.moveTop(centralAreaGeo.bottom() - centerWidgetMargins.bottom() - rect.height()
240 rect.moveTop(centralAreaGeo.y() + sb->
height() + centerWidgetMargins.top());
248 const int topSideBarHeight =
250 const int bottomSideBarHeight =
251 (bottomSideBar && bottomSideBar->
isVisible()) ? bottomSideBar->
height() : 0;
252 rect.setWidth(std::max(300, group->
view()->
minSize().width()));
253 rect.setHeight(centralAreaGeo.height() - topSideBarHeight - bottomSideBarHeight
254 - centerWidgetMargins.top() - centerWidgetMargins.bottom());
255 rect.moveTop(sb->
view()->
mapTo(q->view(), Point(0, 0)).y() + topSideBarHeight - 1);
257 rect.moveLeft(centralAreaGeo.x() + centralAreaGeo.width() - rect.width() - sb->
width()
258 - centerWidgetMargins.right() - margin);
260 rect.moveLeft(margin + centralAreaGeo.x() + centerWidgetMargins.left() + sb->
width());
276 case Core::LayoutBorderLocation_North:
278 case Core::LayoutBorderLocation_East:
280 case Core::LayoutBorderLocation_West:
282 case Core::LayoutBorderLocation_South:
284 case Core::LayoutBorderLocation_All:
285 case Core::LayoutBorderLocation_Verticals:
286 case Core::LayoutBorderLocation_Horizontals:
287 case Core::LayoutBorderLocation_None:
291 KDDW_ERROR(
"Unknown loc={}", loc);
298 case Core::LayoutBorderLocation_North:
300 case Core::LayoutBorderLocation_East:
302 case Core::LayoutBorderLocation_West:
304 case Core::LayoutBorderLocation_South:
306 case Core::LayoutBorderLocation_All:
307 case Core::LayoutBorderLocation_Verticals:
308 case Core::LayoutBorderLocation_Horizontals:
309 case Core::LayoutBorderLocation_None:
318 Core::Item *item = q->layout()->itemForFrame(dw->
d->group());
320 KDDW_ERROR(
"No item for dock widget");
324 const Core::LayoutBorderLocations borders = item->adjacentLayoutBorders();
325 const double aspectRatio = dw->
width() / (std::max(1, dw->
height()) * 1.0);
328 if (borders == Core::LayoutBorderLocation_All) {
333 for (
auto borderLoc :
334 { Core::LayoutBorderLocation_North, Core::LayoutBorderLocation_East,
335 Core::LayoutBorderLocation_West, Core::LayoutBorderLocation_South }) {
336 if (borders == (Core::LayoutBorderLocation_All & ~borderLoc))
341 if ((borders & Core::LayoutBorderLocation_Verticals)
342 == Core::LayoutBorderLocation_Verticals) {
348 if ((borders & Core::LayoutBorderLocation_Horizontals)
349 == Core::LayoutBorderLocation_Horizontals) {
355 if (borders == (Core::LayoutBorderLocation_West | Core::LayoutBorderLocation_South)) {
358 == (Core::LayoutBorderLocation_East | Core::LayoutBorderLocation_South)) {
361 == (Core::LayoutBorderLocation_West | Core::LayoutBorderLocation_North)) {
364 == (Core::LayoutBorderLocation_East | Core::LayoutBorderLocation_North)) {
380void MainWindow::Private::updateOverlayGeometry(Size suggestedSize)
382 if (!m_overlayedDockWidget)
385 Core::SideBar *sb = q->sideBarForDockWidget(m_overlayedDockWidget);
387 KDDW_ERROR(
"Expected a sidebar");
391 const Rect defaultGeometry = rectForOverlay(m_overlayedDockWidget->d->group(), sb->
location());
392 Rect newGeometry = defaultGeometry;
394 Core::Group *group = m_overlayedDockWidget->d->group();
396 if (suggestedSize.isValid() && !suggestedSize.isEmpty()) {
400 const int maxHeight = q->height() - group->
pos().y() - 10;
401 newGeometry.setHeight(std::min(suggestedSize.height(), maxHeight));
405 const int maxHeight = sb->
pos().y() - m_layout->view()->pos().y() - 10;
406 const int bottom = newGeometry.bottom();
407 newGeometry.setHeight(std::min(suggestedSize.height(), maxHeight));
408 newGeometry.moveBottom(bottom);
412 const int maxWidth = sb->
pos().x() - m_layout->view()->pos().x() - 10;
413 const int right = newGeometry.right();
414 newGeometry.setWidth(std::min(suggestedSize.width(), maxWidth));
415 newGeometry.moveRight(right);
419 const int maxWidth = q->width() - group->
pos().x() - 10;
420 newGeometry.setWidth(std::min(suggestedSize.width(), maxWidth));
425 KDDW_ERROR(
"Unexpected sidebar value");
430 m_overlayedDockWidget->d->group()->view()->setGeometry(newGeometry);
433void MainWindow::Private::clearSideBars()
442Rect MainWindow::Private::windowGeometry()
const
450 if (Core::Window::Ptr window = q->view()->window())
451 return window->geometry();
453 return q->window()->geometry();
467 ScopedValueRollback rollback(dw->
d->m_isMovingToSideBar,
true);
472 KDDW_ERROR(
"Minimization supported, probably disabled in Config::self().flags()");
479 if (dw == d->m_overlayedDockWidget)
485 KDDW_ERROR(
"Dock widget isn't in any sidebar");
500 KDDW_ERROR(
"You need to add the dock widget to the sidebar before you can overlay it");
504 if (d->m_overlayedDockWidget == dw) {
514 d->m_overlayedDockWidget = dw;
516 d->updateOverlayGeometry(dw->
d->lastPosition()->lastOverlayedGeometry(sb->
location()).size());
521 dw->
d->isOverlayedChanged.emit(
true);
526 const bool wasOverlayed = d->m_overlayedDockWidget == dw;
535 if (!d->m_overlayedDockWidget)
539 d->m_overlayedDockWidget =
nullptr;
586 return d->m_overlayedDockWidget;
616 bool allClosed =
true;
618 const auto dockWidgets = d->m_layout->dockWidgets();
626 allClosed = allClosed && closed;
649 if (d->name.isEmpty()) {
651 d->uniqueNameChanged.emit();
654 KDDW_ERROR(
"Already has a name. {} {}", this->
uniqueName(), uniqueName);
658bool MainWindow::deserialize(
const LayoutSaver::MainWindow &mw)
661 KDDW_ERROR(
"Refusing to restore MainWindow with different options ; expected={}, has={}",
int(mw.options),
int(
options()));
665 if (d->affinities != mw.affinities) {
666 KDDW_ERROR(
"Affinity name changed from {} to {}", d->affinities, mw.affinities);
668 d->affinities = mw.affinities;
687 KDDW_ERROR(
"Could not find dock widget {} . Won't restore it to sidebar",
uniqueName);
702LayoutSaver::MainWindow MainWindow::serialize()
const
704 LayoutSaver::MainWindow m;
709 m.geometry = d->windowGeometry();
716 m.affinities = d->affinities;
724 m.dockWidgetsPerSideBar[loc] = dockwidgets;
733 if (!d->supportsPersistentCentralWidget()) {
734 KDDW_ERROR(
"MainWindow::setPersistentCentralWidget() requires "
735 "MainWindowOption_HasCentralWidget");
739 if (
auto dw = d->m_persistentCentralDockWidget) {
742 KDDW_ERROR(
"Unexpected null central dock widget");
748 if (
auto dw = d->m_persistentCentralDockWidget)
768 auto it = d->m_sideBars.find(loc);
769 return it == d->m_sideBars.cend() ? nullptr : it->second;
780 return d->m_overlayMargin;
785 if (margin == d->m_overlayMargin)
788 d->m_overlayMargin = margin;
789 d->overlayMarginChanged.emit(margin);
The interface that MainWindow views should implement.
virtual Rect centralAreaGeometry() const =0
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.
void clearSideBarOverlay(bool deleteFrame=true)
closes any overlayed dock widget. The sidebar still displays them as button.
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.
Rect centralAreaGeometry() const
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.
DropArea * dropArea() const
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.
void addDockWidget(KDDockWidgets::Core::DockWidget *dockWidget, KDDockWidgets::Location location, KDDockWidgets::Core::DockWidget *relativeTo=nullptr, KDDockWidgets::InitialOption initialOption={})
Docks a DockWidget into this main window.
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
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 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 setUniqueName(const QString &uniqueName)
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)
bool isEmpty() const const
QTextStream & right(QTextStream &stream)
QMainWindow sub-class to enable KDDockWidgets support.