From 125828e83018cd84cea373598cdf7da15460a1ff Mon Sep 17 00:00:00 2001 From: gexgd0419 <55008943+gexgd0419@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:39:47 +0800 Subject: [PATCH] Add helper for setting tab orders automatically The helper functions are put into separate files under the Helpers folder. The helper is used in OptionsWindow and SettingsWindow. The helper sets the tab order of a widget using its row and column number in the grid layout. The tab orders are assigned first from left to right, then from top to bottom. If in the future a different custom type of layout is used, or a container other than QTabWidget is used, then the helper functions may need to be changed. --- SandboxiePlus/SandMan/Helpers/TabOrder.cpp | 124 ++++++++++++++++++ SandboxiePlus/SandMan/Helpers/TabOrder.h | 4 + SandboxiePlus/SandMan/SandMan.pri | 2 + SandboxiePlus/SandMan/SandMan.vcxproj | 2 + SandboxiePlus/SandMan/SandMan.vcxproj.filters | 6 + .../SandMan/Windows/OptionsWindow.cpp | 56 +------- .../SandMan/Windows/SettingsWindow.cpp | 3 + 7 files changed, 144 insertions(+), 53 deletions(-) create mode 100644 SandboxiePlus/SandMan/Helpers/TabOrder.cpp create mode 100644 SandboxiePlus/SandMan/Helpers/TabOrder.h diff --git a/SandboxiePlus/SandMan/Helpers/TabOrder.cpp b/SandboxiePlus/SandMan/Helpers/TabOrder.cpp new file mode 100644 index 00000000..0009ddd3 --- /dev/null +++ b/SandboxiePlus/SandMan/Helpers/TabOrder.cpp @@ -0,0 +1,124 @@ +#include "stdafx.h" +#include "TabOrder.h" + +// Items to be sorted by row & col +template +struct ChildItem +{ + T item; + int row, col; + template + ChildItem(U&& item, int row, int col) + : item(std::forward(item)), row(row), col(col) {} + bool operator<(const ChildItem& other) const // make it sortable + { + if (row != other.row) + return row < other.row; + return col < other.col; // sort first by row, then by col + } +}; + +void GetWidgetsInOrder(QWidget* widget, std::vector& widgets); +void GetWidgetsInOrder(QLayout* layout, std::vector& widgets); + +// Fills the given list with widgets in the correct tab order (recursively) +void GetWidgetsInOrder(QWidget* widget, std::vector& widgets) +{ + if (widget->focusPolicy() != Qt::FocusPolicy::NoFocus) + { + widgets.push_back(widget); // add the widget itself + } + + if (QLayout* layout = widget->layout()) + { + // if managed by a layout + GetWidgetsInOrder(layout, widgets); + return; + } + + // If not managed by a layout, try to get its child widgets. + // Here only children of QTabWidgets are actually processed. + // More branches will be necessary if there's another type of container widget used. + + if (auto* parent = qobject_cast(widget)) + { + int cnt = parent->count(); + for (int i = 0; i < cnt; i++) + GetWidgetsInOrder(parent->widget(i), widgets); + } +} + +// Fills the given list with widgets in the correct tab order (recursively) +void GetWidgetsInOrder(QLayout* layout, std::vector& widgets) +{ + // Get a list of layout items in the layout, + // then sort by rows and columns to get the correct tab order + + int cnt = layout->count(); + std::vector> items; + + if (QGridLayout* gridLayout = qobject_cast(layout)) + { + for (int i = 0; i < cnt; i++) + { + int row, col, rowSpan, colSpan; + gridLayout->getItemPosition(i, &row, &col, &rowSpan, &colSpan); + items.emplace_back(gridLayout->itemAt(i), row, col); + } + } + else if (QFormLayout* formLayout = qobject_cast(layout)) + { + for (int i = 0; i < cnt; i++) + { + int row; + QFormLayout::ItemRole role; + formLayout->getItemPosition(i, &row, &role); + items.emplace_back(formLayout->itemAt(i), row, (int)role); + } + } + else + { + // For other types of layouts, preserve the order in the layout + for (int i = 0; i < cnt; i++) + { + items.emplace_back(layout->itemAt(i), 0, i); + } + } + + std::stable_sort(items.begin(), items.end()); + + // process all child layouts/widgets in the sorted order + for (const auto& item : items) + { + if (QLayout* l = item.item->layout()) + GetWidgetsInOrder(l, widgets); + else if (QWidget* w = item.item->widget()) + GetWidgetsInOrder(w, widgets); + } +} + +void SetTabOrder(QWidget* root) +{ + std::vector widgets; + GetWidgetsInOrder(root, widgets); + QWidget* prev = nullptr; + for (QWidget* widget : widgets) + { + if (prev) + QWidget::setTabOrder(prev, widget); + prev = widget; + } +} + +void SetTabOrder(QLayout* root) +{ + std::vector widgets; + GetWidgetsInOrder(root, widgets); + QWidget* prev = nullptr; + for (QWidget* widget : widgets) + { + if (prev) + QWidget::setTabOrder(prev, widget); + prev = widget; + } +} diff --git a/SandboxiePlus/SandMan/Helpers/TabOrder.h b/SandboxiePlus/SandMan/Helpers/TabOrder.h new file mode 100644 index 00000000..d4f49f9b --- /dev/null +++ b/SandboxiePlus/SandMan/Helpers/TabOrder.h @@ -0,0 +1,4 @@ +#pragma once + +void SetTabOrder(QWidget* root); +void SetTabOrder(QLayout* root); diff --git a/SandboxiePlus/SandMan/SandMan.pri b/SandboxiePlus/SandMan/SandMan.pri index 5ff41db1..b6cede3c 100644 --- a/SandboxiePlus/SandMan/SandMan.pri +++ b/SandboxiePlus/SandMan/SandMan.pri @@ -23,6 +23,7 @@ HEADERS += ./stdafx.h \ ./Helpers/StorageInfo.h \ ./Helpers/ReadDirectoryChanges.h \ ./Helpers/ReadDirectoryChangesPrivate.h \ + ./Helpers/TabOrder.h \ ./Windows/RecoveryWindow.h \ ./Windows/PopUpWindow.h \ ./Windows/SnapshotsWindow.h \ @@ -74,6 +75,7 @@ SOURCES += ./main.cpp \ ./Helpers/ReadDirectoryChanges.cpp \ ./Helpers/ReadDirectoryChangesPrivate.cpp \ ./Helpers/WindowFromPointEx.cpp \ + ./Helpers/TabOrder.cpp \ ./Windows/OptionsWindow.cpp \ ./Windows/PopUpWindow.cpp \ ./Windows/RecoveryWindow.cpp \ diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj b/SandboxiePlus/SandMan/SandMan.vcxproj index bb436e28..bd8db6c4 100644 --- a/SandboxiePlus/SandMan/SandMan.vcxproj +++ b/SandboxiePlus/SandMan/SandMan.vcxproj @@ -299,6 +299,7 @@ + @@ -485,6 +486,7 @@ + diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj.filters b/SandboxiePlus/SandMan/SandMan.vcxproj.filters index c2a47302..23fc3005 100644 --- a/SandboxiePlus/SandMan/SandMan.vcxproj.filters +++ b/SandboxiePlus/SandMan/SandMan.vcxproj.filters @@ -237,6 +237,9 @@ Windows + + Helpers + @@ -278,6 +281,9 @@ SandMan + + Helpers + diff --git a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp index d97f80c1..78c117eb 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp @@ -8,55 +8,7 @@ #include "../MiscHelpers/Common/SettingsWidgets.h" #include "Helpers/WinAdmin.h" #include "../Wizards/TemplateWizard.h" - - -static bool IsAncestorOf(QObject* container, QObject* obj) -{ - while (obj) - { - if (obj == container) - return true; - obj = obj->parent(); - } - return false; -} - -static QWidgetList GetTabOrder(QObject* container) -{ - QWidgetList list; - QWidget* pWidget = container->findChild(); - - if (!pWidget) - return list; - list.append(pWidget); - - for (QWidget* pPrev = pWidget->previousInFocusChain(); - pPrev && IsAncestorOf(container, pPrev); - pPrev = pPrev->previousInFocusChain()) - { - list.prepend(pPrev); - } - - for (QWidget* pNext = pWidget->nextInFocusChain(); - pNext && IsAncestorOf(container, pNext); - pNext = pNext->nextInFocusChain()) - { - list.append(pNext); - } - - return list; -} - -static void RestoreTabOrder(const QWidgetList& list) -{ - QWidget* pPrev = nullptr; - for (QWidget* pWidget : list) - { - if (pPrev) - QWidget::setTabOrder(pPrev, pWidget); - pPrev = pWidget; - } -} +#include "Helpers/TabOrder.h" class NoEditDelegate : public QStyledItemDelegate { @@ -324,14 +276,12 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri pDummy->setVisible(false); // merge recovery tabs - QWidgetList tabOrder = GetTabOrder(ui.tabsRecovery); QWidget* pWidget3 = new QWidget(); pWidget3->setLayout(ui.gridLayout_10); ui.gridLayout_24->addWidget(pWidget3, 1, 0); QWidget* pWidget4 = new QWidget(); pWidget4->setLayout(ui.gridLayout_56); ui.gridLayout_24->addWidget(pWidget4, 2, 0); - RestoreTabOrder(tabOrder); delete ui.tabsRecovery; ui.gridLayout_24->setContentsMargins(0, 0, 0, 0); @@ -357,7 +307,6 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri if (iOptionLayout == 1) { // merge stop tabs - tabOrder = GetTabOrder(ui.tabsStop); QWidget* pWidget1 = new QWidget(); pWidget1->setLayout(ui.gridLayout_57); ui.gridLayout_17->addWidget(pWidget1, 1, 0); @@ -371,7 +320,6 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri ui.lblStopOpt->setVisible(false); ui.lblStopOpt->setProperty("hidden", true); ui.gridLayout_17->addWidget(pWidget3, 3, 0); - RestoreTabOrder(tabOrder); delete ui.tabsStop; ui.gridLayout_17->setContentsMargins(0, 0, 0, 0); @@ -718,6 +666,8 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri this->addAction(pSetTree); } m_pSearch->setPlaceholderText(tr("Search for options")); + + SetTabOrder(this); } void COptionsWindow::ApplyIniEditFont() diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp index e0bfa296..3d0e1f02 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp @@ -17,6 +17,7 @@ #include #include #include +#include "Helpers/TabOrder.h" #include @@ -628,6 +629,8 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) this->addAction(pSetTree); } m_pSearch->setPlaceholderText(tr("Search for settings")); + + SetTabOrder(this); } void CSettingsWindow::ApplyIniEditFont()