Qt-Advanced-Docking-System/doc/user-guide.md
2022-10-13 15:24:11 +08:00

31 KiB

User Guide

Configuration Flags

The Advanced Docking System has a number of global configuration options to configure the design and the functionality of the docking system. Eachs configuration will be explained in detail in the following sections.

Setting Configuration Flags

You must set the configuration flags before creating the dock manager instance otherwise the manager will not be created correctly and will crash upon being created. That means, setting the configurations flags is the first thing you must do, if you use the library.

CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig);
CDockManager::setConfigFlag(CDockManager::RetainTabSizeWhenCloseButtonHidden, true);
...
d->DockManager = new CDockManager(this);

If you set the configurations flags, you can set individual flags using the function CDockManager::setConfigFlag or you can set all flags using the function CDockManager::setConfigFlags. Instead of settings all flags individualy, it is better to pick a predefined set of configuration flags and then modify individual flags. The following predefined configurations are avilable

  • DefaultNonOpaqueConfig - uses non opaque splitter resizing and non opaque docking
  • DefaultOpaqueConfig - uses opaque splitter resizing and opaque docking

Pick one of those predefined configurations and then modify the following configurations flags to adjust the docking system to your needs.

ActiveTabHasCloseButton

If this flag is set (default configuration), the active tab in a tab area has a close button.

ActiveTabHasCloseButton true

If this flag is cleared, the active tab has no close button. You can combine this with the flag DockAreaCloseButtonClosesTab to use the close button of the dock are to close the single tabs.

ActiveTabHasCloseButton true

DockAreaHasCloseButton

If the flag is set (default configuration) each dock area has a close button.

DockAreaHasCloseButton true

If this flag is cleared, dock areas do not have a close button.

DockAreaHasCloseButton true

DockAreaCloseButtonClosesTab

If the flag is set, the dock area close button closes the active tab, if not set, it closes the complete dock area (default).

OpaqueSplitterResize

The advanced docking system uses standard QSplitters as resize separators and thus supports opaque and non-opaque resizing functionality of QSplitter. In some rare cases, for very complex widgets or on slow machines resizing via separator on the fly may cause flicking and glaring of rendered content inside a widget. This global dock manager flag configures the resizing behaviour of the splitters. If this flag is set, then widgets are resized dynamically (opaquely) while interactively moving the splitters. If you select the predefined configuration DefaultOpaqueConfig, then this is the configured behaviour.

Opaque resizing

If this flag is cleared, the widget resizing is deferred until the mouse button is released - this is some kind of lazy resizing separator. If you select the predefined configuration DefaultNonOpaqueConfig, then this is the configured behaviour.

Non-opaque resizing

XmlAutoFormattingEnabled

If enabled, the XML writer automatically adds line-breaks and indentation to empty sections between elements (ignorable whitespace). This is used, when the current state or perspective is saved. It is disabled by default.

XmlCompressionEnabled

If enabled, the XML output will be compressed and is not human readable anymore. This ie enabled by default to minimize the size of the saved data.

TabCloseButtonIsToolButton

If enabled the tab close buttons will be QToolButtons instead of QPushButtons - disabled by default. Normally the default configuration should be ok but if your application requires QToolButtons instead of QPushButtons for styling reasons or for any other reasons, then you can enable this flag.

AllTabsHaveCloseButton

If this flag is set, then all tabs that are closable show a close button. The advantage of this setting is that the size of the tabs does not change and the user can immediately close each tab. The disadvantage is that all tabs take up more space.

AllTabsHaveCloseButton true

If this flas is cleared, then only the active tab has a close button (default) and therefore the tabs need less space.

AllTabsHaveCloseButton false

RetainTabSizeWhenCloseButtonHidden

If this flag is set, the space for the close button is reserved even if the close button is not visible. This flag is disabled by default. If this flag is disabled, the tab size dynamically changes if the close button is visible / hidden in a tab. If this flag is enabled, the tab size always remains constant, that means, if enabled, the tabs need more space.

