15 #include <QScopedPointer>
16 #include <QSignalMapper>
38 CInfoArea::CInfoArea(QWidget *parent)
39 : QMainWindow(parent),
42 this->setWholeInfoAreaFloating(m_infoAreaFloating);
54 m_childInfoAreas = this->findOwnChildInfoAreas();
55 m_dockWidgetInfoAreas = this->findOwnDockWidgetInfoAreas();
57 this->setDockArea(Qt::TopDockWidgetArea);
58 this->connectTopLevelChanged();
59 this->setFeaturesForDockableWidgets(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable |
60 QDockWidget::DockWidgetClosable);
61 this->tabifyAllWidgets();
64 this->setContextMenuPolicy(Qt::CustomContextMenu);
65 connect(
this, &CInfoArea::customContextMenuRequested,
this, &CInfoArea::showContextMenu);
67 Qt::QueuedConnection);
70 this->onStyleSheetChanged();
73 if (this->statusBar())
75 this->statusBar()->hide();
76 this->statusBar()->setMaximumHeight(0);
80 QPointer<CInfoArea> myself(
this);
82 if (myself) { myself->emitInfoAreaStatus(); }
88 if (!menu) {
return; }
89 bool hasDockedWidgets = this->countDockedWidgetInfoAreas() > 0;
94 menu->addAction(CIcons::refresh16(),
"Reset all floating to defaults",
this,
98 menu->addAction(CIcons::floatOne16(), QStringLiteral(
"Dock / float '%1'").arg(this->windowTitle()),
this,
100 QAction *lockTabBarMenuAction =
new QAction(menu);
101 lockTabBarMenuAction->setObjectName(this->objectName().append(
"LockTabBar"));
102 lockTabBarMenuAction->setIconText(
"Lock tab bar");
103 lockTabBarMenuAction->setIcon(CIcons::lockClosed16());
104 lockTabBarMenuAction->setCheckable(
true);
105 lockTabBarMenuAction->setChecked(m_lockTabBar);
106 menu->addAction(lockTabBarMenuAction);
109 menu->addSeparator();
110 QMenu *subMenuToggleFloat =
new QMenu(
"Toggle Float/Dock", menu);
111 QMenu *subMenuDisplay =
new QMenu(
"Display", menu);
112 QMenu *subMenuRestore =
new QMenu(
"Restore from settings", menu);
113 QMenu *subMenuResetPositions =
new QMenu(
"Reset position", menu);
114 subMenuRestore->setIcon(CIcons::load16());
115 subMenuResetPositions->setIcon(CIcons::refresh16());
120 QSignalMapper *signalMapperToggleFloating =
new QSignalMapper(menu);
123 for (
int i = 0; i < m_dockWidgetInfoAreas.size(); i++)
128 QAction *toggleFloatingMenuAction =
new QAction(menu);
129 toggleFloatingMenuAction->setObjectName(QString(t).append(
"ToggleFloatingAction"));
130 toggleFloatingMenuAction->setIconText(t);
131 toggleFloatingMenuAction->setIcon(pm);
132 toggleFloatingMenuAction->setData(QVariant(i));
133 toggleFloatingMenuAction->setCheckable(
true);
134 toggleFloatingMenuAction->setChecked(!dw->isFloating());
135 subMenuToggleFloat->addAction(toggleFloatingMenuAction);
136 c = connect(toggleFloatingMenuAction, &QAction::toggled, signalMapperToggleFloating,
137 qOverload<>(&QSignalMapper::map));
139 "Cannot map floating action");
140 signalMapperToggleFloating->setMapping(toggleFloatingMenuAction, i);
145 "Cannot connect mapper");
147 menu->addMenu(subMenuDisplay);
148 if (c) { menu->addMenu(subMenuToggleFloat); }
149 menu->addMenu(subMenuResetPositions);
150 menu->addMenu(subMenuRestore);
153 menu->addSeparator();
154 QAction *showMenuText =
new QAction(menu);
155 showMenuText->setObjectName(
"ShowDockedWidgetTextAction");
156 showMenuText->setIconText(
"Show tab text");
157 showMenuText->setIcon(CIcons::headingOne16());
158 showMenuText->setCheckable(
true);
159 showMenuText->setChecked(m_showTabTexts);
160 menu->addAction(showMenuText);
161 connect(showMenuText, &QAction::toggled,
this, &CInfoArea::showTabTexts);
164 QAction *showTabbar =
new QAction(menu);
165 showTabbar->setObjectName(
"ShowTabBar");
166 showTabbar->setIconText(
"Show tab bar");
167 showTabbar->setIcon(CIcons::dockBottom16());
168 showTabbar->setCheckable(
true);
169 showTabbar->setChecked(m_showTabBar);
170 menu->addAction(showTabbar);
171 connect(showTabbar, &QAction::toggled,
this, &CInfoArea::showTabBar);
174 menu->addAction(CIcons::dockBottom16(),
"Toggle tabbar position",
this, &CInfoArea::toggleTabBarPosition);
181 if (!infoArea) {
return false; }
182 if (infoArea->isFloating()) {
return false; }
184 if (!m_tabBar || m_tabBar->count() < 1) {
return false; }
193 if (!m_tabBar || m_tabBar->count() < 1) {
return nullptr; }
196 if (ia->isFloating()) {
continue; }
197 if (ia->isWidgetVisible()) {
return ia; }
205 if (!sel) {
return -1; }
207 int ia = getAreaIndexByWindowTitle(t);
220 QList<QAction *> actions;
224 const QString wt(dockWidgetInfoArea->windowTitleBackup());
225 static const QString keys(
"123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
226 QAction *action =
new QAction(QIcon(pm), wt, parent);
228 action->setObjectName(this->objectName().append(
":getInfoAreaSelectActions:").append(wt));
229 if (withShortcut && i < keys.length())
234 action->setShortcut(QKeySequence(QStringLiteral(
"Ctrl+Shift+%1").arg(keys.at(i))));
238 actions.append(action);
248 QList<QAction *> actions;
252 const QString wt(dockWidgetInfoArea->windowTitleBackup());
253 QAction *action =
new QAction(QIcon(pm), wt, parent);
255 action->setObjectName(this->objectName().append(
":getInfoAreaResetPositionActions:").append(wt));
257 actions.append(action);
267 QList<QAction *> actions;
271 const QString wt(dockWidgetInfoArea->windowTitleBackup());
272 QAction *action =
new QAction(QIcon(pm), wt, parent);
274 action->setObjectName(this->objectName().append(
":getInfoAreaToggleFloatingActions:").append(wt));
276 actions.append(action);
286 QList<QAction *> actions;
290 const QString wt(dockWidgetInfoArea->windowTitleBackup());
291 QAction *action =
new QAction(QIcon(pm), wt, parent);
293 action->setObjectName(this->objectName().append(
":getInfoAreaRestoreActions:").append(wt));
295 actions.append(action);
304 for (
int i = 0; i < m_dockWidgetInfoAreas.size(); i++)
306 if (m_dockWidgetInfoAreas.at(i)->isFloating() == floating) { indexes.append(i); }
319 if (event->key() == Qt::Key_Right)
324 else if (event->key() == Qt::Key_Left)
329 else { QWidget::keyPressEvent(event); }
343 if (dw->isFloating()) {
continue; }
344 dw->toggleFloating();
352 if (!dw || !dw->isFloating()) {
continue; }
361 if (!dw || !dw->isFloating()) {
continue; }
370 const bool f = dw->isFloating();
372 if (f) { dw->show(); }
380 if (!this->isValidAreaIndex(areaIndex)) {
return; }
389 if (!this->isValidAreaIndex(areaIndex)) {
return; }
402 if (m_tabBar->count() < 1) {
return; }
404 if (dw->isFloating()) { dw->show(); }
418 const QObject *sender = QObject::sender();
419 const QAction *action = qobject_cast<const QAction *>(sender);
421 if (!action) {
return; }
422 const int index = action->data().toInt();
428 const QObject *sender = QObject::sender();
429 const QAction *action = qobject_cast<const QAction *>(sender);
431 if (!action) {
return; }
432 const int index = action->data().toInt();
438 const QObject *sender = QObject::sender();
439 const QAction *action = qobject_cast<const QAction *>(sender);
441 if (!action) {
return; }
442 const int index = action->data().toInt();
448 const QObject *sender = QObject::sender();
449 const QAction *action = qobject_cast<const QAction *>(sender);
451 if (!action) {
return; }
452 const int index = action->data().toInt();
458 if (!this->isValidAreaIndex(areaIndex)) {
return; }
467 if (!m_tabBar)
return;
468 if (m_tabBar->count() < 2)
return;
469 if (m_tabBar->currentIndex() > 0) { m_tabBar->setCurrentIndex(m_tabBar->currentIndex() - 1); }
470 else { m_tabBar->setCurrentIndex(m_tabBar->count() - 1); }
475 if (!m_tabBar)
return;
476 if (m_tabBar->count() < 2)
return;
477 if (m_tabBar->currentIndex() < m_tabBar->count() - 2)
479 m_tabBar->setCurrentIndex(m_tabBar->currentIndex() + 1);
481 else { m_tabBar->setCurrentIndex(0); }
488 dw->displayStatusMessage(statusMessage);
490 for (
CInfoArea *ia : std::as_const(m_childInfoAreas)) { ia->displayStatusMessage(statusMessage); }
497 dw->displayStatusMessages(statusMessages);
499 for (
CInfoArea *ia : std::as_const(m_childInfoAreas)) { ia->displayStatusMessages(statusMessages); }
502 void CInfoArea::setDockArea(Qt::DockWidgetArea area)
506 Qt::DockWidgetAreas newAreas =
static_cast<Qt::DockWidgetAreas
>(area);
507 Qt::DockWidgetAreas oldAreas = dw->allowedAreas();
508 if (oldAreas == newAreas) {
continue; }
509 dw->setAllowedAreas(newAreas);
510 this->addDockWidget(area, dw);
514 void CInfoArea::setWholeInfoAreaFloating(
bool floating)
517 m_infoAreaFloating = floating;
518 if (m_infoAreaFloating)
521 this->setWindowFlags(Qt::Dialog);
522 this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
523 this->move(p.rx() + 20, p.ry() + 20);
533 this->setWindowFlags(this->windowFlags() & ~Qt::Window);
535 if (this->parentWidget())
537 this->setVisible(
true);
544 void CInfoArea::tabifyAllWidgets()
547 this->setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::East);
548 const bool init = m_tabBar ? false :
true;
550 for (
int i = 0; i < m_dockWidgetInfoAreas.size(); i++)
552 CDockWidgetInfoArea *first = i > 0 ? m_dockWidgetInfoAreas.at(i - 1) :
nullptr;
553 CDockWidgetInfoArea *after = m_dockWidgetInfoAreas.at(i);
561 const QPoint offset(i * 10, i * 10);
564 after->setOffsetWhenFloating(offset, after->isFrameless());
566 after->setPreferredSizeWhenFloating(floatingSize);
567 after->initialFloating();
574 after->resetWasAlreadyFloating();
576 else { after->setFloating(
false); }
579 if (!first) {
continue; }
581 this->tabifyDockWidget(first, after);
587 m_tabBar = this->findChild<QTabBar *>();
590 if (m_tabBar &&
sGui)
593 m_tabBar->setStyleSheet(qss);
594 m_tabBar->setObjectName(
"comp_MainInfoAreaDockWidgetTab");
595 m_tabBar->setMovable(
false);
596 m_tabBar->setElideMode(Qt::ElideNone);
597 m_tabBar->setUsesScrollButtons(
true);
601 m_tabBar->setShape(QTabBar::TriangularSouth);
604 connect(m_tabBar, &QTabBar::tabBarDoubleClicked,
this, &CInfoArea::onTabBarDoubleClicked,
605 Qt::QueuedConnection);
606 connect(m_tabBar, &QTabBar::currentChanged,
this, &CInfoArea::onTabBarIndexChanged,
607 Qt::QueuedConnection);
612 m_tabBar =
new QTabBar(
this);
618 if (this->countDockedWidgetInfoAreas() > 0) { m_tabBar->setCurrentIndex(0); }
619 if (m_tabBar->count() > 0) { this->setTabPixmaps(); }
622 void CInfoArea::unTabifyAllWidgets()
624 if (m_dockWidgetInfoAreas.size() < 2)
return;
625 CDockWidgetInfoArea *first = m_dockWidgetInfoAreas.constFirst();
626 for (
int i = 1; i < m_dockWidgetInfoAreas.size(); i++)
628 CDockWidgetInfoArea *after = m_dockWidgetInfoAreas.at(i);
630 this->splitDockWidget(first, after, Qt::Horizontal);
634 bool CInfoArea::isValidAreaIndex(
int areaIndex)
const
636 if (!m_tabBar) {
return false; }
637 return areaIndex >= 0 && areaIndex < m_dockWidgetInfoAreas.size();
640 void CInfoArea::connectTopLevelChanged()
642 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
645 Qt::QueuedConnection);
649 QList<CDockWidgetInfoArea *> CInfoArea::findOwnDockWidgetInfoAreas()
const
652 return this->findChildren<CDockWidgetInfoArea *>(QString(), Qt::FindDirectChildrenOnly);
655 QList<CInfoArea *> CInfoArea::findOwnChildInfoAreas()
const
657 return this->findChildren<CInfoArea *>(QString(), Qt::FindDirectChildrenOnly);
660 void CInfoArea::emitInfoAreaStatus()
669 void CInfoArea::onTabBarIndexChanged(
int tabBarIndex)
672 this->emitInfoAreaStatus();
675 int CInfoArea::countDockedWidgetInfoAreas()
const
677 if (!m_tabBar) {
return 0; }
678 return m_tabBar->count();
681 CDockWidgetInfoArea *CInfoArea::getDockWidgetInfoAreaByTabBarIndex(
int tabBarIndex)
const
683 if (tabBarIndex >= m_dockWidgetInfoAreas.count() || tabBarIndex < 0) {
return nullptr; }
684 if (!m_tabBar) {
return nullptr; }
685 const QString t(m_tabBar->tabText(tabBarIndex));
688 if (!t.isEmpty()) {
return this->getDockWidgetInfoAreaByWindowTitle(t); }
693 for (CDockWidgetInfoArea *dw : m_dockWidgetInfoAreas)
695 if (dw->isFloating()) {
continue; }
696 if (c == tabBarIndex) {
return dw; }
699 Q_ASSERT_X(
false, Q_FUNC_INFO,
"no dock widgte found");
703 CDockWidgetInfoArea *CInfoArea::getDockWidgetInfoAreaByWindowTitle(
const QString &title)
const
705 Q_ASSERT_X(!title.isEmpty(), Q_FUNC_INFO,
"No title");
706 for (CDockWidgetInfoArea *dw : m_dockWidgetInfoAreas)
713 int CInfoArea::getAreaIndexByWindowTitle(
const QString &title)
const
715 Q_ASSERT_X(!title.isEmpty(), Q_FUNC_INFO,
"No title");
717 for (
int i = 0; i < m_dockWidgetInfoAreas.size(); i++)
724 Q_ASSERT_X(
false, Q_FUNC_INFO,
"No area for title");
728 int CInfoArea::getTabBarIndexByTitle(
const QString &title)
const
731 if (title.isEmpty()) {
return -1; }
733 if (m_tabBar->count() < 1) {
return -1; }
734 for (
int i = 0; i < m_tabBar->count(); i++)
736 QString tt = m_tabBar->tabText(i);
737 if (tt.isEmpty()) { tt = m_tabBar->tabToolTip(i); }
738 if (tt.isEmpty()) {
continue; }
744 int CInfoArea::dockWidgetInfoAreaToTabBarIndex(
const CDockWidgetInfoArea *dockWidgetInfoArea)
const
746 if (!dockWidgetInfoArea) {
return -1; }
747 if (dockWidgetInfoArea->isFloating()) {
return -1; }
748 int index = this->getTabBarIndexByTitle(dockWidgetInfoArea->windowTitleOrBackup());
753 for (
const CDockWidgetInfoArea *a : m_dockWidgetInfoAreas)
755 if (a == dockWidgetInfoArea)
765 if (index >= m_tabBar->count()) { index = -1; }
773 if (!m_tabBar) {
return; }
774 int tabIndex = this->dockWidgetInfoAreaToTabBarIndex(dockWidgetInfoArea);
775 if (tabIndex >= 0 && tabIndex < m_tabBar->count()) { m_tabBar->setCurrentIndex(tabIndex); }
778 void CInfoArea::setFeaturesForDockableWidgets(QDockWidget::DockWidgetFeatures features)
780 for (
CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas)) { dw->setFeatures(features); }
783 void CInfoArea::setTabPixmaps()
785 if (!m_tabBar) {
return; }
786 for (
int i = 0; i < m_tabBar->count(); i++)
788 const QString t(m_tabBar->tabText(i));
789 const int areaIndex = t.isEmpty() ? i : this->getAreaIndexByWindowTitle(t);
791 m_tabBar->setTabToolTip(i, t);
795 void CInfoArea::onTabBarDoubleClicked(
int tabBarIndex)
799 CLogMessage(
this).
info(u
"Locked, double click will not cause floating");
802 CDockWidgetInfoArea *dw = this->getDockWidgetInfoAreaByTabBarIndex(tabBarIndex);
804 dw->toggleFloating();
806 QPointer<CInfoArea> myself(
this);
808 if (!myself) {
return; }
809 myself->emitInfoAreaStatus();
813 void CInfoArea::onWidgetTopLevelChanged(CDockWidget *dockWidget,
bool topLevel)
815 Q_ASSERT(dockWidget);
817 if (!dockWidget) {
return; }
820 this->setTabPixmaps();
825 const CDockWidgetInfoArea *dwia =
dynamic_cast<CDockWidgetInfoArea *
>(dockWidget);
835 void CInfoArea::onStyleSheetChanged()
841 m_tabBar->setStyleSheet(qss);
845 void CInfoArea::showContextMenu(
const QPoint &pos)
847 QPoint globalPos = this->mapToGlobal(pos);
848 QScopedPointer<QMenu> contextMenu(
new QMenu(
this));
851 QAction *selectedItem = contextMenu.data()->exec(globalPos);
852 Q_UNUSED(selectedItem)
855 void CInfoArea::showTabTexts(
bool show)
857 if (show == m_showTabTexts) {
return; }
858 m_showTabTexts = show;
859 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas)) { dw->showTitleWhenDocked(show); }
862 void CInfoArea::showTabBar(
bool show)
864 if (show == m_showTabBar)
return;
866 if (!m_tabBar)
return;
867 m_tabBar->setVisible(show);
868 m_tabBar->setMaximumHeight(show ? 10000 : 0);
876 Q_ASSERT_X(position == QTabWidget::North || position == QTabWidget::South, Q_FUNC_INFO,
877 "Wrong tabbar position");
878 this->setTabPosition(Qt::TopDockWidgetArea, position);
881 void CInfoArea::toggleTabBarPosition()
883 QTabWidget::TabPosition p =
884 (this->tabPosition(Qt::TopDockWidgetArea) == QTabWidget::North) ? QTabWidget::South : QTabWidget::North;
893 event->setAccepted(
false);
895 else { QMainWindow::closeEvent(event); }
bool isShuttingDown() const
Is application shutting down?
Main window which can be frameless.
const CStyleSheetUtility & getStyleSheetUtility() const
Style sheet handling.
void styleSheetsChanged()
Style sheet changed.
static bool stayOnTop(bool onTop, QWidget *widget)
Window flags / stay on top.
static QPoint mainWidgetGlobalPosition()
Position of main widget.
static bool lenientTitleComparison(const QString &title, const QString &comparison)
Lenient / relaxed.
Info area, hosting dockable widgets.
virtual void toggleFloatingWholeInfoArea()
Toggle dock / floating of the whole info area.
void selectLeftTab()
Select next left tab.
void changedInfoAreaStatus(int currentTabIndex, QList< int > dockedAreas, QList< int > floatingAreas)
Status of info area changed.
void addToContextMenu(QMenu *menu) const
Add items to context menu.
void toggleFloatingByIndex(int areaIndex)
Toggle floating of index.
virtual void closeEvent(QCloseEvent *event)
void toggleVisibility(int areaIndex)
Toggle visibilty.
void selectArea(int areaIndex)
Select area.
void toggleAreaFloatingByAction()
Toggle area floating (sender is QAction)
QList< QAction * > getInfoAreaRestoreActions(QWidget *parent) const
Create a list of actions to restore the info areas. This could be used in a menu or somewhere else.
void floatAllWidgets()
All widgets floating.
QList< QAction * > getInfoAreaToggleFloatingActions(QWidget *parent) const
Create a list of actions to select the info areas and toogle its floating state. This could be used i...
void adjustSizeForAllDockWidgets()
Adjust size for all dock widgets.
void setTabBarPosition(QTabWidget::TabPosition position)
Tab position for docked widgets tab.
void restoreDockWidgetInfoArea()
Restore dock widget`s state (from settings)
virtual void paintEvent(QPaintEvent *event)
void selectRightTab()
Select next right tab.
void selectAreaByAction()
Select area (sender is QAction)
void resetAllWidgetSettings()
Reset all widget settings.
void initInfoArea()
Init area after(!) GUI is initialized.
void toggleTabBarLocked(bool locked)
Toogle lock tabbar.
virtual ~CInfoArea()
Destructor.
void changedInfoAreaTabBarIndex(int index)
Tab bar changed.
QList< const CDockWidgetInfoArea * > getDockWidgetInfoAreas() const
Own dockable widgets.
virtual QSize getPreferredSizeWhenFloating(int areaIndex) const =0
Preferred size when floating (size hint)
void changedWholeInfoAreaFloating(bool floating)
Whole info area floating.
void dockAllWidgets()
Dock all widgets.
QList< int > getAreaIndexesDockedOrFloating(bool floating) const
Docked area indexes.
void restoreDockWidgetInfoAreaByIndex(int areaIndex)
Restore dock widget`s state (from settings)
QList< QAction * > getInfoAreaResetPositionActions(QWidget *parent) const
Create a list of actions to reset the position the info areas. This could be used in a menu or somewh...
void displayStatusMessages(const swift::misc::CStatusMessageList &statusMessages)
Display status messages in all info areas (according their state)
bool isFloating() const
Is the area floating?
bool isSelectedDockWidgetInfoArea(const CDockWidgetInfoArea *infoArea) const
Is given widget selected. Means it is not floating, and the one selected.
void resetAllFloatingWidgetSettings()
Reset all floating widget settings.
virtual const QPixmap & indexToPixmap(int areaIndex) const =0
Info area (index) to icon.
QList< QAction * > getInfoAreaSelectActions(bool withShortcut, QWidget *parent) const
Create a list of actions to select the info areas. This could be used in a menu or somewhere else.
void displayStatusMessage(const swift::misc::CStatusMessage &statusMessage)
Display status message in all info areas (according their state)
const CDockWidgetInfoArea * getSelectedDockInfoArea() const
Get the selected info area (non floating, selected in tabbar)
void resetPosition(int areaIndex)
Reset position.
int getSelectedDockInfoAreaIndex() const
Get the selected info area (non floating, selected in tabbar)
virtual void keyPressEvent(QKeyEvent *event)
void resetPositionByAction()
Reset window position of area (sender is QAction)
void allFloatingOnTop()
All floating info areas on top.
static const QString & fileNameDockWidgetTab()
File name dockwidgettab.qss.
static bool useStyleSheetInDerivedWidget(QWidget *derivedWidget, QStyle::PrimitiveElement element=QStyle::PE_Widget)
Use style sheets in derived widgets.
QString style(const QString &fileName) const
Style for given file name.
Class for emitting a log message.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
Streamable status message, e.g.
Status messages, e.g. from Core -> GUI.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Free functions in swift::misc.
auto makeRange(I begin, I2 end) -> CRange< I >
Returns a CRange constructed from begin and end iterators of deduced types.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
#define SWIFT_VERIFY(COND)
A weaker kind of assert.