From a9965bf6dcd8d35d953ae013c2656a453d8ef548 Mon Sep 17 00:00:00 2001 From: Jan Krassnigg Date: Wed, 13 May 2020 08:04:50 +0200 Subject: [PATCH 1/5] Moved CTitleBarButton and CSpacerWidget declaration into DockAreaTitleBar.h This gets rid of the need to MOC DockAreaTitleBar.h and DockAreaTitleBar.cpp and it means that DockAreaTitleBar.cpp does not need to #include "DockAreaTitleBar.moc" anymore, which is a file that is generated by the build system and therefore may be named differently when using a custom build system. --- src/DockAreaTitleBar.cpp | 126 +++++++++++++-------------------------- src/DockAreaTitleBar.h | 52 ++++++++++++++++ 2 files changed, 94 insertions(+), 84 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index ac9f345..62e9877 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -55,8 +55,6 @@ namespace ads { -using tTitleBarButton = QToolButton; - /** * Private data class of CDockAreaTitleBar class (pimpl) @@ -130,86 +128,6 @@ struct DockAreaTitleBarPrivate IFloatingWidget* makeAreaFloating(const QPoint& Offset, eDragState DragState); };// struct DockAreaTitleBarPrivate - -/** - * Title bar button of a dock area that customizes tTitleBarButton appearance/behaviour - * according to various config flags such as: - * CDockManager::DockAreaHas_xxx_Button - if set to 'false' keeps the button always invisible - * CDockManager::DockAreaHideDisabledButtons - if set to 'true' hides button when it is disabled - */ -class CTitleBarButton : public tTitleBarButton -{ - Q_OBJECT - bool Visible = true; - bool HideWhenDisabled = false; -public: - using Super = tTitleBarButton; - CTitleBarButton(bool visible = true, QWidget* parent = nullptr) - : tTitleBarButton(parent), - Visible(visible), - HideWhenDisabled(DockAreaTitleBarPrivate::testConfigFlag(CDockManager::DockAreaHideDisabledButtons)) - {} - - - /** - * Adjust this visibility change request with our internal settings: - */ - virtual void setVisible(bool visible) override - { - // 'visible' can stay 'true' if and only if this button is configured to generaly visible: - visible = visible && this->Visible; - - // 'visible' can stay 'true' unless: this button is configured to be invisible when it is disabled and it is currently disabled: - if(visible && HideWhenDisabled) - { - visible = isEnabled(); - } - - Super::setVisible(visible); - } - -protected: - /** - * Handle EnabledChanged signal to set button invisible if the configured - */ - bool event(QEvent *ev) override - { - if(QEvent::EnabledChange == ev->type() && HideWhenDisabled) - { - // force setVisible() call - // Calling setVisible() directly here doesn't work well when button is expected to be shown first time - QMetaObject::invokeMethod(this, "setVisible", Qt::QueuedConnection, Q_ARG(bool, isEnabled())); - } - - return Super::event(ev); - } -}; - - -/** - * This spacer widget is here because of the following problem. - * The dock area title bar handles mouse dragging and moving the floating widget. - * The problem is, that if the title bar becomes invisible, i.e. if the dock - * area contains only one single dock widget and the dock area is moved - * into a floating widget, then mouse events are not handled anymore and dragging - * of the floating widget stops. - */ -class CSpacerWidget : public QWidget -{ - Q_OBJECT -public: - using Super = QWidget; - CSpacerWidget(QWidget* Parent = 0) - : Super(Parent) - { - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - setStyleSheet("border: none; background: none;"); - } - virtual QSize sizeHint() const override {return QSize(0, 0);} - virtual QSize minimumSizeHint() const override {return QSize(0, 0);} -}; - - //============================================================================ DockAreaTitleBarPrivate::DockAreaTitleBarPrivate(CDockAreaTitleBar* _public) : _this(_public) @@ -674,10 +592,50 @@ int CDockAreaTitleBar::indexOf(QWidget *widget) const return d->Layout->indexOf(widget); } +//============================================================================ +CTitleBarButton::CTitleBarButton(bool visible /*= true*/, QWidget* parent /*= nullptr*/) : tTitleBarButton(parent), +Visible(visible), +HideWhenDisabled(DockAreaTitleBarPrivate::testConfigFlag(CDockManager::DockAreaHideDisabledButtons)) +{ + +} + +//============================================================================ +void CTitleBarButton::setVisible(bool visible) +{ + // 'visible' can stay 'true' if and only if this button is configured to generaly visible: + visible = visible && this->Visible; + + // 'visible' can stay 'true' unless: this button is configured to be invisible when it is disabled and it is currently disabled: + if (visible && HideWhenDisabled) + { + visible = isEnabled(); + } + + Super::setVisible(visible); +} + +//============================================================================ +bool CTitleBarButton::event(QEvent *ev) +{ + if (QEvent::EnabledChange == ev->type() && HideWhenDisabled) + { + // force setVisible() call + // Calling setVisible() directly here doesn't work well when button is expected to be shown first time + QMetaObject::invokeMethod(this, "setVisible", Qt::QueuedConnection, Q_ARG(bool, isEnabled())); + } + + return Super::event(ev); +} + +//============================================================================ +CSpacerWidget::CSpacerWidget(QWidget* Parent /*= 0*/) : Super(Parent) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setStyleSheet("border: none; background: none;"); +} } // namespace ads -#include "DockAreaTitleBar.moc" - //--------------------------------------------------------------------------- // EOF DockAreaTitleBar.cpp diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index cd28842..3efb8cc 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -31,6 +31,7 @@ // INCLUDES //============================================================================ #include +#include #include "ads_globals.h" @@ -155,6 +156,57 @@ signals: */ void tabBarClicked(int index); }; // class name + +using tTitleBarButton = QToolButton; + + /** + * Title bar button of a dock area that customizes tTitleBarButton appearance/behaviour + * according to various config flags such as: + * CDockManager::DockAreaHas_xxx_Button - if set to 'false' keeps the button always invisible + * CDockManager::DockAreaHideDisabledButtons - if set to 'true' hides button when it is disabled + */ +class CTitleBarButton : public tTitleBarButton +{ + Q_OBJECT + + bool Visible = true; + bool HideWhenDisabled = false; + +public: + using Super = tTitleBarButton; + CTitleBarButton(bool visible = true, QWidget* parent = nullptr); + + /** + * Adjust this visibility change request with our internal settings: + */ + virtual void setVisible(bool visible) override; + +protected: + /** + * Handle EnabledChanged signal to set button invisible if the configured + */ + bool event(QEvent *ev) override; +}; + + +/** +* This spacer widget is here because of the following problem. +* The dock area title bar handles mouse dragging and moving the floating widget. +* The problem is, that if the title bar becomes invisible, i.e. if the dock +* area contains only one single dock widget and the dock area is moved +* into a floating widget, then mouse events are not handled anymore and dragging +* of the floating widget stops. +*/ +class CSpacerWidget : public QWidget +{ + Q_OBJECT +public: + using Super = QWidget; + CSpacerWidget(QWidget* Parent = 0); + virtual QSize sizeHint() const override {return QSize(0, 0);} + virtual QSize minimumSizeHint() const override {return QSize(0, 0);} +}; + } // namespace ads //----------------------------------------------------------------------------- From 4a8b5dd7ab80e788648d3a906dfafcac44fcd576 Mon Sep 17 00:00:00 2001 From: n-elie <40382614+n-elie@users.noreply.github.com> Date: Wed, 13 May 2020 16:05:00 +0200 Subject: [PATCH 2/5] Update PyQt bindings (#168) * Fix include header in sidebar example * Update SIP files and Python examples Co-authored-by: K Lauer Co-authored-by: K Lauer --- demo/demo.py | 121 +++++++++++++++++++++++++------- demo/status_dialog.py | 38 ++++++++++ examples/sidebar/MainWindow.cpp | 2 +- examples/sidebar/sidebar.py | 60 ++++++++++++++++ examples/simple/simple.py | 2 - setup.py | 35 ++++++++- sip/DockComponentsFactory.sip | 2 +- sip/DockManager.sip | 2 +- sip/DockWidgetTab.sip | 2 +- sip/ads_globals.sip | 2 +- 10 files changed, 232 insertions(+), 34 deletions(-) create mode 100644 demo/status_dialog.py create mode 100644 examples/sidebar/sidebar.py diff --git a/demo/demo.py b/demo/demo.py index e1d6adf..c7b2f83 100644 --- a/demo/demo.py +++ b/demo/demo.py @@ -7,7 +7,7 @@ from PyQt5 import uic from PyQt5.QtCore import (QCoreApplication, QDir, Qt, QSettings, QSignalBlocker, QRect, QPoint, qDebug, qInstallMessageHandler, QtDebugMsg, QtInfoMsg, QtWarningMsg, - QtCriticalMsg, QtFatalMsg) + QtCriticalMsg, QtFatalMsg, QSize) from PyQt5.QtGui import (QGuiApplication, QIcon, QCloseEvent) from PyQt5.QtWidgets import (QCalendarWidget, QFileSystemModel, QFrame, QLabel, QMenu, QTreeView, QAction, QWidgetAction, @@ -25,6 +25,7 @@ else: from PyQtAds import QtAds import rc # pyrcc5 demo.qrc -o rc.py +from status_dialog import CStatusDialog UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui') MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE) @@ -100,7 +101,12 @@ def create_calendar_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget: dock_widget = QtAds.CDockWidget("Calendar {}".format(_State.calendar_count)) _State.calendar_count += 1 + # The following lines are for testing the setWidget() and takeWidget() + # functionality dock_widget.setWidget(widget) + dock_widget.setWidget(widget) # what happens if we set a widget if a widget is already set + dock_widget.takeWidget() # we remove the widget + dock_widget.setWidget(widget) # and set the widget again - there should be no error dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow) dock_widget.setIcon(svg_icon(":/adsdemo/images/date_range.svg")) view_menu.addAction(dock_widget.toggleViewAction()) @@ -149,9 +155,15 @@ def create_editor_widget(view_menu: QMenu) -> QtAds.CDockWidget: return dock_widget +class CMinSizeTableWidget(QTableWidget): + """Custom QTableWidget with a minimum size hint to test CDockWidget + setMinimumSizeHintMode() function of CDockWidget""" + + def minimumSizeHint(self) -> QSize: + return QSize(300, 100) def create_table_widget(view_menu: QMenu) -> QtAds.CDockWidget: - widget = QTableWidget() + widget = CMinSizeTableWidget() dock_widget = QtAds.CDockWidget("Table {}".format(_State.table_count)) _State.table_count += 1 COLCOUNT = 5 @@ -165,6 +177,15 @@ def create_table_widget(view_menu: QMenu) -> QtAds.CDockWidget: dock_widget.setWidget(widget) dock_widget.setIcon(svg_icon(":/adsdemo/images/grid_on.svg")) + dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromContent) + toolbar = dock_widget.createDefaultToolBar() + action = toolbar.addAction(svg_icon(":/adsdemo/images/fullscreen.svg"), "Toggle Fullscreen") + def on_toggle_fullscreen(): + if dock_widget.isFullScreen(): + dock_widget.showNormal() + else: + dock_widget.showFullScreen() + action.triggered.connect(on_toggle_fullscreen) view_menu.addAction(dock_widget.toggleViewAction()) return dock_widget @@ -179,7 +200,7 @@ if ACTIVEX_AVAILABLE: return dock_widget -class CustomComponentsFactory(QtAds.CDockComponentsFactory): +class CCustomComponentsFactory(QtAds.CDockComponentsFactory): def createDockAreaTitleBar(self, dock_area: QtAds.CDockAreaWidget) -> QtAds.CDockAreaTitleBar: title_bar = QtAds.CDockAreaTitleBar(dock_area) @@ -192,7 +213,6 @@ class CustomComponentsFactory(QtAds.CDockComponentsFactory): return title_bar - class MainWindow(MainWindowUI, MainWindowBase): save_perspective_action: QAction perspective_list_action: QWidgetAction @@ -213,13 +233,39 @@ class MainWindow(MainWindowUI, MainWindowBase): # a QToolButton instead of a QPushButton # QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.configFlags() | QtAds.CDockManager.TabCloseButtonIsToolButton) + # uncomment the following line if you want to use opaque undocking and + # opaque splitter resizing + #QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DefaultOpaqueConfig); + # 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) + #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) + # uncomment the following line if you don't want close button on DockArea's title bar + #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasCloseButton, false); + + # uncomment the following line if you don't want undock button on DockArea's title bar + #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasUndockButton, false); + + # uncomment the following line if you don't want tabs menu button on DockArea's title bar + #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasTabsMenuButton, false); + + # uncomment the following line if you don't want disabled buttons to appear on DockArea's title bar + #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHideDisabledButtons, true); + + # uncomment the following line if you want to show tabs menu button on DockArea's title bar only when there are more than one tab and at least of them has elided title + #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaDynamicTabsMenuButtonVisibility, true); + + # uncomment the following line if you want floating container to always show application title instead of active dock widget's title + #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetTitle, false); + + # uncomment the following line if you want floating container to show active dock widget's icon instead of always showing application icon + #QtAds.CDockManager.setConfigFlag(QtAds.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. + #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.HideSingleCentralWidgetTitleBar, true); # Now create the dock manager and its content self.dock_manager = QtAds.CDockManager(self) @@ -245,8 +291,6 @@ class MainWindow(MainWindowUI, MainWindowBase): 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): @@ -271,18 +315,13 @@ class MainWindow(MainWindowUI, MainWindowBase): 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) + QtAds.CDockComponentsFactory.setFactory(CCustomComponentsFactory()) 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) @@ -292,6 +331,7 @@ class MainWindow(MainWindowUI, MainWindowBase): 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) @@ -309,7 +349,7 @@ class MainWindow(MainWindowUI, MainWindowBase): 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) @@ -320,9 +360,14 @@ class MainWindow(MainWindowUI, MainWindowBase): 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 = self.menuTests.addAction("Set {} Floating".format(dock_widget.windowTitle())) action.triggered.connect(dock_widget.setFloating) + action = self.menuTests.addAction("Set {} As Current Tab".format(dock_widget.windowTitle())) + action.triggered.connect(dock_widget.setAsCurrentTab) + action = self.menuTests.addAction("Raise {}".format(dock_widget.windowTitle())) + action.triggered.connect(dock_widget.raise_) if ACTIVEX_AVAILABLE: flags = self.dock_manager.configFlags() @@ -353,25 +398,40 @@ class MainWindow(MainWindowUI, MainWindowBase): self.toolBar.addAction(self.perspective_list_action) self.toolBar.addAction(self.save_perspective_action) - a = self.toolBar.addAction("Create Editor") + a = self.toolBar.addAction("Create Floating Editor") + a.setProperty("Floating", True) 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) + self.menuTests.addAction(a) + + a = self.toolBar.addAction("Create Docked Editor") + a.setProperty("Floating", False) + a.setToolTip("Creates a docked editor windows that are deleted on close") + a.setIcon(svg_icon(":/adsdemo/images/docked_editor.svg")) + a.triggered.connect(self.create_editor) + self.menuTests.addAction(a) - a = self.toolBar.addAction("Create Table") + a = self.toolBar.addAction("Create Floating 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) + self.menuTests.addAction(a) + + self.menuTests.addSeparator() + a = self.menuTests.addAction("Show Status Dialog") + a.triggered.connect(self.show_status_dialog) + self.menuTests.addSeparator() def closeEvent(self, event: QCloseEvent): self.save_state() super().closeEvent(event) - def on_action_save_state_triggered(state: bool): + def on_actionSaveState_triggered(self, state: bool): qDebug("MainWindow::on_action_save_state_triggered") self.save_state() - def on_action_restore_state_triggered(state: bool): + def on_actionRestoreState_triggered(self, state: bool): qDebug("MainWindow::on_action_restore_state_triggered") self.restore_state() @@ -403,11 +463,18 @@ class MainWindow(MainWindowUI, MainWindowBase): qDebug("{} visibility_changed({})".format(dock_widget.objectName(), visible)) def create_editor(self): + sender = self.sender() + floating = sender.property("Floating") + print("Floating:", floating) 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) + + if floating: + floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget) + floating_widget.move(QPoint(20, 20)) + else: + self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, dock_widget) def on_editor_close_requested(self): dock_widget = self.sender() @@ -421,6 +488,10 @@ class MainWindow(MainWindowUI, MainWindowBase): dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True) floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget) floating_widget.move(QPoint(40, 40)) + + def show_status_dialog(self): + dialog = CStatusDialog(self.dock_manager) + dialog.exec_() def save_state(self): ''' diff --git a/demo/status_dialog.py b/demo/status_dialog.py new file mode 100644 index 0000000..8c42f15 --- /dev/null +++ b/demo/status_dialog.py @@ -0,0 +1,38 @@ +import os +import sys + +from PyQt5 import uic +from PyQtAds import QtAds + +UI_FILE = os.path.join(os.path.dirname(__file__), 'StatusDialog.ui') +StatusDialogUI, StatusDialogBase = uic.loadUiType(UI_FILE) + +class CStatusDialog(StatusDialogUI, StatusDialogBase): + + def __init__(self, dock_manager: QtAds.CDockManager, parent=None): + super().__init__(parent) + + self.setupUi(self) + + self.dock_manager = dock_manager + self.dock_widgets = self.dock_manager.dockWidgetsMap() + + for key, widget in self.dock_widgets.items(): + self.dockWidgetsComboBox.addItem(key, widget) + + def on_dockWidgetsComboBox_currentIndexChanged(self, index: int): + if not isinstance(index, int): + return + if index < 0: + return + + dock_widget = self.dockWidgetsComboBox.currentData() + self.isClosedCheckBox.setChecked(dock_widget.isClosed()) + self.isFloatingCheckBox.setChecked(dock_widget.isFloating()) + self.tabbedCheckBox.setChecked(dock_widget.isTabbed()) + self.isCurrentTabCheckBox.setChecked(dock_widget.isCurrentTab()) + self.closableCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.DockWidgetClosable) + self.movableCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.DockWidgetMovable) + self.floatableCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.DockWidgetFloatable) + self.deleteOnCloseCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.DockWidgetDeleteOnClose) + self.customCloseHandlingCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.CustomCloseHandling) diff --git a/examples/sidebar/MainWindow.cpp b/examples/sidebar/MainWindow.cpp index 880a5d0..82ecd53 100644 --- a/examples/sidebar/MainWindow.cpp +++ b/examples/sidebar/MainWindow.cpp @@ -1,4 +1,4 @@ -#include "../../examples/simple/MainWindow.h" +#include "MainWindow.h" #include "ui_MainWindow.h" diff --git a/examples/sidebar/sidebar.py b/examples/sidebar/sidebar.py new file mode 100644 index 0000000..27170ba --- /dev/null +++ b/examples/sidebar/sidebar.py @@ -0,0 +1,60 @@ +import os +import sys + +from PyQt5 import uic +from PyQt5.QtCore import Qt, QMargins +from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QPlainTextEdit + +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. + layout = QVBoxLayout(self.dockContainer); + layout.setContentsMargins(QMargins(0, 0, 0, 0)) + self.dock_manager = QtAds.CDockManager(self.dockContainer) + layout.addWidget(self.dock_manager) + + # 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) + + # Create an example editor + te = QPlainTextEdit() + te.setPlaceholderText("Please enter your text here into this QPlainTextEdit...") + dock_widget = QtAds.CDockWidget("Editor 1") + self.menuView.addAction(dock_widget.toggleViewAction()) + self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, dock_widget) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + + w = MainWindow() + w.show() + app.exec_() diff --git a/examples/simple/simple.py b/examples/simple/simple.py index 529bfc1..20c6fd2 100644 --- a/examples/simple/simple.py +++ b/examples/simple/simple.py @@ -1,5 +1,3 @@ -import datetime -import logging import os import sys diff --git a/setup.py b/setup.py index 6ae6e74..2e0d0d6 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ import os import sys import shlex +import shutil import subprocess import glob @@ -141,7 +142,23 @@ class build_ext(sipdistutils.build_ext): def _find_sip(self): """override _find_sip to allow for manually speficied sip path.""" - return self.sip_bin or super()._find_sip() + + # 1. Manually specified sip_bin + if self.sip_bin: + return self.sip_bin + + # 2. Path determined from sipconfig.Configuration() + # This may not exist, depending on conda build configuration. + sip_bin = super()._find_sip() + if os.path.exists(sip_bin): + return sip_bin + + # 3. Finally, fall back to sip binary found in path + sip_bin = shutil.which('sip') + if sip_bin: + return sip_bin + + raise SystemExit('Could not find PyQt SIP binary.') def _sip_compile(self, sip_bin, source, sbf): cmd = [sip_bin] @@ -194,6 +211,8 @@ class build_ext(sipdistutils.build_ext): return super().swig_sources(sources, extension) def build_extension(self, ext): + # /usr/bin/rcc -name ads ../../Qt-Advanced-Docking-System/src/ads.qrc -o release/qrc_ads.cpp + cppsources = [source for source in ext.sources if source.endswith(".cpp")] dir_util.mkpath(self.build_temp, dry_run=self.dry_run) @@ -231,6 +250,17 @@ class build_ext(sipdistutils.build_ext): # Add the temp build directory to include path, for compiler to find # the created .moc files ext.include_dirs += [self._sip_output_dir()] + + # Run rcc on all resource files + resources = [source for source in ext.sources if source.endswith(".qrc")] + for source in resources: + ext.sources.remove(source) + out_file = os.path.join(self.build_temp, "qrc_" + os.path.basename(source).replace(".qrc", ".cpp")) + if newer(header, out_file) or self.force: + spawn.spawn(["rcc", "-name", os.path.splitext(os.path.basename(source))[0], source, "-o", out_file], dry_run=self.dry_run) + + if os.path.getsize(out_file) > 0: + ext.sources.append(out_file) sipdistutils.build_ext.build_extension(self, ext) @@ -262,9 +292,10 @@ class BuildPyCommand(build_py): setup_requires = ["PyQt5"] if REQUIRE_PYQT else [] cpp_sources = glob.glob(os.path.join('src', '*.cpp')) sip_sources = [os.path.join('sip', MODULE_NAME + '.sip')] +resources = [os.path.join('src', MODULE_NAME + '.qrc')] if sys.platform == 'linux': cpp_sources += glob.glob(os.path.join('src', 'linux', '*.cpp')) -ext_modules = [Extension('PyQtAds.QtAds.ads', cpp_sources + sip_sources)] +ext_modules = [Extension('PyQtAds.QtAds.ads', cpp_sources + sip_sources + resources)] install_requires = ["PyQt5"] if sys.platform == 'win32': diff --git a/sip/DockComponentsFactory.sip b/sip/DockComponentsFactory.sip index 139d84b..e227608 100644 --- a/sip/DockComponentsFactory.sip +++ b/sip/DockComponentsFactory.sip @@ -16,7 +16,7 @@ public: 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 setFactory(CDockComponentsFactory* Factory /KeepReference/); static void resetDefaultFactory(); }; diff --git a/sip/DockManager.sip b/sip/DockManager.sip index 19873e6..7a6d5e7 100644 --- a/sip/DockManager.sip +++ b/sip/DockManager.sip @@ -165,12 +165,12 @@ public: DockAreaDynamicTabsMenuButtonVisibility, FloatingContainerHasWidgetTitle, FloatingContainerHasWidgetIcon, + HideSingleCentralWidgetTitleBar, DefaultDockAreaButtons, DefaultBaseConfig, DefaultOpaqueConfig, DefaultNonOpaqueConfig, NonOpaqueWithWindowFrame, - HideSingleCentralWidgetTitleBar, }; typedef QFlags ConfigFlags; diff --git a/sip/DockWidgetTab.sip b/sip/DockWidgetTab.sip index f6c2453..d32a1d2 100644 --- a/sip/DockWidgetTab.sip +++ b/sip/DockWidgetTab.sip @@ -33,7 +33,7 @@ public: bool isTitleElided() const; bool isClosable() const; virtual bool event(QEvent *e); - + void setElideMode(Qt::TextElideMode mode); public slots: virtual void setVisible(bool visible); diff --git a/sip/ads_globals.sip b/sip/ads_globals.sip index 66b0dbe..ea78457 100644 --- a/sip/ads_globals.sip +++ b/sip/ads_globals.sip @@ -10,7 +10,7 @@ namespace ads enum eStateFileVersion { - InitialVerison, + InitialVersion, Version1, CurrentVersion }; From 115e67edc441c258b10d419ec38fd4ea798edcb5 Mon Sep 17 00:00:00 2001 From: Jan Krassnigg Date: Wed, 13 May 2020 16:40:43 +0200 Subject: [PATCH 3/5] Moved private classes into dedicated header --- src/DockAreaTitleBar.cpp | 1 + src/DockAreaTitleBar.h | 51 ---------------------- src/DockAreaTitleBar_p.h | 93 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 51 deletions(-) create mode 100644 src/DockAreaTitleBar_p.h diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 62e9877..aec4cc9 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -39,6 +39,7 @@ #include #include +#include "DockAreaTitleBar_p.h" #include "ads_globals.h" #include "FloatingDockContainer.h" #include "FloatingDragPreview.h" diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index 3efb8cc..2a4505f 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -31,7 +31,6 @@ // INCLUDES //============================================================================ #include -#include #include "ads_globals.h" @@ -157,56 +156,6 @@ signals: void tabBarClicked(int index); }; // class name -using tTitleBarButton = QToolButton; - - /** - * Title bar button of a dock area that customizes tTitleBarButton appearance/behaviour - * according to various config flags such as: - * CDockManager::DockAreaHas_xxx_Button - if set to 'false' keeps the button always invisible - * CDockManager::DockAreaHideDisabledButtons - if set to 'true' hides button when it is disabled - */ -class CTitleBarButton : public tTitleBarButton -{ - Q_OBJECT - - bool Visible = true; - bool HideWhenDisabled = false; - -public: - using Super = tTitleBarButton; - CTitleBarButton(bool visible = true, QWidget* parent = nullptr); - - /** - * Adjust this visibility change request with our internal settings: - */ - virtual void setVisible(bool visible) override; - -protected: - /** - * Handle EnabledChanged signal to set button invisible if the configured - */ - bool event(QEvent *ev) override; -}; - - -/** -* This spacer widget is here because of the following problem. -* The dock area title bar handles mouse dragging and moving the floating widget. -* The problem is, that if the title bar becomes invisible, i.e. if the dock -* area contains only one single dock widget and the dock area is moved -* into a floating widget, then mouse events are not handled anymore and dragging -* of the floating widget stops. -*/ -class CSpacerWidget : public QWidget -{ - Q_OBJECT -public: - using Super = QWidget; - CSpacerWidget(QWidget* Parent = 0); - virtual QSize sizeHint() const override {return QSize(0, 0);} - virtual QSize minimumSizeHint() const override {return QSize(0, 0);} -}; - } // namespace ads //----------------------------------------------------------------------------- diff --git a/src/DockAreaTitleBar_p.h b/src/DockAreaTitleBar_p.h new file mode 100644 index 0000000..c159de2 --- /dev/null +++ b/src/DockAreaTitleBar_p.h @@ -0,0 +1,93 @@ +#ifndef DockAreaTitleBarPH +#define DockAreaTitleBarPH +/******************************************************************************* +** Qt Advanced Docking System +** Copyright (C) 2017 Uwe Kindler +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this library; If not, see . +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaTitleBar_p.h +/// \author Uwe Kindler +/// \date 12.10.2018 +/// \brief Declaration of classes CTitleBarButton and CSpacerWidget +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include +#include + +#include "ads_globals.h" + +namespace ads +{ +using tTitleBarButton = QToolButton; + + /** + * Title bar button of a dock area that customizes tTitleBarButton appearance/behaviour + * according to various config flags such as: + * CDockManager::DockAreaHas_xxx_Button - if set to 'false' keeps the button always invisible + * CDockManager::DockAreaHideDisabledButtons - if set to 'true' hides button when it is disabled + */ +class CTitleBarButton : public tTitleBarButton +{ + Q_OBJECT + + bool Visible = true; + bool HideWhenDisabled = false; + +public: + using Super = tTitleBarButton; + CTitleBarButton(bool visible = true, QWidget* parent = nullptr); + + /** + * Adjust this visibility change request with our internal settings: + */ + virtual void setVisible(bool visible) override; + +protected: + /** + * Handle EnabledChanged signal to set button invisible if the configured + */ + bool event(QEvent *ev) override; +}; + + +/** +* This spacer widget is here because of the following problem. +* The dock area title bar handles mouse dragging and moving the floating widget. +* The problem is, that if the title bar becomes invisible, i.e. if the dock +* area contains only one single dock widget and the dock area is moved +* into a floating widget, then mouse events are not handled anymore and dragging +* of the floating widget stops. +*/ +class CSpacerWidget : public QWidget +{ + Q_OBJECT +public: + using Super = QWidget; + CSpacerWidget(QWidget* Parent = 0); + virtual QSize sizeHint() const override {return QSize(0, 0);} + virtual QSize minimumSizeHint() const override {return QSize(0, 0);} +}; + +} + // namespace ads +//----------------------------------------------------------------------------- +#endif // DockAreaTitleBarPH From 726d73b2c239818ed68c028f86a6094d902e64a3 Mon Sep 17 00:00:00 2001 From: Jan Krassnigg Date: Wed, 13 May 2020 16:47:43 +0200 Subject: [PATCH 4/5] Missing cmake change --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 73a0b10..a246a97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ set(ads_INSTALL_INCLUDE src/ads_globals.h src/DockAreaTabBar.h src/DockAreaTitleBar.h + src/DockAreaTitleBar_p.h src/DockAreaWidget.h src/DockContainerWidget.h src/DockManager.h From d418d92ef48a101e2f7eb789663a0f522fea0bd9 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 13 May 2020 16:57:36 +0200 Subject: [PATCH 5/5] Added missing DockAreaTitleBar_p.h to src.pro --- src/DockAreaTitleBar_p.h | 19 ++++++++++--------- src/src.pro | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/DockAreaTitleBar_p.h b/src/DockAreaTitleBar_p.h index c159de2..b94a510 100644 --- a/src/DockAreaTitleBar_p.h +++ b/src/DockAreaTitleBar_p.h @@ -1,5 +1,5 @@ -#ifndef DockAreaTitleBarPH -#define DockAreaTitleBarPH +#ifndef DockAreaTitleBar_pH +#define DockAreaTitleBar_pH /******************************************************************************* ** Qt Advanced Docking System ** Copyright (C) 2017 Uwe Kindler @@ -39,16 +39,17 @@ namespace ads { using tTitleBarButton = QToolButton; - /** - * Title bar button of a dock area that customizes tTitleBarButton appearance/behaviour - * according to various config flags such as: - * CDockManager::DockAreaHas_xxx_Button - if set to 'false' keeps the button always invisible - * CDockManager::DockAreaHideDisabledButtons - if set to 'true' hides button when it is disabled - */ +/** +* Title bar button of a dock area that customizes tTitleBarButton appearance/behaviour +* according to various config flags such as: +* CDockManager::DockAreaHas_xxx_Button - if set to 'false' keeps the button always invisible +* CDockManager::DockAreaHideDisabledButtons - if set to 'true' hides button when it is disabled +*/ class CTitleBarButton : public tTitleBarButton { Q_OBJECT +private: bool Visible = true; bool HideWhenDisabled = false; @@ -90,4 +91,4 @@ public: } // namespace ads //----------------------------------------------------------------------------- -#endif // DockAreaTitleBarPH +#endif // DockAreaTitleBar_pH diff --git a/src/src.pro b/src/src.pro index 73367b0..f117495 100644 --- a/src/src.pro +++ b/src/src.pro @@ -41,6 +41,7 @@ HEADERS += \ FloatingDragPreview.h \ DockOverlay.h \ DockSplitter.h \ + DockAreaTitleBar_p.h \ DockAreaTitleBar.h \ ElidingLabel.h \ IconProvider.h \