Revision: 76174 http://sourceforge.net/p/brlcad/code/76174 Author: starseeker Date: 2020-06-22 02:33:25 +0000 (Mon, 22 Jun 2020) Log Message: ----------- Replace QDockWidget with https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System for improved docking behavior. Still doesn't give us full top level windows when we undock, but the improved flexibility and feature set of this system looks like it will still be very much worthwhile.
Modified Paths: -------------- brlcad/branches/qtged/src/qged/CMakeLists.txt brlcad/branches/qtged/src/qged/TODO.qt brlcad/branches/qtged/src/qged/main.cxx brlcad/branches/qtged/src/qged/main_window.cxx brlcad/branches/qtged/src/qged/main_window.h Added Paths: ----------- brlcad/branches/qtged/src/qged/qtads/ brlcad/branches/qtged/src/qged/qtads/CMakeLists.txt brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.cpp brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.h brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.cpp brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.h brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar_p.h brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.cpp brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.h brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.cpp brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.h brlcad/branches/qtged/src/qged/qtads/DockContainerWidget.cpp brlcad/branches/qtged/src/qged/qtads/DockContainerWidget.h brlcad/branches/qtged/src/qged/qtads/DockFocusController.cpp brlcad/branches/qtged/src/qged/qtads/DockFocusController.h brlcad/branches/qtged/src/qged/qtads/DockManager.cpp brlcad/branches/qtged/src/qged/qtads/DockManager.h brlcad/branches/qtged/src/qged/qtads/DockOverlay.cpp brlcad/branches/qtged/src/qged/qtads/DockOverlay.h brlcad/branches/qtged/src/qged/qtads/DockSplitter.cpp brlcad/branches/qtged/src/qged/qtads/DockSplitter.h brlcad/branches/qtged/src/qged/qtads/DockWidget.cpp brlcad/branches/qtged/src/qged/qtads/DockWidget.h brlcad/branches/qtged/src/qged/qtads/DockWidgetTab.cpp brlcad/branches/qtged/src/qged/qtads/DockWidgetTab.h brlcad/branches/qtged/src/qged/qtads/DockingStateReader.cpp brlcad/branches/qtged/src/qged/qtads/DockingStateReader.h brlcad/branches/qtged/src/qged/qtads/ElidingLabel.cpp brlcad/branches/qtged/src/qged/qtads/ElidingLabel.h brlcad/branches/qtged/src/qged/qtads/FloatingDockContainer.cpp brlcad/branches/qtged/src/qged/qtads/FloatingDockContainer.h brlcad/branches/qtged/src/qged/qtads/FloatingDragPreview.cpp brlcad/branches/qtged/src/qged/qtads/FloatingDragPreview.h brlcad/branches/qtged/src/qged/qtads/IconProvider.cpp brlcad/branches/qtged/src/qged/qtads/IconProvider.h brlcad/branches/qtged/src/qged/qtads/LICENSE brlcad/branches/qtged/src/qged/qtads/README.md brlcad/branches/qtged/src/qged/qtads/ads.qrc brlcad/branches/qtged/src/qged/qtads/ads_globals.cpp brlcad/branches/qtged/src/qged/qtads/ads_globals.h brlcad/branches/qtged/src/qged/qtads/examples/ brlcad/branches/qtged/src/qged/qtads/examples/CMakeLists.txt brlcad/branches/qtged/src/qged/qtads/examples/deleteonclose/ brlcad/branches/qtged/src/qged/qtads/examples/deleteonclose/CMakeLists.txt brlcad/branches/qtged/src/qged/qtads/examples/deleteonclose/main.cpp brlcad/branches/qtged/src/qged/qtads/examples/demo/ brlcad/branches/qtged/src/qged/qtads/examples/demo/CMakeLists.txt brlcad/branches/qtged/src/qged/qtads/examples/demo/MainWindow.cpp brlcad/branches/qtged/src/qged/qtads/examples/demo/MainWindow.h brlcad/branches/qtged/src/qged/qtads/examples/demo/StatusDialog.cpp brlcad/branches/qtged/src/qged/qtads/examples/demo/StatusDialog.h brlcad/branches/qtged/src/qged/qtads/examples/demo/StatusDialog.ui brlcad/branches/qtged/src/qged/qtads/examples/demo/app.css brlcad/branches/qtged/src/qged/qtads/examples/demo/demo.qrc brlcad/branches/qtged/src/qged/qtads/examples/demo/images/ brlcad/branches/qtged/src/qged/qtads/examples/demo/images/create_floating_editor.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/create_floating_table.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/custom-menu-button.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/date_range.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/docked_editor.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/edit.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/folder.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/folder_open.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/fullscreen.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/grid_on.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/help_outline.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/material_icons_license.txt brlcad/branches/qtged/src/qged/qtads/examples/demo/images/note_add.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/picture_in_picture.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/plus.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/restore.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/images/save.svg brlcad/branches/qtged/src/qged/qtads/examples/demo/main.cpp brlcad/branches/qtged/src/qged/qtads/examples/demo/mainwindow.ui brlcad/branches/qtged/src/qged/qtads/examples/sidebar/ brlcad/branches/qtged/src/qged/qtads/examples/sidebar/CMakeLists.txt brlcad/branches/qtged/src/qged/qtads/examples/sidebar/MainWindow.cpp brlcad/branches/qtged/src/qged/qtads/examples/sidebar/MainWindow.h brlcad/branches/qtged/src/qged/qtads/examples/sidebar/MainWindow.ui brlcad/branches/qtged/src/qged/qtads/examples/sidebar/main.cpp brlcad/branches/qtged/src/qged/qtads/examples/simple/ brlcad/branches/qtged/src/qged/qtads/examples/simple/CMakeLists.txt brlcad/branches/qtged/src/qged/qtads/examples/simple/MainWindow.cpp brlcad/branches/qtged/src/qged/qtads/examples/simple/MainWindow.h brlcad/branches/qtged/src/qged/qtads/examples/simple/MainWindow.ui brlcad/branches/qtged/src/qged/qtads/examples/simple/main.cpp brlcad/branches/qtged/src/qged/qtads/images/ brlcad/branches/qtged/src/qged/qtads/images/close-button-disabled.svg brlcad/branches/qtged/src/qged/qtads/images/close-button-focused.svg brlcad/branches/qtged/src/qged/qtads/images/close-button.svg brlcad/branches/qtged/src/qged/qtads/images/detach-button-disabled.svg brlcad/branches/qtged/src/qged/qtads/images/detach-button.svg brlcad/branches/qtged/src/qged/qtads/images/tabs-menu-button.svg brlcad/branches/qtged/src/qged/qtads/linux/ brlcad/branches/qtged/src/qged/qtads/linux/FloatingWidgetTitleBar.cpp brlcad/branches/qtged/src/qged/qtads/linux/FloatingWidgetTitleBar.h brlcad/branches/qtged/src/qged/qtads/qtadvanceddockingConfig.cmake brlcad/branches/qtged/src/qged/qtads/stylesheets/ brlcad/branches/qtged/src/qged/qtads/stylesheets/default.css brlcad/branches/qtged/src/qged/qtads/stylesheets/default_linux.css brlcad/branches/qtged/src/qged/qtads/stylesheets/focus_highlighting.css brlcad/branches/qtged/src/qged/qtads/stylesheets/focus_highlighting_linux.css Modified: brlcad/branches/qtged/src/qged/CMakeLists.txt =================================================================== --- brlcad/branches/qtged/src/qged/CMakeLists.txt 2020-06-21 19:35:50 UTC (rev 76173) +++ brlcad/branches/qtged/src/qged/CMakeLists.txt 2020-06-22 02:33:25 UTC (rev 76174) @@ -13,6 +13,8 @@ add_definitions(${Qt5Widgets_DEFINITIONS}) endif(BRLCAD_ENABLE_QT) +add_subdirectory(qtads) + # NOTE: We can't use the CMake global values for automoc et. al. # because most of BRL-CAD's targets are not Qt targets. We don't # want to run the automatic moc logic for all of them. @@ -65,7 +67,7 @@ add_executable(qged ${qged_srcs} ${moc_srcs} ${cad_qrc}) qt5_use_modules(qged Widgets OpenGL) - target_link_libraries(qged libbu librt libged ${QT_LIBRARIES} ${OPENGL_LIBRARIES}) + target_link_libraries(qged libbu librt libged qtadvanceddocking ${QT_LIBRARIES} ${OPENGL_LIBRARIES}) target_compile_definitions(qged PRIVATE BRLCADBUILD HAVE_CONFIG_H) install(TARGETS qged RUNTIME DESTINATION ${BIN_DIR} Modified: brlcad/branches/qtged/src/qged/TODO.qt =================================================================== --- brlcad/branches/qtged/src/qged/TODO.qt 2020-06-21 19:35:50 UTC (rev 76173) +++ brlcad/branches/qtged/src/qged/TODO.qt 2020-06-22 02:33:25 UTC (rev 76174) @@ -19,12 +19,3 @@ https://doc.qt.io/qt-5/qml-qtquick-controls-treeview.html http://doc.qt.io/qt-5/qml-qtwebview-webview.html - - - -Look into replacing current window docking system with: - -https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System - -which (if I'm reading this right) would give us toplevel windows -when we undock, among other goodies. Modified: brlcad/branches/qtged/src/qged/main.cxx =================================================================== --- brlcad/branches/qtged/src/qged/main.cxx 2020-06-21 19:35:50 UTC (rev 76173) +++ brlcad/branches/qtged/src/qged/main.cxx 2020-06-22 02:33:25 UTC (rev 76174) @@ -93,7 +93,8 @@ } // TODO - this needs to be a setting that is saved and restored - mainWin.resize(1100, 800); + //mainWin.resize(1100, 800); + mainWin.restore_settings(); // Set up the command prompt's commands cad_register_commands(&app); Modified: brlcad/branches/qtged/src/qged/main_window.cxx =================================================================== --- brlcad/branches/qtged/src/qged/main_window.cxx 2020-06-21 19:35:50 UTC (rev 76173) +++ brlcad/branches/qtged/src/qged/main_window.cxx 2020-06-22 02:33:25 UTC (rev 76174) @@ -41,6 +41,10 @@ connect(cad_open, SIGNAL(triggered()), this, SLOT(open_file())); file_menu->addAction(cad_open); + cad_save_settings = new QAction("Save Settings", this); + connect(cad_save_settings, SIGNAL(triggered()), this, SLOT(save_settings())); + file_menu->addAction(cad_save_settings); + cad_exit = new QAction("Exit", this); connect(cad_exit, SIGNAL(triggered()), this, SLOT(close())); file_menu->addAction(cad_exit); @@ -51,41 +55,27 @@ help_menu = menuBar()->addMenu("Help"); - // Set up OpenGL canvas - canvas = new QGLWidget(); //TODO - will need to subclass this so libdm/libfb updates are done correctly - setCentralWidget(canvas); - // Define dock layout - console_dock = new QDockWidget("Console", this); - addDockWidget(Qt::BottomDockWidgetArea, console_dock); - console_dock->setAllowedAreas(Qt::BottomDockWidgetArea); - view_menu->addAction(console_dock->toggleViewAction()); + dock = new ads::CDockManager(this); - tree_dock = new QDockWidget("Hierarchy", this); - addDockWidget(Qt::LeftDockWidgetArea, tree_dock); - tree_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - view_menu->addAction(tree_dock->toggleViewAction()); + // Set up OpenGL canvas + view_dock = new ads::CDockWidget("Scene"); + view_menu->addAction(view_dock->toggleViewAction()); + canvas = new QGLWidget(); //TODO - will need to subclass this so libdm/libfb updates are done correctly + view_dock->setWidget(canvas); + dock->addDockWidget(ads::CenterDockWidgetArea, view_dock); - panel_dock = new QDockWidget("Edit Panel", this); - addDockWidget(Qt::RightDockWidgetArea, panel_dock); - panel_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - view_menu->addAction(panel_dock->toggleViewAction()); - - /* Because the console usually doesn't need a huge amount of - * horizontal space and the tree can use all the vertical space - * it can get, give the bottom corners to the left/right docks */ - setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); - setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); - - - /***** Create and add the widgets that inhabit the dock *****/ - /* Console */ + console_dock = new ads::CDockWidget("Console"); + view_menu->addAction(console_dock->toggleViewAction()); console = new CADConsole(console_dock); console_dock->setWidget(console); + dock->addDockWidget(ads::BottomDockWidgetArea, console_dock); - /* Geometry Tree */ + /* Geometry Tree */ + tree_dock = new ads::CDockWidget("Hierarchy"); + view_menu->addAction(tree_dock->toggleViewAction()); treemodel = new CADTreeModel(); treeview = new CADTreeView(tree_dock); tree_dock->setWidget(treeview); @@ -102,11 +92,17 @@ QObject::connect(treeview, SIGNAL(customContextMenuRequested(const QPoint&)), treeview, SLOT(context_menu(const QPoint&))); treemodel->populate(DBI_NULL); ((CADApp *)qApp)->cadtreeview = (CADTreeView *)treeview; + dock->addDockWidget(ads::LeftDockWidgetArea, tree_dock); /* Edit panel */ + panel_dock = new ads::CDockWidget("Edit Panel"); + view_menu->addAction(panel_dock->toggleViewAction()); panel = new CADAccordion(panel_dock); panel_dock->setWidget(panel); + dock->addDockWidget(ads::RightDockWidgetArea, panel_dock); + /***** Create and add the widgets that inhabit the dock *****/ + //stdpropview->setMinimumHeight(340); QObject::connect(treeview, SIGNAL(clicked(const QModelIndex &)), panel->stdpropmodel, SLOT(refresh(const QModelIndex &))); @@ -154,6 +150,26 @@ } } +void +BRLCAD_MainWindow::save_settings() +{ + QSettings Settings("Settings.ini", QSettings::IniFormat); + Settings.setValue("mainWindow/Geometry", this->saveGeometry()); + Settings.setValue("mainWindow/State", this->saveState()); + Settings.setValue("mainWindow/DockingState", dock->saveState()); +} + +void +BRLCAD_MainWindow::restore_settings() +{ + if (bu_file_exists("Settings.ini", NULL)) { + QSettings Settings("Settings.ini", QSettings::IniFormat); + this->restoreGeometry(Settings.value("mainWindow/Geometry").toByteArray()); + this->restoreState(Settings.value("mainWindow/State").toByteArray()); + dock->restoreState(Settings.value("mainWindow/DockingState").toByteArray()); + } +} + /* * Local Variables: * mode: C++ Modified: brlcad/branches/qtged/src/qged/main_window.h =================================================================== --- brlcad/branches/qtged/src/qged/main_window.h 2020-06-21 19:35:50 UTC (rev 76173) +++ brlcad/branches/qtged/src/qged/main_window.h 2020-06-22 02:33:25 UTC (rev 76174) @@ -47,8 +47,6 @@ #undef Success #include <QGLWidget> #undef Success -#include <QDockWidget> //TODO - this will need to be replaced with a customized version that makes detached windows full toplevel windows -#undef Success #include <QMenu> #undef Success #include <QMenuBar> @@ -71,6 +69,7 @@ # pragma clang diagnostic pop #endif +#include "qtads/DockManager.h" #include "cadconsole.h" #include "cadtreemodel.h" #include "cadaccordion.h" @@ -80,22 +79,28 @@ Q_OBJECT public: BRLCAD_MainWindow(); + void restore_settings(); QGLWidget *canvas; private slots: void open_file(); + void save_settings(); private: QMenu *file_menu; QAction *cad_open; + QAction *cad_save_settings; + QAction *cad_restore_settings; QAction *cad_exit; QMenu *view_menu; QMenu *help_menu; - QDockWidget *console_dock; - QDockWidget *tree_dock; - QDockWidget *panel_dock; + ads::CDockManager *dock; + ads::CDockWidget *view_dock; + ads::CDockWidget *console_dock; + ads::CDockWidget *tree_dock; + ads::CDockWidget *panel_dock; CADConsole *console; CADTreeModel *treemodel; Added: brlcad/branches/qtged/src/qged/qtads/CMakeLists.txt =================================================================== --- brlcad/branches/qtged/src/qged/qtads/CMakeLists.txt (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/CMakeLists.txt 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,101 @@ +find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(ads_SRCS + ads_globals.cpp + DockAreaTabBar.cpp + DockAreaTitleBar.cpp + DockAreaWidget.cpp + DockContainerWidget.cpp + DockManager.cpp + DockOverlay.cpp + DockSplitter.cpp + DockWidget.cpp + DockWidgetTab.cpp + DockingStateReader.cpp + DockFocusController.cpp + ElidingLabel.cpp + FloatingDockContainer.cpp + FloatingDragPreview.cpp + IconProvider.cpp + DockComponentsFactory.cpp + ads.qrc +) +set(ads_HEADERS + ads_globals.h + DockAreaTabBar.h + DockAreaTitleBar.h + DockAreaTitleBar_p.h + DockAreaWidget.h + DockContainerWidget.h + DockManager.h + DockOverlay.h + DockSplitter.h + DockWidget.h + DockWidgetTab.h + DockingStateReader.h + DockFocusController.h + ElidingLabel.h + FloatingDockContainer.h + FloatingDragPreview.h + IconProvider.h + DockComponentsFactory.h +) +if (UNIX) + set(ads_SRCS linux/FloatingWidgetTitleBar.cpp ${ads_SRCS}) + set(ads_HEADERS linux/FloatingWidgetTitleBar.h ${ads_HEADERS}) +endif() +if(BUILD_STATIC) + add_library(qtadvanceddocking STATIC ${ads_SRCS} ${ads_HEADERS}) + target_compile_definitions(qtadvanceddocking PUBLIC ADS_STATIC) +else() + add_library(qtadvanceddocking SHARED ${ads_SRCS} ${ads_HEADERS}) + target_compile_definitions(qtadvanceddocking PRIVATE ADS_SHARED_EXPORT) +endif() +target_link_libraries(qtadvanceddocking PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets) +set_target_properties(qtadvanceddocking PROPERTIES + AUTOMOC ON + AUTORCC ON + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF + VERSION 1 + EXPORT_NAME "qtadvanceddocking" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin" +) +include(CMakePackageConfigHelpers) +install(FILES ${ads_HEADERS} + DESTINATION include + COMPONENT headers +) +install(FILES + "${CMAKE_SOURCE_DIR}/LICENSE" + "${CMAKE_SOURCE_DIR}/gnu-lgpl-v2.1.md" + DESTINATION license + COMPONENT license +) +install(TARGETS qtadvanceddocking + EXPORT adsTargets + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + INCLUDES DESTINATION include +) + +install(EXPORT adsTargets + FILE adsTargets.cmake + NAMESPACE ads:: + DESTINATION lib/cmake/qtadvanceddocking +) +install(FILES qtadvanceddockingConfig.cmake "${CMAKE_CURRENT_BINARY_DIR}/qtadvanceddockingConfigVersion.cmake" + DESTINATION lib/cmake/qtadvanceddocking +) + +target_include_directories(qtadvanceddocking PUBLIC + $<INSTALL_INTERFACE:include> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> +) + +add_subdirectory(examples) Property changes on: brlcad/branches/qtged/src/qged/qtads/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.cpp =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.cpp (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.cpp 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,498 @@ +/******************************************************************************* +** 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 <http://www.gnu.org/licenses/>. +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaTabBar.cpp +/// \author Uwe Kindler +/// \date 24.08.2018 +/// \brief Implementation of CDockAreaTabBar class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "FloatingDragPreview.h" +#include "DockAreaTabBar.h" + +#include <QMouseEvent> +#include <QScrollBar> +#include <QDebug> +#include <QBoxLayout> +#include <QApplication> +#include <QtGlobal> + +#include "FloatingDockContainer.h" +#include "DockAreaWidget.h" +#include "DockOverlay.h" +#include "DockManager.h" +#include "DockWidget.h" +#include "DockWidgetTab.h" + +#include <iostream> + + +namespace ads +{ +/** + * Private data class of CDockAreaTabBar class (pimpl) + */ +struct DockAreaTabBarPrivate +{ + CDockAreaTabBar* _this; + CDockAreaWidget* DockArea; + QWidget* TabsContainerWidget; + QBoxLayout* TabsLayout; + int CurrentIndex = -1; + + /** + * Private data constructor + */ + DockAreaTabBarPrivate(CDockAreaTabBar* _public); + + /** + * Update tabs after current index changed or when tabs are removed. + * 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 + +//============================================================================ +DockAreaTabBarPrivate::DockAreaTabBarPrivate(CDockAreaTabBar* _public) : + _this(_public) +{ + +} + + +//============================================================================ +void DockAreaTabBarPrivate::updateTabs() +{ + // Set active TAB and update all other tabs to be inactive + for (int i = 0; i < _this->count(); ++i) + { + auto TabWidget = _this->tab(i); + if (!TabWidget) + { + continue; + } + + if (i == CurrentIndex) + { + TabWidget->show(); + TabWidget->setActiveTab(true); + _this->ensureWidgetVisible(TabWidget); + } + else + { + TabWidget->setActiveTab(false); + } + } +} + + +//============================================================================ +CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) : + QScrollArea(parent), + d(new DockAreaTabBarPrivate(this)) +{ + d->DockArea = parent; + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + setFrameStyle(QFrame::NoFrame); + setWidgetResizable(true); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + d->TabsContainerWidget = new QWidget(); + d->TabsContainerWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + d->TabsContainerWidget->setObjectName("tabsContainerWidget"); + d->TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight); + d->TabsLayout->setContentsMargins(0, 0, 0, 0); + d->TabsLayout->setSpacing(0); + d->TabsLayout->addStretch(1); + d->TabsContainerWidget->setLayout(d->TabsLayout); + setWidget(d->TabsContainerWidget); +} + + +//============================================================================ +CDockAreaTabBar::~CDockAreaTabBar() +{ + delete d; +} + + +//============================================================================ +void CDockAreaTabBar::wheelEvent(QWheelEvent* Event) +{ + Event->accept(); + const int direction = Event->angleDelta().y(); + if (direction < 0) + { + horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20); + } + else + { + horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20); + } +} + + +//============================================================================ +void CDockAreaTabBar::setCurrentIndex(int index) +{ + if (index == d->CurrentIndex) + { + return; + } + + if (index < -1 || index > (count() - 1)) + { + qWarning() << Q_FUNC_INFO << "Invalid index" << index; + return; + } + + emit currentChanging(index); + d->CurrentIndex = index; + d->updateTabs(); + updateGeometry(); + emit currentChanged(index); +} + + +//============================================================================ +int CDockAreaTabBar::count() const +{ + // The tab bar contains a stretch item as last item + return d->TabsLayout->count() - 1; +} + + +//=========================================================================== +void CDockAreaTabBar::insertTab(int Index, CDockWidgetTab* Tab) +{ + d->TabsLayout->insertWidget(Index, Tab); + connect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked())); + connect(Tab, SIGNAL(closeRequested()), this, SLOT(onTabCloseRequested())); + connect(Tab, SIGNAL(closeOtherTabsRequested()), this, SLOT(onCloseOtherTabsRequested())); + connect(Tab, SIGNAL(moved(const QPoint&)), this, SLOT(onTabWidgetMoved(const QPoint&))); + connect(Tab, SIGNAL(elidedChanged(bool)), this, SIGNAL(elidedChanged(bool))); + Tab->installEventFilter(this); + emit tabInserted(Index); + if (Index <= d->CurrentIndex) + { + setCurrentIndex(d->CurrentIndex + 1); + } + else if (d->CurrentIndex == -1) + { + setCurrentIndex(Index); + } + + updateGeometry(); +} + + +//=========================================================================== +void CDockAreaTabBar::removeTab(CDockWidgetTab* Tab) +{ + if (!count()) + { + return; + } + ADS_PRINT("CDockAreaTabBar::removeTab "); + int NewCurrentIndex = currentIndex(); + int RemoveIndex = d->TabsLayout->indexOf(Tab); + if (count() == 1) + { + NewCurrentIndex = -1; + } + if (NewCurrentIndex > RemoveIndex) + { + NewCurrentIndex--; + } + else if (NewCurrentIndex == RemoveIndex) + { + NewCurrentIndex = -1; + // First we walk to the right to search for the next visible tab + for (int i = (RemoveIndex + 1); i < count(); ++i) + { + if (tab(i)->isVisibleTo(this)) + { + NewCurrentIndex = i - 1; + break; + } + } + + // If there is no visible tab right to this tab then we walk to + // the left to find a visible tab + if (NewCurrentIndex < 0) + { + for (int i = (RemoveIndex - 1); i >= 0; --i) + { + if (tab(i)->isVisibleTo(this)) + { + NewCurrentIndex = i; + break; + } + } + } + } + + emit removingTab(RemoveIndex); + d->TabsLayout->removeWidget(Tab); + Tab->disconnect(this); + Tab->removeEventFilter(this); + ADS_PRINT("NewCurrentIndex " << NewCurrentIndex); + if (NewCurrentIndex != d->CurrentIndex) + { + setCurrentIndex(NewCurrentIndex); + } + else + { + d->updateTabs(); + } + + updateGeometry(); +} + + +//=========================================================================== +int CDockAreaTabBar::currentIndex() const +{ + return d->CurrentIndex; +} + + +//=========================================================================== +CDockWidgetTab* CDockAreaTabBar::currentTab() const +{ + if (d->CurrentIndex < 0) + { + return nullptr; + } + else + { + return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(d->CurrentIndex)->widget()); + } +} + + +//=========================================================================== +void CDockAreaTabBar::onTabClicked() +{ + CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender()); + if (!Tab) + { + return; + } + + int index = d->TabsLayout->indexOf(Tab); + if (index < 0) + { + return; + } + setCurrentIndex(index); + emit tabBarClicked(index); +} + + +//=========================================================================== +void CDockAreaTabBar::onTabCloseRequested() +{ + CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender()); + int Index = d->TabsLayout->indexOf(Tab); + closeTab(Index); +} + + +//=========================================================================== +void CDockAreaTabBar::onCloseOtherTabsRequested() +{ + auto Sender = qobject_cast<CDockWidgetTab*>(sender()); + for (int i = 0; i < count(); ++i) + { + auto Tab = tab(i); + if (Tab->isClosable() && !Tab->isHidden() && Tab != Sender) + { + // If the dock widget is deleted with the closeTab() call, its tab + // it will no longer be in the layout, and thus the index needs to + // be updated to not skip any tabs + int Offset = Tab->dockWidget()->features().testFlag( + CDockWidget::DockWidgetDeleteOnClose) ? 1 : 0; + closeTab(i); + + // If the the dock widget blocks closing, i.e. if the flag + // CustomCloseHandling is set, and the dock widget is still open, + // then we do not need to correct the index + if (Tab->dockWidget()->isClosed()) + { + i -= Offset; + } + } + } +} + + +//=========================================================================== +CDockWidgetTab* CDockAreaTabBar::tab(int Index) const +{ + if (Index >= count() || Index < 0) + { + return nullptr; + } + return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(Index)->widget()); +} + + +//=========================================================================== +void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos) +{ + CDockWidgetTab* MovingTab = qobject_cast<CDockWidgetTab*>(sender()); + if (!MovingTab) + { + return; + } + + 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) + { + CDockWidgetTab* DropTab = tab(i); + if (DropTab == MovingTab || !DropTab->isVisibleTo(this) + || !DropTab->geometry().contains(MousePos)) + { + continue; + } + + toIndex = d->TabsLayout->indexOf(DropTab); + if (toIndex == fromIndex) + { + toIndex = -1; + } + break; + } + + 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(); + } +} + +//=========================================================================== +void CDockAreaTabBar::closeTab(int Index) +{ + if (Index < 0 || Index >= count()) + { + return; + } + + auto Tab = tab(Index); + if (Tab->isHidden()) + { + return; + } + emit tabCloseRequested(Index); +} + + +//=========================================================================== +bool CDockAreaTabBar::eventFilter(QObject *watched, QEvent *event) +{ + bool Result = Super::eventFilter(watched, event); + CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(watched); + if (!Tab) + { + return Result; + } + + switch (event->type()) + { + case QEvent::Hide: + emit tabClosed(d->TabsLayout->indexOf(Tab)); + updateGeometry(); + break; + + case QEvent::Show: + emit tabOpened(d->TabsLayout->indexOf(Tab)); + updateGeometry(); + break; + + default: + break; + } + + return Result; +} + + +//=========================================================================== +bool CDockAreaTabBar::isTabOpen(int Index) const +{ + if (Index < 0 || Index >= count()) + { + return false; + } + + return !tab(Index)->isHidden(); +} + + +//=========================================================================== +QSize CDockAreaTabBar::minimumSizeHint() const +{ + QSize Size = sizeHint(); + Size.setWidth(10); + return Size; +} + + +//=========================================================================== +QSize CDockAreaTabBar::sizeHint() const +{ + return d->TabsContainerWidget->sizeHint(); +} + +} // namespace ads + + +//--------------------------------------------------------------------------- +// EOF DockAreaTabBar.cpp Property changes on: brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.h =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.h (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.h 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,215 @@ +#ifndef DockAreaTabBarH +#define DockAreaTabBarH +/******************************************************************************* +** 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 <http://www.gnu.org/licenses/>. +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaTabBar.h +/// \author Uwe Kindler +/// \date 24.08.2018 +/// \brief Declaration of CDockAreaTabBar class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include <QScrollArea> +#include "ads_globals.h" + +namespace ads +{ +class CDockAreaWidget; +class CDockWidgetTab; +struct DockAreaTabBarPrivate; +class CDockAreaTitleBar; +class CFloatingDockContainer; +class IFloatingWidget; + +/** + * Custom tabbar implementation for tab area that is shown on top of a + * dock area widget. + * The tabbar displays the tab widgets of the contained dock widgets. + * We cannot use QTabBar here because it does a lot of fancy animations + * that will crash the application if a tab is removed while the animation + * has not finished. And we need to remove a tab, if the user drags a + * a dock widget out of a group of tabbed widgets + */ +class ADS_EXPORT CDockAreaTabBar : public QScrollArea +{ + Q_OBJECT +private: + DockAreaTabBarPrivate* d; ///< private data (pimpl) + friend struct DockAreaTabBarPrivate; + friend class CDockAreaTitleBar; + +private slots: + void onTabClicked(); + void onTabCloseRequested(); + void onCloseOtherTabsRequested(); + void onTabWidgetMoved(const QPoint& GlobalPos); + +protected: + virtual void wheelEvent(QWheelEvent* Event) override; + + +public: + using Super = QScrollArea; + + /** + * Default Constructor + */ + CDockAreaTabBar(CDockAreaWidget* parent); + + /** + * Virtual Destructor + */ + virtual ~CDockAreaTabBar(); + + /** + * Inserts the given dock widget tab at the given position. + * Inserting a new tab at an index less than or equal to the current index + * will increment the current index, but keep the current tab. + */ + void insertTab(int Index, CDockWidgetTab* Tab); + + /** + * Removes the given DockWidgetTab from the tabbar + */ + void removeTab(CDockWidgetTab* Tab); + + /** + * Returns the number of tabs in this tabbar + */ + int count() const; + + /** + * Returns the current index or -1 if no tab is selected + */ + int currentIndex() const; + + /** + * Returns the current tab or a nullptr if no tab is selected. + */ + CDockWidgetTab* currentTab() const; + + /** + * Returns the tab with the given index + */ + CDockWidgetTab* tab(int Index) const; + + /** + * Filters the tab widget events + */ + virtual bool eventFilter(QObject *watched, QEvent *event) override; + + /** + * This function returns true if the tab is open, that means if it is + * visible to the user. If the function returns false, the tab is + * closed + */ + bool isTabOpen(int Index) const; + + /** + * Overrides the minimumSizeHint() function of QScrollArea + * The minimumSizeHint() is bigger than the sizeHint () for the scroll + * area because even if the scrollbars are invisible, the required speace + * is reserved in the minimumSizeHint(). This override simply returns + * sizeHint(); + */ + virtual QSize minimumSizeHint() const override; + + /** + * The function provides a sizeHint that matches the height of the + * internal viewport. + */ + virtual QSize sizeHint() const override; + +public slots: + /** + * This property sets the index of the tab bar's visible tab + */ + void setCurrentIndex(int Index); + + /** + * This function will close the tab given in Index param. + * Closing a tab means, the tab will be hidden, it will not be removed + */ + void closeTab(int Index); + +signals: + /** + * This signal is emitted when the tab bar's current tab is about to be changed. The new + * current has the given index, or -1 if there isn't a new one. + */ + void currentChanging(int Index); + + /** + * This signal is emitted when the tab bar's current tab changes. The new + * current has the given index, or -1 if there isn't a new one + */ + void currentChanged(int Index); + + /** + * This signal is emitted when user clicks on a tab + */ + void tabBarClicked(int index); + + /** + * This signal is emitted when the close button on a tab is clicked. + * The index is the index that should be closed. + */ + void tabCloseRequested(int index); + + /** + * This signal is emitted if a tab has been closed + */ + void tabClosed(int index); + + /** + * This signal is emitted if a tab has been opened. + * A tab is opened if it has been made visible + */ + void tabOpened(int index); + + /** + * This signal is emitted when the tab has moved the tab at index position + * from to index position to. + */ + void tabMoved(int from, int to); + + /** + * This signal is emitted, just before the tab with the given index is + * removed + */ + void removingTab(int index); + + /** + * This signal is emitted if a tab has been inserted + */ + void tabInserted(int index); + + /** + * This signal is emitted when a tab title elide state has been changed + */ + void elidedChanged(bool elided); +}; // class CDockAreaTabBar +} // namespace ads +//----------------------------------------------------------------------------- +#endif // DockAreaTabBarH + Property changes on: brlcad/branches/qtged/src/qged/qtads/DockAreaTabBar.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.cpp =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.cpp (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.cpp 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,650 @@ +/******************************************************************************* +** 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 <http://www.gnu.org/licenses/>. +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaTitleBar.cpp +/// \author Uwe Kindler +/// \date 12.10.2018 +/// \brief Implementation of CDockAreaTitleBar class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "DockAreaTitleBar.h" + +#include <QPushButton> +#include <QToolButton> +#include <QBoxLayout> +#include <QStyle> +#include <QMenu> +#include <QScrollArea> +#include <QMouseEvent> +#include <QDebug> +#include <QPointer> + +#include "DockAreaTitleBar_p.h" +#include "ads_globals.h" +#include "FloatingDockContainer.h" +#include "FloatingDragPreview.h" +#include "DockAreaWidget.h" +#include "DockOverlay.h" +#include "DockManager.h" +#include "DockWidget.h" +#include "DockWidgetTab.h" +#include "DockAreaTabBar.h" +#include "IconProvider.h" +#include "DockComponentsFactory.h" + +#include <iostream> + +namespace ads +{ + +/** + * Private data class of CDockAreaTitleBar class (pimpl) + */ +struct DockAreaTitleBarPrivate +{ + CDockAreaTitleBar* _this; + QPointer<tTitleBarButton> TabsMenuButton; + QPointer<tTitleBarButton> UndockButton; + QPointer<tTitleBarButton> CloseButton; + QBoxLayout* Layout; + CDockAreaWidget* DockArea; + CDockAreaTabBar* TabBar; + bool MenuOutdated = true; + QMenu* TabsMenu; + QList<tTitleBarButton*> DockWidgetActionsButtons; + + QPoint DragStartMousePos; + eDragState DragState = DraggingInactive; + IFloatingWidget* FloatingWidget = nullptr; + + + /** + * Private data constructor + */ + DockAreaTitleBarPrivate(CDockAreaTitleBar* _public); + + /** + * Creates the title bar close and menu buttons + */ + void createButtons(); + + /** + * Creates the internal TabBar + */ + void createTabBar(); + + /** + * Convenience function for DockManager access + */ + CDockManager* dockManager() const + { + return DockArea->dockManager(); + } + + /** + * Returns true if the given config flag is set + * Convenience function to ease config flag testing + */ + static bool testConfigFlag(CDockManager::eConfigFlag Flag) + { + return CDockManager::testConfigFlag(Flag); + } + + /** + * Test function for current drag state + */ + bool isDraggingState(eDragState dragState) const + { + return this->DragState == dragState; + } + + + /** + * Starts floating + */ + void startFloating(const QPoint& Offset); + + /** + * Makes the dock area floating + */ + IFloatingWidget* makeAreaFloating(const QPoint& Offset, eDragState DragState); +};// struct DockAreaTitleBarPrivate + +//============================================================================ +DockAreaTitleBarPrivate::DockAreaTitleBarPrivate(CDockAreaTitleBar* _public) : + _this(_public) +{ + +} + + +//============================================================================ +void DockAreaTitleBarPrivate::createButtons() +{ + QSizePolicy ButtonSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + + // Tabs menu button + TabsMenuButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasTabsMenuButton)); + TabsMenuButton->setObjectName("tabsMenuButton"); + TabsMenuButton->setAutoRaise(true); + TabsMenuButton->setPopupMode(QToolButton::InstantPopup); + internal::setButtonIcon(TabsMenuButton, QStyle::SP_TitleBarUnshadeButton, ads::DockAreaMenuIcon); + QMenu* LTabsMenu = new QMenu(TabsMenuButton); +#ifndef QT_NO_TOOLTIP + LTabsMenu->setToolTipsVisible(true); +#endif + _this->connect(LTabsMenu, SIGNAL(aboutToShow()), SLOT(onTabsMenuAboutToShow())); + TabsMenuButton->setMenu(LTabsMenu); + internal::setToolTip(TabsMenuButton, QObject::tr("List All Tabs")); + TabsMenuButton->setSizePolicy(ButtonSizePolicy); + Layout->addWidget(TabsMenuButton, 0); + _this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)), + SLOT(onTabsMenuActionTriggered(QAction*))); + + // Undock button + UndockButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasUndockButton)); + UndockButton->setObjectName("detachGroupButton"); + UndockButton->setAutoRaise(true); + internal::setToolTip(UndockButton, QObject::tr("Detach Group")); + internal::setButtonIcon(UndockButton, QStyle::SP_TitleBarNormalButton, ads::DockAreaUndockIcon); + UndockButton->setSizePolicy(ButtonSizePolicy); + Layout->addWidget(UndockButton, 0); + _this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked())); + + // Close button + CloseButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasCloseButton)); + CloseButton->setObjectName("dockAreaCloseButton"); + CloseButton->setAutoRaise(true); + internal::setButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, ads::DockAreaCloseIcon); + if (testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab)) + { + internal::setToolTip(CloseButton, QObject::tr("Close Active Tab")); + } + else + { + internal::setToolTip(CloseButton, QObject::tr("Close Group")); + } + CloseButton->setSizePolicy(ButtonSizePolicy); + CloseButton->setIconSize(QSize(16, 16)); + Layout->addWidget(CloseButton, 0); + _this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked())); +} + + +//============================================================================ +void DockAreaTitleBarPrivate::createTabBar() +{ + TabBar = componentsFactory()->createDockAreaTabBar(DockArea); + TabBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + Layout->addWidget(TabBar); + _this->connect(TabBar, SIGNAL(tabClosed(int)), SLOT(markTabsMenuOutdated())); + _this->connect(TabBar, SIGNAL(tabOpened(int)), SLOT(markTabsMenuOutdated())); + _this->connect(TabBar, SIGNAL(tabInserted(int)), SLOT(markTabsMenuOutdated())); + _this->connect(TabBar, SIGNAL(removingTab(int)), SLOT(markTabsMenuOutdated())); + _this->connect(TabBar, SIGNAL(tabMoved(int, int)), SLOT(markTabsMenuOutdated())); + _this->connect(TabBar, SIGNAL(currentChanged(int)), SLOT(onCurrentTabChanged(int))); + _this->connect(TabBar, SIGNAL(tabBarClicked(int)), SIGNAL(tabBarClicked(int))); + _this->connect(TabBar, SIGNAL(elidedChanged(bool)), SLOT(markTabsMenuOutdated())); +} + + +//============================================================================ +IFloatingWidget* DockAreaTitleBarPrivate::makeAreaFloating(const QPoint& Offset, eDragState LDragState) +{ + QSize Size = DockArea->size(); + this->DragState = LDragState; + bool OpaqueUndocking = CDockManager::testConfigFlag(CDockManager::OpaqueUndocking) || + (DraggingFloatingWidget != LDragState); + CFloatingDockContainer* FloatingDockContainer = nullptr; + IFloatingWidget* LFloatingWidget; + if (OpaqueUndocking) + { + LFloatingWidget = FloatingDockContainer = new CFloatingDockContainer(DockArea); + } + else + { + auto w = new CFloatingDragPreview(DockArea); + QObject::connect(w, &CFloatingDragPreview::draggingCanceled, [=]() + { + this->DragState = DraggingInactive; + }); + LFloatingWidget = w; + } + + LFloatingWidget->startFloating(Offset, Size, LDragState, nullptr); + if (FloatingDockContainer) + { + auto TopLevelDockWidget = FloatingDockContainer->topLevelDockWidget(); + if (TopLevelDockWidget) + { + TopLevelDockWidget->emitTopLevelChanged(true); + } + } + + return LFloatingWidget; +} + + +//============================================================================ +void DockAreaTitleBarPrivate::startFloating(const QPoint& Offset) +{ + FloatingWidget = makeAreaFloating(Offset, DraggingFloatingWidget); +} + + +//============================================================================ +CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) : + QFrame(parent), + d(new DockAreaTitleBarPrivate(this)) +{ + d->DockArea = parent; + + setObjectName("dockAreaTitleBar"); + d->Layout = new QBoxLayout(QBoxLayout::LeftToRight); + d->Layout->setContentsMargins(0, 0, 0, 0); + d->Layout->setSpacing(0); + setLayout(d->Layout); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + + d->createTabBar(); + d->Layout->addWidget(new CSpacerWidget(this)); + d->createButtons(); +} + + +//============================================================================ +CDockAreaTitleBar::~CDockAreaTitleBar() +{ + if (!d->CloseButton.isNull()) + { + delete d->CloseButton; + } + + if (!d->TabsMenuButton.isNull()) + { + delete d->TabsMenuButton; + } + + if (!d->UndockButton.isNull()) + { + delete d->UndockButton; + } + delete d; +} + + +//============================================================================ +CDockAreaTabBar* CDockAreaTitleBar::tabBar() const +{ + return d->TabBar; +} + +//============================================================================ +void CDockAreaTitleBar::markTabsMenuOutdated() +{ + if(DockAreaTitleBarPrivate::testConfigFlag(CDockManager::DockAreaDynamicTabsMenuButtonVisibility)) + { + bool hasElidedTabTitle = false; + for (int i = 0; i < d->TabBar->count(); ++i) + { + if (!d->TabBar->isTabOpen(i)) + { + continue; + } + CDockWidgetTab* Tab = d->TabBar->tab(i); + if(Tab->isTitleElided()) + { + hasElidedTabTitle = true; + break; + } + } + bool visible = (hasElidedTabTitle && (d->TabBar->count() > 1)); + QMetaObject::invokeMethod(d->TabsMenuButton, "setVisible", Qt::QueuedConnection, Q_ARG(bool, visible)); + } + d->MenuOutdated = true; +} + +//============================================================================ +void CDockAreaTitleBar::onTabsMenuAboutToShow() +{ + if (!d->MenuOutdated) + { + return; + } + + QMenu* menu = d->TabsMenuButton->menu(); + menu->clear(); + for (int i = 0; i < d->TabBar->count(); ++i) + { + if (!d->TabBar->isTabOpen(i)) + { + continue; + } + auto Tab = d->TabBar->tab(i); + QAction* Action = menu->addAction(Tab->icon(), Tab->text()); + internal::setToolTip(Action, Tab->toolTip()); + Action->setData(i); + } + + d->MenuOutdated = false; +} + + +//============================================================================ +void CDockAreaTitleBar::onCloseButtonClicked() +{ + ADS_PRINT("CDockAreaTitleBar::onCloseButtonClicked"); + if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab)) + { + d->TabBar->closeTab(d->TabBar->currentIndex()); + } + else + { + d->DockArea->closeArea(); + } +} + + +//============================================================================ +void CDockAreaTitleBar::onUndockButtonClicked() +{ + if (d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)) + { + d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive); + } +} + + +//============================================================================ +void CDockAreaTitleBar::onTabsMenuActionTriggered(QAction* Action) +{ + int Index = Action->data().toInt(); + d->TabBar->setCurrentIndex(Index); + emit tabBarClicked(Index); +} + + +//============================================================================ +void CDockAreaTitleBar::updateDockWidgetActionsButtons() +{ + CDockWidget* DockWidget = d->TabBar->currentTab()->dockWidget(); + if (!d->DockWidgetActionsButtons.isEmpty()) + { + for (auto Button : d->DockWidgetActionsButtons) + { + d->Layout->removeWidget(Button); + delete Button; + } + d->DockWidgetActionsButtons.clear(); + } + + auto Actions = DockWidget->titleBarActions(); + if (Actions.isEmpty()) + { + return; + } + + int InsertIndex = indexOf(d->TabsMenuButton); + for (auto Action : Actions) + { + auto Button = new CTitleBarButton(true, this); + Button->setDefaultAction(Action); + Button->setAutoRaise(true); + Button->setPopupMode(QToolButton::InstantPopup); + Button->setObjectName(Action->objectName()); + d->Layout->insertWidget(InsertIndex++, Button, 0); + d->DockWidgetActionsButtons.append(Button); + } +} + + +//============================================================================ +void CDockAreaTitleBar::onCurrentTabChanged(int Index) +{ + if (Index < 0) + { + return; + } + + if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab)) + { + CDockWidget* DockWidget = d->TabBar->tab(Index)->dockWidget(); + d->CloseButton->setEnabled(DockWidget->features().testFlag(CDockWidget::DockWidgetClosable)); + } + + updateDockWidgetActionsButtons(); +} + + +//============================================================================ +QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const +{ + switch (which) + { + case TitleBarButtonTabsMenu: return d->TabsMenuButton; + case TitleBarButtonUndock: return d->UndockButton; + case TitleBarButtonClose: return d->CloseButton; + default: + return nullptr; + } +} + + +//============================================================================ +void CDockAreaTitleBar::setVisible(bool Visible) +{ + Super::setVisible(Visible); + markTabsMenuOutdated(); +} + + +//============================================================================ +void CDockAreaTitleBar::mousePressEvent(QMouseEvent* ev) +{ + if (ev->button() == Qt::LeftButton) + { + ev->accept(); + d->DragStartMousePos = ev->pos(); + d->DragState = DraggingMousePressed; + + if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting)) + { + d->TabBar->currentTab()->setFocus(Qt::OtherFocusReason); + } + return; + } + Super::mousePressEvent(ev); +} + + +//============================================================================ +void CDockAreaTitleBar::mouseReleaseEvent(QMouseEvent* ev) +{ + if (ev->button() == Qt::LeftButton) + { + ADS_PRINT("CDockAreaTitleBar::mouseReleaseEvent"); + ev->accept(); + auto CurrentDragState = d->DragState; + d->DragStartMousePos = QPoint(); + d->DragState = DraggingInactive; + if (DraggingFloatingWidget == CurrentDragState) + { + d->FloatingWidget->finishDragging(); + } + + return; + } + Super::mouseReleaseEvent(ev); +} + + +//============================================================================ +void CDockAreaTitleBar::mouseMoveEvent(QMouseEvent* ev) +{ + Super::mouseMoveEvent(ev); + if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive)) + { + d->DragState = DraggingInactive; + return; + } + + // move floating window + if (d->isDraggingState(DraggingFloatingWidget)) + { + d->FloatingWidget->moveFloating(); + return; + } + + // If this is the last dock area in a floating dock container it does not make + // sense to move it to a new floating widget and leave this one + // empty + if (d->DockArea->dockContainer()->isFloating() + && d->DockArea->dockContainer()->visibleDockAreaCount() == 1) + { + return; + } + + // If one single dock widget in this area is not floatable then the whole + // area is not floatable + // If we do non opaque undocking, then we can create the floating drag + // preview if the dock widget is movable + auto Features = d->DockArea->features(); + if (!Features.testFlag(CDockWidget::DockWidgetFloatable) + && !(Features.testFlag(CDockWidget::DockWidgetMovable) && !CDockManager::testConfigFlag(CDockManager::OpaqueUndocking))) + { + return; + } + + int DragDistance = (d->DragStartMousePos - ev->pos()).manhattanLength(); + if (DragDistance >= CDockManager::startDragDistance()) + { + ADS_PRINT("CDockAreaTitlBar::startFloating"); + d->startFloating(d->DragStartMousePos); + auto Overlay = d->DockArea->dockManager()->containerOverlay(); + Overlay->setAllowedAreas(OuterDockAreas); + } + + return; +} + + +//============================================================================ +void CDockAreaTitleBar::mouseDoubleClickEvent(QMouseEvent *event) +{ + // If this is the last dock area in a dock container it does not make + // sense to move it to a new floating widget and leave this one + // empty + if (d->DockArea->dockContainer()->isFloating() && d->DockArea->dockContainer()->dockAreaCount() == 1) + { + return; + } + + if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)) + { + return; + } + d->makeAreaFloating(event->pos(), DraggingInactive); +} + + +//============================================================================ +void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev) +{ + ev->accept(); + if (d->isDraggingState(DraggingFloatingWidget)) + { + return; + } + + QMenu Menu(this); + auto Action = Menu.addAction(tr("Detach Area"), this, SLOT(onUndockButtonClicked())); + Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)); + Menu.addSeparator(); + Action = Menu.addAction(tr("Close Area"), this, SLOT(onCloseButtonClicked())); + Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetClosable)); + Menu.addAction(tr("Close Other Areas"), d->DockArea, SLOT(closeOtherAreas())); + Menu.exec(ev->globalPos()); +} + + +//============================================================================ +void CDockAreaTitleBar::insertWidget(int index, QWidget *widget) +{ + d->Layout->insertWidget(index, widget); +} + + +//============================================================================ +int CDockAreaTitleBar::indexOf(QWidget *widget) const +{ + return d->Layout->indexOf(widget); +} + +//============================================================================ +CTitleBarButton::CTitleBarButton(bool visible, QWidget* parent) + : tTitleBarButton(parent), + Visible(visible), + HideWhenDisabled(CDockManager::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 + +//--------------------------------------------------------------------------- +// EOF DockAreaTitleBar.cpp Property changes on: brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.h =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.h (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.h 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,162 @@ +#ifndef DockAreaTitleBarH +#define DockAreaTitleBarH +/******************************************************************************* +** 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 <http://www.gnu.org/licenses/>. +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaTitleBar.h +/// \author Uwe Kindler +/// \date 12.10.2018 +/// \brief Declaration of CDockAreaTitleBar class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include <QFrame> + +#include "ads_globals.h" + +QT_FORWARD_DECLARE_CLASS(QAbstractButton) + +namespace ads +{ +class CDockAreaTabBar; +class CDockAreaWidget; +struct DockAreaTitleBarPrivate; + +/** + * Title bar of a dock area. + * The title bar contains a tabbar with all tabs for a dock widget group and + * with a tabs menu button, a undock button and a close button. + */ +class ADS_EXPORT CDockAreaTitleBar : public QFrame +{ + Q_OBJECT +private: + DockAreaTitleBarPrivate* d; ///< private data (pimpl) + friend struct DockAreaTitleBarPrivate; + +private slots: + void onTabsMenuAboutToShow(); + void onCloseButtonClicked(); + void onUndockButtonClicked(); + void onTabsMenuActionTriggered(QAction* Action); + void onCurrentTabChanged(int Index); + +protected: + /** + * Stores mouse position to detect dragging + */ + virtual void mousePressEvent(QMouseEvent* ev) override; + + /** + * Stores mouse position to detect dragging + */ + virtual void mouseReleaseEvent(QMouseEvent* ev) override; + + /** + * Starts floating the complete docking area including all dock widgets, + * if it is not the last dock area in a floating widget + */ + virtual void mouseMoveEvent(QMouseEvent* ev) override; + + /** + * Double clicking the title bar also starts floating of the complete area + */ + virtual void mouseDoubleClickEvent(QMouseEvent *event) override; + + /** + * Show context menu + */ + virtual void contextMenuEvent(QContextMenuEvent *event) override; + +public slots: + /** + * Call this slot to tell the title bar that it should update the tabs menu + * the next time it is shown. + */ + void markTabsMenuOutdated(); + + +public: + using Super = QFrame; + + /** + * Default Constructor + */ + CDockAreaTitleBar(CDockAreaWidget* parent); + + /** + * Virtual Destructor + */ + virtual ~CDockAreaTitleBar(); + + /** + * Returns the pointer to the tabBar() + */ + CDockAreaTabBar* tabBar() const; + + /** + * Returns the button corresponding to the given title bar button identifier + */ + QAbstractButton* button(TitleBarButton which) const; + + /** + * Updates the visibility of the dock widget actions in the title bar + */ + void updateDockWidgetActionsButtons(); + + /** + * Marks the tabs menu outdated before it calls its base class + * implementation + */ + virtual void setVisible(bool Visible) override; + + /** + * Inserts a custom widget at position index into this title bar. + * If index is negative, the widget is added at the end. + * You can use this function to insert custom widgets into the title bar. + */ + void insertWidget(int index, QWidget *widget); + + /** + * Searches for widget widget in this title bar. + * You can use this function, to get the position of the default + * widget in the tile bar. + * \code + * int tabBarIndex = TitleBar->indexOf(TitleBar->tabBar()); + * int closeButtonIndex = TitleBar->indexOf(TitleBar->button(TitleBarButtonClose)); + * \endcode + */ + int indexOf(QWidget *widget) const; + +signals: + /** + * This signal is emitted if a tab in the tab bar is clicked by the user + * or if the user clicks on a tab item in the title bar tab menu. + */ + void tabBarClicked(int index); +}; // class name + +} + // namespace ads +//----------------------------------------------------------------------------- +#endif // DockAreaTitleBarH Property changes on: brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar_p.h =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar_p.h (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar_p.h 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,94 @@ +#ifndef DockAreaTitleBar_pH +#define DockAreaTitleBar_pH +/******************************************************************************* +** 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 <http://www.gnu.org/licenses/>. +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaTitleBar_p.h +/// \author Uwe Kindler +/// \date 12.10.2018 +/// \brief Declaration of classes CTitleBarButton and CSpacerWidget +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include <QFrame> +#include <QToolButton> + +#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 + +private: + 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 // DockAreaTitleBar_pH Property changes on: brlcad/branches/qtged/src/qged/qtads/DockAreaTitleBar_p.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.cpp =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.cpp (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.cpp 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,909 @@ +/******************************************************************************* +** 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 <http://www.gnu.org/licenses/>. +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaWidget.cpp +/// \author Uwe Kindler +/// \date 24.02.2017 +/// \brief Implementation of CDockAreaWidget class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include "DockAreaWidget.h" + +#include <iostream> + +#include <QStackedLayout> +#include <QScrollBar> +#include <QScrollArea> +#include <QWheelEvent> +#include <QStyle> +#include <QPushButton> +#include <QDebug> +#include <QMenu> +#include <QSplitter> +#include <QXmlStreamWriter> +#include <QVector> +#include <QList> + + +#include "DockContainerWidget.h" +#include "DockWidget.h" +#include "FloatingDockContainer.h" +#include "DockManager.h" +#include "DockOverlay.h" +#include "DockAreaTabBar.h" +#include "DockSplitter.h" +#include "DockAreaTitleBar.h" +#include "DockComponentsFactory.h" +#include "DockWidgetTab.h" + + +namespace ads +{ +static const char* const INDEX_PROPERTY = "index"; +static const char* const ACTION_PROPERTY = "action"; + +/** + * Internal dock area layout mimics stack layout but only inserts the current + * widget into the internal QLayout object. + * \warning Only the current widget has a parent. All other widgets + * do not have a parent. That means, a widget that is in this layout may + * return nullptr for its parent() function if it is not the current widget. + */ +class CDockAreaLayout +{ +private: + QBoxLayout* m_ParentLayout; + QList<QWidget*> m_Widgets; + int m_CurrentIndex = -1; + QWidget* m_CurrentWidget = nullptr; + +public: + /** + * Creates an instance with the given parent layout + */ + CDockAreaLayout(QBoxLayout* ParentLayout) + : m_ParentLayout(ParentLayout) + { + + } + + /** + * Returns the number of widgets in this layout + */ + int count() const + { + return m_Widgets.count(); + } + + /** + * Inserts the widget at the given index position into the internal widget + * list + */ + void insertWidget(int index, QWidget* Widget) + { + Widget->setParent(nullptr); + if (index < 0) + { + index = m_Widgets.count(); + } + m_Widgets.insert(index, Widget); + if (m_CurrentIndex < 0) + { + setCurrentIndex(index); + } + else + { + if (index <= m_CurrentIndex ) + { + ++m_CurrentIndex; + } + } + } + + /** + * Removes the given widget from the layout + */ + void removeWidget(QWidget* Widget) + { + if (currentWidget() == Widget) + { + auto LayoutItem = m_ParentLayout->takeAt(1); + if (LayoutItem) + { + LayoutItem->widget()->setParent(nullptr); + } + m_CurrentWidget = nullptr; + m_CurrentIndex = -1; + } + else if (indexOf(Widget) < m_CurrentIndex) + { + --m_CurrentIndex; + } + m_Widgets.removeOne(Widget); + } + + /** + * Returns the current selected widget + */ + QWidget* currentWidget() const + { + return m_CurrentWidget; + } + + /** + * Activates the widget with the give index. + */ + void setCurrentIndex(int index) + { + QWidget *prev = currentWidget(); + QWidget *next = widget(index); + if (!next || (next == prev && !m_CurrentWidget)) + { + return; + } + + bool reenableUpdates = false; + QWidget *parent = m_ParentLayout->parentWidget(); + + if (parent && parent->updatesEnabled()) + { + reenableUpdates = true; + parent->setUpdatesEnabled(false); + } + + auto LayoutItem = m_ParentLayout->takeAt(1); + if (LayoutItem) + { + LayoutItem->widget()->setParent(nullptr); + } + + m_ParentLayout->addWidget(next); + if (prev) + { + prev->hide(); + } + m_CurrentIndex = index; + m_CurrentWidget = next; + + + if (reenableUpdates) + { + parent->setUpdatesEnabled(true); + } + } + + /** + * Returns the index of the current active widget + */ + int currentIndex() const + { + return m_CurrentIndex; + } + + /** + * Returns true if there are no widgets in the layout + */ + bool isEmpty() const + { + return m_Widgets.empty(); + } + + /** + * Returns the index of the given widget + */ + int indexOf(QWidget* w) const + { + return m_Widgets.indexOf(w); + } + + /** + * Returns the widget for the given index + */ + QWidget* widget(int index) const + { + return (index < m_Widgets.size()) ? m_Widgets.at(index) : nullptr; + } + + /** + * Returns the geometry of the current active widget + */ + QRect geometry() const + { + return m_Widgets.empty() ? QRect() : currentWidget()->geometry(); + } +}; + + + +using DockAreaLayout = CDockAreaLayout; + + +/** + * Private data class of CDockAreaWidget class (pimpl) + */ +struct DockAreaWidgetPrivate +{ + CDockAreaWidget* _this = nullptr; + QBoxLayout* Layout = nullptr; + DockAreaLayout* ContentsLayout = nullptr; + CDockAreaTitleBar* TitleBar = nullptr; + CDockManager* DockManager = nullptr; + bool UpdateTitleBarButtons = false; + DockWidgetAreas AllowedAreas = AllDockAreas; + QSize MinSizeHint; + + /** + * Private data constructor + */ + DockAreaWidgetPrivate(CDockAreaWidget* _public); + + /** + * Creates the layout for top area with tabs and close button + */ + void createTitleBar(); + + /** + * Returns the dock widget with the given index + */ + CDockWidget* dockWidgetAt(int index) + { + return qobject_cast<CDockWidget*>(ContentsLayout->widget(index)); + } + + /** + * Convenience function to ease title widget access by index + */ + CDockWidgetTab* tabWidgetAt(int index) + { + return dockWidgetAt(index)->tabWidget(); + } + + + /** + * Returns the tab action of the given dock widget + */ + QAction* dockWidgetTabAction(CDockWidget* DockWidget) const + { + return qvariant_cast<QAction*>(DockWidget->property(ACTION_PROPERTY)); + } + + /** + * Returns the index of the given dock widget + */ + int dockWidgetIndex(CDockWidget* DockWidget) const + { + return DockWidget->property(INDEX_PROPERTY).toInt(); + } + + /** + * Convenience function for tabbar access + */ + CDockAreaTabBar* tabBar() const + { + return TitleBar->tabBar(); + } + + /** + * 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 + + +//============================================================================ +DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) : + _this(_public) +{ + +} + + +//============================================================================ +void DockAreaWidgetPrivate::createTitleBar() +{ + TitleBar = componentsFactory()->createDockAreaTitleBar(_this); + Layout->addWidget(TitleBar); + QObject::connect(tabBar(), &CDockAreaTabBar::tabCloseRequested, _this, &CDockAreaWidget::onTabCloseRequested); + QObject::connect(TitleBar, &CDockAreaTitleBar::tabBarClicked, _this, &CDockAreaWidget::setCurrentIndex); + QObject::connect(tabBar(), &CDockAreaTabBar::tabMoved, _this, &CDockAreaWidget::reorderDockWidget); +} + + +//============================================================================ +void DockAreaWidgetPrivate::updateTitleBarButtonStates() +{ + if (_this->isHidden()) + { + UpdateTitleBarButtons = true; + return; + } + + TitleBar->button(TitleBarButtonClose)->setEnabled( + _this->features().testFlag(CDockWidget::DockWidgetClosable)); + TitleBar->button(TitleBarButtonUndock)->setEnabled( + _this->features().testFlag(CDockWidget::DockWidgetFloatable)); + TitleBar->updateDockWidgetActionsButtons(); + UpdateTitleBarButtons = false; +} + + +//============================================================================ +CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent) : + QFrame(parent), + d(new DockAreaWidgetPrivate(this)) +{ + d->DockManager = DockManager; + d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); + d->Layout->setContentsMargins(0, 0, 0, 0); + d->Layout->setSpacing(0); + setLayout(d->Layout); + + d->createTitleBar(); + d->ContentsLayout = new DockAreaLayout(d->Layout); + if (d->DockManager) + { + emit d->DockManager->dockAreaCreated(this); + } +} + +//============================================================================ +CDockAreaWidget::~CDockAreaWidget() +{ + ADS_PRINT("~CDockAreaWidget()"); + delete d->ContentsLayout; + delete d; +} + + +//============================================================================ +CDockManager* CDockAreaWidget::dockManager() const +{ + return d->DockManager; +} + + +//============================================================================ +CDockContainerWidget* CDockAreaWidget::dockContainer() const +{ + return internal::findParent<CDockContainerWidget*>(this); +} + + +//============================================================================ +void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget) +{ + insertDockWidget(d->ContentsLayout->count(), DockWidget); +} + + +//============================================================================ +void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, + bool Activate) +{ + d->ContentsLayout->insertWidget(index, DockWidget); + DockWidget->setDockArea(this); + DockWidget->tabWidget()->setDockAreaWidget(this); + auto TabWidget = DockWidget->tabWidget(); + // Inserting the tab will change the current index which in turn will + // make the tab widget visible in the slot + d->tabBar()->blockSignals(true); + d->tabBar()->insertTab(index, TabWidget); + 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); + } + // If this dock area is hidden, then we need to make it visible again + // by calling DockWidget->toggleViewInternal(true); + if (!this->isVisible() && d->ContentsLayout->count() > 1 && !dockManager()->isRestoringState()) + { + DockWidget->toggleViewInternal(true); + } + d->updateTitleBarButtonStates(); +} + + +//============================================================================ +void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) +{ + ADS_PRINT("CDockAreaWidget::removeDockWidget"); + auto NextOpenDockWidget = nextOpenDockWidget(DockWidget); + + d->ContentsLayout->removeWidget(DockWidget); + auto TabWidget = DockWidget->tabWidget(); + TabWidget->hide(); + d->tabBar()->removeTab(TabWidget); + CDockContainerWidget* DockContainer = dockContainer(); + if (NextOpenDockWidget) + { + setCurrentDockWidget(NextOpenDockWidget); + } + else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() >= 1) + { + ADS_PRINT("Dock Area empty"); + DockContainer->removeDockArea(this); + this->deleteLater(); + } + else + { + // if contents layout is not empty but there are no more open dock + // widgets, then we need to hide the dock area because it does not + // contain any visible content + hideAreaWithNoVisibleContent(); + } + + d->updateTitleBarButtonStates(); + updateTitleBarVisibility(); + d->updateMinimumSizeHint(); + auto TopLevelDockWidget = DockContainer->topLevelDockWidget(); + if (TopLevelDockWidget) + { + TopLevelDockWidget->emitTopLevelChanged(true); + } + +#if (ADS_DEBUG_LEVEL > 0) + DockContainer->dumpLayout(); +#endif +} + + +//============================================================================ +void CDockAreaWidget::hideAreaWithNoVisibleContent() +{ + this->toggleView(false); + + // Hide empty parent splitters + auto Splitter = internal::findParent<CDockSplitter*>(this); + internal::hideEmptyParentSplitters(Splitter); + + //Hide empty floating widget + CDockContainerWidget* Container = this->dockContainer(); + if (!Container->isFloating() && !CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)) + { + return; + } + + updateTitleBarVisibility(); + auto TopLevelWidget = Container->topLevelDockWidget(); + auto FloatingWidget = Container->floatingWidget(); + if (TopLevelWidget) + { + if (FloatingWidget) + { + FloatingWidget->updateWindowTitle(); + } + CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true); + } + else if (Container->openedDockAreas().isEmpty() && FloatingWidget) + { + FloatingWidget->hide(); + } +} + + +//============================================================================ +void CDockAreaWidget::onTabCloseRequested(int Index) +{ + ADS_PRINT("CDockAreaWidget::onTabCloseRequested " << Index); + auto* DockWidget = dockWidget(Index); + if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose)) + { + DockWidget->closeDockWidgetInternal(); + } + else + { + DockWidget->toggleView(false); + } +} + + +//============================================================================ +CDockWidget* CDockAreaWidget::currentDockWidget() const +{ + int CurrentIndex = currentIndex(); + if (CurrentIndex < 0) + { + return nullptr; + } + + return dockWidget(CurrentIndex); +} + + +//============================================================================ +void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget) +{ + if (dockManager()->isRestoringState()) + { + return; + } + + internalSetCurrentDockWidget(DockWidget); +} + + +//============================================================================ +void CDockAreaWidget::internalSetCurrentDockWidget(CDockWidget* DockWidget) +{ + int Index = index(DockWidget); + if (Index < 0) + { + return; + } + + setCurrentIndex(Index); +} + + +//============================================================================ +void CDockAreaWidget::setCurrentIndex(int index) +{ + auto TabBar = d->tabBar(); + if (index < 0 || index > (TabBar->count() - 1)) + { + qWarning() << Q_FUNC_INFO << "Invalid index" << index; + return; + } + + auto cw = d->ContentsLayout->currentWidget(); + auto nw = d->ContentsLayout->widget(index); + if (cw == nw && !nw->isHidden()) + { + return; + } + + emit currentChanging(index); + TabBar->setCurrentIndex(index); + d->ContentsLayout->setCurrentIndex(index); + d->ContentsLayout->currentWidget()->show(); + emit currentChanged(index); +} + + +//============================================================================ +int CDockAreaWidget::currentIndex() const +{ + return d->ContentsLayout->currentIndex(); +} + + +//============================================================================ +QRect CDockAreaWidget::titleBarGeometry() const +{ + return d->TitleBar->geometry(); +} + +//============================================================================ +QRect CDockAreaWidget::contentAreaGeometry() const +{ + return d->ContentsLayout->geometry(); +} + + +//============================================================================ +int CDockAreaWidget::index(CDockWidget* DockWidget) +{ + return d->ContentsLayout->indexOf(DockWidget); +} + + +//============================================================================ +QList<CDockWidget*> CDockAreaWidget::dockWidgets() const +{ + QList<CDockWidget*> DockWidgetList; + for (int i = 0; i < d->ContentsLayout->count(); ++i) + { + DockWidgetList.append(dockWidget(i)); + } + return DockWidgetList; +} + + +//============================================================================ +int CDockAreaWidget::openDockWidgetsCount() const +{ + int Count = 0; + for (int i = 0; i < d->ContentsLayout->count(); ++i) + { + if (!dockWidget(i)->isClosed()) + { + ++Count; + } + } + return Count; +} + + +//============================================================================ +QList<CDockWidget*> CDockAreaWidget::openedDockWidgets() const +{ + QList<CDockWidget*> DockWidgetList; + for (int i = 0; i < d->ContentsLayout->count(); ++i) + { + CDockWidget* DockWidget = dockWidget(i); + if (!DockWidget->isClosed()) + { + DockWidgetList.append(dockWidget(i)); + } + } + return DockWidgetList; +} + + +//============================================================================ +int CDockAreaWidget::indexOfFirstOpenDockWidget() const +{ + for (int i = 0; i < d->ContentsLayout->count(); ++i) + { + if (!dockWidget(i)->isClosed()) + { + return i; + } + } + + return -1; +} + + +//============================================================================ +int CDockAreaWidget::dockWidgetsCount() const +{ + return d->ContentsLayout->count(); +} + + +//============================================================================ +CDockWidget* CDockAreaWidget::dockWidget(int Index) const +{ + return qobject_cast<CDockWidget*>(d->ContentsLayout->widget(Index)); +} + + +//============================================================================ +void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex) +{ + ADS_PRINT("CDockAreaWidget::reorderDockWidget"); + if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0 + || toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex) + { + ADS_PRINT("Invalid index for tab movement" << fromIndex << toIndex); + return; + } + + auto Widget = d->ContentsLayout->widget(fromIndex); + d->ContentsLayout->removeWidget(Widget); + d->ContentsLayout->insertWidget(toIndex, Widget); + setCurrentIndex(toIndex); +} + + +//============================================================================ +void CDockAreaWidget::toggleDockWidgetView(CDockWidget* DockWidget, bool Open) +{ + Q_UNUSED(DockWidget); + Q_UNUSED(Open); + updateTitleBarVisibility(); +} + + +//============================================================================ +void CDockAreaWidget::updateTitleBarVisibility() +{ + CDockContainerWidget* Container = dockContainer(); + if (!Container) + { + return; + } + + if (CDockManager::testConfigFlag(CDockManager::AlwaysShowTabs)) + { + return; + } + + if (d->TitleBar) + { + bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating() + || CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)); + d->TitleBar->setVisible(!Hidden); + } +} + + +//============================================================================ +void CDockAreaWidget::markTitleBarMenuOutdated() +{ + if (d->TitleBar) + { + d->TitleBar->markTabsMenuOutdated(); + } +} + + + +//============================================================================ +void CDockAreaWidget::saveState(QXmlStreamWriter& s) const +{ + s.writeStartElement("Area"); + s.writeAttribute("Tabs", QString::number(d->ContentsLayout->count())); + auto CurrentDockWidget = currentDockWidget(); + QString Name = CurrentDockWidget ? CurrentDockWidget->objectName() : ""; + s.writeAttribute("Current", Name); + ADS_PRINT("CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count() + << " Current: " << Name); + for (int i = 0; i < d->ContentsLayout->count(); ++i) + { + dockWidget(i)->saveState(s); + } + s.writeEndElement(); +} + + +//============================================================================ +CDockWidget* CDockAreaWidget::nextOpenDockWidget(CDockWidget* DockWidget) const +{ + auto OpenDockWidgets = openedDockWidgets(); + if (OpenDockWidgets.count() > 1 || (OpenDockWidgets.count() == 1 && OpenDockWidgets[0] != DockWidget)) + { + CDockWidget* NextDockWidget; + if (OpenDockWidgets.last() == DockWidget) + { + NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2]; + } + else + { + int NextIndex = OpenDockWidgets.indexOf(DockWidget) + 1; + NextDockWidget = OpenDockWidgets[NextIndex]; + } + + return NextDockWidget; + } + else + { + return nullptr; + } +} + + +//============================================================================ +CDockWidget::DockWidgetFeatures CDockAreaWidget::features(eBitwiseOperator Mode) const +{ + if (BitwiseAnd == Mode) + { + CDockWidget::DockWidgetFeatures Features(CDockWidget::AllDockWidgetFeatures); + for (const auto DockWidget : dockWidgets()) + { + Features &= DockWidget->features(); + } + return Features; + } + else + { + CDockWidget::DockWidgetFeatures Features(CDockWidget::NoDockWidgetFeatures); + for (const auto DockWidget : dockWidgets()) + { + Features |= DockWidget->features(); + } + return Features; + } +} + + +//============================================================================ +void CDockAreaWidget::toggleView(bool Open) +{ + setVisible(Open); + + emit viewToggled(Open); +} + + +//============================================================================ +void CDockAreaWidget::setVisible(bool Visible) +{ + Super::setVisible(Visible); + if (d->UpdateTitleBarButtons) + { + d->updateTitleBarButtonStates(); + } +} + +void CDockAreaWidget::setAllowedAreas(DockWidgetAreas areas) +{ + d->AllowedAreas = areas; +} + +DockWidgetAreas CDockAreaWidget::allowedAreas() const +{ + return d->AllowedAreas; +} + +//============================================================================ +QAbstractButton* CDockAreaWidget::titleBarButton(TitleBarButton which) const +{ + return d->TitleBar->button(which); +} + + +//============================================================================ +void CDockAreaWidget::closeArea() +{ + // If there is only one single dock widget and this widget has the + // DeleteOnClose feature, then we delete the dock widget now + auto OpenDockWidgets = openedDockWidgets(); + if (OpenDockWidgets.count() == 1 && OpenDockWidgets[0]->features().testFlag(CDockWidget::DockWidgetDeleteOnClose)) + { + OpenDockWidgets[0]->closeDockWidgetInternal(); + } + else + { + for (auto DockWidget : openedDockWidgets()) + { + DockWidget->toggleView(false); + } + } +} + + +//============================================================================ +void CDockAreaWidget::closeOtherAreas() +{ + dockContainer()->closeOtherAreas(this); +} + + +//============================================================================ +CDockAreaTitleBar* CDockAreaWidget::titleBar() const +{ + return d->TitleBar; +} + + +//============================================================================ +QSize CDockAreaWidget::minimumSizeHint() const +{ + return d->MinSizeHint.isValid() ? d->MinSizeHint : Super::minimumSizeHint(); +} +} // namespace ads + +//--------------------------------------------------------------------------- +// EOF DockAreaWidget.cpp Property changes on: brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.h =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.h (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.h 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,327 @@ +#ifndef DockAreaWidgetH +#define DockAreaWidgetH +/******************************************************************************* +** 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 <http://www.gnu.org/licenses/>. +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaWidget.h +/// \author Uwe Kindler +/// \date 24.02.2017 +/// \brief Declaration of CDockAreaWidget class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include <QFrame> + +#include "ads_globals.h" +#include "DockWidget.h" + +QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter) +QT_FORWARD_DECLARE_CLASS(QAbstractButton) + +namespace ads +{ +struct DockAreaWidgetPrivate; +class CDockManager; +class CDockContainerWidget; +class DockContainerWidgetPrivate; +class CDockAreaTitleBar; + + +/** + * DockAreaWidget manages multiple instances of DockWidgets. + * It displays a title tab, which is clickable and will switch to + * the contents associated to the title when clicked. + */ +class ADS_EXPORT CDockAreaWidget : public QFrame +{ + Q_OBJECT +private: + DockAreaWidgetPrivate* d; ///< private data (pimpl) + friend struct DockAreaWidgetPrivate; + friend class CDockContainerWidget; + friend class DockContainerWidgetPrivate; + friend class CDockWidgetTab; + friend struct DockWidgetPrivate; + friend class CDockWidget; + friend struct DockManagerPrivate; + friend class CDockManager; + +private slots: + void onTabCloseRequested(int Index); + + /** + * Reorder the index position of DockWidget at fromIndx to toIndex + * if a tab in the tabbar is dragged from one index to another one + */ + void reorderDockWidget(int fromIndex, int toIndex); + +protected: + /** + * Inserts a dock widget into dock area. + * All dockwidgets in the dock area tabified in a stacked layout with tabs. + * The index indicates the index of the new dockwidget in the tabbar and + * in the stacked layout. If the Activate parameter is true, the new + * DockWidget will be the active one in the stacked layout + */ + void insertDockWidget(int index, CDockWidget* DockWidget, bool Activate = true); + + /** + * Add a new dock widget to dock area. + * All dockwidgets in the dock area tabified in a stacked layout with tabs + */ + void addDockWidget(CDockWidget* DockWidget); + + /** + * Removes the given dock widget from the dock area + */ + void removeDockWidget(CDockWidget* DockWidget); + + /** + * Called from dock widget if it is opened or closed + */ + void toggleDockWidgetView(CDockWidget* DockWidget, bool Open); + + /** + * This is a helper function to get the next open dock widget to activate + * if the given DockWidget will be closed or removed. + * The function returns the next widget that should be activated or + * nullptr in case there are no more open widgets in this area. + */ + CDockWidget* nextOpenDockWidget(CDockWidget* DockWidget) const; + + /** + * Returns the index of the given DockWidget in the internal layout + */ + int index(CDockWidget* DockWidget); + + /** + * Call this function, if you already know, that the dock does not + * contain any visible content (any open dock widgets). + */ + void hideAreaWithNoVisibleContent(); + + /** + * Updates the dock area layout and components visibility + */ + void updateTitleBarVisibility(); + + /** + * This is the internal private function for setting the current widget. + * This function is called by the public setCurrentDockWidget() function + * and by the dock manager when restoring the state + */ + void internalSetCurrentDockWidget(CDockWidget* DockWidget); + + /** + * Marks tabs menu to update + */ + void markTitleBarMenuOutdated(); + +protected slots: + void toggleView(bool Open); + +public: + using Super = QFrame; + + /** + * Default Constructor + */ + CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent); + + /** + * Virtual Destructor + */ + virtual ~CDockAreaWidget(); + + /** + * Returns the dock manager object this dock area belongs to + */ + CDockManager* dockManager() const; + + /** + * Returns the dock container widget this dock area widget belongs to or 0 + * if there is no + */ + 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 + */ + QRect titleBarGeometry() const; + + /** + * Returns the rectangle of the content + */ + QRect contentAreaGeometry() const; + + /** + * Returns the number of dock widgets in this area + */ + int dockWidgetsCount() const; + + /** + * Returns a list of all dock widgets in this dock area. + * This list contains open and closed dock widgets. + */ + QList<CDockWidget*> dockWidgets() const; + + /** + * Returns the number of open dock widgets in this area + */ + int openDockWidgetsCount() const; + + /** + * Returns a list of dock widgets that are not closed. + */ + QList<CDockWidget*> openedDockWidgets() const; + + /** + * Returns a dock widget by its index + */ + CDockWidget* dockWidget(int Index) const; + + /** + * Returns the index of the current active dock widget or -1 if there + * are is no active dock widget (ie.e if all dock widgets are closed) + */ + int currentIndex() const; + + /** + * Returns the index of the first open dock widgets in the list of + * dock widgets. + * This function is here for performance reasons. Normally it would + * be possible to take the first dock widget from the list returned by + * openedDockWidgets() function. But that function enumerates all + * dock widgets while this functions stops after the first open dock widget. + * If there are no open dock widgets, the function returns -1. + */ + int indexOfFirstOpenDockWidget() const; + + /** + * Returns the current active dock widget or a nullptr if there is no + * active dock widget (i.e. if all dock widgets are closed) + */ + CDockWidget* currentDockWidget() const; + + /** + * Shows the tab with the given dock widget + */ + void setCurrentDockWidget(CDockWidget* DockWidget); + + /** + * Saves the state into the given stream + */ + void saveState(QXmlStreamWriter& Stream) const; + + /** + * This functions returns the dock widget features of all dock widget in + * this area. + * A bitwise and is used to combine the flags of all dock widgets. That + * means, if only one single dock widget does not support a certain flag, + * the whole dock are does not support the flag. I.e. if one single + * dock widget in this area is not closable, the whole dock are is not + * closable. + */ + CDockWidget::DockWidgetFeatures features(eBitwiseOperator Mode = BitwiseAnd) const; + + /** + * Returns the title bar button corresponding to the given title bar + * button identifier + */ + QAbstractButton* titleBarButton(TitleBarButton which) const; + + /** + * Update the close button if visibility changed + */ + virtual void setVisible(bool Visible) override; + + /** + * Configures the areas of this particular dock area that are allowed for docking + */ + void setAllowedAreas(DockWidgetAreas areas); + + /** + * Returns flags with all allowed drop areas of this particular dock area + */ + DockWidgetAreas allowedAreas() const; + + /** + * Returns the title bar of this dock area + */ + CDockAreaTitleBar* titleBar() const; + +public slots: + /** + * This activates the tab for the given tab index. + * If the dock widget for the given tab is not visible, the this function + * call will make it visible. + */ + void setCurrentIndex(int index); + + /** + * Closes the dock area and all dock widgets in this area + */ + void closeArea(); + + /** + * This function closes all other areas except of this area + */ + void closeOtherAreas(); + +signals: + /** + * This signal is emitted when user clicks on a tab at an index. + */ + void tabBarClicked(int index); + + /** + * This signal is emitted when the tab bar's current tab is about to be changed. The new + * current has the given index, or -1 if there isn't a new one. + * @param index + */ + void currentChanging(int index); + + /** + * This signal is emitted when the tab bar's current tab changes. The new + * current has the given index, or -1 if there isn't a new one + * @param index + */ + void currentChanged(int index); + + /** + * This signal is emitted if the visibility of this dock area is toggled + * via toggle view function + */ + void viewToggled(bool Open); +}; // class DockAreaWidget +} + // namespace ads +//----------------------------------------------------------------------------- +#endif // DockAreaWidgetH Property changes on: brlcad/branches/qtged/src/qged/qtads/DockAreaWidget.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.cpp =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.cpp (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.cpp 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,69 @@ +//============================================================================ +/// \file DockComponentsFactory.cpp +/// \author Uwe Kindler +/// \date 10.02.2020 +/// \brief Implementation of DockComponentsFactory +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "DockComponentsFactory.h" + +#include <memory> + +#include "DockWidgetTab.h" +#include "DockAreaTabBar.h" +#include "DockAreaTitleBar.h" +#include "DockWidget.h" +#include "DockAreaWidget.h" + +namespace ads +{ +static std::unique_ptr<CDockComponentsFactory> DefaultFactory(new CDockComponentsFactory()); + + +//============================================================================ +CDockWidgetTab* CDockComponentsFactory::createDockWidgetTab(CDockWidget* DockWidget) const +{ + return new CDockWidgetTab(DockWidget); +} + + +//============================================================================ +CDockAreaTabBar* CDockComponentsFactory::createDockAreaTabBar(CDockAreaWidget* DockArea) const +{ + return new CDockAreaTabBar(DockArea); +} + + +//============================================================================ +CDockAreaTitleBar* CDockComponentsFactory::createDockAreaTitleBar(CDockAreaWidget* DockArea) const +{ + return new CDockAreaTitleBar(DockArea); +} + + +//============================================================================ +const CDockComponentsFactory* CDockComponentsFactory::factory() +{ + return DefaultFactory.get(); +} + + +//============================================================================ +void CDockComponentsFactory::setFactory(CDockComponentsFactory* Factory) +{ + DefaultFactory.reset(Factory); +} + + +//============================================================================ +void CDockComponentsFactory::resetDefaultFactory() +{ + DefaultFactory.reset(new CDockComponentsFactory()); +} +} // namespace ads + +//--------------------------------------------------------------------------- +// EOF DockComponentsFactory.cpp Property changes on: brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.h =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.h (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.h 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,90 @@ +#ifndef DockComponentsFactoryH +#define DockComponentsFactoryH +//============================================================================ +/// \file DockComponentsFactory.h +/// \author Uwe Kindler +/// \date 10.02.2020 +/// \brief Declaration of DockComponentsFactory +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "ads_globals.h" + +namespace ads +{ +class CDockWidgetTab; +class CDockAreaTitleBar; +class CDockAreaTabBar; +class CDockAreaWidget; +class CDockWidget; + + + +/** + * Factory for creation of certain GUI elements for the docking framework. + * A default unique instance provided by CDockComponentsFactory is used for + * creation of all supported components. To inject your custom components, + * you can create your own derived dock components factory and register + * it via setDefaultFactory() function. + * \code + * CDockComponentsFactory::setDefaultFactory(new MyComponentsFactory())); + * \endcode + */ +class ADS_EXPORT CDockComponentsFactory +{ +public: + /** + * Force virtual destructor + */ + virtual ~CDockComponentsFactory() {} + + /** + * This default implementation just creates a dock widget tab with + * new CDockWidgetTab(DockWIdget). + */ + virtual CDockWidgetTab* createDockWidgetTab(CDockWidget* DockWidget) const; + + /** + * This default implementation just creates a dock area tab bar with + * new CDockAreaTabBar(DockArea). + */ + virtual CDockAreaTabBar* createDockAreaTabBar(CDockAreaWidget* DockArea) const; + + /** + * This default implementation just creates a dock area title bar with + * new CDockAreaTitleBar(DockArea). + */ + virtual CDockAreaTitleBar* createDockAreaTitleBar(CDockAreaWidget* DockArea) const; + + /** + * Returns the default components factory + */ + static const CDockComponentsFactory* factory(); + + /** + * Sets a new default factory for creation of GUI elements. + * This function takes ownership of the given Factory. + */ + static void setFactory(CDockComponentsFactory* Factory); + + /** + * Resets the current factory to the + */ + static void resetDefaultFactory(); +}; + + +/** + * Convenience function to ease factory instance access + */ +inline const CDockComponentsFactory* componentsFactory() +{ + return CDockComponentsFactory::factory(); +} + +} // namespace ads + +//--------------------------------------------------------------------------- +#endif // DockComponentsFactoryH Property changes on: brlcad/branches/qtged/src/qged/qtads/DockComponentsFactory.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: brlcad/branches/qtged/src/qged/qtads/DockContainerWidget.cpp =================================================================== --- brlcad/branches/qtged/src/qged/qtads/DockContainerWidget.cpp (rev 0) +++ brlcad/branches/qtged/src/qged/qtads/DockContainerWidget.cpp 2020-06-22 02:33:25 UTC (rev 76174) @@ -0,0 +1,1783 @@ +/******************************************************************************* +** Qt Advanced Docking System @@ Diff output truncated at 100000 characters. @@ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. _______________________________________________ BRL-CAD Source Commits mailing list brlcad-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/brlcad-commits