AllTabsHaveCloseButton false

OpaqueUndocking

If this flag is set, opaque undocking is active. That means, as soon as you drag a dock widget or a dock area with a number of dock widgets it will be undocked and moved into a floating widget and then the floating widget will be dragged around. That means undocking will take place immediatelly. You can compare this with opaque splitter resizing.

OpaqueUndocking true

If you would like to test opaque undocking, you should set the pedefined config flags CDockManager::DefaultOpaqueConfig.

CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig);

If this flag is cleared (default), then non-opaque undocking is active. In this mode, undocking is more like a standard drag and drop operation. That means, the dragged dock widget or dock area is not undocked immediatelly. Instead, a drag preview widget is created and dragged around to indicate the future position of the dock widget or dock area. The actual dock operation is only executed when the mouse button is released. That makes it possible, to cancel an active drag operation with the escape key.

OpaqueUndocking true

The drag preview widget can be configured by a number of global dock manager flags:

  • DragPreviewIsDynamic
  • DragPreviewShowsContentPixmap
  • DragPreviewHasWindowFrame

Non-opaque undocking is enabled by default. If you would like to enable it explicitely, you can do this by setting the predefined configuration flags CDockManager::DefaultNonOpaqueConfig.

CDockManager::setConfigFlags(CDockManager::DefaultNonOpaqueConfig);

DragPreviewIsDynamic

If non-opaque undocking is enabled, this flag defines the behavior of the drag preview window. If this flag is enabled, then it will give the user the impression, that the floating drag preview is dynamically adjusted to the drop area. In order to give the perfect impression, you should disable the flags DragPreviewShowsContentPixmap and DragPreviewHasWindowFrame.

CDockManager::setConfigFlag(CDockManager::DragPreviewIsDynamic, true);
CDockManager::setConfigFlag(CDockManager::DragPreviewShowsContentPixmap, false);
CDockManager::setConfigFlag(CDockManager::DragPreviewHasWindowFrame, false);

DragPreviewIsDynamic true

DragPreviewShowsContentPixmap

If non-opaque undocking is enabled, the created drag preview window shows a copy of the content of the dock widget / dock are that is dragged, if this flag is enabled (default).

DragPreviewShowsContentPixmap true

If this flag is disabled, the drag preview is only a transparent QRubberBand like window without any content.

DragPreviewShowsContentPixmap true

DragPreviewHasWindowFrame

If non-opaque undocking is enabled, then this flag configures if the drag preview is frameless (default) or looks like a real window. If it is enabled, then the drag preview is a transparent window with a system window frame.

DragPreviewHasWindowFrame true

AlwaysShowTabs

If this option is enabled, the tab of a dock widget is always displayed - even if it is the only visible dock widget in a floating widget. In the image below on the left side, the flag is disabled (default) and on the right side it is enabled.

AlwaysShowTabs false true

DockAreaHasUndockButton

If the flag is set (default) each dock area has an undock button (right image). If the flag is cleared, a dock area has no undock button (left image)

DockAreaHasUndockButton false true

DockAreaHasTabsMenuButton

Tabs are a good way to quickly switch between dockwidgets in a dockarea. However, if the number of dockwidgets in a dockarea is too large, this may affect the usability of the tab bar. To keep track in this situation, you can use the tab menu. The menu allows you to quickly select the dockwidget you want to activate from a drop down menu. This flag shows / hides the tabs menu button in the dock area title bar. On the left side, the tabs menu button flag is cleared.

DockAreaHasTabsMenuButton false true

DockAreaHideDisabledButtons

If certain flags of a dock widget are disabled, like DockWidgetClosable or DockWidgetFloatable, then the corresponding dock area buttons like close button or detach button are disabled (greyed out). This is the default setting.

DockAreaHideDisabledButtons false

If the flag is set, disabled dock area buttons will not appear on the toolbar at all - they are hidden.

