Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
985d164cd1 | ||
|
|
0c9a1ee3f2 | ||
|
|
0bd20883df | ||
|
|
1d8a1e9bb8 | ||
|
|
3adabaec81 | ||
|
|
5695d0d305 | ||
|
|
f1792820e1 | ||
|
|
e091be0b76 | ||
|
|
e4c5eac146 | ||
|
|
cbd2fcb0d3 | ||
|
|
47029190dc | ||
|
|
80aee638c9 | ||
|
|
cdc863e962 | ||
|
|
ef855e3843 | ||
|
|
842d417e8d | ||
|
|
52a64350e6 | ||
|
|
79831d482b | ||
|
|
a4fbaf413b | ||
|
|
b982947cf4 | ||
|
|
bc2ac48eab | ||
|
|
ddbdb83821 | ||
|
|
85626c9a21 | ||
|
|
8bf8309949 | ||
|
|
528f48e6d1 | ||
|
|
28dfcc2a62 | ||
|
|
0bfa2eb88e | ||
|
|
27bbe9f7f5 | ||
|
|
92dbcec7c0 | ||
|
|
2be2f2bc6f | ||
|
|
a083d778bd | ||
|
|
d4770a7d41 | ||
|
|
37365caf8e | ||
|
|
3f5bfc3139 | ||
|
|
4ac7291831 | ||
|
|
b5e9096387 | ||
|
|
19c8e9ffcc | ||
|
|
6a815a836c | ||
|
|
277d3fffe4 | ||
|
|
9502e7bf6c | ||
|
|
8aae6bf70b | ||
|
|
a668fe2f73 | ||
|
|
12bb7b73e9 | ||
|
|
dbf90a4233 | ||
|
|
19331ebe2b | ||
|
|
16a149b436 | ||
|
|
1f995299f0 | ||
|
|
7a17aba42d | ||
|
|
9fe1dd6a88 | ||
|
|
7c2d1891a2 | ||
|
|
998fe9fa11 | ||
|
|
28dc374fc2 | ||
|
|
1b6e449b4a | ||
|
|
0e88467f94 | ||
|
|
d0f4ce3248 | ||
|
|
542618fd4e | ||
|
|
661d0c4356 | ||
|
|
dceaa155c4 | ||
|
|
c541f2c69b | ||
|
|
37d305e50d | ||
|
|
4adef2b774 | ||
|
|
1c2383f8eb | ||
|
|
6c687d28de | ||
|
|
708add3ff5 | ||
|
|
e85b4167bd | ||
|
|
59c783831a | ||
|
|
4cb1931ace | ||
|
|
fe10b570d3 | ||
|
|
f3c5d51380 | ||
|
|
34cb2ae917 | ||
|
|
8cc9cc25ad | ||
|
|
c90fb9413c | ||
|
|
dec170ed24 | ||
|
|
3ffbbfb6d0 | ||
|
|
e8332575f8 | ||
|
|
8c12d912b4 | ||
|
|
fd28f0f751 | ||
|
|
3f09d5c6ea |
79
README.md
@@ -4,6 +4,9 @@
|
||||
[](https://ci.appveyor.com/project/githubuser0xFFFF/qt-advanced-docking-system/branch/master)
|
||||
[](gnu-lgpl-v2.1.md)
|
||||
|
||||
[What's new](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/latest) •
|
||||
[Documentation](doc/user-guide.md)
|
||||
|
||||
Qt Advanced Docking System lets you create customizable layouts using a full
|
||||
featured window docking system similar to what is found in many popular
|
||||
integrated development environments (IDEs) such as Visual Studio.
|
||||
@@ -24,30 +27,33 @@ of his docking system project.
|
||||
|
||||
### Overview
|
||||
|
||||
- [Advanced Docking System for Qt](#advanced-docking-system-for-qt)
|
||||
- [Features](#features)
|
||||
- [Overview](#overview)
|
||||
- [Docking everywhere - no central widget](#docking-everywhere---no-central-widget)
|
||||
- [Docking inside floating windows](#docking-inside-floating-windows)
|
||||
- [Grouped dragging](#grouped-dragging)
|
||||
- [Perspectives for fast switching of the complete main window layout](#perspectives-for-fast-switching-of-the-complete-main-window-layout)
|
||||
- [Opaque and non-opaque splitter resizing](#opaque-and-non-opaque-splitter-resizing)
|
||||
- [Opaque and non-opaque undocking](#opaque-and-non-opaque-undocking)
|
||||
- [Tab-menu for easy handling of many tabbed dock widgets](#tab-menu-for-easy-handling-of-many-tabbed-dock-widgets)
|
||||
- [Many different ways to detach dock widgets](#many-different-ways-to-detach-dock-widgets)
|
||||
- [Supports deletion of dynamically created dock widgets](#supports-deletion-of-dynamically-created-dock-widgets)
|
||||
- [Tested Compatible Environments](#tested-compatible-environments)
|
||||
- [Windows](#windows)
|
||||
- [macOS](#macos)
|
||||
- [Linux](#linux)
|
||||
- [Build](#build)
|
||||
- [Getting started / Example](#getting-started--example)
|
||||
- [Developers](#developers)
|
||||
- [License information](#license-information)
|
||||
- [Alternative Docking System Implementations](#alternative-docking-system-implementations)
|
||||
- [KDDockWidgets](#kddockwidgets)
|
||||
- [QtitanDocking](#qtitandocking)
|
||||
- [Donation](#donation)
|
||||
- [Features](#features)
|
||||
- [Overview](#overview)
|
||||
- [Docking everywhere - no central widget](#docking-everywhere---no-central-widget)
|
||||
- [Docking inside floating windows](#docking-inside-floating-windows)
|
||||
- [Grouped dragging](#grouped-dragging)
|
||||
- [Perspectives for fast switching of the complete main window layout](#perspectives-for-fast-switching-of-the-complete-main-window-layout)
|
||||
- [Opaque and non-opaque splitter resizing](#opaque-and-non-opaque-splitter-resizing)
|
||||
- [Opaque and non-opaque undocking](#opaque-and-non-opaque-undocking)
|
||||
- [Tab-menu for easy handling of many tabbed dock widgets](#tab-menu-for-easy-handling-of-many-tabbed-dock-widgets)
|
||||
- [Many different ways to detach dock widgets](#many-different-ways-to-detach-dock-widgets)
|
||||
- [Supports deletion of dynamically created dock widgets](#supports-deletion-of-dynamically-created-dock-widgets)
|
||||
- [Tested Compatible Environments](#tested-compatible-environments)
|
||||
- [Windows](#windows)
|
||||
- [macOS](#macos)
|
||||
- [Linux](#linux)
|
||||
- [Build](#build)
|
||||
- [Getting started / Example](#getting-started--example)
|
||||
- [Developers](#developers)
|
||||
- [License information](#license-information)
|
||||
- [Alternative Docking System Implementations](#alternative-docking-system-implementations)
|
||||
- [KDDockWidgets](#kddockwidgets)
|
||||
- [QtitanDocking](#qtitandocking)
|
||||
- [Donation](#donation)
|
||||
- [Showcase](#showcase)
|
||||
- [Qt Creator IDE](#qt-creator-ide)
|
||||
- [Qt Design Studio](#qt-design-studio)
|
||||
- [QmixElements](#qmixelements)
|
||||
|
||||
### Docking everywhere - no central widget
|
||||
|
||||
@@ -273,3 +279,28 @@ If this project help you reduce time to develop or if you just like it, you can
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=85R64TMMSY9T6">
|
||||
<img src="doc/donate.png" alt="Donate with PayPal" width="160"/>
|
||||
</a>
|
||||
|
||||
## Showcase
|
||||
|
||||
### [Qt Creator IDE](https://www.qt.io/development-tools)
|
||||
|
||||
From version 4.12 on, Qt Creator uses the Advanced Docking Framework for its
|
||||
Qt Quick Designer. This improves the usability when using multiple screens.
|
||||
|
||||

|
||||
|
||||
### [Qt Design Studio](https://www.qt.io/ui-design-tools)
|
||||
|
||||
Taken from the [Qt Blog](https://www.qt.io/blog/qt-design-studio-1.5-beta-released):
|
||||
|
||||
> The most obvious change in [Qt Design Studio 1.5](https://www.qt.io/blog/qt-design-studio-1.5-beta-released) is the integration of dock widgets using the Qt Advanced Docking System. This allows the user to fully customize the workspace and also to undock any view into its own top level window. This especially improves the usability when using multiple screens.
|
||||
|
||||

|
||||
|
||||
### [QmixElements](https://www.cetoni.com/products/qmixelements/)
|
||||
|
||||
The QmixElements software from [CETONI](https://www.cetoni.com) is a comprehensive,
|
||||
plugin-based and modular laboratory automation software for controlling CETONI devices using a joint graphical user interface. The software features a powerful script system to automate processes. This [blog post](https://www.cetoni.com/blog/qmixelements-advanced-docking-system/) gives a nice overview about the use of the Qt
|
||||
Advanced Docking System in the QmixElements sofware.
|
||||
|
||||

|
||||
|
||||
316
demo.py
@@ -1,316 +0,0 @@
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
from PyQt5.QtCore import (QCoreApplication, QDir, Qt, QSettings, QSignalBlocker,
|
||||
QRect)
|
||||
from PyQt5.QtGui import QGuiApplication
|
||||
from PyQt5.QtWidgets import (QCalendarWidget, QFileSystemModel, QFrame, QLabel,
|
||||
QMenu, QTreeView, QAction, QWidgetAction,
|
||||
QComboBox, QStyle, QSizePolicy, QInputDialog)
|
||||
|
||||
from PyQt5 import QtWidgets
|
||||
|
||||
from PyQtAds import QtAds
|
||||
|
||||
|
||||
class _State:
|
||||
label_count = 0
|
||||
calendar_count = 0
|
||||
file_system_count = 0
|
||||
|
||||
|
||||
def create_long_text_label_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
'''
|
||||
Create long text label dock widget
|
||||
|
||||
Parameters
|
||||
----------
|
||||
view_menu : QMenu
|
||||
|
||||
Returns
|
||||
-------
|
||||
value : QtAds.CDockWidget
|
||||
'''
|
||||
label = QLabel()
|
||||
label.setWordWrap(True)
|
||||
label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
label.setText('''\
|
||||
Label {} {} - Lorem ipsum dolor sit amet, consectetuer
|
||||
adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum
|
||||
sociis natoque penatibus et magnis dis parturient montes, nascetur
|
||||
ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium
|
||||
quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla
|
||||
vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut,
|
||||
imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis
|
||||
pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi.
|
||||
Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu,
|
||||
consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra
|
||||
quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet.
|
||||
'''.format(_State.label_count, str(datetime.datetime.now())))
|
||||
_State.label_count += 1
|
||||
|
||||
dock_widget = QtAds.CDockWidget("Label {}".format(_State.label_count))
|
||||
dock_widget.setWidget(label)
|
||||
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
def create_calendar_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
'''
|
||||
Create calendar dock widget
|
||||
|
||||
Parameters
|
||||
----------
|
||||
view_menu : QMenu
|
||||
|
||||
Returns
|
||||
-------
|
||||
value : QtAds.CDockWidget
|
||||
'''
|
||||
widget = QCalendarWidget()
|
||||
|
||||
dock_widget = QtAds.CDockWidget("Calendar {}".format(_State.calendar_count))
|
||||
_State.calendar_count += 1
|
||||
dock_widget.setWidget(widget)
|
||||
dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow)
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
def create_file_system_tree_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
'''
|
||||
Create file system tree dock widget
|
||||
|
||||
Parameters
|
||||
----------
|
||||
view_menu : QMenu
|
||||
|
||||
Returns
|
||||
-------
|
||||
value : QtAds.CDockWidget
|
||||
'''
|
||||
widget = QTreeView()
|
||||
widget.setFrameShape(QFrame.NoFrame)
|
||||
|
||||
m = QFileSystemModel(widget)
|
||||
m.setRootPath(QDir.currentPath())
|
||||
widget.setModel(m)
|
||||
|
||||
dock_widget = QtAds.CDockWidget("Filesystem {}".format(_State.file_system_count))
|
||||
_State.file_system_count += 1
|
||||
dock_widget.setWidget(widget)
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
class MainWindow(QtWidgets.QMainWindow):
|
||||
save_perspective_action: QAction
|
||||
perspective_list_action: QWidgetAction
|
||||
perspective_combo_box: QComboBox
|
||||
dock_manager: QtAds.CDockManager
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.save_perspective_action = None
|
||||
self.perspective_list_action = None
|
||||
self.perspective_combo_box = None
|
||||
self.dock_manager = None
|
||||
|
||||
self.setup_ui()
|
||||
|
||||
self.dock_manager = QtAds.CDockManager(self)
|
||||
self.perspective_combo_box.activated[str].connect(self.dock_manager.openPerspective)
|
||||
self.create_content()
|
||||
self.resize(800, 600)
|
||||
self.restore_state()
|
||||
self.restore_perspectives()
|
||||
|
||||
def setup_ui(self):
|
||||
self.setObjectName("MainWindow")
|
||||
self.resize(400, 300)
|
||||
self.setDockOptions(QtWidgets.QMainWindow.AllowTabbedDocks)
|
||||
self.centralWidget = QtWidgets.QWidget(self)
|
||||
self.centralWidget.setObjectName("centralWidget")
|
||||
self.setCentralWidget(self.centralWidget)
|
||||
self.status_bar = QtWidgets.QStatusBar(self)
|
||||
self.status_bar.setObjectName("statusBar")
|
||||
self.setStatusBar(self.status_bar)
|
||||
self.menu_bar = QtWidgets.QMenuBar(self)
|
||||
self.menu_bar.setGeometry(QRect(0, 0, 400, 21))
|
||||
self.menu_bar.setObjectName("menuBar")
|
||||
self.menu_file = QtWidgets.QMenu(self.menu_bar)
|
||||
self.menu_file.setObjectName("menuFile")
|
||||
self.menu_view = QtWidgets.QMenu(self.menu_bar)
|
||||
self.menu_view.setObjectName("menuView")
|
||||
self.menu_about = QtWidgets.QMenu(self.menu_bar)
|
||||
self.menu_about.setObjectName("menuAbout")
|
||||
self.setMenuBar(self.menu_bar)
|
||||
self.tool_bar = QtWidgets.QToolBar(self)
|
||||
self.tool_bar.setObjectName("toolBar")
|
||||
self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
|
||||
self.action_exit = QtWidgets.QAction(self)
|
||||
self.action_exit.setObjectName("actionExit")
|
||||
self.action_save_state = QtWidgets.QAction(self)
|
||||
self.action_save_state.setObjectName("actionSaveState")
|
||||
self.action_save_state.triggered.connect(self.saveState)
|
||||
|
||||
self.action_restore_state = QtWidgets.QAction(self)
|
||||
self.action_restore_state.setObjectName("actionRestoreState")
|
||||
self.action_restore_state.triggered.connect(self.restore_state)
|
||||
|
||||
self.menu_file.addAction(self.action_exit)
|
||||
self.menu_file.addAction(self.action_save_state)
|
||||
self.menu_file.addAction(self.action_restore_state)
|
||||
self.menu_bar.addAction(self.menu_file.menuAction())
|
||||
self.menu_bar.addAction(self.menu_view.menuAction())
|
||||
self.menu_bar.addAction(self.menu_about.menuAction())
|
||||
|
||||
self.setWindowTitle("MainWindow")
|
||||
self.menu_file.setTitle("File")
|
||||
self.menu_view.setTitle("View")
|
||||
self.menu_about.setTitle("About")
|
||||
self.tool_bar.setWindowTitle("toolBar")
|
||||
self.action_exit.setText("Exit")
|
||||
self.action_save_state.setText("Save State")
|
||||
self.action_restore_state.setText("Restore State")
|
||||
self.create_actions()
|
||||
|
||||
def create_actions(self):
|
||||
'''
|
||||
Creates the toolbar actions
|
||||
'''
|
||||
self.tool_bar.addAction(self.action_save_state)
|
||||
self.action_save_state.setIcon(self.style().standardIcon(QStyle.SP_DialogSaveButton))
|
||||
self.tool_bar.addAction(self.action_restore_state)
|
||||
self.action_restore_state.setIcon(self.style().standardIcon(QStyle.SP_DialogOpenButton))
|
||||
self.save_perspective_action = QAction("Save Perspective", self)
|
||||
self.save_perspective_action.triggered.connect(self.save_perspective)
|
||||
|
||||
self.perspective_list_action = QWidgetAction(self)
|
||||
self.perspective_combo_box = QComboBox(self)
|
||||
self.perspective_combo_box.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
||||
self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
||||
self.perspective_list_action.setDefaultWidget(self.perspective_combo_box)
|
||||
self.tool_bar.addSeparator()
|
||||
self.tool_bar.addAction(self.perspective_list_action)
|
||||
self.tool_bar.addAction(self.save_perspective_action)
|
||||
|
||||
def create_content(self):
|
||||
'''
|
||||
Fill the dock manager with dock widgets
|
||||
'''
|
||||
# Test container docking
|
||||
view_menu = self.menu_view
|
||||
dock_widget = create_calendar_dock_widget(view_menu)
|
||||
dock_widget.setIcon(self.style().standardIcon(QStyle.SP_DialogOpenButton))
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
|
||||
self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget)
|
||||
self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, create_long_text_label_dock_widget(view_menu))
|
||||
file_system_widget = create_file_system_tree_dock_widget(view_menu)
|
||||
tool_bar = file_system_widget.createDefaultToolBar()
|
||||
tool_bar.addAction(self.action_save_state)
|
||||
tool_bar.addAction(self.action_restore_state)
|
||||
self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, file_system_widget)
|
||||
file_system_widget = create_file_system_tree_dock_widget(view_menu)
|
||||
tool_bar = file_system_widget.createDefaultToolBar()
|
||||
tool_bar.addAction(self.action_save_state)
|
||||
tool_bar.addAction(self.action_restore_state)
|
||||
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
|
||||
top_dock_area = self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, file_system_widget)
|
||||
dock_widget = create_calendar_dock_widget(view_menu)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
|
||||
dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna")
|
||||
self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area)
|
||||
|
||||
# Test dock area docking
|
||||
right_dock_area = self.dock_manager.addDockWidget(
|
||||
QtAds.RightDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), top_dock_area)
|
||||
self.dock_manager.addDockWidget(
|
||||
QtAds.TopDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), right_dock_area)
|
||||
|
||||
bottom_dock_area = self.dock_manager.addDockWidget(
|
||||
QtAds.BottomDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), right_dock_area)
|
||||
|
||||
self.dock_manager.addDockWidget(
|
||||
QtAds.RightDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), right_dock_area)
|
||||
self.dock_manager.addDockWidget(
|
||||
QtAds.CenterDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), bottom_dock_area)
|
||||
|
||||
def save_state(self):
|
||||
'''
|
||||
Saves the dock manager state and the main window geometry
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
settings.setValue("mainWindow/Geometry", self.saveGeometry())
|
||||
settings.setValue("mainWindow/State", self.saveState())
|
||||
settings.setValue("mainWindow/DockingState", self.dock_manager.saveState())
|
||||
|
||||
def save_perspectives(self):
|
||||
'''
|
||||
Save the list of perspectives
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
self.dock_manager.savePerspectives(settings)
|
||||
|
||||
def restore_state(self):
|
||||
'''
|
||||
Restores the dock manager state
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
geom = settings.value("mainWindow/Geometry")
|
||||
if geom is not None:
|
||||
self.restoreGeometry(geom)
|
||||
|
||||
state = settings.value("mainWindow/State")
|
||||
if state is not None:
|
||||
self.restoreState(state)
|
||||
|
||||
state = settings.value("mainWindow/DockingState")
|
||||
if state is not None:
|
||||
self.dock_manager.restore_state(state)
|
||||
|
||||
def restore_perspectives(self):
|
||||
'''
|
||||
Restore the perspective listo of the dock manager
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
self.dock_manager.loadPerspectives(settings)
|
||||
self.perspective_combo_box.clear()
|
||||
self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
|
||||
|
||||
def save_perspective(self):
|
||||
perspective_name, ok = QInputDialog.getText(self, 'Save perspective', 'Enter unique name:')
|
||||
if ok and perspective_name:
|
||||
self.dock_manager.addPerspective(perspective_name)
|
||||
_ = QSignalBlocker(self.perspective_combo_box)
|
||||
self.perspective_combo_box.clear()
|
||||
self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
|
||||
self.perspective_combo_box.setCurrentText(perspective_name)
|
||||
self.save_perspectives()
|
||||
|
||||
|
||||
def main(app_):
|
||||
main_window = MainWindow()
|
||||
main_window.show()
|
||||
state = main_window.dock_manager.saveState()
|
||||
# print('This is what the saved state looks like in XML:')
|
||||
# print(str(state, 'utf-8'))
|
||||
# print()
|
||||
# main_window.dock_manager.restore_state(state)
|
||||
return main_window
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# logging.basicConfig(level='DEBUG')
|
||||
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
|
||||
QGuiApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
||||
app = QtWidgets.QApplication([])
|
||||
window = main(app)
|
||||
window.show()
|
||||
app.exec_()
|
||||
@@ -30,6 +30,8 @@ set(ads_demo_SRCS
|
||||
main.cpp
|
||||
MainWindow.cpp
|
||||
mainwindow.ui
|
||||
StatusDialog.cpp
|
||||
StatusDialog.ui
|
||||
demo.qrc
|
||||
)
|
||||
add_executable(AdvancedDockingSystemDemo WIN32 ${ads_demo_SRCS})
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
#include "DockAreaTabBar.h"
|
||||
#include "FloatingDockContainer.h"
|
||||
#include "DockComponentsFactory.h"
|
||||
#include "StatusDialog.h"
|
||||
|
||||
|
||||
|
||||
@@ -169,7 +170,12 @@ static ads::CDockWidget* createCalendarDockWidget(QMenu* ViewMenu)
|
||||
static int CalendarCount = 0;
|
||||
QCalendarWidget* w = new QCalendarWidget();
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Calendar %1").arg(CalendarCount++));
|
||||
// The following lines are for testing the setWidget() and takeWidget()
|
||||
// functionality
|
||||
DockWidget->setWidget(w);
|
||||
DockWidget->setWidget(w); // what happens if we set a widget if a widget is already set
|
||||
DockWidget->takeWidget(); // we remove the widget
|
||||
DockWidget->setWidget(w); // and set the widget again - there should be no error
|
||||
DockWidget->setToggleViewActionMode(ads::CDockWidget::ActionModeShow);
|
||||
DockWidget->setIcon(svgIcon(":/adsdemo/images/date_range.svg"));
|
||||
ViewMenu->addAction(DockWidget->toggleViewAction());
|
||||
@@ -224,11 +230,27 @@ static ads::CDockWidget* createEditorWidget(QMenu* ViewMenu)
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
/**
|
||||
* Custom QTableWidget with a minimum size hint to test CDockWidget
|
||||
* setMinimumSizeHintMode() function of CDockWidget
|
||||
*/
|
||||
class CMinSizeTableWidget : public QTableWidget
|
||||
{
|
||||
public:
|
||||
using QTableWidget::QTableWidget;
|
||||
virtual QSize minimumSizeHint() const override
|
||||
{
|
||||
return QSize(300, 100);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//============================================================================
|
||||
static ads::CDockWidget* createTableWidget(QMenu* ViewMenu)
|
||||
{
|
||||
static int TableCount = 0;
|
||||
QTableWidget* w = new QTableWidget();
|
||||
auto w = new CMinSizeTableWidget();
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Table %1").arg(TableCount++));
|
||||
static int colCount = 5;
|
||||
static int rowCount = 30;
|
||||
@@ -244,6 +266,20 @@ static ads::CDockWidget* createTableWidget(QMenu* ViewMenu)
|
||||
}
|
||||
DockWidget->setWidget(w);
|
||||
DockWidget->setIcon(svgIcon(":/adsdemo/images/grid_on.svg"));
|
||||
DockWidget->setMinimumSizeHintMode(ads::CDockWidget::MinimumSizeHintFromContent);
|
||||
auto ToolBar = DockWidget->createDefaultToolBar();
|
||||
auto Action = ToolBar->addAction(svgIcon(":/adsdemo/images/fullscreen.svg"), "Toggle Fullscreen");
|
||||
QObject::connect(Action, &QAction::triggered, [=]()
|
||||
{
|
||||
if (DockWidget->isFullScreen())
|
||||
{
|
||||
DockWidget->showNormal();
|
||||
}
|
||||
else
|
||||
{
|
||||
DockWidget->showFullScreen();
|
||||
}
|
||||
});
|
||||
ViewMenu->addAction(DockWidget->toggleViewAction());
|
||||
return DockWidget;
|
||||
}
|
||||
@@ -316,8 +352,6 @@ void MainWindowPrivate::createContent()
|
||||
QMenu* ViewMenu = ui.menuView;
|
||||
auto DockWidget = createCalendarDockWidget(ViewMenu);
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetClosable, false);
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetMovable, false);
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetFloatable, false);
|
||||
auto SpecialDockArea = DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
|
||||
|
||||
// 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):
|
||||
@@ -351,9 +385,6 @@ void MainWindowPrivate::createContent()
|
||||
// We create a calendar widget and clear all flags to prevent the dock area
|
||||
// from closing
|
||||
DockWidget = createCalendarDockWidget(ViewMenu);
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetClosable, false);
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetMovable, false);
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetFloatable, false);
|
||||
DockWidget->setTabToolTip(QString("Tab ToolTip\nHodie est dies magna"));
|
||||
auto DockArea = DockManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, TopDockArea);
|
||||
|
||||
@@ -363,6 +394,7 @@ void MainWindowPrivate::createContent()
|
||||
CustomButton->setToolTip(QObject::tr("Create Editor"));
|
||||
CustomButton->setIcon(svgIcon(":/adsdemo/images/plus.svg"));
|
||||
CustomButton->setAutoRaise(true);
|
||||
|
||||
auto TitleBar = DockArea->titleBar();
|
||||
int Index = TitleBar->indexOf(TitleBar->tabBar());
|
||||
TitleBar->insertWidget(Index + 1, CustomButton);
|
||||
@@ -381,8 +413,12 @@ void MainWindowPrivate::createContent()
|
||||
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
|
||||
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), BottomDockArea);
|
||||
|
||||
auto Action = ui.menuView->addAction(QString("Set %1 floating").arg(DockWidget->windowTitle()));
|
||||
auto Action = ui.menuTests->addAction(QString("Set %1 Floating").arg(DockWidget->windowTitle()));
|
||||
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setFloating()));
|
||||
Action = ui.menuTests->addAction(QString("Set %1 As Current Tab").arg(DockWidget->windowTitle()));
|
||||
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setAsCurrentTab()));
|
||||
Action = ui.menuTests->addAction(QString("Raise %1").arg(DockWidget->windowTitle()));
|
||||
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(raise()));
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (!DockManager->configFlags().testFlag(ads::CDockManager::OpaqueUndocking))
|
||||
@@ -424,11 +460,18 @@ void MainWindowPrivate::createActions()
|
||||
a->setToolTip("Creates floating dynamic dockable editor windows that are deleted on close");
|
||||
a->setIcon(svgIcon(":/adsdemo/images/note_add.svg"));
|
||||
_this->connect(a, SIGNAL(triggered()), SLOT(createEditor()));
|
||||
ui.menuTests->addAction(a);
|
||||
|
||||
a = ui.toolBar->addAction("Create Table");
|
||||
a->setToolTip("Creates floating dynamic dockable table with millions of entries");
|
||||
a->setIcon(svgIcon(":/adsdemo/images/grid_on.svg"));
|
||||
_this->connect(a, SIGNAL(triggered()), SLOT(createTable()));
|
||||
ui.menuTests->addAction(a);
|
||||
|
||||
ui.menuTests->addSeparator();
|
||||
a = ui.menuTests->addAction("Show Status Dialog");
|
||||
_this->connect(a, SIGNAL(triggered()), SLOT(showStatusDialog()));
|
||||
ui.menuTests->addSeparator();
|
||||
}
|
||||
|
||||
|
||||
@@ -479,7 +522,7 @@ CMainWindow::CMainWindow(QWidget *parent) :
|
||||
{
|
||||
using namespace ads;
|
||||
d->ui.setupUi(this);
|
||||
|
||||
setWindowTitle(QApplication::instance()->applicationName());
|
||||
d->createActions();
|
||||
|
||||
// uncomment the following line if the tab close button should be
|
||||
@@ -515,13 +558,14 @@ CMainWindow::CMainWindow(QWidget *parent) :
|
||||
// uncomment the following line if you want floating container to show active dock widget's icon instead of always showing application icon
|
||||
//CDockManager::setConfigFlag(CDockManager::FloatingContainerHasWidgetIcon, true);
|
||||
|
||||
// uncomment the following line if you want a central widget in the main dock container (the dock manager) without a titlebar
|
||||
// If you enable this code, you can test it in the demo with the Calendar 0
|
||||
// dock widget.
|
||||
// CDockManager::setConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar, true);
|
||||
|
||||
// Now create the dock manager and its content
|
||||
d->DockManager = new CDockManager(this);
|
||||
|
||||
// uncomment the following line to have the old style where the dock
|
||||
// area close button closes the active tab
|
||||
// CDockManager::setConfigFlags({CDockManager::DockAreaHasCloseButton
|
||||
// | CDockManager::DockAreaCloseButtonClosesTab});
|
||||
connect(d->PerspectiveComboBox, SIGNAL(activated(const QString&)),
|
||||
d->DockManager, SLOT(openPerspective(const QString&)));
|
||||
|
||||
@@ -648,3 +692,11 @@ void CMainWindow::createTable()
|
||||
FloatingWidget->move(QPoint(40, 40));
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CMainWindow::showStatusDialog()
|
||||
{
|
||||
CStatusDialog Dialog(d->DockManager);
|
||||
Dialog.exec();
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ private slots:
|
||||
void createEditor();
|
||||
void createTable();
|
||||
void onEditorCloseRequested();
|
||||
void showStatusDialog();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
88
demo/StatusDialog.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
//============================================================================
|
||||
/// \file StatusDialog.cpp
|
||||
/// \author Uwe Kindler
|
||||
/// \date 13.04.2020
|
||||
/// \brief Implementation of CStatusDialog class
|
||||
//============================================================================
|
||||
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include "StatusDialog.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "DockManager.h"
|
||||
#include "DockWidget.h"
|
||||
#include "ui_StatusDialog.h"
|
||||
|
||||
/**
|
||||
* Private data class of CStatusDialog class (pimpl)
|
||||
*/
|
||||
struct StatusDialogPrivate
|
||||
{
|
||||
CStatusDialog *_this;
|
||||
Ui::CStatusDialogClass ui;
|
||||
ads::CDockManager* DockManager;
|
||||
QMap<QString, ads::CDockWidget*> DockWidgets;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
*/
|
||||
StatusDialogPrivate(CStatusDialog *_public);
|
||||
};
|
||||
// struct StatusDialogPrivate
|
||||
|
||||
//============================================================================
|
||||
StatusDialogPrivate::StatusDialogPrivate(CStatusDialog *_public) :
|
||||
_this(_public)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
CStatusDialog::CStatusDialog(ads::CDockManager* DockManager) :
|
||||
QDialog(DockManager),
|
||||
d(new StatusDialogPrivate(this))
|
||||
{
|
||||
d->ui.setupUi(this);
|
||||
d->DockManager = DockManager;
|
||||
d->DockWidgets = DockManager->dockWidgetsMap();
|
||||
|
||||
for (auto it = d->DockWidgets.begin(); it != d->DockWidgets.end(); ++it)
|
||||
{
|
||||
QVariant vDockWidget = QVariant::fromValue(it.value());
|
||||
d->ui.dockWidgetsComboBox->addItem(it.key(), vDockWidget);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
CStatusDialog::~CStatusDialog()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CStatusDialog::on_dockWidgetsComboBox_currentIndexChanged(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto vDockWidget = d->ui.dockWidgetsComboBox->currentData();
|
||||
auto DockWidget = vDockWidget.value<ads::CDockWidget*>();
|
||||
d->ui.isClosedCheckBox->setChecked(DockWidget->isClosed());
|
||||
d->ui.isFloatingCheckBox->setChecked(DockWidget->isFloating());
|
||||
d->ui.tabbedCheckBox->setChecked(DockWidget->isTabbed());
|
||||
d->ui.isCurrentTabCheckBox->setChecked(DockWidget->isCurrentTab());
|
||||
d->ui.closableCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::DockWidgetClosable));
|
||||
d->ui.movableCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::DockWidgetMovable));
|
||||
d->ui.floatableCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::DockWidgetFloatable));
|
||||
d->ui.deleteOnCloseCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::DockWidgetDeleteOnClose));
|
||||
d->ui.customCloseHandlingCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::CustomCloseHandling));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// EOF StatusDialog.cpp
|
||||
47
demo/StatusDialog.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef StatusDialogH
|
||||
#define StatusDialogH
|
||||
//============================================================================
|
||||
/// \file StatusDialog.h
|
||||
/// \author Uwe Kindler
|
||||
/// \date 13.04.2020
|
||||
/// \brief Declaration of CStatusDialog class
|
||||
//============================================================================
|
||||
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include <QDialog>
|
||||
|
||||
namespace ads {class CDockManager;}
|
||||
struct StatusDialogPrivate;
|
||||
|
||||
/**
|
||||
* Displays status info about dock widgets
|
||||
*/
|
||||
class CStatusDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
StatusDialogPrivate* d; ///< private data (pimpl)
|
||||
friend class StatusDialogPrivate;
|
||||
|
||||
private slots:
|
||||
void on_dockWidgetsComboBox_currentIndexChanged(int index);
|
||||
|
||||
protected:
|
||||
public:
|
||||
using Super = QDialog;
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
CStatusDialog(ads::CDockManager* parent);
|
||||
|
||||
/**
|
||||
* Virtual Destructor
|
||||
*/
|
||||
virtual ~CStatusDialog();
|
||||
}; // class StatusDialog
|
||||
|
||||
// namespace namespace_name
|
||||
//-----------------------------------------------------------------------------
|
||||
#endif // StatusDialogH
|
||||
146
demo/StatusDialog.ui
Normal file
@@ -0,0 +1,146 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CStatusDialogClass</class>
|
||||
<widget class="QDialog" name="CStatusDialogClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>357</width>
|
||||
<height>331</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dock Widget Status</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="dockWidgetLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dock Widget:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="dockWidgetsComboBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="statusGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Status</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="isClosedCheckBox">
|
||||
<property name="text">
|
||||
<string>closed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="isFloatingCheckBox">
|
||||
<property name="text">
|
||||
<string>floating</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="tabbedCheckBox">
|
||||
<property name="text">
|
||||
<string>tabbed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="isCurrentTabCheckBox">
|
||||
<property name="text">
|
||||
<string>is current tab</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="flagsGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Feature Flags</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="closableCheckBox">
|
||||
<property name="text">
|
||||
<string>DockWidgetClosable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="movableCheckBox">
|
||||
<property name="text">
|
||||
<string>DockWidgetMovable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="floatableCheckBox">
|
||||
<property name="text">
|
||||
<string>DockWidgetFloatable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="deleteOnCloseCheckBox">
|
||||
<property name="text">
|
||||
<string>DockWidgetDeleteOnClose</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="customCloseHandlingCheckBox">
|
||||
<property name="text">
|
||||
<string>CustomCloseHandling</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -18,13 +18,16 @@ adsBuildStatic {
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
MainWindow.cpp
|
||||
MainWindow.cpp \
|
||||
StatusDialog.cpp
|
||||
|
||||
HEADERS += \
|
||||
MainWindow.h
|
||||
MainWindow.h \
|
||||
StatusDialog.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
mainwindow.ui \
|
||||
StatusDialog.ui
|
||||
|
||||
RESOURCES += demo.qrc
|
||||
|
||||
|
||||
505
demo/demo.py
Normal file
@@ -0,0 +1,505 @@
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
from PyQt5 import uic
|
||||
from PyQt5.QtCore import (QCoreApplication, QDir, Qt, QSettings, QSignalBlocker,
|
||||
QRect, QPoint, qDebug, qInstallMessageHandler,
|
||||
QtDebugMsg, QtInfoMsg, QtWarningMsg,
|
||||
QtCriticalMsg, QtFatalMsg)
|
||||
from PyQt5.QtGui import (QGuiApplication, QIcon, QCloseEvent)
|
||||
from PyQt5.QtWidgets import (QCalendarWidget, QFileSystemModel, QFrame, QLabel,
|
||||
QMenu, QTreeView, QAction, QWidgetAction,
|
||||
QComboBox, QStyle, QSizePolicy, QInputDialog, QMenu,
|
||||
QToolButton, QWidget, QPlainTextEdit,
|
||||
QTableWidget, QTableWidgetItem, QApplication,
|
||||
QMessageBox)
|
||||
try:
|
||||
from PyQt5.QAxContainer import QAxWidget
|
||||
except ImportError:
|
||||
ACTIVEX_AVAILABLE = False
|
||||
else:
|
||||
ACTIVEX_AVAILABLE = True
|
||||
|
||||
from PyQtAds import QtAds
|
||||
|
||||
import rc # pyrcc5 demo.qrc -o rc.py
|
||||
|
||||
UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
|
||||
MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
|
||||
|
||||
|
||||
class _State:
|
||||
label_count = 0
|
||||
calendar_count = 0
|
||||
file_system_count = 0
|
||||
editor_count = 0
|
||||
table_count = 0
|
||||
activex_count = 0
|
||||
|
||||
|
||||
def features_string(dock_widget: QtAds.CDockWidget) -> str:
|
||||
'''Function returns a features string with closable (c), movable (m) and floatable (f)
|
||||
features. i.e. The following string is for a not closable but movable and floatable
|
||||
widget: c- m+ f+'''
|
||||
|
||||
f = dock_widget.features()
|
||||
closable = f & QtAds.CDockWidget.DockWidgetClosable
|
||||
movable = f & QtAds.CDockWidget.DockWidgetMovable
|
||||
floatable = f &QtAds.CDockWidget.DockWidgetFloatable
|
||||
|
||||
return "c{} m{} f{}".format("+" if closable else "-",
|
||||
"+" if movable else "-",
|
||||
"+" if floatable else "-")
|
||||
|
||||
|
||||
def append_feature_string_to_window_title(dock_widget: QtAds.CDockWidget):
|
||||
'''Appends the string returned by features_string() to the window title of
|
||||
the given DockWidget'''
|
||||
|
||||
dock_widget.setWindowTitle(dock_widget.windowTitle() + " ({})".format(features_string(dock_widget)))
|
||||
|
||||
|
||||
def svg_icon(filename: str):
|
||||
'''Helper function to create an SVG icon'''
|
||||
# This is a workaround, because because in item views SVG icons are not
|
||||
# properly scaled an look blurry or pixelate
|
||||
icon = QIcon(filename)
|
||||
icon.addPixmap(icon.pixmap(92))
|
||||
return icon
|
||||
|
||||
|
||||
def create_long_text_label_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
label = QLabel()
|
||||
label.setWordWrap(True)
|
||||
label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
label.setText('''\
|
||||
Label {} {} - Lorem ipsum dolor sit amet, consectetuer
|
||||
adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum
|
||||
sociis natoque penatibus et magnis dis parturient montes, nascetur
|
||||
ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium
|
||||
quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla
|
||||
vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut,
|
||||
imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis
|
||||
pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi.
|
||||
Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu,
|
||||
consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra
|
||||
quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet.
|
||||
'''.format(_State.label_count, datetime.datetime.now().strftime("%H:%M:%S:%f")))
|
||||
dock_widget = QtAds.CDockWidget("Label {}".format(_State.label_count))
|
||||
_State.label_count += 1
|
||||
dock_widget.setWidget(label)
|
||||
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
def create_calendar_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
widget = QCalendarWidget()
|
||||
|
||||
dock_widget = QtAds.CDockWidget("Calendar {}".format(_State.calendar_count))
|
||||
_State.calendar_count += 1
|
||||
dock_widget.setWidget(widget)
|
||||
dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow)
|
||||
dock_widget.setIcon(svg_icon(":/adsdemo/images/date_range.svg"))
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
def create_file_system_tree_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
widget = QTreeView()
|
||||
widget.setFrameShape(QFrame.NoFrame)
|
||||
|
||||
m = QFileSystemModel(widget)
|
||||
m.setRootPath(QDir.currentPath())
|
||||
widget.setModel(m)
|
||||
|
||||
dock_widget = QtAds.CDockWidget("Filesystem {}".format(_State.file_system_count))
|
||||
_State.file_system_count += 1
|
||||
dock_widget.setWidget(widget)
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
def create_editor_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
widget = QPlainTextEdit()
|
||||
widget.setPlaceholderText("This is an editor. If you close the editor, it will be "
|
||||
"deleted. Enter your text here.")
|
||||
widget.setStyleSheet("border: none")
|
||||
dock_widget = QtAds.CDockWidget("Editor {}".format(_State.editor_count))
|
||||
_State.editor_count += 1
|
||||
dock_widget.setWidget(widget)
|
||||
dock_widget.setIcon(svg_icon(":/adsdemo/images/edit.svg"))
|
||||
dock_widget.setFeature(QtAds.CDockWidget.CustomCloseHandling, True)
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
|
||||
options_menu = QMenu(dock_widget)
|
||||
options_menu.setTitle("Options")
|
||||
options_menu.setToolTip(options_menu.title())
|
||||
options_menu.setIcon(svg_icon(":/adsdemo/images/custom-menu-button.svg"))
|
||||
menu_action = options_menu.menuAction()
|
||||
# The object name of the action will be set for the QToolButton that
|
||||
# is created in the dock area title bar. You can use this name for CSS
|
||||
# styling
|
||||
menu_action.setObjectName("options_menu")
|
||||
dock_widget.setTitleBarActions([options_menu.menuAction()])
|
||||
a = options_menu.addAction("Clear Editor")
|
||||
a.triggered.connect(widget.clear)
|
||||
|
||||
return dock_widget
|
||||
|
||||
|
||||
def create_table_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
widget = QTableWidget()
|
||||
dock_widget = QtAds.CDockWidget("Table {}".format(_State.table_count))
|
||||
_State.table_count += 1
|
||||
COLCOUNT = 5
|
||||
ROWCOUNT = 30
|
||||
widget.setColumnCount(COLCOUNT)
|
||||
widget.setRowCount(ROWCOUNT)
|
||||
for col in range(ROWCOUNT):
|
||||
widget.setHorizontalHeaderItem(col, QTableWidgetItem("Col {}".format(col+1)))
|
||||
for row in range(ROWCOUNT):
|
||||
widget.setItem(row, col, QTableWidgetItem("T {:}-{:}".format(row+1, col+1)))
|
||||
|
||||
dock_widget.setWidget(widget)
|
||||
dock_widget.setIcon(svg_icon(":/adsdemo/images/grid_on.svg"))
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
if ACTIVEX_AVAILABLE:
|
||||
def create_activex_widget(view_menu: QMenu, parent: QWidget = None) -> QtAds.CDockWidget:
|
||||
widget = QAxWidget("{6bf52a52-394a-11d3-b153-00c04f79faa6}", parent)
|
||||
dock_widget = QtAds.CDockWidget("Active X {}".format(_State.activex_count))
|
||||
_State.activex_count += 1
|
||||
dock_widget.setWidget(widget)
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
class CustomComponentsFactory(QtAds.CDockComponentsFactory):
|
||||
|
||||
def createDockAreaTitleBar(self, dock_area: QtAds.CDockAreaWidget) -> QtAds.CDockAreaTitleBar:
|
||||
title_bar = QtAds.CDockAreaTitleBar(dock_area)
|
||||
custom_button = QToolButton(dock_area)
|
||||
custom_button.setToolTip("Help")
|
||||
custom_button.setIcon(svg_icon(":/adsdemo/images/help_outline.svg"))
|
||||
custom_button.setAutoRaise(True)
|
||||
index = title_bar.indexOf(title_bar.button(QtAds.TitleBarButtonTabsMenu))
|
||||
title_bar.insertWidget(index + 1, custom_button)
|
||||
return title_bar
|
||||
|
||||
|
||||
|
||||
class MainWindow(MainWindowUI, MainWindowBase):
|
||||
save_perspective_action: QAction
|
||||
perspective_list_action: QWidgetAction
|
||||
perspective_combo_box: QComboBox
|
||||
dock_manager: QtAds.CDockManager
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.save_perspective_action = None
|
||||
self.perspective_list_action = None
|
||||
self.perspective_combo_box = None
|
||||
self.dock_manager = None
|
||||
|
||||
self.setupUi(self)
|
||||
self.create_actions()
|
||||
|
||||
# uncomment the following line if the tab close button should be
|
||||
# a QToolButton instead of a QPushButton
|
||||
# QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.configFlags() | QtAds.CDockManager.TabCloseButtonIsToolButton)
|
||||
|
||||
# uncomment the following line if you want a fixed tab width that does
|
||||
# not change if the visibility of the close button changes
|
||||
# QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.RetainTabSizeWhenCloseButtonHidden, True)
|
||||
|
||||
# uncomment the follwing line if you want to use non opaque undocking and splitter
|
||||
# movements
|
||||
# QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DefaultNonOpaqueConfig)
|
||||
|
||||
# Now create the dock manager and its content
|
||||
self.dock_manager = QtAds.CDockManager(self)
|
||||
|
||||
# Uncomment the following line to have the old style where the dock
|
||||
# area close button closes the active tab
|
||||
# QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DockAreaHasCloseButton
|
||||
# | QtAds.CDockManager.DockAreaCloseButtonClosesTab)
|
||||
self.perspective_combo_box.activated[str].connect(self.dock_manager.openPerspective)
|
||||
|
||||
self.create_content()
|
||||
# Default window geometry - center on screen
|
||||
self.resize(1280, 720)
|
||||
self.setGeometry(QStyle.alignedRect(
|
||||
Qt.LeftToRight, Qt.AlignCenter, self.frameSize(),
|
||||
QGuiApplication.primaryScreen().availableGeometry()))
|
||||
|
||||
# self.restore_state()
|
||||
self.restore_perspectives()
|
||||
|
||||
def create_content(self):
|
||||
# Test container docking
|
||||
view_menu = self.menuView
|
||||
dock_widget = create_calendar_dock_widget(view_menu)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
|
||||
special_dock_area = self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget)
|
||||
|
||||
# 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):
|
||||
special_dock_area.setAllowedAreas(QtAds.OuterDockAreas)
|
||||
# special_dock_area.setAllowedAreas(QtAds.LeftDockWidgetArea | QtAds.RightDockWidgetArea) # just for testing
|
||||
|
||||
self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, create_long_text_label_dock_widget(view_menu))
|
||||
file_system_widget = create_file_system_tree_dock_widget(view_menu)
|
||||
tool_bar = file_system_widget.createDefaultToolBar()
|
||||
tool_bar.addAction(self.actionSaveState)
|
||||
tool_bar.addAction(self.actionRestoreState)
|
||||
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
|
||||
append_feature_string_to_window_title(file_system_widget)
|
||||
self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, file_system_widget)
|
||||
|
||||
file_system_widget = create_file_system_tree_dock_widget(view_menu)
|
||||
tool_bar = file_system_widget.createDefaultToolBar()
|
||||
tool_bar.addAction(self.actionSaveState)
|
||||
tool_bar.addAction(self.actionRestoreState)
|
||||
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
|
||||
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
|
||||
append_feature_string_to_window_title(file_system_widget)
|
||||
|
||||
# Test custom factory - we inject a help button into the title bar
|
||||
self.factory = CustomComponentsFactory()
|
||||
QtAds.CDockComponentsFactory.setFactory(self.factory)
|
||||
top_dock_area = self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, file_system_widget)
|
||||
QtAds.CDockComponentsFactory.resetDefaultFactory()
|
||||
|
||||
|
||||
# We create a calendar widget and clear all flags to prevent the dock area
|
||||
# from closing
|
||||
dock_widget = create_calendar_dock_widget(view_menu)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
|
||||
dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna")
|
||||
dock_area = self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area)
|
||||
|
||||
# Now we add a custom button to the dock area title bar that will create
|
||||
# new editor widgets when clicked
|
||||
custom_button = QToolButton(dock_area)
|
||||
custom_button.setToolTip("Create Editor")
|
||||
custom_button.setIcon(svg_icon(":/adsdemo/images/plus.svg"))
|
||||
custom_button.setAutoRaise(True)
|
||||
title_bar = dock_area.titleBar()
|
||||
index = title_bar.indexOf(title_bar.tabBar())
|
||||
title_bar.insertWidget(index + 1, custom_button)
|
||||
def on_button_clicked():
|
||||
dock_widget = create_editor_widget(self.menuView)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
|
||||
self.dock_manager.addDockWidgetTabToArea(dock_widget, dock_area)
|
||||
dock_widget.closeRequested.connect(self.on_editor_close_requested)
|
||||
custom_button.clicked.connect(on_button_clicked)
|
||||
|
||||
# Test dock area docking
|
||||
right_dock_area = self.dock_manager.addDockWidget(
|
||||
QtAds.RightDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), top_dock_area)
|
||||
self.dock_manager.addDockWidget(
|
||||
QtAds.TopDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), right_dock_area)
|
||||
|
||||
bottom_dock_area = self.dock_manager.addDockWidget(
|
||||
QtAds.BottomDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), right_dock_area)
|
||||
|
||||
self.dock_manager.addDockWidget(
|
||||
QtAds.CenterDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), right_dock_area)
|
||||
self.dock_manager.addDockWidget(
|
||||
QtAds.CenterDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), bottom_dock_area)
|
||||
|
||||
action = self.menuView.addAction("Set {} floating".format(dock_widget.windowTitle()))
|
||||
action.triggered.connect(dock_widget.setFloating)
|
||||
|
||||
if ACTIVEX_AVAILABLE:
|
||||
flags = self.dock_manager.configFlags()
|
||||
if flags & QtAds.CDockManager.OpaqueUndocking:
|
||||
self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea,
|
||||
create_activex_widget(view_menu), right_dock_area)
|
||||
|
||||
for dock_widget in self.dock_manager.dockWidgetsMap().values():
|
||||
dock_widget.viewToggled.connect(self.on_view_toggled)
|
||||
dock_widget.visibilityChanged.connect(self.on_view_visibility_changed)
|
||||
|
||||
def create_actions(self):
|
||||
self.toolBar.addAction(self.actionSaveState)
|
||||
self.toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||
self.actionSaveState.setIcon(svg_icon(":/adsdemo/images/save.svg"))
|
||||
self.toolBar.addAction(self.actionRestoreState)
|
||||
self.actionRestoreState.setIcon(svg_icon(":/adsdemo/images/restore.svg"))
|
||||
|
||||
self.save_perspective_action = QAction("Create Perspective", self)
|
||||
self.save_perspective_action.setIcon(svg_icon(":/adsdemo/images/picture_in_picture.svg"))
|
||||
self.save_perspective_action.triggered.connect(self.save_perspective)
|
||||
self.perspective_list_action = QWidgetAction(self)
|
||||
self.perspective_combo_box = QComboBox(self)
|
||||
self.perspective_combo_box.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
||||
self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
||||
self.perspective_list_action.setDefaultWidget(self.perspective_combo_box)
|
||||
self.toolBar.addSeparator()
|
||||
self.toolBar.addAction(self.perspective_list_action)
|
||||
self.toolBar.addAction(self.save_perspective_action)
|
||||
|
||||
a = self.toolBar.addAction("Create Editor")
|
||||
a.setToolTip("Creates floating dynamic dockable editor windows that are deleted on close")
|
||||
a.setIcon(svg_icon(":/adsdemo/images/note_add.svg"))
|
||||
a.triggered.connect(self.create_editor)
|
||||
|
||||
a = self.toolBar.addAction("Create Table")
|
||||
a.setToolTip("Creates floating dynamic dockable table with millions of entries")
|
||||
a.setIcon(svg_icon(":/adsdemo/images/grid_on.svg"))
|
||||
a.triggered.connect(self.create_table)
|
||||
|
||||
def closeEvent(self, event: QCloseEvent):
|
||||
self.save_state()
|
||||
super().closeEvent(event)
|
||||
|
||||
def on_action_save_state_triggered(state: bool):
|
||||
qDebug("MainWindow::on_action_save_state_triggered")
|
||||
self.save_state()
|
||||
|
||||
def on_action_restore_state_triggered(state: bool):
|
||||
qDebug("MainWindow::on_action_restore_state_triggered")
|
||||
self.restore_state()
|
||||
|
||||
def save_perspective(self):
|
||||
perspective_name, ok = QInputDialog.getText(self, "Save perspective",
|
||||
"Enter unique name:")
|
||||
|
||||
if ok and perspective_name:
|
||||
self.dock_manager.addPerspective(perspective_name)
|
||||
_ = QSignalBlocker(self.perspective_combo_box)
|
||||
self.perspective_combo_box.clear()
|
||||
self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
|
||||
self.perspective_combo_box.setCurrentText(perspective_name)
|
||||
|
||||
self.save_perspectives()
|
||||
|
||||
def on_view_toggled(self, open: bool):
|
||||
dock_widget = self.sender()
|
||||
if dock_widget is None:
|
||||
return
|
||||
|
||||
qDebug("{} view_toggled({})".format(dock_widget.objectName(), open))
|
||||
|
||||
def on_view_visibility_changed(self, visible: bool):
|
||||
dock_widget = self.sender()
|
||||
if dock_widget is None:
|
||||
return
|
||||
|
||||
qDebug("{} visibility_changed({})".format(dock_widget.objectName(), visible))
|
||||
|
||||
def create_editor(self):
|
||||
dock_widget = create_editor_widget(self.menuView)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
|
||||
floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget)
|
||||
floating_widget.move(QPoint(20, 20))
|
||||
dock_widget.closeRequested.connect(self.on_editor_close_requested)
|
||||
|
||||
def on_editor_close_requested(self):
|
||||
dock_widget = self.sender()
|
||||
result = QMessageBox.question(self, "Close Editor",
|
||||
"Editor {} contains unsaved changes? Would you like to close it?".format(dock_widget.windowTitle()))
|
||||
if result == QMessageBox.Yes:
|
||||
dock_widget.closeDockWidget()
|
||||
|
||||
def create_table(self):
|
||||
dock_widget = create_table_widget(self.menuView)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
|
||||
floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget)
|
||||
floating_widget.move(QPoint(40, 40))
|
||||
|
||||
def save_state(self):
|
||||
'''
|
||||
Saves the dock manager state and the main window geometry
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
settings.setValue("mainWindow/Geometry", self.saveGeometry())
|
||||
settings.setValue("mainWindow/State", self.saveState())
|
||||
settings.setValue("mainWindow/DockingState", self.dock_manager.saveState())
|
||||
|
||||
def restore_state(self):
|
||||
'''
|
||||
Restores the dock manager state
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
geom = settings.value("mainWindow/Geometry")
|
||||
if geom is not None:
|
||||
self.restoreGeometry(geom)
|
||||
|
||||
state = settings.value("mainWindow/State")
|
||||
if state is not None:
|
||||
self.restoreState(state)
|
||||
|
||||
state = settings.value("mainWindow/DockingState")
|
||||
if state is not None:
|
||||
self.dock_manager.restore_state(state)
|
||||
|
||||
def save_perspectives(self):
|
||||
'''
|
||||
Save the list of perspectives
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
self.dock_manager.savePerspectives(settings)
|
||||
|
||||
def restore_perspectives(self):
|
||||
'''
|
||||
Restore the perspective listo of the dock manager
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
self.dock_manager.loadPerspectives(settings)
|
||||
self.perspective_combo_box.clear()
|
||||
self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
|
||||
|
||||
def save_perspective(self):
|
||||
perspective_name, ok = QInputDialog.getText(self, 'Save perspective', 'Enter unique name:')
|
||||
if ok and perspective_name:
|
||||
self.dock_manager.addPerspective(perspective_name)
|
||||
_ = QSignalBlocker(self.perspective_combo_box)
|
||||
self.perspective_combo_box.clear()
|
||||
self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
|
||||
self.perspective_combo_box.setCurrentText(perspective_name)
|
||||
self.save_perspectives()
|
||||
|
||||
|
||||
def my_message_output(type, context, msg):
|
||||
if type == QtDebugMsg:
|
||||
print("Debug: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
|
||||
elif type == QtInfoMsg:
|
||||
print("Info: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
|
||||
elif type == QtWarningMsg:
|
||||
print("Warning: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
|
||||
elif type == QtCriticalMsg:
|
||||
print("Critical: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
|
||||
elif type == QtFatalMsg:
|
||||
print("Fatal: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
|
||||
QGuiApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
||||
app = QApplication(sys.argv)
|
||||
app.setQuitOnLastWindowClosed(True)
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "app.css"), "r") as style_sheet_file:
|
||||
app.setStyleSheet(style_sheet_file.read())
|
||||
|
||||
qInstallMessageHandler(my_message_output)
|
||||
qDebug("Message handler test")
|
||||
|
||||
mw = MainWindow()
|
||||
mw.show()
|
||||
app.exec_()
|
||||
@@ -13,5 +13,6 @@
|
||||
<file>app.css</file>
|
||||
<file>images/plus.svg</file>
|
||||
<file>images/help_outline.svg</file>
|
||||
<file>images/fullscreen.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
6
demo/images/fullscreen.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>settings_overscan icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M981.33,213.33v597.34c0,46.93 -38.4,85.33 -85.33,85.33h-768c-46.93,0 -85.33,-38.4 -85.33,-85.33v-597.34c0,-46.93 38.4,-85.33 85.33,-85.33h768c46.93,0 85.33,38.4 85.33,85.33zM896,212.91h-768v598.18h768zM256,597.33l-106.67,-84.9l106.67,-85.76zM597.33,341.33h-170.66l85.76,-106.66zM874.67,512.43l-106.67,84.9v-170.66zM512.43,789.33l-85.76,-106.66h170.66z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 776 B |
@@ -41,6 +41,7 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
std::shared_ptr<int> b;
|
||||
QApplication a(argc, argv);
|
||||
a.setApplicationName("Advanced Docking System Demo");
|
||||
a.setQuitOnLastWindowClosed(true);
|
||||
|
||||
QFile StyleSheetFile(":/adsdemo/app.css");
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionExit"/>
|
||||
<addaction name="actionSaveState"/>
|
||||
<addaction name="actionRestoreState"/>
|
||||
</widget>
|
||||
@@ -45,8 +44,14 @@
|
||||
<string>About</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTests">
|
||||
<property name="title">
|
||||
<string>Tests</string>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menuTests"/>
|
||||
<addaction name="menuAbout"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
|
||||
@@ -14,18 +14,17 @@ styles as much as possible.
|
||||
|
||||
### Overview
|
||||
|
||||
- [Advanced Docking System for Qt](#advanced-docking-system-for-qt)
|
||||
- [Features](#features)
|
||||
- [Overview](#overview)
|
||||
- [Docking everywhere - no central widget](#docking-everywhere---no-central-widget)
|
||||
- [Docking inside floating windows](#docking-inside-floating-windows)
|
||||
- [Grouped dragging](#grouped-dragging)
|
||||
- [Perspectives for fast switching of the complete main window layout](#perspectives-for-fast-switching-of-the-complete-main-window-layout)
|
||||
- [Opaque and non-opaque splitter resizing](#opaque-and-non-opaque-splitter-resizing)
|
||||
- [Opaque and non-opaque undocking](#opaque-and-non-opaque-undocking)
|
||||
- [Tab-menu for easy handling of many tabbed dock widgets](#tab-menu-for-easy-handling-of-many-tabbed-dock-widgets)
|
||||
- [Many different ways to detach dock widgets](#many-different-ways-to-detach-dock-widgets)
|
||||
- [Supports deletion of dynamically created dock widgets](#supports-deletion-of-dynamically-created-dock-widgets)
|
||||
- [Features](#features)
|
||||
- [Overview](#overview)
|
||||
- [Docking everywhere - no central widget](#docking-everywhere---no-central-widget)
|
||||
- [Docking inside floating windows](#docking-inside-floating-windows)
|
||||
- [Grouped dragging](#grouped-dragging)
|
||||
- [Perspectives for fast switching of the complete main window layout](#perspectives-for-fast-switching-of-the-complete-main-window-layout)
|
||||
- [Opaque and non-opaque splitter resizing](#opaque-and-non-opaque-splitter-resizing)
|
||||
- [Opaque and non-opaque undocking](#opaque-and-non-opaque-undocking)
|
||||
- [Tab-menu for easy handling of many tabbed dock widgets](#tab-menu-for-easy-handling-of-many-tabbed-dock-widgets)
|
||||
- [Many different ways to detach dock widgets](#many-different-ways-to-detach-dock-widgets)
|
||||
- [Supports deletion of dynamically created dock widgets](#supports-deletion-of-dynamically-created-dock-widgets)
|
||||
|
||||
### Docking everywhere - no central widget
|
||||
|
||||
@@ -33,8 +32,8 @@ There is no central widget like in the Qt docking system. You can dock on every
|
||||
border of the main window or you can dock into each dock area - so you are
|
||||
free to dock almost everywhere.
|
||||
|
||||
\
|
||||
\
|
||||

|
||||
|
||||

|
||||
|
||||
### Docking inside floating windows
|
||||
@@ -42,8 +41,8 @@ free to dock almost everywhere.
|
||||
There is no difference between the main window and a floating window. Docking
|
||||
into floating windows is supported.
|
||||
|
||||
\
|
||||
\
|
||||

|
||||
|
||||

|
||||
|
||||
### Grouped dragging
|
||||
@@ -52,8 +51,8 @@ When dragging the titlebar of a dock, all the tabs that are tabbed with it are
|
||||
going to be dragged. So you can move complete groups of tabbed widgets into
|
||||
a floating widget or from one dock area to another one.
|
||||
|
||||
\
|
||||
\
|
||||

|
||||
|
||||

|
||||
|
||||
### Perspectives for fast switching of the complete main window layout
|
||||
@@ -64,8 +63,8 @@ perspective to make your own custom perspective. Later you can simply
|
||||
select a perspective from the perspective list to quickly switch the complete
|
||||
main window layout.
|
||||
|
||||
\
|
||||
\
|
||||

|
||||
|
||||

|
||||
|
||||
### Opaque and non-opaque splitter resizing
|
||||
|
||||
BIN
doc/cfg_flag_ActiveTabHasCloseButton_false.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
doc/cfg_flag_ActiveTabHasCloseButton_true.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
doc/cfg_flag_AllTabsHaveCloseButton_true.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
doc/cfg_flag_AlwaysShowTabs_false_true.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
BIN
doc/cfg_flag_DockAreaHasCloseButton_false.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
doc/cfg_flag_DockAreaHasCloseButton_true.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
doc/cfg_flag_DockAreaHasTabsMenuButton_false_true.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
doc/cfg_flag_DockAreaHasUndockButton_false_true.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
doc/cfg_flag_DockAreaHideDisabledButtons_false.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
doc/cfg_flag_DockAreaHideDisabledButtons_true.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
doc/cfg_flag_DragPreviewHasWindowFrame_true.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
doc/cfg_flag_DragPreviewShowsContentPixmap_false.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
doc/cfg_flag_DragPreviewShowsContentPixmap_true.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
doc/cfg_flag_FloatingContainerHasWidgetIcon_false.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
doc/cfg_flag_FloatingContainerHasWidgetIcon_true.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
doc/cfg_flag_FloatingContainerHasWidgetTitle_false.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
doc/cfg_flag_FloatingContainerHasWidgetTitle_true.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
doc/cfg_flag_HideSingleCentralWidgetTitleBar_false.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
doc/cfg_flag_HideSingleCentralWidgetTitleBar_true.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
doc/cfg_flag_RetainTabSizeWhenCloseButtonHidden_true.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
doc/dynamic_drag_preview.gif
Normal file
|
After Width: | Height: | Size: 763 KiB |
BIN
doc/non_opaque_undocking.gif
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
doc/opaque_undocking.gif
Normal file
|
After Width: | Height: | Size: 503 KiB |
BIN
doc/qmix_elements.png
Normal file
|
After Width: | Height: | Size: 539 KiB |
BIN
doc/qt_design_studio.png
Normal file
|
After Width: | Height: | Size: 157 KiB |
BIN
doc/qtcreator.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
299
doc/user-guide.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# User Guide
|
||||
|
||||
- [Configuration Flags](#configuration-flags)
|
||||
- [Setting Configuration Flags](#setting-configuration-flags)
|
||||
- [`ActiveTabHasCloseButton`](#activetabhasclosebutton)
|
||||
- [`DockAreaHasCloseButton`](#dockareahasclosebutton)
|
||||
- [`DockAreaCloseButtonClosesTab`](#dockareaclosebuttonclosestab)
|
||||
- [`OpaqueSplitterResize`](#opaquesplitterresize)
|
||||
- [`XmlAutoFormattingEnabled`](#xmlautoformattingenabled)
|
||||
- [`XmlCompressionEnabled`](#xmlcompressionenabled)
|
||||
- [`TabCloseButtonIsToolButton`](#tabclosebuttonistoolbutton)
|
||||
- [`AllTabsHaveCloseButton`](#alltabshaveclosebutton)
|
||||
- [`RetainTabSizeWhenCloseButtonHidden`](#retaintabsizewhenclosebuttonhidden)
|
||||
- [`OpaqueUndocking`](#opaqueundocking)
|
||||
- [`DragPreviewIsDynamic`](#dragpreviewisdynamic)
|
||||
- [`DragPreviewShowsContentPixmap`](#dragpreviewshowscontentpixmap)
|
||||
- [`DragPreviewHasWindowFrame`](#dragpreviewhaswindowframe)
|
||||
- [`AlwaysShowTabs`](#alwaysshowtabs)
|
||||
- [`DockAreaHasUndockButton`](#dockareahasundockbutton)
|
||||
- [`DockAreaHasTabsMenuButton`](#dockareahastabsmenubutton)
|
||||
- [`DockAreaHideDisabledButtons`](#dockareahidedisabledbuttons)
|
||||
- [`DockAreaDynamicTabsMenuButtonVisibility`](#dockareadynamictabsmenubuttonvisibility)
|
||||
- [`FloatingContainerHasWidgetTitle`](#floatingcontainerhaswidgettitle)
|
||||
- [`FloatingContainerHasWidgetIcon`](#floatingcontainerhaswidgeticon)
|
||||
- [`HideSingleCentralWidgetTitleBar`](#hidesinglecentralwidgettitlebar)
|
||||
|
||||
## Configuration Flags
|
||||
|
||||
The Advanced Docking System has a number of global configuration options to
|
||||
configure the design and the functionality of the docking system. Each
|
||||
configuration will be explained in detail in the following sections.
|
||||
|
||||
### Setting Configuration Flags
|
||||
|
||||
You should set the configuration flags before you create the dock manager
|
||||
instance. That means, setting the configurations flags is the first thing
|
||||
you do, if you use the library.
|
||||
|
||||
```c++
|
||||
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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

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

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

|
||||
|
||||
### `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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
### `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.
|
||||
|
||||

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

|
||||
|
||||
### `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.
|
||||
|
||||

|
||||
|
||||
### `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.
|
||||
|
||||

|
||||
|
||||
If you would like to test opaque undocking, you should set the pedefined config
|
||||
flags `CDockManager::DefaultOpaqueConfig`.
|
||||
|
||||
```c++
|
||||
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.
|
||||
|
||||

|
||||
|
||||
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`.
|
||||
|
||||
```c++
|
||||
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`.
|
||||
|
||||
```c++
|
||||
CDockManager::setConfigFlag(CDockManager::DragPreviewIsDynamic, true);
|
||||
CDockManager::setConfigFlag(CDockManager::DragPreviewShowsContentPixmap, false);
|
||||
CDockManager::setConfigFlag(CDockManager::DragPreviewHasWindowFrame, false);
|
||||
```
|
||||
|
||||

|
||||
|
||||
### `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).
|
||||
|
||||

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

|
||||
|
||||
### `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.
|
||||
|
||||

|
||||
|
||||
### `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.
|
||||
|
||||

|
||||
|
||||
### `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)
|
||||
|
||||

|
||||
|
||||
### `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.
|
||||
|
||||

|
||||
|
||||
### `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.
|
||||
|
||||

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

|
||||
|
||||
### `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.
|
||||
|
||||

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

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

|
||||
|
||||
otherwise it displays application name as window title.
|
||||
|
||||

|
||||
|
||||
### `FloatingContainerHasWidgetIcon`
|
||||
|
||||
If set, the floating widget icon reflects the icon of the current dock widget
|
||||
|
||||

|
||||
|
||||
otherwise (default setting) it displays application icon.
|
||||
|
||||

|
||||
|
||||
### `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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
52
example/example.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
from PyQt5 import uic
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QApplication, QLabel
|
||||
|
||||
from PyQtAds import QtAds
|
||||
|
||||
UI_FILE = os.path.join(os.path.dirname(__file__), 'MainWindow.ui')
|
||||
MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
|
||||
|
||||
|
||||
class MainWindow(MainWindowUI, MainWindowBase):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setupUi(self)
|
||||
|
||||
# Create the dock manager. Because the parent parameter is a QMainWindow
|
||||
# the dock manager registers itself as the central widget.
|
||||
self.dock_manager = QtAds.CDockManager(self)
|
||||
|
||||
# Create example content label - this can be any application specific
|
||||
# widget
|
||||
l = QLabel()
|
||||
l.setWordWrap(True)
|
||||
l.setAlignment(Qt.AlignTop | Qt.AlignLeft);
|
||||
l.setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
|
||||
|
||||
# Create a dock widget with the title Label 1 and set the created label
|
||||
# as the dock widget content
|
||||
dock_widget = QtAds.CDockWidget("Label 1")
|
||||
dock_widget.setWidget(l)
|
||||
|
||||
# Add the toggleViewAction of the dock widget to the menu to give
|
||||
# the user the possibility to show the dock widget if it has been closed
|
||||
self.menuView.addAction(dock_widget.toggleViewAction())
|
||||
|
||||
# Add the dock widget to the top dock widget area
|
||||
self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, dock_widget)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
w = MainWindow()
|
||||
w.show()
|
||||
app.exec_()
|
||||
@@ -1,41 +0,0 @@
|
||||
{% set data = load_setup_py_data() %}
|
||||
|
||||
package:
|
||||
name: pyqtads
|
||||
version: {{ data.get('version') }}
|
||||
|
||||
source:
|
||||
path: ../
|
||||
|
||||
build:
|
||||
number: 0
|
||||
script: python setup.py install --single-version-externally-managed --record=record.txt --conda-recipe
|
||||
|
||||
requirements:
|
||||
build:
|
||||
- python
|
||||
- setuptools
|
||||
- pyqt>=5.9
|
||||
- sip>=4.19
|
||||
run:
|
||||
- python
|
||||
- pyqt>=5.9
|
||||
- sip>=4.19
|
||||
- pywin32 [win]
|
||||
|
||||
test:
|
||||
imports:
|
||||
- PyQtAds
|
||||
|
||||
about:
|
||||
home: {{ data.get('url') }}
|
||||
license: {{ data.get('license') }}
|
||||
license_family: LGPL
|
||||
license_file: 'LICENSE.md'
|
||||
summary: {{ data.get('description') }}
|
||||
description: {{ data.get('description') }}
|
||||
doc_url: ''
|
||||
dev_url: {{ data.get('url') }}
|
||||
|
||||
extra:
|
||||
recipe-maintainers: 'nicolas.elie@cnrs.fr'
|
||||
70
setup.py
@@ -18,7 +18,7 @@ from PyQt5.pyrcc_main import processResourceFile
|
||||
|
||||
MODULE_NAME = "ads"
|
||||
SRC_PATH = "PyQtAds"
|
||||
|
||||
|
||||
REQUIRE_PYQT = True
|
||||
if "--conda-recipe" in sys.argv:
|
||||
REQUIRE_PYQT = False
|
||||
@@ -40,7 +40,7 @@ class HostPythonConfiguration(object):
|
||||
else:
|
||||
self.data_dir = sys.prefix + '/share'
|
||||
self.lib_dir = sys.prefix + '/lib'
|
||||
|
||||
|
||||
|
||||
class TargetQtConfiguration(object):
|
||||
def __init__(self, qmake):
|
||||
@@ -63,12 +63,12 @@ class TargetQtConfiguration(object):
|
||||
setattr(self, name, value)
|
||||
|
||||
pipe.close()
|
||||
|
||||
|
||||
|
||||
class build_ext(sipdistutils.build_ext):
|
||||
|
||||
|
||||
description = "Builds the " + MODULE_NAME + " module."
|
||||
|
||||
|
||||
user_options = sipdistutils.build_ext.user_options + [
|
||||
('qmake-bin=', None, "Path to qmake binary"),
|
||||
('sip-bin=', None, "Path to sip binary"),
|
||||
@@ -78,7 +78,7 @@ class build_ext(sipdistutils.build_ext):
|
||||
('sip-dir=', None, "Path to module's SIP files"),
|
||||
('inc-dir=', None, "Path to module's include files")
|
||||
]
|
||||
|
||||
|
||||
def initialize_options (self):
|
||||
super().initialize_options()
|
||||
self.qmake_bin = 'qmake'
|
||||
@@ -92,16 +92,16 @@ class build_ext(sipdistutils.build_ext):
|
||||
self.inc_dir = None
|
||||
self.pyconfig = HostPythonConfiguration()
|
||||
self.qtconfig = TargetQtConfiguration(self.qmake_bin)
|
||||
self.config = sipconfig.Configuration()
|
||||
self.config = sipconfig.Configuration()
|
||||
self.config.default_mod_dir = ("/usr/local/lib/python%i.%i/dist-packages" %
|
||||
(sys.version_info.major, sys.version_info.minor))
|
||||
|
||||
|
||||
def finalize_options (self):
|
||||
super().finalize_options()
|
||||
|
||||
if not self.qt_include_dir:
|
||||
self.qt_include_dir = self.qtconfig.QT_INSTALL_HEADERS
|
||||
|
||||
|
||||
if not self.qt_libinfix:
|
||||
try:
|
||||
with open(os.path.join(self.qtconfig.QT_INSTALL_PREFIX, 'mkspecs', 'qconfig.pri'), 'r') as f:
|
||||
@@ -113,16 +113,16 @@ class build_ext(sipdistutils.build_ext):
|
||||
|
||||
if not self.pyqt_sip_dir:
|
||||
self.pyqt_sip_dir = os.path.join(self.pyconfig.data_dir, 'sip', 'PyQt5')
|
||||
|
||||
|
||||
if not self.pyqt_sip_flags:
|
||||
self.pyqt_sip_flags = PYQT_CONFIGURATION.get('sip_flags', '')
|
||||
|
||||
|
||||
if not self.sip_files_dir:
|
||||
self.sip_files_dir = os.path.abspath(os.path.join(".", "sip"))
|
||||
|
||||
|
||||
if not self.sip_inc_dir:
|
||||
self.sip_inc_dir = self.pyconfig.venv_inc_dir
|
||||
|
||||
|
||||
if not self.inc_dir:
|
||||
self.inc_dir = os.path.abspath(os.path.join(".", "src"))
|
||||
|
||||
@@ -138,12 +138,12 @@ class build_ext(sipdistutils.build_ext):
|
||||
if not self.pyqt_sip_flags:
|
||||
raise SystemExit('Could not find PyQt SIP flags. '
|
||||
'Please specify via --pyqt-sip-flags=')
|
||||
|
||||
|
||||
def _find_sip(self):
|
||||
"""override _find_sip to allow for manually speficied sip path."""
|
||||
return self.sip_bin or super()._find_sip()
|
||||
|
||||
def _sip_compile(self, sip_bin, source, sbf):
|
||||
|
||||
def _sip_compile(self, sip_bin, source, sbf):
|
||||
cmd = [sip_bin]
|
||||
if hasattr(self, 'sip_opts'):
|
||||
cmd += self.sip_opts
|
||||
@@ -157,11 +157,11 @@ class build_ext(sipdistutils.build_ext):
|
||||
"-c", self._sip_output_dir(),
|
||||
"-b", sbf,
|
||||
"-w", "-o"]
|
||||
|
||||
|
||||
cmd += shlex.split(self.pyqt_sip_flags) # use same SIP flags as for PyQt5
|
||||
cmd.append(source)
|
||||
self.spawn(cmd)
|
||||
|
||||
|
||||
def swig_sources (self, sources, extension=None):
|
||||
if not self.extensions:
|
||||
return
|
||||
@@ -179,7 +179,7 @@ class build_ext(sipdistutils.build_ext):
|
||||
extension.libraries += ['Qt5Core' + self.qt_libinfix,
|
||||
'Qt5Gui' + self.qt_libinfix,
|
||||
'Qt5Widgets' + self.qt_libinfix]
|
||||
|
||||
|
||||
if sys.platform == 'win32':
|
||||
extension.library_dirs += [self.qtconfig.QT_INSTALL_LIBS,
|
||||
self.inc_dir, self._sip_output_dir()]
|
||||
@@ -192,30 +192,46 @@ class build_ext(sipdistutils.build_ext):
|
||||
extension.extra_compile_args += ['-std=c++11']
|
||||
|
||||
return super().swig_sources(sources, extension)
|
||||
|
||||
|
||||
def build_extension(self, ext):
|
||||
cppsources = [source for source in ext.sources if source.endswith(".cpp")]
|
||||
|
||||
|
||||
dir_util.mkpath(self.build_temp, dry_run=self.dry_run)
|
||||
|
||||
def get_moc_args(out_file, source):
|
||||
if sys.platform.startswith('linux'):
|
||||
return ["moc", "-D", "Q_OS_LINUX=1", "-o", out_file, source]
|
||||
if sys.platform.startswith('darwin'):
|
||||
return ["moc", "-D", "Q_OS_MACOS=1", "-o", out_file, source]
|
||||
if sys.platform.startswith('win'):
|
||||
return ["moc", "-D", "Q_OS_WIN=1", "-o", out_file, source]
|
||||
return ["moc", "-o", out_file, source]
|
||||
|
||||
# Run moc on all header files.
|
||||
for source in cppsources:
|
||||
# *.cpp -> *.moc
|
||||
moc_file = os.path.basename(source).replace(".cpp", ".moc")
|
||||
out_file = os.path.join(self.build_temp, moc_file)
|
||||
|
||||
if newer(source, out_file) or self.force:
|
||||
spawn.spawn(get_moc_args(out_file, source), dry_run=self.dry_run)
|
||||
|
||||
header = source.replace(".cpp", ".h")
|
||||
if os.path.exists(header):
|
||||
# *.h -> moc_*.cpp
|
||||
moc_file = "moc_" + os.path.basename(header).replace(".h", ".cpp")
|
||||
out_file = os.path.join(self.build_temp, moc_file)
|
||||
|
||||
|
||||
if newer(header, out_file) or self.force:
|
||||
call_arg = ["moc", "-o", out_file, header]
|
||||
spawn.spawn(call_arg, dry_run=self.dry_run)
|
||||
|
||||
spawn.spawn(get_moc_args(out_file, header), dry_run=self.dry_run)
|
||||
|
||||
if os.path.getsize(out_file) > 0:
|
||||
ext.sources.append(out_file)
|
||||
|
||||
# Add the temp build directory to include path, for compiler to find
|
||||
# the created .moc files
|
||||
ext.include_dirs += [self._sip_output_dir()]
|
||||
|
||||
|
||||
sipdistutils.build_ext.build_extension(self, ext)
|
||||
|
||||
|
||||
@@ -253,7 +269,7 @@ ext_modules = [Extension('PyQtAds.QtAds.ads', cpp_sources + sip_sources)]
|
||||
install_requires = ["PyQt5"]
|
||||
if sys.platform == 'win32':
|
||||
install_requires.append("pywin32")
|
||||
|
||||
|
||||
|
||||
with open('README.md', 'r') as f:
|
||||
LONG_DESCRIPTION = f.read()
|
||||
|
||||
82
simple.py
@@ -1,82 +0,0 @@
|
||||
import logging
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQtAds import QtAds
|
||||
|
||||
|
||||
class MainWindow(QtWidgets.QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setup_ui()
|
||||
self.dock_manager = QtAds.CDockManager(self)
|
||||
|
||||
self.dock_widgets = []
|
||||
|
||||
for label_text, area in (
|
||||
('1 Top', QtAds.TopDockWidgetArea),
|
||||
('2 Bottom', QtAds.BottomDockWidgetArea),
|
||||
('3 Left', QtAds.LeftDockWidgetArea),
|
||||
('4 Right', QtAds.RightDockWidgetArea),
|
||||
):
|
||||
# Create example content label - this can be any application specific
|
||||
# widget
|
||||
label = QtWidgets.QLabel()
|
||||
label.setWordWrap(True)
|
||||
label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
label.setText(f"{label_text}: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
|
||||
|
||||
# Create a dock widget with the title Label 1 and set the created label
|
||||
# as the dock widget content
|
||||
dock_widget = QtAds.CDockWidget(label_text)
|
||||
dock_widget.setWidget(label)
|
||||
self.dock_widgets.append(dock_widget)
|
||||
|
||||
# Add the toggleViewAction of the dock widget to the menu to give
|
||||
# the user the possibility to show the dock widget if it has been closed
|
||||
self.menu_view.addAction(dock_widget.toggleViewAction())
|
||||
|
||||
# Add the dock widget to the top dock widget area
|
||||
self.dock_manager.addDockWidget(area, dock_widget)
|
||||
|
||||
def setup_ui(self):
|
||||
self.setWindowTitle("MainWindow")
|
||||
self.setObjectName("MainWindow")
|
||||
self.resize(400, 300)
|
||||
self.central_widget = QtWidgets.QWidget(self)
|
||||
self.central_widget.setObjectName("central_widget")
|
||||
self.setCentralWidget(self.central_widget)
|
||||
|
||||
self.menu_bar = QtWidgets.QMenuBar(self)
|
||||
self.menu_bar.setGeometry(QtCore.QRect(0, 0, 400, 21))
|
||||
self.menu_bar.setObjectName("menuBar")
|
||||
|
||||
self.menu_view = QtWidgets.QMenu(self.menu_bar)
|
||||
self.menu_view.setObjectName("menu_view")
|
||||
self.menu_view.setTitle("View")
|
||||
self.setMenuBar(self.menu_bar)
|
||||
|
||||
self.status_bar = QtWidgets.QStatusBar(self)
|
||||
self.status_bar.setObjectName("statusBar")
|
||||
self.setStatusBar(self.status_bar)
|
||||
self.menu_bar.addAction(self.menu_view.menuAction())
|
||||
|
||||
|
||||
def main(app):
|
||||
main = MainWindow()
|
||||
main.show()
|
||||
state = main.dock_manager.saveState()
|
||||
print('This is what the saved state looks like in XML:')
|
||||
print(state)
|
||||
print()
|
||||
main.dock_manager.restoreState(state)
|
||||
return main
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(level='DEBUG')
|
||||
app = QtWidgets.QApplication([])
|
||||
window = main(app)
|
||||
window.show()
|
||||
print('shown')
|
||||
app.exec_()
|
||||
@@ -13,14 +13,6 @@ class CDockAreaTabBar : QScrollArea
|
||||
|
||||
protected:
|
||||
virtual void wheelEvent(QWheelEvent* Event);
|
||||
virtual void mousePressEvent(QMouseEvent* ev);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* ev);
|
||||
virtual void mouseMoveEvent(QMouseEvent* ev);
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
void startFloating(const QPoint& Offset);
|
||||
ads::IFloatingWidget* makeAreaFloating(const QPoint& Offset,
|
||||
ads::eDragState DragState);
|
||||
ads::eDragState dragState() const;
|
||||
|
||||
public:
|
||||
CDockAreaTabBar(ads::CDockAreaWidget* parent /TransferThis/);
|
||||
@@ -35,6 +27,7 @@ public:
|
||||
bool isTabOpen(int Index) const;
|
||||
virtual QSize minimumSizeHint() const;
|
||||
virtual QSize sizeHint() const;
|
||||
void elidedChanged(bool elided);
|
||||
|
||||
public slots:
|
||||
void setCurrentIndex(int Index);
|
||||
@@ -54,4 +47,4 @@ signals:
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
%End
|
||||
|
||||
@@ -11,6 +11,13 @@ class CDockAreaTitleBar : QFrame
|
||||
#include <DockAreaTitleBar.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent* ev);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* ev);
|
||||
virtual void mouseMoveEvent(QMouseEvent* ev);
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
virtual void contextMenuEvent(QContextMenuEvent *event);
|
||||
|
||||
public slots:
|
||||
void markTabsMenuOutdated();
|
||||
|
||||
@@ -20,7 +27,10 @@ public:
|
||||
virtual ~CDockAreaTitleBar();
|
||||
ads::CDockAreaTabBar* tabBar() const;
|
||||
QAbstractButton* button(ads::TitleBarButton which) const;
|
||||
void updateDockWidgetActionsButtons();
|
||||
virtual void setVisible(bool Visible);
|
||||
void insertWidget(int index, QWidget *widget /Transfer/ );
|
||||
int indexOf(QWidget *widget) const;
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
@@ -42,12 +42,16 @@ public:
|
||||
int currentIndex() const;
|
||||
int indexOfFirstOpenDockWidget() const;
|
||||
ads::CDockWidget* currentDockWidget() const;
|
||||
void setCurrentDockWidget(ads::CDockWidget* DockWidget /Transfer/);
|
||||
void setCurrentDockWidget(ads::CDockWidget* DockWidget);
|
||||
void saveState(QXmlStreamWriter& Stream) const;
|
||||
ads::CDockWidget::DockWidgetFeatures features() const;
|
||||
ads::CDockWidget::DockWidgetFeatures features(ads::eBitwiseOperator Mode = ads::BitwiseAnd) const;
|
||||
QAbstractButton* titleBarButton(ads::TitleBarButton which) const;
|
||||
virtual void setVisible(bool Visible);
|
||||
|
||||
void setAllowedAreas(DockWidgetAreas areas);
|
||||
DockWidgetAreas allowedAreas() const;
|
||||
CDockAreaTitleBar* titleBar() const;
|
||||
|
||||
public slots:
|
||||
void setCurrentIndex(int index);
|
||||
void closeArea();
|
||||
|
||||
26
sip/DockComponentsFactory.sip
Normal file
@@ -0,0 +1,26 @@
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockComponentsFactory
|
||||
{
|
||||
|
||||
%TypeHeaderCode
|
||||
#include <DockComponentsFactory.h>
|
||||
%End
|
||||
|
||||
public:
|
||||
virtual ~CDockComponentsFactory();
|
||||
virtual CDockWidgetTab* createDockWidgetTab(CDockWidget* DockWidget /Transfer/ ) const;
|
||||
virtual CDockAreaTabBar* createDockAreaTabBar(CDockAreaWidget* DockArea /Transfer/ ) const;
|
||||
virtual CDockAreaTitleBar* createDockAreaTitleBar(CDockAreaWidget* DockArea /Transfer/ ) const;
|
||||
static const CDockComponentsFactory* factory();
|
||||
static void setFactory(CDockComponentsFactory* Factory);
|
||||
static void resetDefaultFactory();
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
@@ -23,13 +23,12 @@ protected:
|
||||
QSplitter* rootSplitter() const;
|
||||
void createRootSplitter();
|
||||
void dropFloatingWidget(ads::CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos);
|
||||
void dropWidget(QWidget* widget, const QPoint& TargetPos);
|
||||
void dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget);
|
||||
void addDockArea(ads::CDockAreaWidget* DockAreaWidget /Transfer/, ads::DockWidgetArea area = ads::CenterDockWidgetArea);
|
||||
void removeDockArea(ads::CDockAreaWidget* area /Transfer/);
|
||||
void removeDockArea(ads::CDockAreaWidget* area /TransferBack/);
|
||||
void saveState(QXmlStreamWriter& Stream) const;
|
||||
bool restoreState(CDockingStateReader& Stream, bool Testing);
|
||||
ads::CDockAreaWidget* lastAddedDockAreaWidget(ads::DockWidgetArea area) const;
|
||||
bool hasTopLevelDockWidget() const;
|
||||
ads::CDockWidget* topLevelDockWidget() const;
|
||||
ads::CDockAreaWidget* topLevelDockArea() const;
|
||||
QList<ads::CDockWidget*> dockWidgets() const;
|
||||
@@ -88,6 +87,7 @@ public:
|
||||
* If all dock widgets in a dock area are closed, the dock area will be closed
|
||||
*/
|
||||
QList<ads::CDockAreaWidget*> openedDockAreas() const;
|
||||
bool hasTopLevelDockWidget() const;
|
||||
|
||||
/**
|
||||
* Returns the number of dock areas in this container
|
||||
|
||||
@@ -134,6 +134,8 @@ protected:
|
||||
ads::CDockOverlay* containerOverlay() const;
|
||||
ads::CDockOverlay* dockAreaOverlay() const;
|
||||
|
||||
virtual void showEvent(QShowEvent *event);
|
||||
|
||||
public:
|
||||
enum eViewMenuInsertionOrder
|
||||
{
|
||||
@@ -143,7 +145,7 @@ public:
|
||||
|
||||
enum eConfigFlag
|
||||
{
|
||||
ActiveTabHasCloseButton,
|
||||
ActiveTabHasCloseButton,
|
||||
DockAreaHasCloseButton,
|
||||
DockAreaCloseButtonClosesTab,
|
||||
OpaqueSplitterResize,
|
||||
@@ -152,13 +154,23 @@ public:
|
||||
TabCloseButtonIsToolButton,
|
||||
AllTabsHaveCloseButton,
|
||||
RetainTabSizeWhenCloseButtonHidden,
|
||||
OpaqueUndocking,
|
||||
DragPreviewIsDynamic,
|
||||
DragPreviewShowsContentPixmap,
|
||||
DragPreviewHasWindowFrame,
|
||||
DefaultConfig,
|
||||
DefaultNonOpaqueConfig,
|
||||
NonOpaqueWithWindowFrame,
|
||||
OpaqueUndocking,
|
||||
DragPreviewIsDynamic,
|
||||
DragPreviewShowsContentPixmap,
|
||||
DragPreviewHasWindowFrame,
|
||||
AlwaysShowTabs,
|
||||
DockAreaHasUndockButton,
|
||||
DockAreaHasTabsMenuButton,
|
||||
DockAreaHideDisabledButtons,
|
||||
DockAreaDynamicTabsMenuButtonVisibility,
|
||||
FloatingContainerHasWidgetTitle,
|
||||
FloatingContainerHasWidgetIcon,
|
||||
DefaultDockAreaButtons,
|
||||
DefaultBaseConfig,
|
||||
DefaultOpaqueConfig,
|
||||
DefaultNonOpaqueConfig,
|
||||
NonOpaqueWithWindowFrame,
|
||||
HideSingleCentralWidgetTitleBar,
|
||||
};
|
||||
typedef QFlags<ads::CDockManager::eConfigFlag> ConfigFlags;
|
||||
|
||||
@@ -167,6 +179,7 @@ public:
|
||||
static ads::CDockManager::ConfigFlags configFlags();
|
||||
static void setConfigFlags(const ads::CDockManager::ConfigFlags Flags);
|
||||
static void setConfigFlag(ads::CDockManager::eConfigFlag Flag, bool On = true);
|
||||
static bool testConfigFlag(eConfigFlag Flag);
|
||||
static ads::CIconProvider& iconProvider();
|
||||
ads::CDockAreaWidget* addDockWidget(ads::DockWidgetArea area, ads::CDockWidget* Dockwidget /Transfer/,
|
||||
ads::CDockAreaWidget* DockAreaWidget /Transfer/ = 0);
|
||||
@@ -180,7 +193,7 @@ public:
|
||||
QMap<QString, ads::CDockWidget*> dockWidgetsMap() const;
|
||||
const QList<ads::CDockContainerWidget*> dockContainers() const;
|
||||
const QList<ads::CFloatingDockContainer*> floatingWidgets() const;
|
||||
virtual unsigned int zOrderIndex() const;
|
||||
unsigned int zOrderIndex() const;
|
||||
QByteArray saveState(int version = 1) const;
|
||||
bool restoreState(const QByteArray &state, int version = 1);
|
||||
void addPerspective(const QString& UniquePrespectiveName);
|
||||
@@ -206,6 +219,7 @@ signals:
|
||||
void stateRestored();
|
||||
void openingPerspective(const QString& PerspectiveName);
|
||||
void perspectiveOpened(const QString& PerspectiveName);
|
||||
void floatingWidgetCreated(CFloatingDockContainer* FloatingWidget);
|
||||
void dockAreaCreated(ads::CDockAreaWidget* DockArea);
|
||||
void dockWidgetAboutToBeRemoved(ads::CDockWidget* DockWidget);
|
||||
void dockWidgetRemoved(ads::CDockWidget* DockWidget);
|
||||
|
||||
@@ -24,9 +24,11 @@ public:
|
||||
void setAllowedAreas(ads::DockWidgetAreas areas);
|
||||
ads::DockWidgetAreas allowedAreas() const;
|
||||
ads::DockWidgetArea dropAreaUnderCursor() const;
|
||||
ads::DockWidgetArea visibleDropAreaUnderCursor() const;
|
||||
ads::DockWidgetArea showOverlay(QWidget* target);
|
||||
void hideOverlay();
|
||||
void enableDropPreview(bool Enable);
|
||||
bool dropPreviewEnabled() const;
|
||||
QRect dropOverlayRect() const;
|
||||
virtual bool event(QEvent *e);
|
||||
|
||||
@@ -58,6 +60,8 @@ protected:
|
||||
void setIconOverlayColor(const QColor& Color);
|
||||
void setIconArrowColor(const QColor& Color);
|
||||
void setIconShadowColor(const QColor& Color);
|
||||
virtual void showEvent(QShowEvent* e);
|
||||
void setAreaWidgets(const QHash<ads::DockWidgetArea, QWidget*>& widgets);
|
||||
|
||||
public:
|
||||
CDockOverlayCross(ads::CDockOverlay* overlay /TransferThis/);
|
||||
|
||||
@@ -16,6 +16,9 @@ public:
|
||||
CDockSplitter(Qt::Orientation orientation, QWidget *parent /TransferThis/ = 0);
|
||||
virtual ~CDockSplitter();
|
||||
bool hasVisibleContent() const;
|
||||
QWidget* firstWidget() const;
|
||||
QWidget* lastWidget() const;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -12,15 +12,16 @@ class CDockWidget : QFrame
|
||||
%End
|
||||
|
||||
protected:
|
||||
void setDockManager(ads::CDockManager* DockManager /Transfer/);
|
||||
void setDockArea(ads::CDockAreaWidget* DockArea /Transfer/);
|
||||
void setToggleViewActionChecked(bool Checked);
|
||||
void saveState(QXmlStreamWriter& Stream) const;
|
||||
void flagAsUnassigned();
|
||||
static void emitTopLevelEventForWidget(ads::CDockWidget* TopLevelDockWidget, bool Floating);
|
||||
void emitTopLevelChanged(bool Floating);
|
||||
void setClosedState(bool Closed);
|
||||
void toggleViewInternal(bool Open);
|
||||
void setDockManager(ads::CDockManager* DockManager /Transfer/ );
|
||||
void setDockArea(ads::CDockAreaWidget* DockArea /Transfer/ );
|
||||
void setToggleViewActionChecked(bool Checked);
|
||||
void saveState(QXmlStreamWriter& Stream) const;
|
||||
void flagAsUnassigned();
|
||||
static void emitTopLevelEventForWidget(ads::CDockWidget* TopLevelDockWidget, bool Floating);
|
||||
void emitTopLevelChanged(bool Floating);
|
||||
void setClosedState(bool Closed);
|
||||
void toggleViewInternal(bool Open);
|
||||
bool closeDockWidgetInternal(bool ForceClose = false);
|
||||
|
||||
public:
|
||||
enum DockWidgetFeature
|
||||
@@ -29,7 +30,9 @@ public:
|
||||
DockWidgetMovable,
|
||||
DockWidgetFloatable,
|
||||
DockWidgetDeleteOnClose,
|
||||
AllDockWidgetFeatures,
|
||||
CustomCloseHandling,
|
||||
DefaultDockWidgetFeatures,
|
||||
AllDockWidgetFeatures,
|
||||
NoDockWidgetFeatures
|
||||
};
|
||||
typedef QFlags<ads::CDockWidget::DockWidgetFeature> DockWidgetFeatures;
|
||||
@@ -47,6 +50,12 @@ public:
|
||||
ForceScrollArea,
|
||||
ForceNoScrollArea
|
||||
};
|
||||
|
||||
enum eMinimumSizeHintMode
|
||||
{
|
||||
MinimumSizeHintFromDockWidget,
|
||||
MinimumSizeHintFromContent
|
||||
};
|
||||
|
||||
enum eToggleViewActionMode
|
||||
{
|
||||
@@ -73,30 +82,43 @@ public:
|
||||
bool isClosed() const;
|
||||
QAction* toggleViewAction() const;
|
||||
void setToggleViewActionMode(ads::CDockWidget::eToggleViewActionMode Mode);
|
||||
void setMinimumSizeHintMode(ads::CDockWidget::eMinimumSizeHintMode Mode);
|
||||
void setIcon(const QIcon& Icon);
|
||||
QIcon icon() const;
|
||||
QToolBar* toolBar() const;
|
||||
QToolBar* createDefaultToolBar();
|
||||
void setToolBar(QToolBar* ToolBar);
|
||||
void setToolBar(QToolBar* ToolBar /Transfer/ );
|
||||
void setToolBarStyle(Qt::ToolButtonStyle Style, ads::CDockWidget::eState State);
|
||||
Qt::ToolButtonStyle toolBarStyle(ads::CDockWidget::eState State) const;
|
||||
void setToolBarIconSize(const QSize& IconSize, ads::CDockWidget::eState State);
|
||||
QSize toolBarIconSize(eState State) const;
|
||||
void setTitleBarActions(QList<QAction*> actions);
|
||||
virtual QList<QAction*> titleBarActions() const;
|
||||
|
||||
void setTabToolTip(const QString &text);
|
||||
bool isFullScreen() const;
|
||||
bool isTabbed() const;
|
||||
bool isCurrentTab() const;
|
||||
|
||||
public:
|
||||
virtual bool event(QEvent *e);
|
||||
|
||||
public slots:
|
||||
void toggleView(bool Open = true);
|
||||
void setAsCurrentTab();
|
||||
void raise();
|
||||
void setFloating();
|
||||
void deleteDockWidget();
|
||||
void closeDockWidget();
|
||||
void showFullScreen();
|
||||
void showNormal();
|
||||
|
||||
signals:
|
||||
void viewToggled(bool Open);
|
||||
void closed();
|
||||
void titleChanged(const QString& Title);
|
||||
void topLevelChanged(bool topLevel);
|
||||
void closeRequested();
|
||||
void visibilityChanged(bool visible);
|
||||
void featuresChanged(ads::CDockWidget::DockWidgetFeatures features);
|
||||
};
|
||||
|
||||
@@ -23,13 +23,14 @@ public:
|
||||
virtual ~CDockWidgetTab();
|
||||
bool isActiveTab() const;
|
||||
void setActiveTab(bool active);
|
||||
ads::CDockWidget* dockWidget() const;
|
||||
void setDockAreaWidget(ads::CDockAreaWidget* DockArea /Transfer/);
|
||||
ads::CDockAreaWidget* dockAreaWidget() const;
|
||||
ads::CDockWidget* dockWidget() const;
|
||||
void setIcon(const QIcon& Icon);
|
||||
const QIcon& icon() const;
|
||||
QString text() const;
|
||||
void setText(const QString& title);
|
||||
bool isTitleElided() const;
|
||||
bool isClosable() const;
|
||||
virtual bool event(QEvent *e);
|
||||
|
||||
@@ -43,6 +44,7 @@ signals:
|
||||
void closeRequested();
|
||||
void closeOtherTabsRequested();
|
||||
void moved(const QPoint& GlobalPos);
|
||||
void elidedChanged(bool elided);
|
||||
}; // class DockWidgetTab
|
||||
};
|
||||
// namespace ads
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
virtual ~CElidingLabel();
|
||||
Qt::TextElideMode elideMode() const;
|
||||
void setElideMode(Qt::TextElideMode mode);
|
||||
|
||||
bool isElided() const;
|
||||
|
||||
public:
|
||||
virtual QSize minimumSizeHint() const;
|
||||
@@ -33,6 +33,7 @@ public:
|
||||
signals:
|
||||
void clicked();
|
||||
void doubleClicked();
|
||||
void elidedChanged(bool elided);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
// NOTE: there is a separate sip/linux/FloatingDockContainer.sip as the base
|
||||
// class for CFloatingDockContainer changes for Linux.
|
||||
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
%If (WS_X11)
|
||||
typedef QDockWidget tFloatingWidgetBase;
|
||||
%End
|
||||
%If (!WS_X11)
|
||||
typedef QWidget tFloatingWidgetBase;
|
||||
%End
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
@@ -20,7 +30,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class CFloatingDockContainer : QWidget, ads::IFloatingWidget
|
||||
class CFloatingDockContainer : tFloatingWidgetBase, ads::IFloatingWidget
|
||||
{
|
||||
|
||||
%TypeHeaderCode
|
||||
@@ -46,7 +56,6 @@ protected:
|
||||
virtual void closeEvent(QCloseEvent *event);
|
||||
virtual void hideEvent(QHideEvent *event);
|
||||
virtual void showEvent(QShowEvent *event);
|
||||
virtual bool eventFilter(QObject *watched, QEvent *event);
|
||||
|
||||
public:
|
||||
CFloatingDockContainer(ads::CDockManager* DockManager /TransferThis/);
|
||||
|
||||
@@ -12,6 +12,10 @@ class CFloatingDragPreview : QWidget, ads::IFloatingWidget
|
||||
#include <FloatingDragPreview.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
virtual void moveEvent(QMoveEvent *event);
|
||||
virtual void paintEvent(QPaintEvent *e);
|
||||
CFloatingDragPreview(QWidget* Content /TransferThis/, QWidget* parent /TransferThis/);
|
||||
|
||||
public:
|
||||
CFloatingDragPreview(ads::CDockWidget* Content /TransferThis/ );
|
||||
@@ -21,6 +25,7 @@ public:
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
public: // implements IFloatingWidget
|
||||
virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
|
||||
ads::eDragState DragState, QWidget* MouseEventHandler);
|
||||
|
||||
@@ -35,4 +40,4 @@ signals:
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
%End
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
%Module(name=PyQtAds.QtAds.ads, call_super_init=True, keyword_arguments="Optional", use_limited_api=True)
|
||||
%Import QtCore/QtCoremod.sip
|
||||
%DefaultSupertype sip.simplewrapper
|
||||
%Platforms {Linux macOS Windows}
|
||||
|
||||
%Include ads_globals.sip
|
||||
%Include DockWidget.sip
|
||||
%Include DockAreaTabBar.sip
|
||||
%Include DockAreaTitleBar.sip
|
||||
%Include DockAreaWidget.sip
|
||||
%Include DockComponentsFactory.sip
|
||||
%Include DockContainerWidget.sip
|
||||
%Include DockingStateReader.sip
|
||||
%Include DockManager.sip
|
||||
@@ -18,6 +18,6 @@
|
||||
%Include FloatingDockContainer.sip
|
||||
%Include FloatingDragPreview.sip
|
||||
%Include IconProvider.sip
|
||||
%If (Linux)
|
||||
%If (WS_X11)
|
||||
%Include linux/FloatingWidgetTitleBar.sip
|
||||
%End
|
||||
%End
|
||||
|
||||
@@ -8,6 +8,13 @@ namespace ads
|
||||
#include <ads_globals.h>
|
||||
%End
|
||||
|
||||
enum eStateFileVersion
|
||||
{
|
||||
InitialVerison,
|
||||
Version1,
|
||||
CurrentVersion
|
||||
};
|
||||
|
||||
enum DockWidgetArea
|
||||
{
|
||||
NoDockWidgetArea,
|
||||
@@ -49,6 +56,12 @@ namespace ads
|
||||
IconCount,
|
||||
};
|
||||
|
||||
enum eBitwiseOperator
|
||||
{
|
||||
BitwiseAnd,
|
||||
BitwiseOr
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
%End
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace ads
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <FloatingWidgetTitleBar.h>
|
||||
#include <linux/FloatingWidgetTitleBar.h>
|
||||
%End
|
||||
|
||||
class CFloatingWidgetTitleBar : QWidget
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QDebug>
|
||||
#include <QBoxLayout>
|
||||
#include <QApplication>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include "FloatingDockContainer.h"
|
||||
#include "DockAreaWidget.h"
|
||||
@@ -69,6 +70,16 @@ struct DockAreaTabBarPrivate
|
||||
* The function reassigns the stylesheet to update the tabs
|
||||
*/
|
||||
void updateTabs();
|
||||
|
||||
/**
|
||||
* Convenience function to access first tab
|
||||
*/
|
||||
CDockWidgetTab* firstTab() const {return _this->tab(0);}
|
||||
|
||||
/**
|
||||
* Convenience function to access last tab
|
||||
*/
|
||||
CDockWidgetTab* lastTab() const {return _this->tab(_this->count() - 1);}
|
||||
};
|
||||
// struct DockAreaTabBarPrivate
|
||||
|
||||
@@ -366,6 +377,8 @@ void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos)
|
||||
|
||||
int fromIndex = d->TabsLayout->indexOf(MovingTab);
|
||||
auto MousePos = mapFromGlobal(GlobalPos);
|
||||
MousePos.rx() = qMax(d->firstTab()->geometry().left(), MousePos.x());
|
||||
MousePos.rx() = qMin(d->lastTab()->geometry().right(), MousePos.x());
|
||||
int toIndex = -1;
|
||||
// Find tab under mouse
|
||||
for (int i = 0; i < count(); ++i)
|
||||
@@ -381,38 +394,23 @@ void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos)
|
||||
if (toIndex == fromIndex)
|
||||
{
|
||||
toIndex = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (toIndex < 0)
|
||||
{
|
||||
toIndex = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Now check if the mouse is behind the last tab
|
||||
if (toIndex < 0)
|
||||
{
|
||||
if (MousePos.x() > tab(count() - 1)->geometry().right())
|
||||
{
|
||||
ADS_PRINT("after all tabs");
|
||||
toIndex = count() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
toIndex = fromIndex;
|
||||
}
|
||||
}
|
||||
|
||||
d->TabsLayout->removeWidget(MovingTab);
|
||||
d->TabsLayout->insertWidget(toIndex, MovingTab);
|
||||
if (toIndex >= 0)
|
||||
if (toIndex > -1)
|
||||
{
|
||||
d->TabsLayout->removeWidget(MovingTab);
|
||||
d->TabsLayout->insertWidget(toIndex, MovingTab);
|
||||
ADS_PRINT("tabMoved from " << fromIndex << " to " << toIndex);
|
||||
emit tabMoved(fromIndex, toIndex);
|
||||
setCurrentIndex(toIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure that the moved tab is reset to its start position
|
||||
d->TabsLayout->update();
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
@@ -247,6 +247,7 @@ struct DockAreaWidgetPrivate
|
||||
CDockManager* DockManager = nullptr;
|
||||
bool UpdateTitleBarButtons = false;
|
||||
DockWidgetAreas AllowedAreas = AllDockAreas;
|
||||
QSize MinSizeHint;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
@@ -303,6 +304,20 @@ struct DockAreaWidgetPrivate
|
||||
* Udpates the enable state of the close and detach button
|
||||
*/
|
||||
void updateTitleBarButtonStates();
|
||||
|
||||
/**
|
||||
* Scans all contained dock widgets for the max. minimum size hint
|
||||
*/
|
||||
void updateMinimumSizeHint()
|
||||
{
|
||||
MinSizeHint = QSize();
|
||||
for (int i = 0; i < ContentsLayout->count(); ++i)
|
||||
{
|
||||
auto Widget = ContentsLayout->widget(i);
|
||||
MinSizeHint.setHeight(qMax(MinSizeHint.height(), Widget->minimumSizeHint().height()));
|
||||
MinSizeHint.setWidth(qMax(MinSizeHint.width(), Widget->minimumSizeHint().width()));
|
||||
}
|
||||
}
|
||||
};
|
||||
// struct DockAreaWidgetPrivate
|
||||
|
||||
@@ -407,6 +422,8 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
|
||||
d->tabBar()->blockSignals(false);
|
||||
TabWidget->setVisible(!DockWidget->isClosed());
|
||||
DockWidget->setProperty(INDEX_PROPERTY, index);
|
||||
d->MinSizeHint.setHeight(qMax(d->MinSizeHint.height(), DockWidget->minimumSizeHint().height()));
|
||||
d->MinSizeHint.setWidth(qMax(d->MinSizeHint.width(), DockWidget->minimumSizeHint().width()));
|
||||
if (Activate)
|
||||
{
|
||||
setCurrentIndex(index);
|
||||
@@ -447,6 +464,7 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
|
||||
|
||||
d->updateTitleBarButtonStates();
|
||||
updateTitleBarVisibility();
|
||||
d->updateMinimumSizeHint();
|
||||
auto TopLevelDockWidget = DockContainer->topLevelDockWidget();
|
||||
if (TopLevelDockWidget)
|
||||
{
|
||||
@@ -470,7 +488,7 @@ void CDockAreaWidget::hideAreaWithNoVisibleContent()
|
||||
|
||||
//Hide empty floating widget
|
||||
CDockContainerWidget* Container = this->dockContainer();
|
||||
if (!Container->isFloating())
|
||||
if (!Container->isFloating() && !CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -480,10 +498,13 @@ void CDockAreaWidget::hideAreaWithNoVisibleContent()
|
||||
auto FloatingWidget = Container->floatingWidget();
|
||||
if (TopLevelWidget)
|
||||
{
|
||||
FloatingWidget->updateWindowTitle();
|
||||
if (FloatingWidget)
|
||||
{
|
||||
FloatingWidget->updateWindowTitle();
|
||||
}
|
||||
CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true);
|
||||
}
|
||||
else if (Container->openedDockAreas().isEmpty())
|
||||
else if (Container->openedDockAreas().isEmpty() && FloatingWidget)
|
||||
{
|
||||
FloatingWidget->hide();
|
||||
}
|
||||
@@ -497,7 +518,6 @@ void CDockAreaWidget::onTabCloseRequested(int Index)
|
||||
auto* DockWidget = dockWidget(Index);
|
||||
if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
|
||||
{
|
||||
//DockWidget->deleteDockWidget();
|
||||
DockWidget->closeDockWidgetInternal();
|
||||
}
|
||||
else
|
||||
@@ -712,7 +732,9 @@ void CDockAreaWidget::updateTitleBarVisibility()
|
||||
|
||||
if (d->TitleBar)
|
||||
{
|
||||
d->TitleBar->setVisible(!Container->isFloating() || !Container->hasTopLevelDockWidget());
|
||||
bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating()
|
||||
|| CDockManager::configFlags().testFlag(CDockManager::HideSingleCentralWidgetTitleBar));
|
||||
d->TitleBar->setVisible(!Hidden);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -864,6 +886,13 @@ CDockAreaTitleBar* CDockAreaWidget::titleBar() const
|
||||
{
|
||||
return d->TitleBar;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QSize CDockAreaWidget::minimumSizeHint() const
|
||||
{
|
||||
return d->MinSizeHint.isValid() ? d->MinSizeHint : Super::minimumSizeHint();
|
||||
}
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -164,6 +164,13 @@ public:
|
||||
*/
|
||||
CDockContainerWidget* dockContainer() const;
|
||||
|
||||
/**
|
||||
* Returns the largest minimumSizeHint() of the dock widgets in this
|
||||
* area.
|
||||
* The minimum size hint is updated if a dock widget is removed or added.
|
||||
*/
|
||||
virtual QSize minimumSizeHint() const override;
|
||||
|
||||
/**
|
||||
* Returns the rectangle of the title area
|
||||
*/
|
||||
|
||||
@@ -679,6 +679,23 @@ void DockContainerWidgetPrivate::moveToContainer(QWidget* Widget, DockWidgetArea
|
||||
}
|
||||
else
|
||||
{
|
||||
// We check, if we insert the dropped widget into the same place that
|
||||
// it already has and do nothing, if it is the same place. It would
|
||||
// also work without this check, but it looks nicer with the check
|
||||
// because there will be no layout updates
|
||||
auto Splitter = internal::findParent<CDockSplitter*>(DroppedDockArea);
|
||||
auto InsertParam = internal::dockAreaInsertParameters(area);
|
||||
if (Splitter == RootSplitter && InsertParam.orientation() == Splitter->orientation())
|
||||
{
|
||||
if (InsertParam.append() && Splitter->lastWidget() == DroppedDockArea)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (!InsertParam.append() && Splitter->firstWidget() == DroppedDockArea)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
DroppedDockArea->dockContainer()->removeDockArea(DroppedDockArea);
|
||||
NewDockArea = DroppedDockArea;
|
||||
}
|
||||
@@ -1436,41 +1453,16 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockContainerWidget::dropWidget(QWidget* Widget, const QPoint& TargetPos)
|
||||
void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget)
|
||||
{
|
||||
ADS_PRINT("CDockContainerWidget::dropFloatingWidget");
|
||||
CDockWidget* SingleDockWidget = topLevelDockWidget();
|
||||
CDockAreaWidget* DockArea = dockAreaAt(TargetPos);
|
||||
auto dropArea = InvalidDockWidgetArea;
|
||||
auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
|
||||
|
||||
if (DockArea)
|
||||
if (TargetAreaWidget)
|
||||
{
|
||||
auto dropOverlay = d->DockManager->dockAreaOverlay();
|
||||
dropOverlay->setAllowedAreas(DockArea->allowedAreas());
|
||||
dropArea = dropOverlay->showOverlay(DockArea);
|
||||
if (ContainerDropArea != InvalidDockWidgetArea &&
|
||||
ContainerDropArea != dropArea)
|
||||
{
|
||||
dropArea = InvalidDockWidgetArea;
|
||||
}
|
||||
|
||||
if (dropArea != InvalidDockWidgetArea)
|
||||
{
|
||||
ADS_PRINT("Dock Area Drop Content: " << dropArea);
|
||||
d->moveToNewSection(Widget, DockArea, dropArea);
|
||||
}
|
||||
d->moveToNewSection(Widget, TargetAreaWidget, DropArea);
|
||||
}
|
||||
|
||||
// mouse is over container
|
||||
if (InvalidDockWidgetArea == dropArea)
|
||||
else
|
||||
{
|
||||
dropArea = ContainerDropArea;
|
||||
ADS_PRINT("Container Drop Content: " << dropArea);
|
||||
if (dropArea != InvalidDockWidgetArea)
|
||||
{
|
||||
d->moveToContainer(Widget, dropArea);
|
||||
}
|
||||
d->moveToContainer(Widget, DropArea);
|
||||
}
|
||||
|
||||
// If there was a top level widget before the drop, then it is not top
|
||||
@@ -1622,11 +1614,6 @@ CDockAreaWidget* CDockContainerWidget::lastAddedDockAreaWidget(DockWidgetArea ar
|
||||
//============================================================================
|
||||
bool CDockContainerWidget::hasTopLevelDockWidget() const
|
||||
{
|
||||
if (!isFloating())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto DockAreas = openedDockAreas();
|
||||
if (DockAreas.count() != 1)
|
||||
{
|
||||
@@ -1660,11 +1647,6 @@ CDockWidget* CDockContainerWidget::topLevelDockWidget() const
|
||||
//============================================================================
|
||||
CDockAreaWidget* CDockContainerWidget::topLevelDockArea() const
|
||||
{
|
||||
if (!isFloating())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto DockAreas = openedDockAreas();
|
||||
if (DockAreas.count() != 1)
|
||||
{
|
||||
|
||||
@@ -55,8 +55,8 @@ class CDockingStateReader;
|
||||
* Container that manages a number of dock areas with single dock widgets
|
||||
* or tabyfied dock widgets in each area.
|
||||
* Each window that support docking has a DockContainerWidget. That means
|
||||
* the main application window and all floating windows are ore contain
|
||||
* an DockContainerWidget.
|
||||
* the main application window and all floating windows contain a
|
||||
* DockContainerWidget instance.
|
||||
*/
|
||||
class ADS_EXPORT CDockContainerWidget : public QFrame
|
||||
{
|
||||
@@ -96,9 +96,13 @@ protected:
|
||||
void dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos);
|
||||
|
||||
/**
|
||||
* Drop a dock area or a dock widget given in widget parameter
|
||||
* Drop a dock area or a dock widget given in widget parameter.
|
||||
* If the TargetAreaWidget is a nullptr, then the DropArea indicates
|
||||
* the drop area for the container. If the given TargetAreaWidget is not
|
||||
* a nullptr, then the DropArea indicates the drop area in the given
|
||||
* TargetAreaWidget
|
||||
*/
|
||||
void dropWidget(QWidget* Widget, const QPoint& TargetPos);
|
||||
void dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget);
|
||||
|
||||
/**
|
||||
* Adds the given dock area to this container widget
|
||||
|
||||
@@ -55,6 +55,20 @@
|
||||
#include "DockingStateReader.h"
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the resources specified by the .qrc file with the specified base
|
||||
* name. Normally, when resources are built as part of the application, the
|
||||
* resources are loaded automatically at startup. The Q_INIT_RESOURCE() macro
|
||||
* is necessary on some platforms for resources stored in a static library.
|
||||
* Because GCC caues a linker error if we put Q_INIT_RESOURCE into the
|
||||
* loadStyleSheet() function, we place it into a function outside of the ads
|
||||
* namespace
|
||||
*/
|
||||
static void initResource()
|
||||
{
|
||||
Q_INIT_RESOURCE(ads);
|
||||
}
|
||||
|
||||
|
||||
namespace ads
|
||||
{
|
||||
@@ -148,6 +162,7 @@ DockManagerPrivate::DockManagerPrivate(CDockManager* _public) :
|
||||
//============================================================================
|
||||
void DockManagerPrivate::loadStylesheet()
|
||||
{
|
||||
initResource();
|
||||
QString Result;
|
||||
#ifdef Q_OS_LINUX
|
||||
QFile StyleSheetFile(":ads/stylesheets/default_linux.css");
|
||||
@@ -778,6 +793,10 @@ QAction* CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction,
|
||||
d->addActionToMenu(GroupMenu->menuAction(), d->ViewMenu, AlphabeticallySorted);
|
||||
d->ViewMenuGroups.insert(Group, GroupMenu);
|
||||
}
|
||||
else if (GroupMenu->icon().isNull() && !GroupIcon.isNull())
|
||||
{
|
||||
GroupMenu->setIcon(GroupIcon);
|
||||
}
|
||||
|
||||
d->addActionToMenu(ToggleViewAction, GroupMenu, AlphabeticallySorted);
|
||||
return GroupMenu->menuAction();
|
||||
|
||||
@@ -30,18 +30,11 @@
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include <ads_globals.h>
|
||||
#include <DockContainerWidget.h>
|
||||
#include <DockWidget.h>
|
||||
#include <FloatingDockContainer.h>
|
||||
#include <qbytearray.h>
|
||||
#include <qflags.h>
|
||||
#include <qlist.h>
|
||||
#include <qmap.h>
|
||||
#include <qobjectdefs.h>
|
||||
#include <qstring.h>
|
||||
#include <qstringlist.h>
|
||||
#include <QtGui/qicon.h>
|
||||
#include "ads_globals.h"
|
||||
#include "DockContainerWidget.h"
|
||||
#include "DockWidget.h"
|
||||
#include "FloatingDockContainer.h"
|
||||
|
||||
|
||||
class QSettings;
|
||||
class QMenu;
|
||||
@@ -142,6 +135,7 @@ public:
|
||||
/**
|
||||
* These global configuration flags configure some global dock manager
|
||||
* settings.
|
||||
* Set the dock manager flags, before you create the dock manager instance.
|
||||
*/
|
||||
enum eConfigFlag
|
||||
{
|
||||
@@ -161,10 +155,12 @@ public:
|
||||
AlwaysShowTabs = 0x2000,///< 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.
|
||||
DockAreaHasUndockButton = 0x4000, //!< If the flag is set each dock area has an undock button
|
||||
DockAreaHasTabsMenuButton = 0x8000, //!< If the flag is set each dock area has a tabs menu button
|
||||
DockAreaHideDisabledButtons = 0x10000, //!< If the flag is set disabled dock area buttons will not appear on the tollbar at all (enabling them will bring them back)
|
||||
DockAreaDynamicTabsMenuButtonVisibility = 0x20000, //!< If the flag is set dock area will disable a tabs menu button when there is only one tab in the area
|
||||
FloatingContainerHasWidgetTitle = 0x40000,
|
||||
FloatingContainerHasWidgetIcon = 0x80000,
|
||||
DockAreaHideDisabledButtons = 0x10000, //!< If the flag is set disabled dock area buttons will not appear on the toolbar at all (enabling them will bring them back)
|
||||
DockAreaDynamicTabsMenuButtonVisibility = 0x20000, //!< If the flag is set, the tabs menu button will be shown only when it is required - that means, if the tabs are elided. If the tabs are not elided, it is hidden
|
||||
FloatingContainerHasWidgetTitle = 0x40000, //!< If set, the Floating Widget window title reflects the title of the current dock widget otherwise it displays application name as window title
|
||||
FloatingContainerHasWidgetIcon = 0x80000, //!< If set, the Floating Widget icon reflects the icon of the current dock widget otherwise it displays application icon
|
||||
HideSingleCentralWidgetTitleBar = 0x100000, //!< 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 widgets and enables the creation of some kind of "central" widget
|
||||
|
||||
|
||||
DefaultDockAreaButtons = DockAreaHasCloseButton
|
||||
@@ -195,12 +191,12 @@ public:
|
||||
* Before you create any dock widgets, you should properly setup the
|
||||
* configuration flags via setConfigFlags().
|
||||
*/
|
||||
CDockManager(QWidget* parent = 0);
|
||||
CDockManager(QWidget* parent = nullptr);
|
||||
|
||||
/**
|
||||
* Virtual Destructor
|
||||
*/
|
||||
virtual ~CDockManager();
|
||||
virtual ~CDockManager() override;
|
||||
|
||||
/**
|
||||
* This function returns the global configuration flags
|
||||
@@ -209,12 +205,14 @@ public:
|
||||
|
||||
/**
|
||||
* Sets the global configuration flags for the whole docking system.
|
||||
* Call this function before you create your first dock widget.
|
||||
* Call this function before you create the dock manager and before
|
||||
* your create the first dock widget.
|
||||
*/
|
||||
static void setConfigFlags(const ConfigFlags Flags);
|
||||
|
||||
/**
|
||||
* Set a certain config flag
|
||||
* Set a certain config flag.
|
||||
* \see setConfigFlags()
|
||||
*/
|
||||
static void setConfigFlag(eConfigFlag Flag, bool On = true);
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <QWindow>
|
||||
|
||||
#include "DockAreaWidget.h"
|
||||
#include "DockAreaTitleBar.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -387,6 +388,7 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
|
||||
}
|
||||
|
||||
if (DockArea->allowedAreas().testFlag(CenterDockWidgetArea)
|
||||
&& !DockArea->titleBar()->isHidden()
|
||||
&& DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(QCursor::pos())))
|
||||
{
|
||||
return CenterDockWidgetArea;
|
||||
@@ -396,6 +398,20 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
DockWidgetArea CDockOverlay::visibleDropAreaUnderCursor() const
|
||||
{
|
||||
if (isHidden() || !d->DropPreviewEnabled)
|
||||
{
|
||||
return InvalidDockWidgetArea;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dropAreaUnderCursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
DockWidgetArea CDockOverlay::showOverlay(QWidget* target)
|
||||
{
|
||||
|
||||
@@ -81,6 +81,13 @@ public:
|
||||
*/
|
||||
DockWidgetArea dropAreaUnderCursor() const;
|
||||
|
||||
/**
|
||||
* This function returns the same like dropAreaUnderCursor() if this
|
||||
* overlay is not hidden and if drop preview is enabled and returns
|
||||
* InvalidDockWidgetArea if it is hidden or drop preview is disabled.
|
||||
*/
|
||||
DockWidgetArea visibleDropAreaUnderCursor() const;
|
||||
|
||||
/**
|
||||
* Show the drop overly for the given target widget
|
||||
*/
|
||||
|
||||
@@ -88,6 +88,20 @@ bool CDockSplitter::hasVisibleContent() const
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QWidget* CDockSplitter::firstWidget() const
|
||||
{
|
||||
return (count() > 0) ? widget(0) : nullptr;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QWidget* CDockSplitter::lastWidget() const
|
||||
{
|
||||
return (count() > 0) ? widget(count() - 1) : nullptr;
|
||||
}
|
||||
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -61,6 +61,16 @@ public:
|
||||
* Returns true, if any of the internal widgets is visible
|
||||
*/
|
||||
bool hasVisibleContent() const;
|
||||
|
||||
/**
|
||||
* Returns first widget or nullptr if splitter is empty
|
||||
*/
|
||||
QWidget* firstWidget() const;
|
||||
|
||||
/**
|
||||
* Returns last widget of nullptr is splitter is empty
|
||||
*/
|
||||
QWidget* lastWidget() const;
|
||||
}; // class CDockSplitter
|
||||
|
||||
} // namespace ads
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <QDebug>
|
||||
#include <QToolBar>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QWindow>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
@@ -82,6 +83,7 @@ struct DockWidgetPrivate
|
||||
QSize ToolBarIconSizeFloating = QSize(24, 24);
|
||||
bool IsFloatingTopLevel = false;
|
||||
QList<QAction*> TitleBarActions;
|
||||
CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
@@ -173,6 +175,12 @@ void DockWidgetPrivate::updateParentDockArea()
|
||||
return;
|
||||
}
|
||||
|
||||
// we don't need to change the current tab if the
|
||||
// current dock widget is not the one being closed
|
||||
if (DockArea->currentDockWidget() != _this){
|
||||
return;
|
||||
}
|
||||
|
||||
auto NextDockWidget = DockArea->nextOpenDockWidget(_this);
|
||||
if (NextDockWidget)
|
||||
{
|
||||
@@ -250,7 +258,12 @@ void CDockWidget::setToggleViewActionChecked(bool Checked)
|
||||
//============================================================================
|
||||
void CDockWidget::setWidget(QWidget* widget, eInsertMode InsertMode)
|
||||
{
|
||||
QScrollArea* ScrollAreaWidget = qobject_cast<QScrollArea*>(widget);
|
||||
if (d->Widget)
|
||||
{
|
||||
takeWidget();
|
||||
}
|
||||
|
||||
auto ScrollAreaWidget = qobject_cast<QAbstractScrollArea*>(widget);
|
||||
if (ScrollAreaWidget || ForceNoScrollArea == InsertMode)
|
||||
{
|
||||
d->Layout->addWidget(widget);
|
||||
@@ -273,10 +286,26 @@ void CDockWidget::setWidget(QWidget* widget, eInsertMode InsertMode)
|
||||
//============================================================================
|
||||
QWidget* CDockWidget::takeWidget()
|
||||
{
|
||||
d->ScrollArea->takeWidget();
|
||||
d->Layout->removeWidget(d->Widget);
|
||||
d->Widget->setParent(nullptr);
|
||||
return d->Widget;
|
||||
QWidget* w = nullptr;
|
||||
if (d->ScrollArea)
|
||||
{
|
||||
d->Layout->removeWidget(d->ScrollArea);
|
||||
w = d->ScrollArea->takeWidget();
|
||||
delete d->ScrollArea;
|
||||
d->ScrollArea = nullptr;
|
||||
}
|
||||
else if (d->Widget)
|
||||
{
|
||||
d->Layout->removeWidget(d->Widget);
|
||||
w = d->Widget;
|
||||
d->Widget = nullptr;
|
||||
}
|
||||
|
||||
if (w)
|
||||
{
|
||||
w->setParent(nullptr);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
@@ -418,6 +447,13 @@ void CDockWidget::setToggleViewActionMode(eToggleViewActionMode Mode)
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setMinimumSizeHintMode(eMinimumSizeHintMode Mode)
|
||||
{
|
||||
d->MinimumSizeHintMode = Mode;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::toggleView(bool Open)
|
||||
{
|
||||
@@ -747,7 +783,14 @@ void CDockWidget::setClosedState(bool Closed)
|
||||
//============================================================================
|
||||
QSize CDockWidget::minimumSizeHint() const
|
||||
{
|
||||
return QSize(60, 40);
|
||||
if (d->MinimumSizeHintMode == CDockWidget::MinimumSizeHintFromDockWidget || !d->Widget)
|
||||
{
|
||||
return QSize(60, 40);
|
||||
}
|
||||
else
|
||||
{
|
||||
return d->Widget->minimumSizeHint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -809,6 +852,7 @@ bool CDockWidget::closeDockWidgetInternal(bool ForceClose)
|
||||
}
|
||||
}
|
||||
deleteDockWidget();
|
||||
emit closed();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -833,6 +877,91 @@ QList<QAction*> CDockWidget::titleBarActions() const
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::showFullScreen()
|
||||
{
|
||||
if (isFloating())
|
||||
{
|
||||
dockContainer()->floatingWidget()->showFullScreen();
|
||||
}
|
||||
else
|
||||
{
|
||||
Super::showFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::showNormal()
|
||||
{
|
||||
if (isFloating())
|
||||
{
|
||||
dockContainer()->floatingWidget()->showNormal();
|
||||
}
|
||||
else
|
||||
{
|
||||
Super::showNormal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockWidget::isFullScreen() const
|
||||
{
|
||||
if (isFloating())
|
||||
{
|
||||
return dockContainer()->floatingWidget()->isFullScreen();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Super::isFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setAsCurrentTab()
|
||||
{
|
||||
if (d->DockArea && !isClosed())
|
||||
{
|
||||
d->DockArea->setCurrentDockWidget(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockWidget::isTabbed() const
|
||||
{
|
||||
return d->DockArea && (d->DockArea->openDockWidgetsCount() > 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockWidget::isCurrentTab() const
|
||||
{
|
||||
return d->DockArea && (d->DockArea->currentDockWidget() == this);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::raise()
|
||||
{
|
||||
if (isClosed())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
setAsCurrentTab();
|
||||
if (isInFloatingContainer())
|
||||
{
|
||||
auto FloatingWindow = window();
|
||||
FloatingWindow->raise();
|
||||
FloatingWindow->activateWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -147,8 +147,8 @@ public:
|
||||
|
||||
enum DockWidgetFeature
|
||||
{
|
||||
DockWidgetClosable = 0x01,
|
||||
DockWidgetMovable = 0x02,///< this feature is not properly implemented yet and is ignored
|
||||
DockWidgetClosable = 0x01,///< dock widget has a close button
|
||||
DockWidgetMovable = 0x02,///< dock widget is movable and can be moved to a new position in the current dock container
|
||||
DockWidgetFloatable = 0x04,
|
||||
DockWidgetDeleteOnClose = 0x08, ///< deletes the dock widget when it is closed
|
||||
CustomCloseHandling = 0x10,
|
||||
@@ -189,6 +189,23 @@ public:
|
||||
ForceNoScrollArea
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The mode of the minimumSizeHint() that is returned by the DockWidget
|
||||
* minimumSizeHint() function.
|
||||
* To ensure, that a dock widget does not block resizing, the dock widget
|
||||
* reimplements minimumSizeHint() function to return a very small minimum
|
||||
* size hint. If you would like to adhere the minimumSizeHint() from the
|
||||
* content widget, the set the minimumSizeHintMode() to
|
||||
* MinimumSizeHintFromContent.
|
||||
*/
|
||||
enum eMinimumSizeHintMode
|
||||
{
|
||||
MinimumSizeHintFromDockWidget,
|
||||
MinimumSizeHintFromContent
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This mode configures the behavior of the toggle view action.
|
||||
* If the mode if ActionModeToggle, then the toggle view action is
|
||||
@@ -225,7 +242,8 @@ public:
|
||||
virtual ~CDockWidget();
|
||||
|
||||
/**
|
||||
* We return a fixed minimum size hint for all dock widgets
|
||||
* We return a fixed minimum size hint or the size hint of the content
|
||||
* widget if minimum size hint mode is MinimumSizeHintFromContent
|
||||
*/
|
||||
virtual QSize minimumSizeHint() const override;
|
||||
|
||||
@@ -334,6 +352,13 @@ public:
|
||||
*/
|
||||
void setToggleViewActionMode(eToggleViewActionMode Mode);
|
||||
|
||||
/**
|
||||
* Configures the minimum size hint that is returned by the
|
||||
* minimumSizeHint() function.
|
||||
* \see eMinimumSizeHintMode for a detailed description
|
||||
*/
|
||||
void setMinimumSizeHintMode(eMinimumSizeHintMode Mode);
|
||||
|
||||
/**
|
||||
* Sets the dock widget icon that is shown in tabs and in toggle view
|
||||
* actions
|
||||
@@ -346,13 +371,10 @@ public:
|
||||
QIcon icon() const;
|
||||
|
||||
/**
|
||||
* If the WithToolBar layout flag is enabled, then this function returns
|
||||
* the dock widget toolbar. If the flag is disabled, the function returns
|
||||
* a nullptr.
|
||||
* This function returns the dock widget top tool bar.
|
||||
* If no toolbar is assigned, this function returns nullptr. To get a vaild
|
||||
* toolbar you either need to create a default empty toolbar via
|
||||
* createDefaultToolBar() function or you need to assign you custom
|
||||
* createDefaultToolBar() function or you need to assign your custom
|
||||
* toolbar via setToolBar().
|
||||
*/
|
||||
QToolBar* toolBar() const;
|
||||
@@ -427,6 +449,26 @@ public:
|
||||
void setTabToolTip(const QString &text);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns true if the dock widget is floating and if the floating dock
|
||||
* container is full screen
|
||||
*/
|
||||
bool isFullScreen() const;
|
||||
|
||||
/**
|
||||
* Returns true if this dock widget is in a dock area, that contains at
|
||||
* least 2 opened dock widgets
|
||||
*/
|
||||
bool isTabbed() const;
|
||||
|
||||
/**
|
||||
* Returns true if this dock widget is the current one in the dock
|
||||
* area widget that contains it.
|
||||
* If the dock widget is the only opened dock widget in a dock area,
|
||||
* the true is returned
|
||||
*/
|
||||
bool isCurrentTab() const;
|
||||
|
||||
public: // reimplements QFrame -----------------------------------------------
|
||||
/**
|
||||
* Emits titleChanged signal if title change event occurs
|
||||
@@ -440,6 +482,23 @@ public slots:
|
||||
*/
|
||||
void toggleView(bool Open = true);
|
||||
|
||||
/**
|
||||
* Makes this dock widget the current tab in its dock area.
|
||||
* The function only has an effect, if the dock widget is open. A call
|
||||
* to this function will not toggle the view, so if it is closed,
|
||||
* nothing will happen
|
||||
*/
|
||||
void setAsCurrentTab();
|
||||
|
||||
/**
|
||||
* Brings the dock widget to the front
|
||||
* This means:
|
||||
* - If the dock widget is tabbed with other dock widgets but its tab is not current, it's made current.
|
||||
* - If the dock widget is floating, QWindow::raise() is called.
|
||||
* This only applies if the dock widget is already open. If closed, does nothing.
|
||||
*/
|
||||
void raise();
|
||||
|
||||
/**
|
||||
* This function will make a docked widget floating
|
||||
*/
|
||||
@@ -456,6 +515,26 @@ public slots:
|
||||
*/
|
||||
void closeDockWidget();
|
||||
|
||||
/**
|
||||
* Shows the widget in full-screen mode.
|
||||
* Normally this function only affects windows. To make the interface
|
||||
* compatible to QDockWidget, this function also maximizes a floating
|
||||
* dock widget.
|
||||
*
|
||||
* \note Full-screen mode works fine under Windows, but has certain
|
||||
* problems (doe not work) under X (Linux). These problems are due to
|
||||
* limitations of the ICCCM protocol that specifies the communication
|
||||
* between X11 clients and the window manager. ICCCM simply does not
|
||||
* understand the concept of non-decorated full-screen windows.
|
||||
*/
|
||||
void showFullScreen();
|
||||
|
||||
/**
|
||||
* This function complements showFullScreen() to restore the widget
|
||||
* after it has been in full screen mode.
|
||||
*/
|
||||
void showNormal();
|
||||
|
||||
|
||||
signals:
|
||||
/**
|
||||
|
||||
@@ -68,6 +68,7 @@ struct DockWidgetTabPrivate
|
||||
QLabel* IconLabel = nullptr;
|
||||
tTabLabel* TitleLabel;
|
||||
QPoint GlobalDragStartMousePosition;
|
||||
QPoint DragStartMousePosition;
|
||||
bool IsActiveTab = false;
|
||||
CDockAreaWidget* DockArea = nullptr;
|
||||
eDragState DragState = DraggingInactive;
|
||||
@@ -150,6 +151,15 @@ struct DockWidgetTabPrivate
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the drag start position in global and local coordinates
|
||||
*/
|
||||
void saveDragStartMousePosition(const QPoint& GlobalPos)
|
||||
{
|
||||
GlobalDragStartMousePosition = GlobalPos;
|
||||
DragStartMousePosition = _this->mapFromGlobal(GlobalPos);
|
||||
}
|
||||
};
|
||||
// struct DockWidgetTabPrivate
|
||||
|
||||
@@ -205,6 +215,8 @@ void DockWidgetTabPrivate::moveTab(QMouseEvent* ev)
|
||||
QPoint Distance = ev->globalPos() - GlobalDragStartMousePosition;
|
||||
Distance.setY(0);
|
||||
auto TargetPos = Distance + TabDragStartPosition;
|
||||
TargetPos.rx() = qMax(TargetPos.x(), 0);
|
||||
TargetPos.rx() = qMin(_this->parentWidget()->rect().right() - _this->width() + 1, TargetPos.rx());
|
||||
_this->move(TargetPos);
|
||||
_this->raise();
|
||||
}
|
||||
@@ -229,8 +241,6 @@ bool DockWidgetTabPrivate::startFloating(eDragState DraggingState)
|
||||
|
||||
ADS_PRINT("startFloating");
|
||||
DragState = DraggingState;
|
||||
auto DragStartMousePosition = _this->mapFromGlobal(GlobalDragStartMousePosition);
|
||||
QSize Size = DockArea->size();
|
||||
IFloatingWidget* FloatingWidget = nullptr;
|
||||
bool OpaqueUndocking = CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking) ||
|
||||
(DraggingFloatingWidget != DraggingState);
|
||||
@@ -238,13 +248,16 @@ bool DockWidgetTabPrivate::startFloating(eDragState DraggingState)
|
||||
// If section widget has multiple tabs, we take only one tab
|
||||
// If it has only one single tab, we can move the complete
|
||||
// dock area into floating widget
|
||||
QSize Size;
|
||||
if (DockArea->dockWidgetsCount() > 1)
|
||||
{
|
||||
FloatingWidget = createFloatingWidget(DockWidget, OpaqueUndocking);
|
||||
Size = DockWidget->size();
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatingWidget = createFloatingWidget(DockArea, OpaqueUndocking);
|
||||
Size = DockArea->size();
|
||||
}
|
||||
|
||||
if (DraggingFloatingWidget == DraggingState)
|
||||
@@ -287,7 +300,7 @@ void CDockWidgetTab::mousePressEvent(QMouseEvent* ev)
|
||||
if (ev->button() == Qt::LeftButton)
|
||||
{
|
||||
ev->accept();
|
||||
d->GlobalDragStartMousePosition = ev->globalPos();
|
||||
d->saveDragStartMousePosition(ev->globalPos());
|
||||
d->DragState = DraggingMousePressed;
|
||||
emit clicked();
|
||||
return;
|
||||
@@ -304,6 +317,7 @@ void CDockWidgetTab::mouseReleaseEvent(QMouseEvent* ev)
|
||||
{
|
||||
auto CurrentDragState = d->DragState;
|
||||
d->GlobalDragStartMousePosition = QPoint();
|
||||
d->DragStartMousePosition = QPoint();
|
||||
d->DragState = DraggingInactive;
|
||||
|
||||
switch (CurrentDragState)
|
||||
@@ -354,9 +368,11 @@ void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev)
|
||||
d->moveTab(ev);
|
||||
}
|
||||
|
||||
auto MappedPos = mapToParent(ev->pos());
|
||||
bool MouseOutsideBar = (MappedPos.x() < 0) || (MappedPos.x() > parentWidget()->rect().right());
|
||||
// Maybe a fixed drag distance is better here ?
|
||||
int DragDistanceY = qAbs(d->GlobalDragStartMousePosition.y() - ev->globalPos().y());
|
||||
if (DragDistanceY >= CDockManager::startDragDistance())
|
||||
if (DragDistanceY >= CDockManager::startDragDistance() || MouseOutsideBar)
|
||||
{
|
||||
// If this is the last dock area in a dock container with only
|
||||
// one single dock widget it does not make sense to move it to a new
|
||||
@@ -380,7 +396,7 @@ void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev)
|
||||
// tab because it looks strange if it remains on its dragged position
|
||||
if (d->isDraggingState(DraggingTab) && !CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking))
|
||||
{
|
||||
this->move(d->TabDragStartPosition);
|
||||
parentWidget()->layout()->update();
|
||||
}
|
||||
d->startFloating();
|
||||
}
|
||||
@@ -412,7 +428,7 @@ void CDockWidgetTab::contextMenuEvent(QContextMenuEvent* ev)
|
||||
return;
|
||||
}
|
||||
|
||||
d->GlobalDragStartMousePosition = ev->globalPos();
|
||||
d->saveDragStartMousePosition(ev->globalPos());
|
||||
QMenu Menu(this);
|
||||
|
||||
const bool isFloatable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable);
|
||||
@@ -542,7 +558,7 @@ void CDockWidgetTab::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
if ((!d->DockArea->dockContainer()->isFloating() || d->DockArea->dockWidgetsCount() > 1)
|
||||
&& d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||
{
|
||||
d->GlobalDragStartMousePosition = event->globalPos();
|
||||
d->saveDragStartMousePosition(event->globalPos());
|
||||
d->startFloating(DraggingInactive);
|
||||
}
|
||||
|
||||
@@ -564,6 +580,8 @@ void CDockWidgetTab::setText(const QString& title)
|
||||
d->TitleLabel->setText(title);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockWidgetTab::isTitleElided() const
|
||||
{
|
||||
return d->TitleLabel->isElided();
|
||||
@@ -585,7 +603,8 @@ void CDockWidgetTab::detachDockWidget()
|
||||
{
|
||||
return;
|
||||
}
|
||||
d->GlobalDragStartMousePosition = QCursor::pos();
|
||||
|
||||
d->saveDragStartMousePosition(QCursor::pos());
|
||||
d->startFloating(DraggingInactive);
|
||||
}
|
||||
|
||||
@@ -615,6 +634,13 @@ void CDockWidgetTab::onDockWidgetFeaturesChanged()
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidgetTab::setElideMode(Qt::TextElideMode mode)
|
||||
{
|
||||
d->TitleLabel->setElideMode(mode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace ads
|
||||
|
||||
@@ -147,6 +147,11 @@ public:
|
||||
*/
|
||||
virtual bool event(QEvent *e) override;
|
||||
|
||||
/**
|
||||
* Sets the text elide mode
|
||||
*/
|
||||
void setElideMode(Qt::TextElideMode mode);
|
||||
|
||||
|
||||
public slots:
|
||||
virtual void setVisible(bool visible) override;
|
||||
|
||||
@@ -197,13 +197,13 @@ QSize CElidingLabel::sizeHint() const
|
||||
//============================================================================
|
||||
void CElidingLabel::setText(const QString &text)
|
||||
{
|
||||
d->Text = text;
|
||||
if (d->isModeElideNone())
|
||||
{
|
||||
Super::setText(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
d->Text = text;
|
||||
internal::setToolTip(this, text);
|
||||
d->elideText(this->size().width());
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <QDebug>
|
||||
#include <QAbstractButton>
|
||||
#include <QElapsedTimer>
|
||||
#include <QTime>
|
||||
|
||||
#include "DockContainerWidget.h"
|
||||
#include "DockAreaWidget.h"
|
||||
@@ -66,6 +67,7 @@ struct FloatingDockContainerPrivate
|
||||
QPoint DragStartMousePosition;
|
||||
CDockContainerWidget *DropContainer = nullptr;
|
||||
CDockAreaWidget *SingleDockArea = nullptr;
|
||||
QPoint DragStartPos;
|
||||
#ifdef Q_OS_LINUX
|
||||
QWidget* MouseEventHandler = nullptr;
|
||||
CFloatingWidgetTitleBar* TitleBar = nullptr;
|
||||
@@ -109,6 +111,10 @@ struct FloatingDockContainerPrivate
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Reflect the current dock widget title in the floating widget windowTitle()
|
||||
* depending on the CDockManager::FloatingContainerHasWidgetTitle flag
|
||||
*/
|
||||
void reflectCurrentWidget(CDockWidget* CurrentWidget)
|
||||
{
|
||||
// reflect CurrentWidget's title if configured to do so, otherwise display application name as window title
|
||||
@@ -133,6 +139,11 @@ struct FloatingDockContainerPrivate
|
||||
_this->setWindowIcon(QApplication::windowIcon());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles escape key press when dragging around the floating widget
|
||||
*/
|
||||
void handleEscapeKey();
|
||||
};
|
||||
// struct FloatingDockContainerPrivate
|
||||
|
||||
@@ -158,14 +169,14 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
|
||||
|| DockManager->containerOverlay()->dropAreaUnderCursor()
|
||||
!= InvalidDockWidgetArea)
|
||||
{
|
||||
// Resize the floating widget to the size of the highlighted drop area
|
||||
// rectangle
|
||||
CDockOverlay *Overlay = DockManager->containerOverlay();
|
||||
if (!Overlay->dropOverlayRect().isValid())
|
||||
{
|
||||
Overlay = DockManager->dockAreaOverlay();
|
||||
}
|
||||
|
||||
// Resize the floating widget to the size of the highlighted drop area
|
||||
// rectangle
|
||||
QRect Rect = Overlay->dropOverlayRect();
|
||||
int FrameWidth = (_this->frameSize().width() - _this->rect().width())
|
||||
/ 2;
|
||||
@@ -264,6 +275,17 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &GlobalPos)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void FloatingDockContainerPrivate::handleEscapeKey()
|
||||
{
|
||||
ADS_PRINT("FloatingDockContainerPrivate::handleEscapeKey()");
|
||||
setState(DraggingInactive);
|
||||
DockManager->containerOverlay()->hideOverlay();
|
||||
DockManager->dockAreaOverlay()->hideOverlay();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CFloatingDockContainer::CFloatingDockContainer(CDockManager *DockManager) :
|
||||
tFloatingWidgetBase(DockManager),
|
||||
@@ -363,6 +385,9 @@ void CFloatingDockContainer::moveEvent(QMoveEvent *event)
|
||||
switch (d->DraggingState)
|
||||
{
|
||||
case DraggingMousePressed:
|
||||
#ifdef Q_OS_WIN
|
||||
qApp->installEventFilter(this);
|
||||
#endif
|
||||
d->setState(DraggingFloatingWidget);
|
||||
d->updateDropOverlays(QCursor::pos());
|
||||
break;
|
||||
@@ -380,6 +405,8 @@ void CFloatingDockContainer::moveEvent(QMoveEvent *event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
@@ -443,6 +470,7 @@ void CFloatingDockContainer::showEvent(QShowEvent *event)
|
||||
Super::showEvent(event);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CFloatingDockContainer::event(QEvent *e)
|
||||
{
|
||||
@@ -458,21 +486,17 @@ bool CFloatingDockContainer::event(QEvent *e)
|
||||
// It is really great to work around the whole NonClientMouseArea
|
||||
// bugs
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
|
||||
if (e->type()
|
||||
== QEvent::NonClientAreaMouseButtonPress /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
|
||||
{
|
||||
ADS_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type());
|
||||
d->setState(DraggingMousePressed);
|
||||
}
|
||||
if (e->type() == QEvent::NonClientAreaMouseButtonPress /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
|
||||
#else
|
||||
if (e->type() == QEvent::NonClientAreaMouseButtonPress && QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
|
||||
#endif
|
||||
{
|
||||
ADS_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type());
|
||||
ADS_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type());
|
||||
d->DragStartPos = pos();
|
||||
d->setState(DraggingMousePressed);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case DraggingMousePressed:
|
||||
switch (e->type())
|
||||
@@ -515,12 +539,49 @@ bool CFloatingDockContainer::event(QEvent *e)
|
||||
}
|
||||
|
||||
#if (ADS_DEBUG_LEVEL > 0)
|
||||
qDebug() << "CFloatingDockContainer::event " << e->type();
|
||||
qDebug() << QTime::currentTime() << "CFloatingDockContainer::event " << e->type();
|
||||
#endif
|
||||
return QWidget::event(e);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CFloatingDockContainer::eventFilter(QObject *watched, QEvent *e)
|
||||
{
|
||||
Q_UNUSED(watched);
|
||||
// I have not found a way to detect non client area key press events to
|
||||
// handle escape key presses. On Windows, if the escape key is pressed while
|
||||
// dragging around a widget, the widget position is reset to its start position
|
||||
// which in turn generates a QEvent::NonClientAreaMouseButtonRelease event
|
||||
// if the mouse is outside of the widget after the move to its initial position
|
||||
// or a QEvent::MouseButtonRelease event, if the mouse is inside of teh widget
|
||||
// after the position has been reset.
|
||||
// So we can install an event filter on the application to get these events
|
||||
// here to properly cancel dragging and hide the overlays.
|
||||
// If we are in DraggingFloatingWidget state, it means the widget
|
||||
// has been dragged already but if the position is the same like
|
||||
// the start position, then this is an indication that the escape
|
||||
// key has been pressed.
|
||||
if (e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::NonClientAreaMouseButtonRelease)
|
||||
{
|
||||
ADS_PRINT("CFloatingDockContainer::eventFilter QEvent::MouseButtonRelease or"
|
||||
"QEvent::NonClientAreaMouseButtonRelease" << "d->DragggingState " << d->DraggingState);
|
||||
qApp->removeEventFilter(this);
|
||||
if (d->DragStartPos == pos())
|
||||
{
|
||||
d->handleEscapeKey();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if (ADS_DEBUG_LEVEL > 0)
|
||||
qDebug() << QTime::currentTime() << "CFloatingDockContainer::eventFilter " << e->type();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CFloatingDockContainer::startFloating(const QPoint &DragStartMousePos,
|
||||
const QSize &Size, eDragState DragState, QWidget *MouseEventHandler)
|
||||
|
||||
@@ -68,6 +68,8 @@ class CDockingStateReader;
|
||||
class IFloatingWidget
|
||||
{
|
||||
public:
|
||||
virtual ~IFloatingWidget() = default;
|
||||
|
||||
/**
|
||||
* Starts floating.
|
||||
* This function should get called typically from a mouse press event
|
||||
@@ -180,6 +182,7 @@ protected: // reimplements QWidget
|
||||
virtual void closeEvent(QCloseEvent *event) override;
|
||||
virtual void hideEvent(QHideEvent *event) override;
|
||||
virtual void showEvent(QShowEvent *event) override;
|
||||
virtual bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
public:
|
||||
using Super = QWidget;
|
||||
|
||||
@@ -40,6 +40,7 @@ struct FloatingDragPreviewPrivate
|
||||
qreal WindowOpacity;
|
||||
bool Hidden = false;
|
||||
QPixmap ContentPreviewPixmap;
|
||||
bool Canceled = false;
|
||||
|
||||
|
||||
/**
|
||||
@@ -59,11 +60,18 @@ struct FloatingDragPreviewPrivate
|
||||
*/
|
||||
void cancelDragging()
|
||||
{
|
||||
Canceled = true;
|
||||
emit _this->draggingCanceled();
|
||||
DockManager->containerOverlay()->hideOverlay();
|
||||
DockManager->dockAreaOverlay()->hideOverlay();
|
||||
_this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the real floating widget in case the mouse is released outside
|
||||
* outside of any drop area
|
||||
*/
|
||||
void createFloatingWidget();
|
||||
};
|
||||
// struct LedArrayPanelPrivate
|
||||
|
||||
@@ -85,11 +93,6 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*if (DockContainer == ContainerWidget)
|
||||
{
|
||||
continue;
|
||||
}*/
|
||||
|
||||
QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos);
|
||||
if (ContainerWidget->rect().contains(MappedPos))
|
||||
{
|
||||
@@ -148,6 +151,14 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
|
||||
else
|
||||
{
|
||||
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
|
||||
if (VisibleDockAreas <= 1)
|
||||
{
|
||||
ContainerOverlay->hideOverlay();
|
||||
}
|
||||
|
||||
if (DockArea == ContentSourceArea && InvalidDockWidgetArea == ContainerDropArea)
|
||||
{
|
||||
DropContainer = nullptr;
|
||||
@@ -168,6 +179,40 @@ FloatingDragPreviewPrivate::FloatingDragPreviewPrivate(CFloatingDragPreview *_pu
|
||||
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void FloatingDragPreviewPrivate::createFloatingWidget()
|
||||
{
|
||||
CDockWidget* DockWidget = qobject_cast<CDockWidget*>(Content);
|
||||
CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(Content);
|
||||
|
||||
CFloatingDockContainer* FloatingWidget = nullptr;
|
||||
|
||||
if (DockWidget && DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||
{
|
||||
FloatingWidget = new CFloatingDockContainer(DockWidget);
|
||||
}
|
||||
else if (DockArea && DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||
{
|
||||
FloatingWidget = new CFloatingDockContainer(DockArea);
|
||||
}
|
||||
|
||||
if (FloatingWidget)
|
||||
{
|
||||
FloatingWidget->setGeometry(_this->geometry());
|
||||
FloatingWidget->show();
|
||||
if (!CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
|
||||
{
|
||||
QApplication::processEvents();
|
||||
int FrameHeight = FloatingWidget->frameGeometry().height() - FloatingWidget->geometry().height();
|
||||
QRect FixedGeometry = _this->geometry();
|
||||
FixedGeometry.adjust(0, FrameHeight, 0, 0);
|
||||
FloatingWidget->setGeometry(FixedGeometry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CFloatingDragPreview::CFloatingDragPreview(QWidget* Content, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
@@ -206,6 +251,10 @@ CFloatingDragPreview::CFloatingDragPreview(QWidget* Content, QWidget* parent) :
|
||||
|
||||
connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
|
||||
SLOT(onApplicationStateChanged(Qt::ApplicationState)));
|
||||
|
||||
// The only safe way to receive escape key presses is to install an event
|
||||
// filter for the application object
|
||||
qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -220,10 +269,6 @@ CFloatingDragPreview::CFloatingDragPreview(CDockWidget* Content)
|
||||
d->ContenSourceContainer = Content->dockContainer();
|
||||
}
|
||||
setWindowTitle(Content->windowTitle());
|
||||
|
||||
// We need to install an event filter for the given Content
|
||||
// widget to receive the escape key press
|
||||
Content->dockAreaWidget()->installEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -235,10 +280,6 @@ CFloatingDragPreview::CFloatingDragPreview(CDockAreaWidget* Content)
|
||||
d->ContentSourceArea = Content;
|
||||
d->ContenSourceContainer = Content->dockContainer();
|
||||
setWindowTitle(Content->currentDockWidget()->windowTitle());
|
||||
|
||||
// We need to install an event filter for the given Content
|
||||
// widget to receive the escape key press
|
||||
Content->installEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -285,45 +326,33 @@ void CFloatingDragPreview::moveEvent(QMoveEvent *event)
|
||||
void CFloatingDragPreview::finishDragging()
|
||||
{
|
||||
ADS_PRINT("CFloatingDragPreview::finishDragging");
|
||||
auto DockDropArea = d->DockManager->dockAreaOverlay()->dropAreaUnderCursor();
|
||||
auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
|
||||
bool DropPossible = (DockDropArea != InvalidDockWidgetArea) || (ContainerDropArea != InvalidDockWidgetArea);
|
||||
if (d->DropContainer && DropPossible)
|
||||
auto DockDropArea = d->DockManager->dockAreaOverlay()->visibleDropAreaUnderCursor();
|
||||
auto ContainerDropArea = d->DockManager->containerOverlay()->visibleDropAreaUnderCursor();
|
||||
if (!d->DropContainer)
|
||||
{
|
||||
d->DropContainer->dropWidget(d->Content, QCursor::pos());
|
||||
d->createFloatingWidget();
|
||||
}
|
||||
else
|
||||
else if (DockDropArea != InvalidDockWidgetArea)
|
||||
{
|
||||
CDockWidget* DockWidget = qobject_cast<CDockWidget*>(d->Content);
|
||||
CFloatingDockContainer* FloatingWidget = nullptr;
|
||||
|
||||
if (DockWidget && DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||
d->DropContainer->dropWidget(d->Content, DockDropArea, d->DropContainer->dockAreaAt(QCursor::pos()));
|
||||
}
|
||||
else if (ContainerDropArea != InvalidDockWidgetArea)
|
||||
{
|
||||
// If there is only one single dock area, and we drop into the center
|
||||
// then we tabify the dropped widget into the only visible dock area
|
||||
if (d->DropContainer->visibleDockAreaCount() <= 1 && CenterDockWidgetArea == ContainerDropArea)
|
||||
{
|
||||
FloatingWidget = new CFloatingDockContainer(DockWidget);
|
||||
d->DropContainer->dropWidget(d->Content, ContainerDropArea, d->DropContainer->dockAreaAt(QCursor::pos()));
|
||||
}
|
||||
else
|
||||
{
|
||||
CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(d->Content);
|
||||
if (DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||
{
|
||||
FloatingWidget = new CFloatingDockContainer(DockArea);
|
||||
}
|
||||
}
|
||||
|
||||
if (FloatingWidget)
|
||||
{
|
||||
FloatingWidget->setGeometry(this->geometry());
|
||||
FloatingWidget->show();
|
||||
if (!CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
|
||||
{
|
||||
QApplication::processEvents();
|
||||
int FrameHeight = FloatingWidget->frameGeometry().height() - FloatingWidget->geometry().height();
|
||||
QRect FixedGeometry = this->geometry();
|
||||
FixedGeometry.adjust(0, FrameHeight, 0, 0);
|
||||
FloatingWidget->setGeometry(FixedGeometry);
|
||||
}
|
||||
d->DropContainer->dropWidget(d->Content, ContainerDropArea, nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
d->createFloatingWidget();
|
||||
}
|
||||
|
||||
this->close();
|
||||
d->DockManager->containerOverlay()->hideOverlay();
|
||||
@@ -380,7 +409,7 @@ void CFloatingDragPreview::onApplicationStateChanged(Qt::ApplicationState state)
|
||||
bool CFloatingDragPreview::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
Q_UNUSED(watched);
|
||||
if (event->type() == QEvent::KeyPress)
|
||||
if (!d->Canceled && event->type() == QEvent::KeyPress)
|
||||
{
|
||||
QKeyEvent* e = static_cast<QKeyEvent*>(event);
|
||||
if (e->key() == Qt::Key_Escape)
|
||||
@@ -395,7 +424,6 @@ bool CFloatingDragPreview::eventFilter(QObject *watched, QEvent *event)
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace ads
|
||||
{
|
||||
enum eStateFileVersion
|
||||
{
|
||||
InitialVerison = 0,
|
||||
InitialVersion = 0,
|
||||
Version1 = 1,
|
||||
CurrentVersion = Version1
|
||||
};
|
||||
|
||||