DockAreaHideDisabledButtons true

DockAreaDynamicTabsMenuButtonVisibility

If this flag is cleared, the the tabs menu button is always visible. This is the default setting. If the flag is set, the tabs menu button will be shown only when it is required - that means, if the tabs are elided.

DockAreaDynamicTabsMenuButtonVisibility false

If the tabs are not elided, the tabs menu button is hidden.

DockAreaDynamicTabsMenuButtonVisibility false

FloatingContainerHasWidgetTitle

If set (default), the floating widget window title reflects the title of the current dock widget.

FloatingContainerHasWidgetTitle true

otherwise it displays application name as window title.

FloatingContainerHasWidgetTitle false

FloatingContainerHasWidgetIcon

If set, the floating widget icon reflects the icon of the current dock widget

FloatingContainerHasWidgetIcon true

otherwise (default setting) it displays application icon.

FloatingContainerHasWidgetIcon false

HideSingleCentralWidgetTitleBar

If there is only one single visible dock widget in the main dock container (the dock manager) and if this flag is set, then the titlebar of this dock widget will be hidden. This only makes sense for non draggable and non floatable dock widgets and enables the creation of some kind of "central" static widget. Because the titlebar is hidden, it is not possible to drag out the central widget to make it floating or to close it via the close button.

HideSingleCentralWidgetTitleBar true

The Advanced Docking System is meant for applications without a static central widget and normally does not know anything about a central static widget. Therefore this flag is disabled by default and a central single dock widget still has a titlebar to drag it out of the main window.

HideSingleCentralWidgetTitleBar false

FocusHighlighting

If this is enabled, the docking system is able to highlight the tab and the components of a dock area with a different style (i.e. a different color). This option is disabled by default and needs to be enabled explicitely because it adds some overhead. The dock manager needs to react on focus changes and dock widget dragging to highlight the right dock widget. You should enable it only, if you really need it for your application.

If the feature is enabled, you can also connect to the new dock manager signal focusedDockWidgetChanged(CDockWidget* old, CDockWidget* now) to react on focus changes and to prepare the content of the focused dock widget.

You can click into the tab, the titlebar or the content of a dock widget to focus it.

FocusHighlighting

For the focused dock widget and dock widget tab, the property focused will be set to true and you can use this property to style the focused dock widget differently. The picture above uses the following styling:

/* Color the tab with the nhighlight color */
ads--CDockWidgetTab[focused="true"]
{
    background: palette(highlight);
    border-color: palette(highlight);
}

/* Use a different colored close button icon to match the test color */
ads--CDockWidgetTab[focused="true"] > #tabCloseButton
{
	qproperty-icon: url(:/ads/images/close-button-focused.svg)
}

/* Make a hovered focused close button a little bit lighter */
ads--CDockWidgetTab[focused="true"] > #tabCloseButton:hover
{
	background: rgba(255, 255, 255, 48);
}

/* Make a pressed focused close button even more lighter */
ads--CDockWidgetTab[focused="true"] > #tabCloseButton:pressed
{
	background: rgba(255, 255, 255, 92);
}

/* Use a different color for the tab label */
ads--CDockWidgetTab[focused="true"] QLabel
{
    color: palette(light);
}

/* Paint a nice solid line for the whole title bar to create the illusion
   of an active tab */
ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar
{
	background: transparent;
	border-bottom: 2px solid palette(highlight);
	padding-bottom: 0px;
}

If you have a content widget that does not support focussing for some reason (like QVTKOpenGLStereoWidget from the VTK library), then you can manually switch the focus by reacting on mouse events. The following code shows, how to install en event filter on the QVTKOpenGLStereoWidget to properly switch the focus on QEvent::MouseButtonPress:

static ads::CDockWidget* createVTK2DWindow(QMenu* ViewMenu, QObject* EventFilter)
{
    QVTKOpenGLStereoWidget* qvtkOpenGLStereoWidget = new QVTKOpenGLStereoWidget;
    ads::CDockWidget* DockWidget = new ads::CDockWidget("2D Window");
    DockWidget->setWidget(qvtkOpenGLStereoWidget);
    qvtkOpenGLStereoWidget->installEventFilter(EventFilter);
    qvtkOpenGLStereoWidget->setProperty("DockWidget", QVariant::fromValue(DockWidget));
    return DockWidget;
}

Now we can use the event filter function to react on mouse events and then use the dock manager function setDockWidgetFocused() to switch the focus:

bool CMainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (event->type() == QEvent::MouseButtonPress)
    {
        QVTKOpenGLStereoWidget* vtkWidget =  qobject_cast<QVTKOpenGLStereoWidget*>(watched);
        auto vDockWidget = vtkWidget->property("DockWidget");
        ads::CDockWidget* DockWidget = nullptr;
        if (vDockWidget.isValid())
        {
            DockWidget = qvariant_cast<ads::CDockWidget*>(vDockWidget);
        }

        if (DockWidget)
        {
            d->DockManager->setDockWidgetFocused(DockWidget);
        }
    }
    return false;
}

EqualSplitOnInsertion

This flag configures how the space is distributed if a new dock widget is inserted into an existing dock area. The flag is disabled by default. If 3 dock widgets are inserted with the following code

d->DockManager->addDockWidget(ads::RightDockWidgetArea, DockWidget, EditorArea);

then this is the result, if the flag is disabled:

EqualSplitOnInsertion false

If the flag is enabled, then the space is equally distributed to all widgets in a splitter:

EqualSplitOnInsertion true

FloatingContainerForceNativeTitleBar (Linux only)

Since release 3.6 the library supports native title bars and window decorations for floating widgets on Linux (thanks to a user contribution). Native title bars and window decorations are supported by most Linux window managers, such as Compiz or Xfwm. Some window managers like KWin do not properly support this feature. Native floating widgets look better because of the native styling and the support all window manager features like snapping to window borders or maximizing. The library tries to detect the window manager during runtime and activates native window decorations if possible:

FloatingContainerForceNativeTitleBar true

If you would like to overwrite this autodetection, then you can activate this flag to force native window titlebars. You can overwrite autodetection and this flag, if you set the environment variable ADS_UseNativeTitle to 0 or 1.

FloatingContainerForceQWidgetTitleBar (Linux only)

If your window manager (i.e. KWin) does not properly support native floating windows, the docking library falls back to QWidget based floating widget title bars.

FloatingContainerForceNativeTitleBar false

If you would like to overwrite autodetection, then you can activate this flag to force QWidget based title bars. You can overwrite autodetection and this flag, if you set the environment variable ADS_UseNativeTitle to 0 or 1.

MiddleMouseButtonClosesTab

If the flag is set, the user can use the mouse middle button to close the tab under the mouse. So you do not need to exactly hit the tab close button to close tab. Just click with the middle mouse button on a tab like this is possible in various web browsers.

MiddleMouseButtonClosesTab true

DockWidget Feature Flags

DockWidgetClosable

If set, the dock widget will have a close button.

DockWidgetMovable

If a dock widget is movable, then it and can be moved to a new position in the current dock container. Disable this flag to prevent moving of a dock widget via mouse. If the OpaqueUndocking configuration flag is set, then dock widgets are immediately undocked into floating widgets. That means, moving is only possible in this case, if the dock widget is also floatable (feature flag DockWidgetFloatable is set).

DockWidgetFloatable

If set, a dock widget can be dragged into a floating window.

DockWidgetDeleteOnClose

Deletes the dock widget and its content when it is closed.

CustomCloseHandling

Clicking the close button will not close the dock widget but emits the closeRequested() signal instead. This allows the application to implement a custom close handling.

DockWidgetFocusable

If this is enabled, a dock widget can get focus highlighting.

DockWidgetForceCloseWithArea

A dock widget will be closed when the dock area hosting it is closed. If the DockWidgetDeleteOnClose feature is enabled for a dock widget, then it will be deleted, if the user clicks the close button of this dock widget. If the user clicks the close button of the dock area that contains this widget, then only the visibility of the dock widget is toggled. If this feature flag is set, the closing the dock area also closes the dock widget. That means, if the dock widget feature DockWidgetDeleteOnClose is set for the dock widgets in a dock area, then all dock widgets will be deleted if the dock area is closed.

NoTab

A dock widget tab will never be shown if this flag is set.

DeleteContentOnClose

Deletes only the contained widget on close, keeping the dock widget intact and in place. Attempts to rebuild the contents widget on show if there is a widget factory set. See issue #365 for more details.

Central Widget

The Advanced Docking System has been developed to overcome the limitations of the native Qt docking system with its central widget concept. This was the reason that until version 3.6 of the library, there was no support for such thing like a central widget. Thanks to the contribution of a user the library now supports a central widget.

In the Advanced Docking System a central widget is a docking widget that is neither closable nor movable or floatable. A central widget has no title bar and so it is not possible for the user to hide, close or drag the central widget. If there is a central widget, then also the distribution of the sizes for the dock widgets around the central widget is different:

  • no central widget (default) - on resizing the available space is distributed to all dock widgets - the size of all dock widgets shrinks or grows
  • with central widget - on resizing only the central widget is resized - the dock widgets around the central widget keep their size (see the animation below)

Central Widget

To set a central widget, you just need to pass your central dock widget to the dock manager setCentralWidget function:

auto* CentralDockArea = DockManager->setCentralWidget(CentralDockWidget);

See the centralwidget example to learn how it works.

Note

The central widget needs to be the first dock widget that is added to the dock manager. The function does not work and returns a nullptr if there are already other dock widgets registered. So setCentralWidget should be the first function that you call when adding dock widgets.

Empty Dock Area

Some applications require a fixed DockArea that is always visible, even if it does not contain any DockWidgets. I.e. the DockArea is in this case a kind of central widget that is always visible (see this issue).

Since version 3.7.1 the advanced docking system supports this feature. The emptydockarea example shows how this can be implemented with the library. You just need to create a dock widget and set the feature flag CDockWidget::NoTab. This permanently hides the tab widget of this area and removes it from the tab menu. For this special dock widget you should also disable all other features (movable, closable and floatable) to prevent closing and moving of this widget. If you use the CDockManager::setCentralWidget function like in the example code below, then you don't need to disable these features because this is done in the setCentralWidget function.

QLabel* label = new QLabel();
label->setText("This is a DockArea which is always visible, even if it does not contain any DockWidgets.");
label->setAlignment(Qt::AlignCenter);
CDockWidget* CentralDockWidget = new CDockWidget("CentralWidget");
CentralDockWidget->setWidget(label);
CentralDockWidget->setFeature(ads::CDockWidget::NoTab, true);// set the flag before adding the widget to dock manager
auto* CentralDockArea = DockManager->setCentralWidget(CentralDockWidget);

Custom Close Handling

Normally clicking the close button of a dock widget will just hide the widget and the user can show it again using the toggleView() action of the dock widget. This is meant for user interfaces with a static amount of widgets. But the advanced docking system also supports dynamic dock widgets that will get deleted on close. If you set the dock widget flag DockWidgetDeleteOnClose for a certain dock widget, then it will be deleted as soon as you close this dock widget. This enables the implementation of user interfaces with dynamically created editors, like in word processing applications or source code development tools.

When an entire area is closed, the default behavior is to hide the dock widgets it contains regardless of the DockWidgetDeleteOnClose flag except if there is only one dock widget. In this special case, the DockWidgetDeleteOnClose flag is followed. This behavior can be changed by setting the DockWidgetForceCloseWithArea flag to all the dock widgets that needs to be closed with their area.

Auto Hide Dock Widgets

Enabling this feature adds a pin icon to each dock area that will pin the dock widgets in the area to the left, right or bottom edge of the window as a side tab. The dock widget is then normally hidden, but showing the view by clicking the tab would overlay the dock widget on top of all the other widgets.

Auto hide demo

The area dock widgets are added to are based on the distance to the left, right and bottom edge.

Note: Overlay, Pin, and Auto Hide here all refer to the same functionality.

Setting Configuration Flags

Setting and enabling the overlay feature is similar to setting config flags, but do be aware that it uses a different eOverlayFlag enum and not the eConfigFlag enum. This is only relevant if you call CDockManager::setConfigFlags for the ConfigFlags, as it would mean you have to call CDockManager::setConfigFlags a second time for the AutoHideFlags.

CDockManager::setConfigFlags(CDockManager::DefaultAutoHideConfig);
CDockManager::setConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly, true);
...
d->DockManager = new CDockManager(this);

Adding Auto Hide Widgets

Adding an overlay widget is similar to adding a dock widget, simply call dockManager->addAutoHideDockWidget.

d->DockManager = new CDockManager(this);
CDockWidget* TableDockWidget = new CDockWidget("Table 1");
TableDockWidget->setDefaultOverlayDockProportion(0.5); // Default size in proportion to the window size when adding the overlay widget
DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last);

See autohide example to learn how it works.

Configuration Flags For Auto Hide Widgets

  • DockContainerHasLeftSideBar, DockContainerHasRightSideBar, DockContainerHasBottomSideBar -> Enabling each of these enables the side bar at each location. Disabling any of them would mean that the widget cannot be added at that location, so it would be added at the next available location. E.g. If you only enable DockContainerHasRightSideBar and DockContainerHasBottomSideBar then it will be added to the bottom side bar or right side bar respectively. If none of these are enabled, the auto hide button will not be added, as at least one of them must be enabled to work.
  • DockAreaHasAutoHideButton -> Adds the auto hide button to the title bar of the dock area
  • LeftSideBarPrioritizeIconOnly, RightSideBarPrioritizeIconOnly, BottomSideBarPrioritizeIconOnly -> If this is set, the side bar this is enabled with will prioritize showing an icon only, as opposed to an icon and text. This is set per side bar, so if you only enable LeftSideBarPrioritizeIconOnly, the right and bottom side bars will still show the icon and the text. This is only relevant if an icon is set, otherwise it will only show text as usual.
  • AutoHideDockAreaHasTitle -> Adds the title of the dock window where the title bar would be.
  • DefaultAutoHideConfig -> Enables DockContainerHasLeftSideBar, DockContainerHasRightSideBar, DockContainerHasBottomSideBar, DockAreaHasAutoHideButton, AutoHideDockAreaHasTitle

Limitations

  • Currently the LeftBottom and RightBottom areas can only be added programatically, and not through the pin icon. These are used if you'd like to add a new dock widget separated from the normal dock areas.

  • Adding a DockWidget (e.g. via addDockWidget) to an overlayed DockArea that already has a dockwidget is undefined behavior. An overlayed dock area does not have tabs and does not support more than one DockWidget in it's area. If you want to add a DockWidget to a DockArea that could be overlayed, check first if it's overlayed via CDockArea::isAutoHide and handle it accordingly (typically by adding the overlay dock widget as a side tab instead of to the area).

Styling

The Advanced Docking System supports styling via Qt Style Sheets. All components like splitters, tabs, buttons, titlebar and icons are styleable this way.

Disabling the Internal Style Sheet

The dock manager uses an internal stylesheet to style its components. That means, the style that you see in the demo application comes from the internal stylesheets that you will find in src/stylesheets folder. If you want to disable this internal stylesheet because your application uses its own, just call the function for settings the stylesheet with an empty string.

DockManager->setStyleSheet("");