From 76796796bec37a1670cfc4e0b1e42e7b1096b237 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 6 Jan 2021 18:44:10 +0100 Subject: Re-organize settings. Add setting to remember filters when restarting MO. --- src/CMakeLists.txt | 3 +- src/filterlist.cpp | 5 +- src/settings.cpp | 10 + src/settings.h | 5 + src/settingsdialog.cpp | 2 + src/settingsdialog.ui | 785 ++++++++++++++++++------------------ src/settingsdialoggeneral.cpp | 27 -- src/settingsdialoggeneral.h | 1 - src/settingsdialoguserinterface.cpp | 53 +++ src/settingsdialoguserinterface.h | 15 + src/settingsdialogworkarounds.cpp | 2 - 11 files changed, 488 insertions(+), 420 deletions(-) create mode 100644 src/settingsdialoguserinterface.cpp create mode 100644 src/settingsdialoguserinterface.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b74137e..a068f1a8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,7 +103,6 @@ add_filter(NAME src/mainwindow GROUPS filetree filetreeitem filetreemodel - filterlist mainwindow savestab statusbar @@ -145,6 +144,7 @@ add_filter(NAME src/modlist GROUPS ) add_filter(NAME src/modlist/view GROUPS + filterlist modlistview modlistviewactions modlistcontextmenu @@ -202,6 +202,7 @@ add_filter(NAME src/settingsdialog GROUPS settingsdialogplugins settingsdialogsteam settingsdialogworkarounds + settingsdialoguserinterface disableproxyplugindialog ) diff --git a/src/filterlist.cpp b/src/filterlist.cpp index 4c1c6fff..b594bcc6 100644 --- a/src/filterlist.cpp +++ b/src/filterlist.cpp @@ -234,7 +234,10 @@ void FilterList::restoreState(const Settings& s) s.widgets().restoreIndex(ui->filtersSeparators); s.widgets().restoreChecked(ui->filtersAnd); s.widgets().restoreChecked(ui->filtersOr); - s.widgets().restoreTreeCheckState(ui->filters, CriteriaItem::StateRole); + + if (m_core.settings().interface().saveFilters()) { + s.widgets().restoreTreeCheckState(ui->filters, CriteriaItem::StateRole); + } checkCriteria(); } diff --git a/src/settings.cpp b/src/settings.cpp index e04cd0c1..7f943904 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2195,6 +2195,16 @@ void InterfaceSettings::setCollapsibleSeparatorsConflicts(bool b) set(m_Settings, "Settings", "collapsible_separators_conflicts", b); } +bool InterfaceSettings::saveFilters() const +{ + return get(m_Settings, "Settings", "save_filters", false); +} + +void InterfaceSettings::setSaveFilters(bool b) +{ + set(m_Settings, "Settings", "save_filters", b); +} + bool InterfaceSettings::compactDownloads() const { return get(m_Settings, "Settings", "compact_downloads", false); diff --git a/src/settings.h b/src/settings.h index 043b22a4..d61f3c20 100644 --- a/src/settings.h +++ b/src/settings.h @@ -631,6 +631,11 @@ public: bool collapsibleSeparatorsConflicts() const; void setCollapsibleSeparatorsConflicts(bool b); + // whether to save/restore filter states between runs + // + bool saveFilters() const; + void setSaveFilters(bool b); + // whether to show compact downloads // bool compactDownloads() const; diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index c4a53fcd..d6b7ceec 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -25,6 +25,7 @@ along with Mod Organizer. If not, see . #include "settingsdialogpaths.h" #include "settingsdialogplugins.h" #include "settingsdialogsteam.h" +#include "settingsdialoguserinterface.h" #include "settingsdialogworkarounds.h" using namespace MOBase; @@ -39,6 +40,7 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings& setti ui->setupUi(this); m_tabs.push_back(std::unique_ptr(new GeneralSettingsTab(settings, *this))); + m_tabs.push_back(std::unique_ptr(new UserInterfaceSettingsTab(settings, *this))); m_tabs.push_back(std::unique_ptr(new PathsSettingsTab(settings, *this))); m_tabs.push_back(std::unique_ptr(new DiagnosticsSettingsTab(settings, *this))); m_tabs.push_back(std::unique_ptr(new NexusSettingsTab(settings, *this))); diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index ae4f4f34..a22beacd 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -7,7 +7,7 @@ 0 0 820 - 652 + 651 @@ -23,434 +23,473 @@ General - - - - - Qt::Vertical - - + + + + - 0 - 0 + 16777215 + 16777215 - + + Reset all choices made in dialogs. + + + Reset all choices made in dialogs. + + + Reset Dialog Choices + + - - - - Updates + + + + Show confirmation when changing instance - - - - - Check for Mod Organizer updates on Github on startup. - - - Check for Mod Organizer updates on Github on startup. - + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + - Check for updates + Language - - - - Update to non-stable releases. - - - Update to non-stable releases. - + + - Install Pre-releases (Betas) + Style - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - - - - User Interface - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Language - - - - - - - Style - - - - - - - Visual theme of the user interface. - - - Visual theme of the user interface. - - - - - - - Explore... - - - - - - - The language of the user interface. - - - The language of the user interface. - - - - - - - https://www.transifex.com/mod-organizer-2-team/mod-organizer-2/ - - - <a href="https://www.transifex.com/mod-organizer-2-team/mod-organizer-2/">Help translate Mod Organizer</a> - - - true - - - - - - - - + + - Dialogs will always be centered on the main window, but will remember their size. + Visual theme of the user interface. - Dialogs will always be centered on the main window, but will remember their size. - - - Always center dialogs + Visual theme of the user interface. - - + + - Show confirmation when changing instance + Explore... - - + + - Whether double-clicking on a file opens the preview window or launches the program associated with it. This applies to the Data tab as well as the Conflicts and Filetree tabs in the mod info window. - - - Open previews on double-click - - - - - - - - 16777215 - 16777215 - - - - Reset all choices made in dialogs. + The language of the user interface. - Reset all choices made in dialogs. - - - Reset Dialog Choices + The language of the user interface. - - + + - Modify the categories available to arrange your mods. - - - Modify the categories available to arrange your mods. + https://www.transifex.com/mod-organizer-2-team/mod-organizer-2/ - Configure Mod Categories - - - - - - - Qt::Vertical + <a href="https://www.transifex.com/mod-organizer-2-team/mod-organizer-2/">Help translate Mod Organizer</a> - - - 0 - 0 - + + true - + - - + + + + Modify the categories available to arrange your mods. + + + Modify the categories available to arrange your mods. + + + Configure Mod Categories + + + + + + + Dialogs will always be centered on the main window, but will remember their size. + + + Dialogs will always be centered on the main window, but will remember their size. + + + Always center dialogs + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + Whether double-clicking on a file opens the preview window or launches the program associated with it. This applies to the Data tab as well as the Conflicts and Filetree tabs in the mod info window. + + + Open previews on double-click + + + + + - Download List + Updates - + - + - Show meta information instead of file names in the download list. + Check for Mod Organizer updates on Github on startup. - Show meta information instead of file names in the download list. + Check for Mod Organizer updates on Github on startup. - Show Meta Information + Check for updates - + - Make the download list more compact. + Update to non-stable releases. - Make the download list more compact. + Update to non-stable releases. - Compact List + Install Pre-releases (Betas) - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - Colors + + + + + + + + User Interface + + + + + + 0 - - - - - QAbstractItemView::NoEditTriggers - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - QAbstractItemView::ScrollPerPixel - - - false - - - false - - - false - - - true - - - false - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Colors set on separators will also be shown in the mod list scrollbar at the location of the separator. This can be useful for quickly navigating to a specific separator. - - - Colors set on separators will also be shown in the mod list scrollbar at the location of the separator. This can be useful for quickly navigating to a specific separator. - - - Show mod list separator colors on the scrollbar - - - true + + + + + 0 + 0 + + + + Mod List + + + + + + Colors set on separators will also be shown in the mod list scrollbar at the location of the separator. This can be useful for quickly navigating to a specific separator. + + + Colors set on separators will also be shown in the mod list scrollbar at the location of the separator. This can be useful for quickly navigating to a specific separator. + + + Show mod list separator colors on the scrollbar + + + true + + + + + + + Disable this to no longer display mods installed outside MO in the mod list (left pane). Assets from those mods will then be treated as having lowest mod priority together with the original game content. + + + By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. +However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. + +If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps, esms, and esls) displayed in the right pane are completely unaffected by this feature. + + + Display mods installed outside MO + + + true + + + + + + + Save the current filters when closing MO2 and restore them on startup. + + + Save the current filters when closing MO2 and restore them on startup. + + + Remembers selected filters after restarting MO + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 5 + + + + + + + + Collapsible Separators + + + false + + + true + + + + 7 - - - - - - Qt::Horizontal + + 7 - - - 40 - 20 - + + + + Display mod conflicts on separator when collapsed. + + + Display mod conflicts on separator when collapsed. + + + Show conflicts on separators + + + true + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 0 + 0 + + + + + + + + + + + Download List + + + + + + Show meta information instead of file names in the download list. + + + Show meta information instead of file names in the download list. + + + Show Meta Information + + + + + + + Make the download list more compact. + + + Make the download list more compact. + + + Compact List + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + + + + + + Colors + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + QAbstractItemView::ScrollPerPixel + + + false + + + false + + + false + + + true + + + false + + + + + + + + 0 - - - - - - Reset all colors to their default value. + + 0 - - Reset all colors to their default value. + + 0 - - Reset Colors + + 0 - - - - - - - + + + + Reset all colors to their default value. + + + Reset all colors to their default value. + + + Reset Colors + + + + + + + + + + - - - + + + + Qt::Vertical + + - 0 - 0 + 20 + 40 - - Mod List - - - - - - Allow collapsing separators when sorting by ascending priority. - - - Use collapsible separators - - - true - - - false - - - - - - - Display mod conflicts on separator when collapsed. - - - Display mod conflicts on separator when collapsed. - - - Show conflicts on separators - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 0 - 0 - - - - - - + @@ -1520,25 +1559,6 @@ I don't yet know what the circumstances are, but user reports imply it is in som - - - - Disable this to no longer display mods installed outside MO in the mod list (left pane). Assets from those mods will then be treated as having lowest mod priority together with the original game content. - - - By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. -However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. - -If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps, esms, and esls) displayed in the right pane are completely unaffected by this feature. - - - Display mods installed outside MO - - - true - - - @@ -1572,7 +1592,7 @@ Uncheck this if you want to use Mod Organizer with total conversions (like Nehri - + Enable parsing of Archives. This is an Experimental Feature. Has negative effects on performance and known incorrectness. @@ -1824,16 +1844,7 @@ programs you are intentionally running. tabWidget languageBox styleBox - centerDialogs - resetDialogsButton - categoriesBtn - showMetaBox - compactBox - checkForUpdates usePrereleaseBox - colorTable - colorSeparatorsBox - resetColorsBtn baseDirEdit browseBaseDirBtn downloadDirEdit @@ -1869,8 +1880,6 @@ programs you are intentionally running. hideUncheckedBox forceEnableBox lockGUIBox - displayForeignBox - enableArchiveParsingBox bsaDateBtn execBlacklistBtn resetGeometryBtn diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp index 7b854260..11294d2a 100644 --- a/src/settingsdialoggeneral.cpp +++ b/src/settingsdialoggeneral.cpp @@ -17,32 +17,17 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) addStyles(); selectStyle(); - ui->colorTable->load(s); - - // connect before setting to trigger - QObject::connect(ui->collapsibleSeparatorsBox, &QCheckBox::stateChanged, [=](auto&& state) { - ui->collapsibleSeparatorsConflictsBox->setEnabled(state == Qt::Checked); - }); - ui->centerDialogs->setChecked(settings().geometry().centerDialogs()); ui->changeGameConfirmation->setChecked(settings().interface().showChangeGameConfirmation()); ui->doubleClickPreviews->setChecked(settings().interface().doubleClicksOpenPreviews()); - ui->compactBox->setChecked(settings().interface().compactDownloads()); - ui->showMetaBox->setChecked(settings().interface().metaDownloads()); ui->checkForUpdates->setChecked(settings().checkForUpdates()); ui->usePrereleaseBox->setChecked(settings().usePrereleases()); - ui->colorSeparatorsBox->setChecked(settings().colors().colorSeparatorScrollbar()); - ui->collapsibleSeparatorsConflictsBox->setChecked(settings().interface().collapsibleSeparatorsConflicts()); - ui->collapsibleSeparatorsBox->setChecked(settings().interface().collapsibleSeparators()); QObject::connect(ui->exploreStyles, &QPushButton::clicked, [&]{ onExploreStyles(); }); QObject::connect( ui->categoriesBtn, &QPushButton::clicked, [&]{ onEditCategories(); }); - QObject::connect( - ui->resetColorsBtn, &QPushButton::clicked, [&]{ onResetColors(); }); - QObject::connect( ui->resetDialogsButton, &QPushButton::clicked, [&]{ onResetDialogs(); }); } @@ -67,18 +52,11 @@ void GeneralSettingsTab::update() emit settings().styleChanged(newStyle); } - ui->colorTable->commitColors(); - settings().geometry().setCenterDialogs(ui->centerDialogs->isChecked()); settings().interface().setShowChangeGameConfirmation(ui->changeGameConfirmation->isChecked()); settings().interface().setDoubleClicksOpenPreviews(ui->doubleClickPreviews->isChecked()); - settings().interface().setCompactDownloads(ui->compactBox->isChecked()); - settings().interface().setMetaDownloads(ui->showMetaBox->isChecked()); settings().setCheckForUpdates(ui->checkForUpdates->isChecked()); settings().setUsePrereleases(ui->usePrereleaseBox->isChecked()); - settings().colors().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked()); - settings().interface().setCollapsibleSeparators(ui->collapsibleSeparatorsBox->isChecked()); - settings().interface().setCollapsibleSeparatorsConflicts(ui->collapsibleSeparatorsConflictsBox->isChecked()); } void GeneralSettingsTab::addLanguages() @@ -204,11 +182,6 @@ void GeneralSettingsTab::onEditCategories() } } -void GeneralSettingsTab::onResetColors() -{ - ui->colorTable->resetColors(); -} - void GeneralSettingsTab::onResetDialogs() { const auto r = QMessageBox::question( diff --git a/src/settingsdialoggeneral.h b/src/settingsdialoggeneral.h index 455edcaf..51e0dc72 100644 --- a/src/settingsdialoggeneral.h +++ b/src/settingsdialoggeneral.h @@ -22,7 +22,6 @@ private: void onExploreStyles(); void onEditCategories(); - void onResetColors(); void onResetDialogs(); }; diff --git a/src/settingsdialoguserinterface.cpp b/src/settingsdialoguserinterface.cpp new file mode 100644 index 00000000..550b4ddd --- /dev/null +++ b/src/settingsdialoguserinterface.cpp @@ -0,0 +1,53 @@ +#include "settingsdialoguserinterface.h" +#include "ui_settingsdialog.h" +#include "shared/appconfig.h" +#include "categoriesdialog.h" +#include "colortable.h" +#include +#include + +using namespace MOBase; + +UserInterfaceSettingsTab::UserInterfaceSettingsTab(Settings& s, SettingsDialog& d) + : SettingsTab(s, d) +{ + + // connect before setting to trigger + QObject::connect(ui->collapsibleSeparatorsBox, &QGroupBox::toggled, [=](auto&& on) { + ui->collapsibleSeparatorsConflictsBox->setEnabled(on); + }); + + // mod list + ui->displayForeignBox->setChecked(settings().interface().displayForeign()); + ui->colorSeparatorsBox->setChecked(settings().colors().colorSeparatorScrollbar()); + ui->collapsibleSeparatorsConflictsBox->setChecked(settings().interface().collapsibleSeparatorsConflicts()); + ui->collapsibleSeparatorsBox->setChecked(settings().interface().collapsibleSeparators()); + ui->saveFiltersBox->setChecked(settings().interface().saveFilters()); + + // download list + ui->compactBox->setChecked(settings().interface().compactDownloads()); + ui->showMetaBox->setChecked(settings().interface().metaDownloads()); + + // colors + ui->colorTable->load(s); + + QObject::connect(ui->resetColorsBtn, &QPushButton::clicked, [&] { ui->colorTable->resetColors(); }); + +} + +void UserInterfaceSettingsTab::update() +{ + // mod list + settings().colors().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked()); + settings().interface().setDisplayForeign(ui->displayForeignBox->isChecked()); + settings().interface().setCollapsibleSeparators(ui->collapsibleSeparatorsBox->isChecked()); + settings().interface().setCollapsibleSeparatorsConflicts(ui->collapsibleSeparatorsConflictsBox->isChecked()); + settings().interface().setSaveFilters(ui->saveFiltersBox->isChecked()); + + // download list + settings().interface().setCompactDownloads(ui->compactBox->isChecked()); + settings().interface().setMetaDownloads(ui->showMetaBox->isChecked()); + + // colors + ui->colorTable->commitColors(); +} diff --git a/src/settingsdialoguserinterface.h b/src/settingsdialoguserinterface.h new file mode 100644 index 00000000..8b4d48fa --- /dev/null +++ b/src/settingsdialoguserinterface.h @@ -0,0 +1,15 @@ +#ifndef SETTINGSDIALOGUSERINTERFACE_H +#define SETTINGSDIALOGUSERINTERFACE_H + +#include "settingsdialog.h" +#include "settings.h" + +class UserInterfaceSettingsTab : public SettingsTab +{ +public: + UserInterfaceSettingsTab(Settings& settings, SettingsDialog& dialog); + + void update() override; +}; + +#endif // SETTINGSDIALOGGENERAL_H diff --git a/src/settingsdialogworkarounds.cpp b/src/settingsdialogworkarounds.cpp index 1c5fbe26..c050c722 100644 --- a/src/settingsdialogworkarounds.cpp +++ b/src/settingsdialogworkarounds.cpp @@ -24,7 +24,6 @@ WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings& s, SettingsDialog& d) ui->hideUncheckedBox->setChecked(settings().game().hideUncheckedPlugins()); ui->forceEnableBox->setChecked(settings().game().forceEnableCoreFiles()); - ui->displayForeignBox->setChecked(settings().interface().displayForeign()); ui->lockGUIBox->setChecked(settings().interface().lockGUI()); ui->enableArchiveParsingBox->setChecked(settings().archiveParsing()); @@ -48,7 +47,6 @@ void WorkaroundsSettingsTab::update() settings().game().setHideUncheckedPlugins(ui->hideUncheckedBox->isChecked()); settings().game().setForceEnableCoreFiles(ui->forceEnableBox->isChecked()); - settings().interface().setDisplayForeign(ui->displayForeignBox->isChecked()); settings().interface().setLockGUI(ui->lockGUIBox->isChecked()); settings().setArchiveParsing(ui->enableArchiveParsingBox->isChecked()); settings().setExecutablesBlacklist(m_ExecutableBlacklist); -- cgit v1.3.1 From 1ac3f4d8e8ee7461f047d34e196df40499e89557 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 6 Jan 2021 19:43:21 +0100 Subject: Display children contents in collapsed separator. --- src/CMakeLists.txt | 1 + src/genericicondelegate.cpp | 16 ++------- src/genericicondelegate.h | 5 ++- src/icondelegate.cpp | 11 ++++-- src/icondelegate.h | 22 +++++++++--- src/modconflicticondelegate.cpp | 33 +++++------------- src/modconflicticondelegate.h | 15 ++++----- src/modcontenticondelegate.cpp | 57 +++++++++++++++++++++++++++++++ src/modcontenticondelegate.h | 30 +++++++++++++++++ src/modflagicondelegate.cpp | 16 ++------- src/modflagicondelegate.h | 22 ++++++------ src/modlist.cpp | 30 ----------------- src/modlist.h | 17 +++------- src/modlistview.cpp | 75 +++++++++++++++++++++++++++++++++++------ src/modlistview.h | 7 ++++ 15 files changed, 222 insertions(+), 135 deletions(-) create mode 100644 src/modcontenticondelegate.cpp create mode 100644 src/modcontenticondelegate.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a068f1a8..c274f989 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -149,6 +149,7 @@ add_filter(NAME src/modlist/view GROUPS modlistviewactions modlistcontextmenu modflagicondelegate + modcontenticondelegate modconflicticondelegate ) diff --git a/src/genericicondelegate.cpp b/src/genericicondelegate.cpp index 1e00f0e9..7afaca3f 100644 --- a/src/genericicondelegate.cpp +++ b/src/genericicondelegate.cpp @@ -4,28 +4,18 @@ #include -GenericIconDelegate::GenericIconDelegate(QObject *parent, int role, int logicalIndex, int compactSize) - : IconDelegate(parent) +GenericIconDelegate::GenericIconDelegate(QTreeView* parent, int role, int logicalIndex, int compactSize) + : IconDelegate(parent, logicalIndex, compactSize) , m_Role(role) - , m_LogicalIndex(logicalIndex) - , m_CompactSize(compactSize) - , m_Compact(false) { } -void GenericIconDelegate::columnResized(int logicalIndex, int, int newSize) -{ - if (logicalIndex == m_LogicalIndex) { - m_Compact = newSize < m_CompactSize; - } -} - QList GenericIconDelegate::getIcons(const QModelIndex &index) const { QList result; if (index.isValid()) { for (const QVariant &var : index.data(m_Role).toList()) { - if (!m_Compact || !var.toString().isEmpty()) { + if (!compact() || !var.toString().isEmpty()) { result.append(var.toString()); } } diff --git a/src/genericicondelegate.h b/src/genericicondelegate.h index 98605250..52db2bb6 100644 --- a/src/genericicondelegate.h +++ b/src/genericicondelegate.h @@ -20,9 +20,8 @@ public: * of the view, the delegate will turn off this behaviour if the column is smaller than "compactSize" * @param compactSize see explanation of logicalIndex */ - GenericIconDelegate(QObject *parent = nullptr, int role = Qt::UserRole + 1, int logicalIndex = -1, int compactSize = 150); -public slots: - void columnResized(int logicalIndex, int oldSize, int newSize); + GenericIconDelegate(QTreeView* parent, int role = Qt::UserRole + 1, int logicalIndex = -1, int compactSize = 150); + private: virtual QList getIcons(const QModelIndex &index) const; virtual size_t getNumIcons(const QModelIndex &index) const; diff --git a/src/icondelegate.cpp b/src/icondelegate.cpp index 901b5731..813395a2 100644 --- a/src/icondelegate.cpp +++ b/src/icondelegate.cpp @@ -27,9 +27,16 @@ along with Mod Organizer. If not, see . using namespace MOBase; -IconDelegate::IconDelegate(QObject* parent) - : QStyledItemDelegate(parent) +IconDelegate::IconDelegate(QTreeView* view, int column, int compactSize) : + QStyledItemDelegate(view), m_column(column), m_compactSize(compactSize), m_compact(false) { + if (view) { + connect(view->header(), &QHeaderView::sectionResized, [=](int column, int, int size) { + if (column == m_column) { + m_compact = size < m_compactSize; + } + }); + } } void IconDelegate::paintIcons( diff --git a/src/icondelegate.h b/src/icondelegate.h index bac71a62..a123470e 100644 --- a/src/icondelegate.h +++ b/src/icondelegate.h @@ -20,9 +20,9 @@ along with Mod Organizer. If not, see . #ifndef ICONDELEGATE_H #define ICONDELEGATE_H -#include "modinfo.h" -#include #include +#include +#include class IconDelegate : public QStyledItemDelegate @@ -30,16 +30,28 @@ class IconDelegate : public QStyledItemDelegate Q_OBJECT; public: - explicit IconDelegate(QObject *parent = 0); - virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + explicit IconDelegate(QTreeView* view, int column = -1, int compactSize = 100); + + void paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + +protected: + + // check if icons should be compacted or not + // + bool compact() const { return m_compact; } static void paintIcons( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index, const QList& icons); -protected: virtual QList getIcons(const QModelIndex &index) const = 0; virtual size_t getNumIcons(const QModelIndex &index) const = 0; + +private: + + int m_column; + int m_compactSize; + bool m_compact; }; #endif // ICONDELEGATE_H diff --git a/src/modconflicticondelegate.cpp b/src/modconflicticondelegate.cpp index 73c47a03..fc0ee48a 100644 --- a/src/modconflicticondelegate.cpp +++ b/src/modconflicticondelegate.cpp @@ -7,21 +7,10 @@ using namespace MOBase; ModConflictIconDelegate::ModConflictIconDelegate(ModListView* view, int logicalIndex, int compactSize) - : IconDelegate(view) - , m_View(view) - , m_LogicalIndex(logicalIndex) - , m_CompactSize(compactSize) - , m_Compact(false) + : IconDelegate(view, logicalIndex, compactSize), m_view(view) { } -void ModConflictIconDelegate::columnResized(int logicalIndex, int, int newSize) -{ - if (logicalIndex == m_LogicalIndex) { - m_Compact = newSize < m_CompactSize; - } -} - QList ModConflictIconDelegate::getIconsForFlags( std::vector flags, bool compact) { @@ -94,8 +83,8 @@ QList ModConflictIconDelegate::getIcons(const QModelIndex &index) const } bool compact; - auto flags = m_View->conflictFlags(index, &compact); - return getIconsForFlags(flags, compact || m_Compact); + auto flags = m_view->conflictFlags(index, &compact); + return getIconsForFlags(flags, compact || this->compact()); } QString ModConflictIconDelegate::getFlagIcon(ModInfo::EConflictFlag flag) @@ -119,19 +108,13 @@ QString ModConflictIconDelegate::getFlagIcon(ModInfo::EConflictFlag flag) size_t ModConflictIconDelegate::getNumIcons(const QModelIndex &index) const { - unsigned int modIdx = index.data(ModList::IndexRole).toInt(); - if (modIdx < ModInfo::getNumMods()) { - ModInfo::Ptr info = ModInfo::getByIndex(modIdx); - std::vector flags = info->getConflictFlags(); - size_t count = flags.size(); - if (std::find_first_of(flags.begin(), flags.end(), - s_ConflictFlags.begin(), s_ConflictFlags.end()) == flags.end()) { - ++count; - } - return count; - } else { + QVariant modIndex = index.data(ModList::IndexRole); + + if (!modIndex.isValid()) { return 0; } + + return m_view->conflictFlags(index, nullptr).size(); } QSize ModConflictIconDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &modelIndex) const diff --git a/src/modconflicticondelegate.h b/src/modconflicticondelegate.h index a44ce89b..fd524444 100644 --- a/src/modconflicticondelegate.h +++ b/src/modconflicticondelegate.h @@ -4,6 +4,7 @@ #include #include "icondelegate.h" +#include "modinfo.h" class ModListView; @@ -12,12 +13,9 @@ class ModConflictIconDelegate : public IconDelegate Q_OBJECT; public: - explicit ModConflictIconDelegate(ModListView* parent = nullptr, int logicalIndex = -1, int compactSize = 80); + explicit ModConflictIconDelegate(ModListView* view, int logicalIndex = -1, int compactSize = 80); QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex &index) const override; -public slots: - void columnResized(int logicalIndex, int oldSize, int newSize); - protected: static QList getIconsForFlags(std::vector flags, bool compact); @@ -26,6 +24,10 @@ protected: QList getIcons(const QModelIndex &index) const override; size_t getNumIcons(const QModelIndex &index) const override; + // constructor for color table + // + ModConflictIconDelegate() : ModConflictIconDelegate(nullptr) { } + private: static constexpr std::array s_ConflictFlags{ ModInfo::FLAG_CONFLICT_MIXED, @@ -43,10 +45,7 @@ private: ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN }; - ModListView* m_View; - int m_LogicalIndex; - int m_CompactSize; - bool m_Compact; + ModListView* m_view; }; #endif // MODCONFLICTICONDELEGATE_H diff --git a/src/modcontenticondelegate.cpp b/src/modcontenticondelegate.cpp new file mode 100644 index 00000000..57a4dc6d --- /dev/null +++ b/src/modcontenticondelegate.cpp @@ -0,0 +1,57 @@ +#include "modcontenticondelegate.h" + +#include "modlistview.h" + +ModContentIconDelegate::ModContentIconDelegate(ModListView* view, int column, int compactSize) + : IconDelegate(view, column, compactSize), m_view(view) +{ +} + +QList ModContentIconDelegate::getIcons(const QModelIndex& index) const +{ + QVariant modIndex = index.data(ModList::IndexRole); + + if (!modIndex.isValid()) { + return {}; + } + + bool compact; + auto icons = m_view->contentsIcons(index, &compact); + + if (compact || this->compact()) { + icons.removeAll(QString()); + } + + return icons; +} + +size_t ModContentIconDelegate::getNumIcons(const QModelIndex& index) const +{ + return getIcons(index).size(); +} + +bool ModContentIconDelegate::helpEvent( + QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index) +{ + if (!event || !view) { + return false; + } + if (event->type() == QEvent::ToolTip) { + // this code is from QAbstractItemDelegate::helpEvent, only the the way + // text is retrieved has been changed + QHelpEvent* he = static_cast(event); + const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp + const QString tooltip = index.isValid() ? m_view->contentsTooltip(index) : QString(); + QRect rect; + if (index.isValid()) { + const QRect r = view->visualRect(index); + rect = QRect(view->mapToGlobal(r.topLeft()), r.size()); + } + QToolTip::showText(he->globalPos(), tooltip, view, rect); + event->setAccepted(!tooltip.isEmpty()); + return true; + } + else { + return IconDelegate::helpEvent(event, view, option, index); + } +} diff --git a/src/modcontenticondelegate.h b/src/modcontenticondelegate.h new file mode 100644 index 00000000..c195df18 --- /dev/null +++ b/src/modcontenticondelegate.h @@ -0,0 +1,30 @@ +#ifndef MODCONTENTICONDELEGATE_H +#define MODCONTENTICONDELEGATE_H + +#include "icondelegate.h" + +class ModListView; + +class ModContentIconDelegate : public IconDelegate +{ + Q_OBJECT +public: + + explicit ModContentIconDelegate(ModListView* view, int column = -1, int compactSize = 150); + + bool helpEvent(QHelpEvent* event, QAbstractItemView* view, + const QStyleOptionViewItem& option, const QModelIndex& index) override; + +protected: + QList getIcons(const QModelIndex& index) const override; + size_t getNumIcons(const QModelIndex& index) const override; + + // constructor for color table + // + ModContentIconDelegate() : ModContentIconDelegate(nullptr) { } + +private: + ModListView* m_view; +}; + +#endif // GENERICICONDELEGATE_H diff --git a/src/modflagicondelegate.cpp b/src/modflagicondelegate.cpp index 3ac1085e..c709f30d 100644 --- a/src/modflagicondelegate.cpp +++ b/src/modflagicondelegate.cpp @@ -5,21 +5,11 @@ using namespace MOBase; -ModFlagIconDelegate::ModFlagIconDelegate(QObject *parent, int logicalIndex, int compactSize) - : IconDelegate(parent) - , m_LogicalIndex(logicalIndex) - , m_CompactSize(compactSize) - , m_Compact(false) +ModFlagIconDelegate::ModFlagIconDelegate(QTreeView* view, int column, int compactSize) + : IconDelegate(view, column, compactSize) { } -void ModFlagIconDelegate::columnResized(int logicalIndex, int, int newSize) -{ - if (logicalIndex == m_LogicalIndex) { - m_Compact = newSize < m_CompactSize; - } -} - QList ModFlagIconDelegate::getIconsForFlags( std::vector flags, bool compact) { @@ -44,7 +34,7 @@ QList ModFlagIconDelegate::getIcons(const QModelIndex &index) const if (modid.isValid()) { ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt()); - return getIconsForFlags(info->getFlags(), m_Compact); + return getIconsForFlags(info->getFlags(), compact()); } return {}; diff --git a/src/modflagicondelegate.h b/src/modflagicondelegate.h index c6c7c3e8..63ab8978 100644 --- a/src/modflagicondelegate.h +++ b/src/modflagicondelegate.h @@ -1,32 +1,30 @@ #ifndef MODFLAGICONDELEGATE_H #define MODFLAGICONDELEGATE_H +#include + #include "icondelegate.h" +#include "modinfo.h" class ModFlagIconDelegate : public IconDelegate { Q_OBJECT; public: - explicit ModFlagIconDelegate(QObject *parent = 0, int logicalIndex = -1, int compactSize = 120); + explicit ModFlagIconDelegate(QTreeView* view, int column = -1, int compactSize = 120); QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; - static QList getIconsForFlags( - std::vector flags, bool compact); - +protected: + static QList getIconsForFlags(std::vector flags, bool compact); static QString getFlagIcon(ModInfo::EFlag flag); -public slots: - void columnResized(int logicalIndex, int oldSize, int newSize); - -protected: QList getIcons(const QModelIndex &index) const override; size_t getNumIcons(const QModelIndex &index) const override; -private: - int m_LogicalIndex; - int m_CompactSize; - bool m_Compact; + // constructor for color table + // + ModFlagIconDelegate() : ModFlagIconDelegate(nullptr) { } + }; #endif // MODFLAGICONDELEGATE_H diff --git a/src/modlist.cpp b/src/modlist.cpp index ea1d2754..055778f3 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -194,30 +194,6 @@ QString ModList::getConflictFlagText(ModInfo::EConflictFlag flag, ModInfo::Ptr m } } - -QVariantList ModList::contentsToIcons(const std::set &contents) const -{ - QVariantList result; - m_Organizer->modDataContents().forEachContentInOrOut( - contents, - [&result](auto const& content) { result.append(content.icon()); }, - [&result](auto const&) { result.append(QString()); }); - return result; -} - -QString ModList::contentsToToolTip(const std::set &contents) const -{ - QString result(""); - m_Organizer->modDataContents().forEachContentIn(contents, [&result](auto const& content) { - result.append(QString("" - "") - .arg(content.icon()).arg(content.name())); - }); - result.append("
%2
"); - return result; -} - - QVariant ModList::data(const QModelIndex &modelIndex, int role) const { if (m_Profile == nullptr) return QVariant(); @@ -385,9 +361,6 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const default: return QtGroupingProxy::AGGR_NONE; } } - else if (role == ContentsRole) { - return contentsToIcons(modInfo->getContents()); - } else if (role == GameNameRole) { return modInfo->gameName(); } @@ -494,9 +467,6 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return result; } - else if (column == COL_CONTENT) { - return contentsToToolTip(modInfo->getContents()); - } else if (column == COL_NAME) { try { return modInfo->getDescription(); diff --git a/src/modlist.h b/src/modlist.h index 1d94749c..5c7f28ee 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -69,19 +69,14 @@ public: // grouping I assume?) AggrRole = Qt::UserRole + 2, - // data(ContentsRole) contains mod data contents as a QVariantList - // containing icon paths - ContentsRole = Qt::UserRole + 3, - - GameNameRole = Qt::UserRole + 4, - - PriorityRole = Qt::UserRole + 5, + GameNameRole = Qt::UserRole + 3, + PriorityRole = Qt::UserRole + 4, // marking role for the scrollbar - ScrollMarkRole = Qt::UserRole + 6, + ScrollMarkRole = Qt::UserRole + 5, // this is the first available role - ModUserRole = Qt::UserRole + 7 + ModUserRole = Qt::UserRole + 6 }; enum EColumn { @@ -354,10 +349,6 @@ private: QString getColumnToolTip(int column) const; - QVariantList contentsToIcons(const std::set &contentIds) const; - - QString contentsToToolTip(const std::set &contentsIds) const; - ModList::EColumn getEnabledColumn(int index) const; QVariant categoryData(int categoryID, int column, int role) const; diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 4b285733..63999ce9 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -18,6 +18,7 @@ #include "log.h" #include "modflagicondelegate.h" #include "modconflicticondelegate.h" +#include "modcontenticondelegate.h" #include "modlistviewactions.h" #include "modlistdropinfo.h" #include "modlistcontextmenu.h" @@ -741,17 +742,9 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo connect(header(), &QHeaderView::sectionResized, [=](int logicalIndex, int oldSize, int newSize) { m_sortProxy->setColumnVisible(logicalIndex, newSize != 0); }); - GenericIconDelegate* contentDelegate = new GenericIconDelegate(this, ModList::ContentsRole, ModList::COL_CONTENT, 150); - ModFlagIconDelegate* flagDelegate = new ModFlagIconDelegate(this, ModList::COL_FLAGS, 120); - ModConflictIconDelegate* conflictFlagDelegate = new ModConflictIconDelegate(this, ModList::COL_CONFLICTFLAGS, 80); - - connect(header(), &QHeaderView::sectionResized, contentDelegate, &GenericIconDelegate::columnResized); - connect(header(), &QHeaderView::sectionResized, flagDelegate, &ModFlagIconDelegate::columnResized); - connect(header(), &QHeaderView::sectionResized, conflictFlagDelegate, &ModConflictIconDelegate::columnResized); - - setItemDelegateForColumn(ModList::COL_FLAGS, flagDelegate); - setItemDelegateForColumn(ModList::COL_CONFLICTFLAGS, conflictFlagDelegate); - setItemDelegateForColumn(ModList::COL_CONTENT, contentDelegate); + setItemDelegateForColumn(ModList::COL_FLAGS, new ModFlagIconDelegate(this, ModList::COL_FLAGS, 120)); + setItemDelegateForColumn(ModList::COL_CONFLICTFLAGS, new ModConflictIconDelegate(this, ModList::COL_CONFLICTFLAGS, 80)); + setItemDelegateForColumn(ModList::COL_CONTENT, new ModContentIconDelegate(this, ModList::COL_CONTENT, 150)); if (m_core->settings().geometry().restoreState(header())) { // hack: force the resize-signal to be triggered because restoreState doesn't seem to do that @@ -1118,6 +1111,66 @@ std::vector ModListView::conflictFlags(const QModelIndex return flags; } +std::set ModListView::contents(const QModelIndex& index, bool* includeChildren) const +{ + auto modIndex = index.data(ModList::IndexRole); + if (!modIndex.isValid()) { + return {}; + } + ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); + auto contents = info->getContents(); + bool children = false; + + if (info->isSeparator() + && hasCollapsibleSeparators() + && m_core->settings().interface().collapsibleSeparatorsConflicts() + && !isExpanded(index.sibling(index.row(), 0))) { + + // combine the child contents + std::set eContents(contents.begin(), contents.end()); + for (int i = 0; i < model()->rowCount(index); ++i) { + auto cIndex = model()->index(i, index.column(), index).data(ModList::IndexRole).toInt(); + auto cContents = ModInfo::getByIndex(cIndex)->getContents(); + eContents.insert(cContents.begin(), cContents.end()); + } + contents = { eContents.begin(), eContents.end() }; + children = true; + } + + if (includeChildren) { + *includeChildren = children; + } + + return contents; +} + +QList ModListView::contentsIcons(const QModelIndex& index, bool* forceCompact) const +{ + auto contents = this->contents(index, forceCompact); + QList result; + m_core->modDataContents().forEachContentInOrOut( + contents, + [&result](auto const& content) { result.append(content.icon()); }, + [&result](auto const&) { result.append(QString()); }); + return result; +} + +QString ModListView::contentsTooltip(const QModelIndex& index) const +{ + auto contents = this->contents(index, nullptr); + if (contents.empty()) { + return {}; + } + QString result(""); + m_core->modDataContents().forEachContentIn(contents, [&result](auto const& content) { + result.append(QString("" + "") + .arg(content.icon()).arg(content.name())); + }); + result.append("
%2
"); + return result; +} + void ModListView::onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { if (hasCollapsibleSeparators()) { diff --git a/src/modlistview.h b/src/modlistview.h index 2fed4969..48e003bd 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -173,6 +173,7 @@ protected slots: private: friend class ModConflictIconDelegate; + friend class ModContentIconDelegate; friend class ModListStyledItemDelegated; friend class ModListViewMarkingScrollBar; @@ -199,6 +200,12 @@ private: std::vector conflictFlags( const QModelIndex& index, bool* forceCompact = nullptr) const; + // retrieve the content icons and tooltip for the given index + // + std::set contents(const QModelIndex& index, bool* includeChildren) const; + QList contentsIcons(const QModelIndex& index, bool* forceCompact = nullptr) const; + QString contentsTooltip(const QModelIndex& index) const; + // get/set the selected items on the view, this method return/take indices // from the mod list model, not the view, so it's safe to restore // -- cgit v1.3.1 From 183440d6949578c2c626022d42ee412919a19552 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 7 Jan 2021 19:47:13 +0100 Subject: Display mod flags on collapsed separators. --- src/modflagicondelegate.cpp | 10 ++++++---- src/modflagicondelegate.h | 7 ++++++- src/modlistview.cpp | 44 +++++++++++++++++++++++++++++++++++--------- src/modlistview.h | 6 ++++++ 4 files changed, 53 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/modflagicondelegate.cpp b/src/modflagicondelegate.cpp index c709f30d..30a3c376 100644 --- a/src/modflagicondelegate.cpp +++ b/src/modflagicondelegate.cpp @@ -1,12 +1,13 @@ #include "modflagicondelegate.h" #include "modlist.h" +#include "modlistview.h" #include #include using namespace MOBase; -ModFlagIconDelegate::ModFlagIconDelegate(QTreeView* view, int column, int compactSize) - : IconDelegate(view, column, compactSize) +ModFlagIconDelegate::ModFlagIconDelegate(ModListView* view, int column, int compactSize) + : IconDelegate(view, column, compactSize), m_view(view) { } @@ -33,8 +34,9 @@ QList ModFlagIconDelegate::getIcons(const QModelIndex &index) const QVariant modid = index.data(ModList::IndexRole); if (modid.isValid()) { - ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt()); - return getIconsForFlags(info->getFlags(), compact()); + bool compact; + auto flags = m_view->modFlags(index, &compact); + return getIconsForFlags(flags, compact || this->compact()); } return {}; diff --git a/src/modflagicondelegate.h b/src/modflagicondelegate.h index 63ab8978..24dd4a0e 100644 --- a/src/modflagicondelegate.h +++ b/src/modflagicondelegate.h @@ -6,12 +6,14 @@ #include "icondelegate.h" #include "modinfo.h" +class ModListView; + class ModFlagIconDelegate : public IconDelegate { Q_OBJECT; public: - explicit ModFlagIconDelegate(QTreeView* view, int column = -1, int compactSize = 120); + explicit ModFlagIconDelegate(ModListView* view, int column = -1, int compactSize = 120); QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; protected: @@ -25,6 +27,9 @@ protected: // ModFlagIconDelegate() : ModFlagIconDelegate(nullptr) { } +private: + ModListView* m_view; + }; #endif // MODFLAGICONDELEGATE_H diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 63999ce9..7c67c599 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -217,10 +217,8 @@ std::optional ModListView::nextMod(unsigned int modIndex) const ModInfo::Ptr mod = ModInfo::getByIndex(modIndex); - // skip overwrite and backups and separators - if (mod->hasFlag(ModInfo::FLAG_OVERWRITE) || - mod->hasFlag(ModInfo::FLAG_BACKUP) || - mod->hasFlag(ModInfo::FLAG_SEPARATOR)) { + // skip overwrite, backups and separators + if (mod->isOverwrite() || mod->isBackup() || mod->isSeparator()) { continue; } @@ -246,12 +244,9 @@ std::optional ModListView::prevMod(unsigned int modIndex) const modIndex = index.data(ModList::IndexRole).toInt(); - // skip overwrite and backups and separators + // skip overwrite, backups and separators ModInfo::Ptr mod = ModInfo::getByIndex(modIndex); - - if (mod->hasFlag(ModInfo::FLAG_OVERWRITE) || - mod->hasFlag(ModInfo::FLAG_BACKUP) || - mod->hasFlag(ModInfo::FLAG_SEPARATOR)) { + if (mod->isOverwrite() || mod->isBackup() || mod->isSeparator()) { continue; } @@ -1080,6 +1075,37 @@ QColor ModListView::markerColor(const QModelIndex& index) const return QColor(); } +std::vector ModListView::modFlags(const QModelIndex& index, bool* forceCompact) const +{ + ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); + + auto flags = info->getFlags(); + bool compact = false; + if (info->isSeparator() + && hasCollapsibleSeparators() + && m_core->settings().interface().collapsibleSeparatorsConflicts() + && !isExpanded(index.sibling(index.row(), 0))) { + + // combine the child conflicts + std::set eFlags(flags.begin(), flags.end()); + for (int i = 0; i < model()->rowCount(index); ++i) { + auto cIndex = model()->index(i, index.column(), index).data(ModList::IndexRole).toInt(); + auto cFlags = ModInfo::getByIndex(cIndex)->getFlags(); + eFlags.insert(cFlags.begin(), cFlags.end()); + } + flags = { eFlags.begin(), eFlags.end() }; + + // force compact because there can be a lots of flags here + compact = true; + } + + if (forceCompact) { + *forceCompact = true; + } + + return flags; +} + std::vector ModListView::conflictFlags(const QModelIndex& index, bool* forceCompact) const { ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); diff --git a/src/modlistview.h b/src/modlistview.h index 48e003bd..af4e83c0 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -173,6 +173,7 @@ protected slots: private: friend class ModConflictIconDelegate; + friend class ModFlagIconDelegate; friend class ModContentIconDelegate; friend class ModListStyledItemDelegated; friend class ModListViewMarkingScrollBar; @@ -195,6 +196,11 @@ private: // QColor markerColor(const QModelIndex& index) const; + // retrieve the mod flags for the given index + // + std::vector modFlags( + const QModelIndex& index, bool* forceCompact = nullptr) const; + // retrieve the conflicts flags for the given index // std::vector conflictFlags( -- cgit v1.3.1 From 5765439c7cff4e314a0c5732432bdb7b20e91efd Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 7 Jan 2021 19:47:31 +0100 Subject: Alt+Click select/deselect the rows below from a separator. --- src/modlistview.cpp | 24 ++++++++++++++++++++++++ src/modlistview.h | 1 + 2 files changed, 25 insertions(+) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 7c67c599..7c770709 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -1311,6 +1311,30 @@ void ModListView::timerEvent(QTimerEvent* event) } } +void ModListView::mousePressEvent(QMouseEvent* event) +{ + // we call the parent class first so that we can use the actual + // selection state of the item after + QTreeView::mousePressEvent(event); + + const auto index = indexAt(event->pos()); + + if (event->isAccepted() + && hasCollapsibleSeparators() + && index.isValid() && model()->hasChildren(indexAt(event->pos())) + && (event->modifiers() & Qt::AltModifier)) { + + const auto flag = selectionModel()->isSelected(index) ? + QItemSelectionModel::Select : QItemSelectionModel::Deselect; + const bool expanded = isExpanded(index); + const QItemSelection selection( + model()->index(0, index.column(), index), + model()->index(model()->rowCount(index) - 1, index.column(), index)); + selectionModel()->select(selection, flag | QItemSelectionModel::Rows); + setExpanded(index, expanded); + } +} + bool ModListView::event(QEvent* event) { if (event->type() == QEvent::KeyPress diff --git a/src/modlistview.h b/src/modlistview.h index af4e83c0..08ecd935 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -161,6 +161,7 @@ protected: void dragEnterEvent(QDragEnterEvent* event) override; void dragMoveEvent(QDragMoveEvent* event) override; void dropEvent(QDropEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; bool event(QEvent* event) override; protected slots: -- cgit v1.3.1 From f919e0917344d7396f03423ef4fcd4d41fe37b07 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 7 Jan 2021 20:11:26 +0100 Subject: Show conflicts and highligth plugins from collapsed separators. --- src/modinfo.cpp | 1 + src/modinfo.h | 63 ++++++++++++++----------------- src/modinfowithconflictinfo.h | 21 ++++------- src/modlistview.cpp | 87 ++++++++++++++++++++----------------------- src/modlistview.h | 15 +++++--- src/settingsdialog.ui | 6 +-- 6 files changed, 89 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/src/modinfo.cpp b/src/modinfo.cpp index c76cb4ad..b46a68ab 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -49,6 +49,7 @@ using namespace MOBase; using namespace MOShared; +const std::set ModInfo::s_EmptySet; std::vector ModInfo::s_Collection; ModInfo::Ptr ModInfo::s_Overwrite; std::map ModInfo::s_ModsByName; diff --git a/src/modinfo.h b/src/modinfo.h index 08ed94f8..634ea900 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -868,46 +868,35 @@ public: // Nexus stuff public: // Conflicts - /** - * @return retrieve list of mods (as mod index) that are overwritten by this one. - * Updates may be delayed. - */ - virtual std::set getModOverwrite() const { - return std::set(); } + // retrieve the list of mods (as mod index) that are overwritten by this one. + // Updates may be delayed. + // + virtual const std::set& getModOverwrite() const { return s_EmptySet; } - /** - * @return list of mods (as mod index) that overwrite this one. Updates may be delayed. - */ - virtual std::set getModOverwritten() const { - return std::set(); } + // retrieve the list of mods (as mod index) that overwrite this one. + // Updates may be delayed. + // + virtual const std::set& getModOverwritten() const { return s_EmptySet; } - /** - * @return retrieve list of mods (as mod index) with archives that are overwritten by - * this one. Updates may be delayed - */ - virtual std::set getModArchiveOverwrite() const { - return std::set(); } + // retrieve the list of mods (as mod index) with archives that are overwritten by + // this one. Updates may be delayed + // + virtual const std::set& getModArchiveOverwrite() const { return s_EmptySet; } - /** - * @return list of mods (as mod index) with archives that overwrite this one. Updates - * may be delayed. - */ - virtual std::set getModArchiveOverwritten() const { - return std::set(); } + // retrieve the list of mods (as mod index) with archives that overwrite this one. Updates + // may be delayed. + // + virtual const std::set& getModArchiveOverwritten() const { return s_EmptySet; } - /** - * @return the list of mods (as mod index) with archives that are overwritten by loose - * files of this mod. Updates may be delayed. - */ - virtual std::set getModArchiveLooseOverwrite() const { - return std::set(); } + // retrieve the list of mods (as mod index) with archives that are overwritten by loose + // files of this mod. Updates may be delayed. + // + virtual const std::set& getModArchiveLooseOverwrite() const { return s_EmptySet; } - /** - * @return the list of mods (as mod index) with loose files that overwrite this one's - * archive files. Updates may be delayed. - */ - virtual std::set getModArchiveLooseOverwritten() const { - return std::set(); } + // retrieve the list of mods (as mod index) with loose files that overwrite this one's + // archive files. Updates may be delayed. + // + virtual const std::set& getModArchiveLooseOverwritten() const { return s_EmptySet; } /** * @brief Update conflict information. @@ -960,6 +949,10 @@ protected: MOBase::VersionInfo m_Version; bool m_PluginSelected = false; + // empty set that can be returned in overwrite functions by + // default + static const std::set s_EmptySet; + protected: friend class OrganizerCore; diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h index 889f1246..c9cddb60 100644 --- a/src/modinfowithconflictinfo.h +++ b/src/modinfowithconflictinfo.h @@ -52,21 +52,16 @@ public: /** * @brief clear all caches held for this mod */ - virtual void clearCaches() override; + void clearCaches() override; - virtual std::set getModOverwrite() const override { return m_OverwriteList; } + const std::set& getModOverwrite() const override { return m_OverwriteList; } + const std::set& getModOverwritten() const override { return m_OverwrittenList; } + const std::set& getModArchiveOverwrite() const override { return m_ArchiveOverwriteList; } + const std::set& getModArchiveOverwritten() const override { return m_ArchiveOverwrittenList; } + const std::set& getModArchiveLooseOverwrite() const override { return m_ArchiveLooseOverwriteList; } + const std::set& getModArchiveLooseOverwritten() const override { return m_ArchiveLooseOverwrittenList; } - virtual std::set getModOverwritten() const override { return m_OverwrittenList; } - - virtual std::set getModArchiveOverwrite() const override { return m_ArchiveOverwriteList; } - - virtual std::set getModArchiveOverwritten() const override { return m_ArchiveOverwrittenList; } - - virtual std::set getModArchiveLooseOverwrite() const override { return m_ArchiveLooseOverwriteList; } - - virtual std::set getModArchiveLooseOverwritten() const override { return m_ArchiveLooseOverwrittenList; } - - virtual void doConflictCheck() const override; + void doConflictCheck() const override; public slots: diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 7c770709..2c9634bd 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -417,7 +417,7 @@ void ModListView::onModPrioritiesChanged(const QModelIndexList& indices) } // update conflict check on the moved mod modInfo->doConflictCheck(); - setOverwriteMarkers(modInfo); + setOverwriteMarkers(selectionModel()->selectedRows()); } } } @@ -682,7 +682,8 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo m_actions = new ModListViewActions(core, *m_filters, factory, this, mwui->espList, mw); ui = { mwui->groupCombo, mwui->activeModsCounter, mwui->modFilterEdit, - mwui->currentCategoryLabel, mwui->clearFiltersButton, mwui->filtersSeparators + mwui->currentCategoryLabel, mwui->clearFiltersButton, mwui->filtersSeparators, + mwui->espList }; connect(m_core, &OrganizerCore::modInstalled, [=](auto&& name) { onModInstalled(name); }); @@ -765,16 +766,6 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo header()->setSectionResizeMode(ModList::COL_NAME, QHeaderView::Stretch); } - // highligth plugins - connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=](auto&& selected) { - std::vector modIndices; - for (auto& idx : selectionModel()->selectedRows()) { - modIndices.push_back(idx.data(ModList::IndexRole).toInt()); - } - m_core->pluginList()->highlightPlugins(modIndices, *m_core->directoryStructure()); - mwui->espList->verticalScrollBar()->repaint(); - }); - // prevent the name-column from being hidden header()->setSectionHidden(ModList::COL_NAME, false); @@ -962,35 +953,23 @@ void ModListView::clearOverwriteMarkers() m_markers.archiveLooseOverwritten.clear(); } -void ModListView::setOverwriteMarkers(const std::set& overwrite, const std::set& overwritten) -{ - m_markers.overwrite = overwrite; - m_markers.overwritten = overwritten; -} - -void ModListView::setArchiveOverwriteMarkers(const std::set& overwrite, const std::set& overwritten) -{ - m_markers.archiveOverwrite = overwrite; - m_markers.archiveOverwritten = overwritten; -} - -void ModListView::setArchiveLooseOverwriteMarkers(const std::set& overwrite, const std::set& overwritten) -{ - m_markers.archiveLooseOverwrite = overwrite; - m_markers.archiveLooseOverwritten = overwritten; -} - -void ModListView::setOverwriteMarkers(ModInfo::Ptr mod) +void ModListView::setOverwriteMarkers(const QModelIndexList& indexes) { - if (mod) { - setOverwriteMarkers(mod->getModOverwrite(), mod->getModOverwritten()); - setArchiveOverwriteMarkers(mod->getModArchiveOverwrite(), mod->getModArchiveOverwritten()); - setArchiveLooseOverwriteMarkers(mod->getModArchiveLooseOverwrite(), mod->getModArchiveLooseOverwritten()); - } - else { - setOverwriteMarkers({}, {}); - setArchiveOverwriteMarkers({}, {}); - setArchiveLooseOverwriteMarkers({}, {}); + const auto insert = [](auto& dest, const auto& from) { + dest.insert(from.begin(), from.end()); + }; + clearOverwriteMarkers(); + for (auto& idx : indexes) { + auto mIndex = idx.data(ModList::IndexRole); + if (mIndex.isValid()) { + auto info = ModInfo::getByIndex(mIndex.toInt()); + insert(m_markers.overwrite, info->getModOverwrite()); + insert(m_markers.overwritten, info->getModOverwritten()); + insert(m_markers.archiveOverwrite, info->getModArchiveOverwrite()); + insert(m_markers.archiveOverwritten, info->getModArchiveOverwritten()); + insert(m_markers.archiveLooseOverwrite, info->getModArchiveLooseOverwrite()); + insert(m_markers.archiveLooseOverwritten, info->getModArchiveLooseOverwritten()); + } } dataChanged(model()->index(0, 0), model()->index(model()->rowCount(), model()->columnCount())); verticalScrollBar()->repaint(); @@ -1207,15 +1186,29 @@ void ModListView::onSelectionChanged(const QItemSelection& selected, const QItem } } - if (selected.count()) { - auto index = selected.indexes().last(); - ModInfo::Ptr selectedMod = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); - setOverwriteMarkers(selectedMod); - } - else { - setOverwriteMarkers(nullptr); + QModelIndexList indexes = selectionModel()->selectedRows(); + + if (m_core->settings().interface().collapsibleSeparatorsConflicts()) { + for (auto& idx : selectionModel()->selectedRows()) { + if (hasCollapsibleSeparators() + && model()->hasChildren(idx) + && !isExpanded(idx)) { + for (int i = 0; i < model()->rowCount(idx); ++i) { + indexes.append(model()->index(i, idx.column(), idx)); + } + } + } } + setOverwriteMarkers(indexes); + + // highligth plugins + std::vector modIndices; + for (auto& idx : indexes) { + modIndices.push_back(idx.data(ModList::IndexRole).toInt()); + } + m_core->pluginList()->highlightPlugins(modIndices, *m_core->directoryStructure()); + ui.pluginList->verticalScrollBar()->repaint(); } void ModListView::onFiltersCriteria(const std::vector& criteria) diff --git a/src/modlistview.h b/src/modlistview.h index 08ecd935..53be08c5 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -23,6 +23,7 @@ class MainWindow; class Profile; class ModListByPriorityProxy; class ModListViewActions; +class PluginListView; class ModListView : public QTreeView { @@ -183,15 +184,14 @@ private: void onModInstalled(const QString& modName); void onModFilterActive(bool filterActive); - // overwrite markers + // clear overwrite markers (without repainting) + // void clearOverwriteMarkers(); - void setOverwriteMarkers(const std::set& overwrite, const std::set& overwritten); - void setArchiveOverwriteMarkers(const std::set& overwrite, const std::set& overwritten); - void setArchiveLooseOverwriteMarkers(const std::set& overwrite, const std::set& overwritten); - // set overwrite markers from the mod and repaint (if mod is nullptr, clear overwrite and repaint) + // set overwrite markers from the mod in the given list and repaint (if the list + // is empty, clear overwrite and repaint) // - void setOverwriteMarkers(ModInfo::Ptr mod); + void setOverwriteMarkers(const QModelIndexList& indexes); // retrieve the marker color for the given index // @@ -251,6 +251,9 @@ private: QLabel* currentCategory; QPushButton* clearFilters; QComboBox* filterSeparators; + + // the plugin list (for highligths) + PluginListView* pluginList; }; OrganizerCore* m_core; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index a22beacd..527f9a91 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -318,13 +318,13 @@ If you disable this feature, MO will only display official DLCs this way. Please - Display mod conflicts on separator when collapsed. + Display mod conflicts on and from separator when collapsed, and show plugins from collapsed separators. - Display mod conflicts on separator when collapsed. + Display mod conflicts on and from separator when collapsed, and show plugins from collapsed separators. - Show conflicts on separators + Show conflicts and plugins on separators and from separators true -- cgit v1.3.1 From 80371ae2ccdb233f9aa92c8982bad6a136c54ae9 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 7 Jan 2021 20:33:01 +0100 Subject: Update markers and plugins highligths when separator is expanded/collapsed. --- src/modlistview.cpp | 81 +++++++++++++++++++++++++++-------------------------- src/modlistview.h | 10 ++++++- 2 files changed, 50 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 2c9634bd..7b1b6f0c 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -138,6 +138,14 @@ ModListView::ModListView(QWidget* parent) connect(this, &ModListView::doubleClicked, this, &ModListView::onDoubleClicked); connect(this, &ModListView::customContextMenuRequested, this, &ModListView::onCustomContextMenuRequested); + // the timeout is pretty small because its main purpose is to avoid + // refreshing multiple times when calling expandAll() or collapseAll() + // which emit a lots of expanded/collapsed signals in a very small + // time window + m_refreshMarkersTimer.setInterval(50); + m_refreshMarkersTimer.setSingleShot(true); + connect(&m_refreshMarkersTimer, &QTimer::timeout, [=] { refreshMarkersAndPlugins(); }); + installEventFilter(new CopyEventFilter(this, [=](auto& index) { QVariant mIndex = index.data(ModList::IndexRole); QString name = index.data(Qt::DisplayRole).toString(); @@ -432,8 +440,8 @@ void ModListView::onModInstalled(const QString& modName) QModelIndex qIndex = indexModelToView(m_core->modList()->index(index, 0)); - if (hasCollapsibleSeparators()) { - setExpanded(qIndex, true); + if (hasCollapsibleSeparators() && qIndex.parent().isValid()) { + setExpanded(qIndex.parent(), true); } // focus, scroll to and select @@ -777,7 +785,9 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo }); connect(m_core->modList(), &ModList::externalFolderDropped, this, &ModListView::onExternalFolderDropped); - connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &ModListView::onSelectionChanged); + connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=] { m_refreshMarkersTimer.start(); }); + connect(this, &QTreeView::collapsed, [=] { m_refreshMarkersTimer.start(); }); + connect(this, &QTreeView::expanded, [=] { m_refreshMarkersTimer.start(); }); // filters connect(m_sortProxy, &ModListSortProxy::filterActive, this, &ModListView::onModFilterActive); @@ -975,6 +985,34 @@ void ModListView::setOverwriteMarkers(const QModelIndexList& indexes) verticalScrollBar()->repaint(); } +void ModListView::refreshMarkersAndPlugins() +{ + QModelIndexList indexes = selectionModel()->selectedRows(); + + if (m_core->settings().interface().collapsibleSeparatorsConflicts()) { + for (auto& idx : selectionModel()->selectedRows()) { + if (hasCollapsibleSeparators() + && model()->hasChildren(idx) + && !isExpanded(idx)) { + for (int i = 0; i < model()->rowCount(idx); ++i) { + indexes.append(model()->index(i, idx.column(), idx)); + } + } + } + } + + setOverwriteMarkers(indexes); + + // highligth plugins + std::vector modIndices; + for (auto& idx : indexes) { + modIndices.push_back(idx.data(ModList::IndexRole).toInt()); + } + m_core->pluginList()->highlightPlugins(modIndices, *m_core->directoryStructure()); + ui.pluginList->verticalScrollBar()->repaint(); +} + + void ModListView::setHighlightedMods(const std::vector& pluginIndices) { m_markers.highlight.clear(); @@ -1176,41 +1214,6 @@ QString ModListView::contentsTooltip(const QModelIndex& index) const return result; } -void ModListView::onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) -{ - if (hasCollapsibleSeparators()) { - for (auto& idx : selected.indexes()) { - if (idx.parent().isValid() && !isExpanded(idx.parent())) { - setExpanded(idx.parent(), true); - } - } - } - - QModelIndexList indexes = selectionModel()->selectedRows(); - - if (m_core->settings().interface().collapsibleSeparatorsConflicts()) { - for (auto& idx : selectionModel()->selectedRows()) { - if (hasCollapsibleSeparators() - && model()->hasChildren(idx) - && !isExpanded(idx)) { - for (int i = 0; i < model()->rowCount(idx); ++i) { - indexes.append(model()->index(i, idx.column(), idx)); - } - } - } - } - - setOverwriteMarkers(indexes); - - // highligth plugins - std::vector modIndices; - for (auto& idx : indexes) { - modIndices.push_back(idx.data(ModList::IndexRole).toInt()); - } - m_core->pluginList()->highlightPlugins(modIndices, *m_core->directoryStructure()); - ui.pluginList->verticalScrollBar()->repaint(); -} - void ModListView::onFiltersCriteria(const std::vector& criteria) { setFilterCriteria(criteria); @@ -1319,12 +1322,10 @@ void ModListView::mousePressEvent(QMouseEvent* event) const auto flag = selectionModel()->isSelected(index) ? QItemSelectionModel::Select : QItemSelectionModel::Deselect; - const bool expanded = isExpanded(index); const QItemSelection selection( model()->index(0, index.column(), index), model()->index(model()->rowCount(index) - 1, index.column(), index)); selectionModel()->select(selection, flag | QItemSelectionModel::Rows); - setExpanded(index, expanded); } } diff --git a/src/modlistview.h b/src/modlistview.h index 53be08c5..1a174568 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -169,7 +169,6 @@ protected slots: void onCustomContextMenuRequested(const QPoint& pos); void onDoubleClicked(const QModelIndex& index); - void onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); void onFiltersCriteria(const std::vector& filters); private: @@ -184,6 +183,11 @@ private: void onModInstalled(const QString& modName); void onModFilterActive(bool filterActive); + // refresh the overwrite markers and the highligthed plugins from + // the current selection + // + void refreshMarkersAndPlugins(); + // clear overwrite markers (without repainting) // void clearOverwriteMarkers(); @@ -267,6 +271,10 @@ private: QtGroupingProxy* m_byCategoryProxy; QtGroupingProxy* m_byNexusIdProxy; + // marker used to avoid calling refreshing markers to many + // time in a row + QTimer m_refreshMarkersTimer; + // maintain collapsed items for each proxy to avoid // losing them on model reset std::map> m_collapsed; -- cgit v1.3.1 From fc60ea5b7a023493375a6fced6572156f48e36c3 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 7 Jan 2021 20:56:08 +0100 Subject: Add option to have different separator collapsed/expanded states between profiles. --- src/mainwindow.cpp | 1 - src/modlistview.cpp | 22 +++++++++++++++++++--- src/modlistview.h | 5 +---- src/organizercore.cpp | 1 + src/organizercore.h | 7 +++++++ src/settings.cpp | 10 ++++++++++ src/settings.h | 5 +++++ src/settingsdialog.ui | 13 +++++++++++++ src/settingsdialoguserinterface.cpp | 3 +++ 9 files changed, 59 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f761a5f0..ce98772a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1495,7 +1495,6 @@ void MainWindow::startExeAction() void MainWindow::activateSelectedProfile() { m_OrganizerCore.setCurrentProfile(ui->profileBox->currentText()); - ui->modList->setProfile(m_OrganizerCore.currentProfile()); m_SavesTab->refreshSaveList(); m_OrganizerCore.refresh(); diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 7b1b6f0c..ec31d4dc 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -167,10 +167,24 @@ void ModListView::refresh() updateGroupByProxy(); } -void ModListView::setProfile(Profile* profile) +void ModListView::onProfileChanged(Profile* oldProfile, Profile* newProfile) { - m_sortProxy->setProfile(profile); - m_byPriorityProxy->setProfile(profile); + const auto perProfileSeparators = + m_core->settings().interface().collapsibleSeparatorsPerProfile(); + + // save expanded/collapsed state of separators + if (oldProfile && perProfileSeparators) { + auto& collapsed = m_collapsed[m_byPriorityProxy]; + oldProfile->storeSetting("UserInterface", "collapsed_separators", QStringList(collapsed.begin(), collapsed.end())); + } + + m_sortProxy->setProfile(newProfile); + m_byPriorityProxy->setProfile(newProfile); + + if (newProfile && perProfileSeparators) { + auto collapsed = newProfile->setting("UserInterface", "collapsed_separators", QStringList()).toStringList(); + m_collapsed[m_byPriorityProxy] = { collapsed.begin(), collapsed.end() }; + } } bool ModListView::hasCollapsibleSeparators() const @@ -694,7 +708,9 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo mwui->espList }; + connect(m_core, &OrganizerCore::modInstalled, [=](auto&& name) { onModInstalled(name); }); + connect(m_core, &OrganizerCore::profileChanged, this, &ModListView::onProfileChanged); connect(core.modList(), &ModList::modPrioritiesChanged, [=](auto&& indices) { onModPrioritiesChanged(indices); }); connect(core.modList(), &ModList::clearOverwrite, [=] { m_actions->clearOverwrite(); }); connect(core.modList(), &ModList::modStatesChanged, [=] { updateModCount(); }); diff --git a/src/modlistview.h b/src/modlistview.h index 1a174568..d8e08a99 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -57,10 +57,6 @@ public: void restoreState(const Settings& s); void saveState(Settings& s) const; - // set the current profile - // - void setProfile(Profile* profile); - // check if collapsible separators are currently used // bool hasCollapsibleSeparators() const; @@ -170,6 +166,7 @@ protected slots: void onCustomContextMenuRequested(const QPoint& pos); void onDoubleClicked(const QModelIndex& index); void onFiltersCriteria(const std::vector& filters); + void onProfileChanged(Profile* oldProfile, Profile* newProfile); private: diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d952bc4c..90771c0a 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -602,6 +602,7 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) m_CurrentProfile->debugDump(); + emit profileChanged(oldProfile.get(), m_CurrentProfile.get()); m_ProfileChanged(oldProfile.get(), m_CurrentProfile.get()); } diff --git a/src/organizercore.h b/src/organizercore.h index 24de26ee..905fb111 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -406,6 +406,13 @@ signals: void close(); + // emitted when the profile is changed, before notifying plugins + // + // the new profile can be stored but the old one is temporary and + // should not be + // + void profileChanged(Profile* oldProfile, Profile* newProfile); + // Notify that the directory structure is ready to be used on the main thread // Use queued connections void directoryStructureReady(); diff --git a/src/settings.cpp b/src/settings.cpp index 7f943904..251e2b15 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2195,6 +2195,16 @@ void InterfaceSettings::setCollapsibleSeparatorsConflicts(bool b) set(m_Settings, "Settings", "collapsible_separators_conflicts", b); } +bool InterfaceSettings::collapsibleSeparatorsPerProfile() const +{ + return get(m_Settings, "Settings", "collapsible_separators_per_profile", false); +} + +void InterfaceSettings::setCollapsibleSeparatorsPerProfile(bool b) +{ + set(m_Settings, "Settings", "collapsible_separators_per_profile", b); +} + bool InterfaceSettings::saveFilters() const { return get(m_Settings, "Settings", "save_filters", false); diff --git a/src/settings.h b/src/settings.h index d61f3c20..efcfee57 100644 --- a/src/settings.h +++ b/src/settings.h @@ -631,6 +631,11 @@ public: bool collapsibleSeparatorsConflicts() const; void setCollapsibleSeparatorsConflicts(bool b); + // whether each profile should have its own expansion state + // + bool collapsibleSeparatorsPerProfile() const; + void setCollapsibleSeparatorsPerProfile(bool b); + // whether to save/restore filter states between runs // bool saveFilters() const; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 527f9a91..b09a26de 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -331,6 +331,19 @@ If you disable this feature, MO will only display official DLCs this way. Please + + + + Do not share the collapse/expanded state of separators between profiles. + + + Do not share the collapse/expanded state of separators between profiles. + + + Profile-specific collapse states for separators + + +
diff --git a/src/settingsdialoguserinterface.cpp b/src/settingsdialoguserinterface.cpp index 550b4ddd..5d856395 100644 --- a/src/settingsdialoguserinterface.cpp +++ b/src/settingsdialoguserinterface.cpp @@ -15,6 +15,7 @@ UserInterfaceSettingsTab::UserInterfaceSettingsTab(Settings& s, SettingsDialog& // connect before setting to trigger QObject::connect(ui->collapsibleSeparatorsBox, &QGroupBox::toggled, [=](auto&& on) { ui->collapsibleSeparatorsConflictsBox->setEnabled(on); + ui->collapsibleSeparatorsPerProfileBox->setEnabled(on); }); // mod list @@ -22,6 +23,7 @@ UserInterfaceSettingsTab::UserInterfaceSettingsTab(Settings& s, SettingsDialog& ui->colorSeparatorsBox->setChecked(settings().colors().colorSeparatorScrollbar()); ui->collapsibleSeparatorsConflictsBox->setChecked(settings().interface().collapsibleSeparatorsConflicts()); ui->collapsibleSeparatorsBox->setChecked(settings().interface().collapsibleSeparators()); + ui->collapsibleSeparatorsPerProfileBox->setChecked(settings().interface().collapsibleSeparatorsPerProfile()); ui->saveFiltersBox->setChecked(settings().interface().saveFilters()); // download list @@ -42,6 +44,7 @@ void UserInterfaceSettingsTab::update() settings().interface().setDisplayForeign(ui->displayForeignBox->isChecked()); settings().interface().setCollapsibleSeparators(ui->collapsibleSeparatorsBox->isChecked()); settings().interface().setCollapsibleSeparatorsConflicts(ui->collapsibleSeparatorsConflictsBox->isChecked()); + settings().interface().setCollapsibleSeparatorsPerProfile(ui->collapsibleSeparatorsPerProfileBox->isChecked()); settings().interface().setSaveFilters(ui->saveFiltersBox->isChecked()); // download list -- cgit v1.3.1 From 7d9fa5e4f96840321ff996b4c637b7cd686c3570 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 7 Jan 2021 21:46:58 +0100 Subject: Fix drop below collapsed separator. --- src/modlistbypriorityproxy.cpp | 38 ++++++++++++++++++++++++-------------- src/modlistbypriorityproxy.h | 10 +++++++++- src/modlistview.cpp | 10 +++++++++- src/modlistview.h | 8 +++++++- 4 files changed, 49 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/modlistbypriorityproxy.cpp b/src/modlistbypriorityproxy.cpp index 6f549d91..c0d70571 100644 --- a/src/modlistbypriorityproxy.cpp +++ b/src/modlistbypriorityproxy.cpp @@ -183,6 +183,25 @@ bool ModListByPriorityProxy::setData(const QModelIndex& index, const QVariant& v return QAbstractProxyModel::setData(index, value, role); } +std::pair ModListByPriorityProxy::dropSeparators(const ModListDropInfo& dropInfo) const +{ + bool hasSeparator = false; + unsigned int firstRowIndex = -1; + + int firstRowPriority = INT_MAX; + for (auto sourceRow : dropInfo.rows()) { + hasSeparator = hasSeparator || ModInfo::getByIndex(sourceRow)->isSeparator(); + if (m_profile->getModPriority(sourceRow) < firstRowPriority) { + firstRowIndex = sourceRow; + firstRowPriority = m_profile->getModPriority(sourceRow); + } + } + + bool firstRowSeparator = firstRowIndex != -1 && ModInfo::getByIndex(firstRowIndex)->isSeparator(); + + return { hasSeparator, firstRowSeparator }; +} + bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const { ModListDropInfo dropInfo(data, m_core); @@ -193,19 +212,7 @@ bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, Qt::DropActi if (dropInfo.isModDrop()) { - bool hasSeparator = false; - unsigned int firstRowIndex = -1; - - int firstRowPriority = INT_MAX; - for (auto sourceRow : dropInfo.rows()) { - hasSeparator = hasSeparator || ModInfo::getByIndex(sourceRow)->isSeparator(); - if (m_profile->getModPriority(sourceRow) < firstRowPriority) { - firstRowIndex = sourceRow; - firstRowPriority = m_profile->getModPriority(sourceRow); - } - } - - bool firstRowSeparator = firstRowIndex != -1 && ModInfo::getByIndex(firstRowIndex)->isSeparator(); + auto [hasSeparator, firstRowSeparator] = dropSeparators(dropInfo); // row = -1 and invalid parent means we're dropping onto an item, we don't want to drop // separators onto items or items into their own separator @@ -264,6 +271,7 @@ bool ModListByPriorityProxy::dropMimeData(const QMimeData* data, Qt::DropAction } } else { + if (row >= 0) { if (!parent.isValid()) { if (row < m_Root.children.size()) { @@ -271,6 +279,7 @@ bool ModListByPriorityProxy::dropMimeData(const QMimeData* data, Qt::DropAction if (row > 0 && m_Root.children[row - 1]->mod->isSeparator() && !m_Root.children[row - 1]->children.empty() + && m_dropExpanded && m_dropPosition == ModListView::DropPosition::BelowItem) { sourceRow = m_Root.children[row - 1]->children[0]->index; } @@ -316,7 +325,8 @@ QModelIndex ModListByPriorityProxy::index(int row, int column, const QModelIndex return createIndex(row, column, parentItem->children[row].get()); } -void ModListByPriorityProxy::onDropEnter(const QMimeData*, ModListView::DropPosition dropPosition) +void ModListByPriorityProxy::onDropEnter(const QMimeData*, bool dropExpanded, ModListView::DropPosition dropPosition) { + m_dropExpanded = dropExpanded; m_dropPosition = dropPosition; } diff --git a/src/modlistbypriorityproxy.h b/src/modlistbypriorityproxy.h index 6b48678a..c64a7973 100644 --- a/src/modlistbypriorityproxy.h +++ b/src/modlistbypriorityproxy.h @@ -16,6 +16,7 @@ #include "modlistview.h" class ModList; +class ModListDropInfo; class Profile; class ModListByPriorityProxy : public QAbstractProxyModel @@ -46,7 +47,7 @@ public: public slots: - void onDropEnter(const QMimeData* data, ModListView::DropPosition dropPosition); + void onDropEnter(const QMimeData* data, bool dropExpanded, ModListView::DropPosition dropPosition); protected slots: @@ -54,6 +55,11 @@ protected slots: private: + // returns a pair of boolean, the first one indicates if the drop info + // contains separators, the first one if the first row is a separator + // + std::pair dropSeparators(const ModListDropInfo& dropInfo) const; + void buildTree(); struct TreeItem { @@ -83,6 +89,8 @@ private: private: OrganizerCore& m_core; Profile* m_profile; + + bool m_dropExpanded = false; ModListView::DropPosition m_dropPosition = ModListView::DropPosition::OnItem; }; diff --git a/src/modlistview.cpp b/src/modlistview.cpp index ec31d4dc..91d522a6 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -1295,10 +1295,18 @@ void ModListView::dragMoveEvent(QDragMoveEvent* event) void ModListView::dropEvent(QDropEvent* event) { + // from Qt source + QModelIndex index; + if (viewport()->rect().contains(event->pos())) { + index = indexAt(event->pos()); + if (!index.isValid() || !visualRect(index).contains(event->pos())) + index = QModelIndex(); + } + // this event is used by the byPriorityProxy to know if allow // dropping mod between a separator and its first mod (there // is no way to deduce this except using dropIndicatorPosition()) - emit dropEntered(event->mimeData(), static_cast(dropIndicatorPosition())); + emit dropEntered(event->mimeData(), isExpanded(index), static_cast(dropIndicatorPosition())); // see selectedIndexes() m_inDragMoveEvent = true; diff --git a/src/modlistview.h b/src/modlistview.h index d8e08a99..6301a5da 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -90,8 +90,14 @@ public: signals: + // emitted for dragEnter events + // void dragEntered(const QMimeData* mimeData); - void dropEntered(const QMimeData* mimeData, DropPosition position); + + // emitted for dropEnter events, the boolean indicates if the drop target + // is expanded and the position of the indicator + // + void dropEntered(const QMimeData* mimeData, bool dropExpanded, DropPosition position); public slots: -- cgit v1.3.1 From c06d28e3a388d53543897c7fcafe3ed3507dce78 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 7 Jan 2021 21:57:47 +0100 Subject: Tentative fix for drop indicator appearance at the top of the mod list. --- src/moapplication.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/moapplication.cpp b/src/moapplication.cpp index 709bcbda..9de54f2f 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -65,9 +65,19 @@ public: { } - void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const { + void drawPrimitive( + PrimitiveElement element, const QStyleOption* option, + QPainter* painter, const QWidget* widget) const override + { if (element == QStyle::PE_IndicatorItemViewItemDrop) { + // 0. Fix a bug that made the drop indicator sometimes appear on top + // of the mod list when selecting a mod. + if (option->rect.height() == 0 + && option->rect.bottomRight() == QPoint(-1, -1)) { + return; + } + // 1. full-width drop indicator QRect rect(option->rect); if (auto* view = qobject_cast(widget)) { -- cgit v1.3.1 From abd82f88db694557a9eac0706f6831f150123c7b Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 7 Jan 2021 22:25:07 +0100 Subject: Fix Alt+Click for selecting children of separators. --- src/modlistview.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/modlistview.h | 1 + 2 files changed, 46 insertions(+) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 91d522a6..53070d08 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -1333,10 +1333,19 @@ void ModListView::timerEvent(QTimerEvent* event) void ModListView::mousePressEvent(QMouseEvent* event) { + // disable edit if Alt is pressed + auto triggers = editTriggers(); + if (event->modifiers() & Qt::AltModifier) { + setEditTriggers(NoEditTriggers); + } + // we call the parent class first so that we can use the actual // selection state of the item after QTreeView::mousePressEvent(event); + // restore triggers + setEditTriggers(triggers); + const auto index = indexAt(event->pos()); if (event->isAccepted() @@ -1353,6 +1362,42 @@ void ModListView::mousePressEvent(QMouseEvent* event) } } +void ModListView::mouseReleaseEvent(QMouseEvent* event) +{ + // this is a duplicate of mousePressEvent because for some reason + // the selection is not always triggered in mousePressEvent and only + // doing it here create a small lag between the selection of the + // separator and the children + + // disable edit if Alt is pressed + auto triggers = editTriggers(); + if (event->modifiers() & Qt::AltModifier) { + setEditTriggers(NoEditTriggers); + } + + // we call the parent class first so that we can use the actual + // selection state of the item after + QTreeView::mouseReleaseEvent(event); + + const auto index = indexAt(event->pos()); + + // restore triggers + setEditTriggers(triggers); + + if (event->isAccepted() + && hasCollapsibleSeparators() + && index.isValid() && model()->hasChildren(indexAt(event->pos())) + && (event->modifiers() & Qt::AltModifier)) { + + const auto flag = selectionModel()->isSelected(index) ? + QItemSelectionModel::Select : QItemSelectionModel::Deselect; + const QItemSelection selection( + model()->index(0, index.column(), index), + model()->index(model()->rowCount(index) - 1, index.column(), index)); + selectionModel()->select(selection, flag | QItemSelectionModel::Rows); + } +} + bool ModListView::event(QEvent* event) { if (event->type() == QEvent::KeyPress diff --git a/src/modlistview.h b/src/modlistview.h index 6301a5da..3b64e01b 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -165,6 +165,7 @@ protected: void dragMoveEvent(QDragMoveEvent* event) override; void dropEvent(QDropEvent* event) override; void mousePressEvent(QMouseEvent* event) override; + void mouseReleaseEvent(QMouseEvent* event) override; bool event(QEvent* event) override; protected slots: -- cgit v1.3.1 From 2d9fbc74219341d2592bf50e7d96318e554ac583 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 7 Jan 2021 22:27:37 +0100 Subject: Remove dropSeparators() method from proxy. --- src/modlistbypriorityproxy.cpp | 32 ++++++++++++-------------------- src/modlistbypriorityproxy.h | 5 ----- 2 files changed, 12 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/modlistbypriorityproxy.cpp b/src/modlistbypriorityproxy.cpp index c0d70571..e0efe585 100644 --- a/src/modlistbypriorityproxy.cpp +++ b/src/modlistbypriorityproxy.cpp @@ -183,25 +183,6 @@ bool ModListByPriorityProxy::setData(const QModelIndex& index, const QVariant& v return QAbstractProxyModel::setData(index, value, role); } -std::pair ModListByPriorityProxy::dropSeparators(const ModListDropInfo& dropInfo) const -{ - bool hasSeparator = false; - unsigned int firstRowIndex = -1; - - int firstRowPriority = INT_MAX; - for (auto sourceRow : dropInfo.rows()) { - hasSeparator = hasSeparator || ModInfo::getByIndex(sourceRow)->isSeparator(); - if (m_profile->getModPriority(sourceRow) < firstRowPriority) { - firstRowIndex = sourceRow; - firstRowPriority = m_profile->getModPriority(sourceRow); - } - } - - bool firstRowSeparator = firstRowIndex != -1 && ModInfo::getByIndex(firstRowIndex)->isSeparator(); - - return { hasSeparator, firstRowSeparator }; -} - bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const { ModListDropInfo dropInfo(data, m_core); @@ -211,8 +192,19 @@ bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, Qt::DropActi } if (dropInfo.isModDrop()) { + bool hasSeparator = false; + unsigned int firstRowIndex = -1; + + int firstRowPriority = INT_MAX; + for (auto sourceRow : dropInfo.rows()) { + hasSeparator = hasSeparator || ModInfo::getByIndex(sourceRow)->isSeparator(); + if (m_profile->getModPriority(sourceRow) < firstRowPriority) { + firstRowIndex = sourceRow; + firstRowPriority = m_profile->getModPriority(sourceRow); + } + } - auto [hasSeparator, firstRowSeparator] = dropSeparators(dropInfo); + bool firstRowSeparator = firstRowIndex != -1 && ModInfo::getByIndex(firstRowIndex)->isSeparator(); // row = -1 and invalid parent means we're dropping onto an item, we don't want to drop // separators onto items or items into their own separator diff --git a/src/modlistbypriorityproxy.h b/src/modlistbypriorityproxy.h index c64a7973..5cd66c62 100644 --- a/src/modlistbypriorityproxy.h +++ b/src/modlistbypriorityproxy.h @@ -55,11 +55,6 @@ protected slots: private: - // returns a pair of boolean, the first one indicates if the drop info - // contains separators, the first one if the first row is a separator - // - std::pair dropSeparators(const ModListDropInfo& dropInfo) const; - void buildTree(); struct TreeItem { -- cgit v1.3.1 From d923730452e129260dc08a2a909c897eb9475ce7 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 8 Jan 2021 13:06:01 +0100 Subject: Allow double-click to accept choice in ListDialog. --- src/listdialog.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/listdialog.cpp b/src/listdialog.cpp index 2ad88408..9334186a 100644 --- a/src/listdialog.cpp +++ b/src/listdialog.cpp @@ -26,6 +26,7 @@ ListDialog::ListDialog(QWidget *parent) { ui->setupUi(this); ui->filterEdit->setFocus(); + connect(ui->choiceList, &QListWidget::itemDoubleClicked, this, &QDialog::accept); } ListDialog::~ListDialog() -- cgit v1.3.1 From 7b684f4d15fa8f75fe802f9dd1534cf4ee2c25ea Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 8 Jan 2021 17:41:10 +0100 Subject: Tentative fix for automatic text color when markers or separator colors are used. --- src/modlistview.cpp | 21 ++++++++++++++++----- src/settings.cpp | 8 ++++---- 2 files changed, 20 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 53070d08..6b5ae66b 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -82,18 +82,29 @@ public: if (!color.isValid()) { color = index.data(Qt::BackgroundRole).value(); } - else { - // disable alternating row if the color is from the children - opt.features &= ~QStyleOptionViewItem::Alternate; - } opt.backgroundBrush = color; + // we need to find the background color to compute the ideal text color + // but the mod list view uses alternate color so we need to find the + // right color + auto bg = opt.palette.base().color(); + auto vrow = (opt.rect.y() - m_view->verticalOffset()) / opt.rect.height(); + if (vrow % 2 == 1) { + bg = opt.palette.alternateBase().color(); + } + // compute ideal foreground color for some rows if (color.isValid()) { if ((index.column() == ModList::COL_NAME && ModInfo::getByIndex(index.data(ModList::IndexRole).toInt())->isSeparator()) || index.column() == ModList::COL_NOTES) { - opt.palette.setBrush(QPalette::Text, ColorSettings::idealTextColor(color)); + + // combine the color with the background and then find the "ideal" text color + const auto a = color.alpha() / 255.; + int r = (1 - a) * bg.red() + a * color.red(), + g = (1 - a) * bg.green() + a * color.green(), + b = (1 - a) * bg.blue() + a * color.blue(); + opt.palette.setBrush(QPalette::Text, ColorSettings::idealTextColor(QColor(r, g, b))); } } diff --git a/src/settings.cpp b/src/settings.cpp index 251e2b15..488a9b01 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1326,12 +1326,12 @@ void ColorSettings::setColorSeparatorScrollbar(bool b) QColor ColorSettings::idealTextColor(const QColor& rBackgroundColor) { - if (rBackgroundColor.alpha() == 0) + if (rBackgroundColor.alpha() < 50) return QColor(Qt::black); - const int THRESHOLD = 106 * 255.0f / rBackgroundColor.alpha(); - int BackgroundDelta = (rBackgroundColor.red() * 0.299) + (rBackgroundColor.green() * 0.587) + (rBackgroundColor.blue() * 0.114); - return QColor((255 - BackgroundDelta <= THRESHOLD) ? Qt::black : Qt::white); + // "inverse' of luminance of the background + int iLuminance = (rBackgroundColor.red() * 0.299) + (rBackgroundColor.green() * 0.587) + (rBackgroundColor.blue() * 0.114); + return QColor(iLuminance >= 128 ? Qt::black : Qt::white); } -- cgit v1.3.1 From 5fb590efe3f101d2a9d284232b6aa4b54a9d5de4 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 8 Jan 2021 20:13:24 +0100 Subject: Fix vertical alignment of icons. --- src/icondelegate.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/icondelegate.cpp b/src/icondelegate.cpp index 813395a2..7205ba62 100644 --- a/src/icondelegate.cpp +++ b/src/icondelegate.cpp @@ -49,6 +49,8 @@ void IconDelegate::paintIcons( int iconWidth = icons.size() > 0 ? ((option.rect.width() / icons.size()) - 4) : 16; iconWidth = std::min(16, iconWidth); + const int margin = (option.rect.height() - iconWidth) / 2; + painter->translate(option.rect.topLeft()); for (const QString &iconId : icons) { if (iconId.isEmpty()) { @@ -64,7 +66,7 @@ void IconDelegate::paintIcons( } QPixmapCache::insert(fullIconId, icon); } - painter->drawPixmap(x, 2, iconWidth, iconWidth, icon); + painter->drawPixmap(x, margin, iconWidth, iconWidth, icon); x += iconWidth + 4; } @@ -79,6 +81,7 @@ void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, else { QStyledItemDelegate::paint(painter, option, index); } + paintIcons(painter, option, index, getIcons(index)); } -- cgit v1.3.1 From 3e5d71923ffa41e2af552024cd929aca93830fd0 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 8 Jan 2021 20:14:37 +0100 Subject: Rename ModListStyledItemDelegated -> ModListStyledItemDelegate. --- src/modlistview.cpp | 8 ++++---- src/modlistview.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 6b5ae66b..f4f045c6 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -41,13 +41,13 @@ using namespace MOShared; // handling (e.g. checkbox, edit, etc.), so we also need to override // the visualRect() function from the mod list view. // -class ModListStyledItemDelegated : public QStyledItemDelegate +class ModListStyledItemDelegate : public QStyledItemDelegate { ModListView* m_view; public: - ModListStyledItemDelegated(ModListView* view) : + ModListStyledItemDelegate(ModListView* view) : QStyledItemDelegate(view), m_view(view) { } void initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const override @@ -144,7 +144,7 @@ ModListView::ModListView(QWidget* parent) MOBase::setCustomizableColumns(this); setAutoExpandDelay(750); - setItemDelegate(new ModListStyledItemDelegated(this)); + setItemDelegate(new ModListStyledItemDelegate(this)); connect(this, &ModListView::doubleClicked, this, &ModListView::onDoubleClicked); connect(this, &ModListView::customContextMenuRequested, this, &ModListView::onCustomContextMenuRequested); @@ -855,7 +855,7 @@ void ModListView::saveState(Settings& s) const QRect ModListView::visualRect(const QModelIndex& index) const { // this shift the visualRect() from QTreeView to match the new actual - // zone after removing indentation (see the ModListStyledItemDelegated) + // zone after removing indentation (see the ModListStyledItemDelegate) QRect rect = QTreeView::visualRect(index); if (hasCollapsibleSeparators() && index.column() == 0 && index.isValid() diff --git a/src/modlistview.h b/src/modlistview.h index 3b64e01b..c9588181 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -180,7 +180,7 @@ private: friend class ModConflictIconDelegate; friend class ModFlagIconDelegate; friend class ModContentIconDelegate; - friend class ModListStyledItemDelegated; + friend class ModListStyledItemDelegate; friend class ModListViewMarkingScrollBar; void onModPrioritiesChanged(const QModelIndexList& indices); -- cgit v1.3.1 From 2606b10c7efdaa65e56ece77bad90bd55c154111 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 8 Jan 2021 20:15:01 +0100 Subject: Display upgrade/warning for versions on collapsed separators. --- src/CMakeLists.txt | 1 + src/modlistversiondelegate.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++ src/modlistversiondelegate.h | 21 +++++++++++++++ src/modlistview.cpp | 2 ++ 4 files changed, 84 insertions(+) create mode 100644 src/modlistversiondelegate.cpp create mode 100644 src/modlistversiondelegate.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c274f989..d1092637 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -151,6 +151,7 @@ add_filter(NAME src/modlist/view GROUPS modflagicondelegate modcontenticondelegate modconflicticondelegate + modlistversiondelegate ) add_filter(NAME src/plugins GROUPS diff --git a/src/modlistversiondelegate.cpp b/src/modlistversiondelegate.cpp new file mode 100644 index 00000000..f60edcf8 --- /dev/null +++ b/src/modlistversiondelegate.cpp @@ -0,0 +1,60 @@ +#include "modlistversiondelegate.h" + +#include "modlistview.h" +#include "log.h" + +ModListVersionDelegate::ModListVersionDelegate(ModListView* view) : + QItemDelegate(view), m_view(view) { } + + +void ModListVersionDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + m_view->itemDelegate()->paint(painter, option, index); + + if (m_view->hasCollapsibleSeparators() + && m_view->model()->hasChildren(index) + && !m_view->isExpanded(index.sibling(index.row(), 0))) { + auto* model = m_view->model(); + + bool downgrade = false, upgrade = false; + + for (int i = 0; i < model->rowCount(index); ++i) { + const auto mIndex = model->index(i, index.column(), index).data(ModList::IndexRole); + if (mIndex.isValid()) { + auto info = ModInfo::getByIndex(mIndex.toInt()); + downgrade = downgrade || info->downgradeAvailable(); + upgrade = upgrade || info->updateAvailable(); + } + } + + const int margin = m_view->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, m_view) + 1; + + QStyleOptionViewItem opt(option); + const int sz = m_view->style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, m_view); + opt.decorationSize = QSize(sz, sz); + opt.decorationAlignment = Qt::AlignCenter; + + if (upgrade) { + QIcon icon(":/MO/gui/update_available"); + QPixmap pixmap = decoration(opt, icon); + + QSize pm = icon.actualSize(opt.decorationSize); + pm.rwidth() += 2 * margin; + opt.rect.setRect(opt.rect.x(), opt.rect.y(), pm.width(), opt.rect.height()); + + drawDecoration(painter, opt, opt.rect, pixmap); + } + + if (downgrade) { + QIcon icon(":/MO/gui/warning"); + QPixmap pixmap = decoration(opt, icon); + + QSize pm = icon.actualSize(opt.decorationSize); + pm.rwidth() += 2 * margin; + opt.rect.setRect(opt.rect.x() + opt.decorationSize.width() + margin, opt.rect.y(), pm.width(), opt.rect.height()); + + drawDecoration(painter, opt, opt.rect, pixmap); + + } + } +} diff --git a/src/modlistversiondelegate.h b/src/modlistversiondelegate.h new file mode 100644 index 00000000..8a51e9b4 --- /dev/null +++ b/src/modlistversiondelegate.h @@ -0,0 +1,21 @@ +#ifndef MODLISTVERSIONDELEGATE_H +#define MODLISTVERSIONDELEGATE_H + +#include + +class ModListView; + +class ModListVersionDelegate : public QItemDelegate +{ +public: + ModListVersionDelegate(ModListView* view); + + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + + +private: + + ModListView* m_view; +}; + +#endif diff --git a/src/modlistview.cpp b/src/modlistview.cpp index f4f045c6..c23cd34b 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -19,6 +19,7 @@ #include "modflagicondelegate.h" #include "modconflicticondelegate.h" #include "modcontenticondelegate.h" +#include "modlistversiondelegate.h" #include "modlistviewactions.h" #include "modlistdropinfo.h" #include "modlistcontextmenu.h" @@ -776,6 +777,7 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo setItemDelegateForColumn(ModList::COL_FLAGS, new ModFlagIconDelegate(this, ModList::COL_FLAGS, 120)); setItemDelegateForColumn(ModList::COL_CONFLICTFLAGS, new ModConflictIconDelegate(this, ModList::COL_CONFLICTFLAGS, 80)); setItemDelegateForColumn(ModList::COL_CONTENT, new ModContentIconDelegate(this, ModList::COL_CONTENT, 150)); + setItemDelegateForColumn(ModList::COL_VERSION, new ModListVersionDelegate(this)); if (m_core->settings().geometry().restoreState(header())) { // hack: force the resize-signal to be triggered because restoreState doesn't seem to do that -- cgit v1.3.1 From 883ca5d376d9cc7de17620d3b0444e201c683da0 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 8 Jan 2021 20:34:00 +0100 Subject: Left-align warning icon if there is no update icon in the column version. --- src/modlistversiondelegate.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modlistversiondelegate.cpp b/src/modlistversiondelegate.cpp index f60edcf8..657718f5 100644 --- a/src/modlistversiondelegate.cpp +++ b/src/modlistversiondelegate.cpp @@ -41,8 +41,10 @@ void ModListVersionDelegate::paint(QPainter* painter, const QStyleOptionViewItem QSize pm = icon.actualSize(opt.decorationSize); pm.rwidth() += 2 * margin; opt.rect.setRect(opt.rect.x(), opt.rect.y(), pm.width(), opt.rect.height()); - drawDecoration(painter, opt, opt.rect, pixmap); + + // add margin for next icon (if any) + opt.rect.adjust(opt.decorationSize.width() + margin, 0, 0, 0); } if (downgrade) { @@ -51,7 +53,7 @@ void ModListVersionDelegate::paint(QPainter* painter, const QStyleOptionViewItem QSize pm = icon.actualSize(opt.decorationSize); pm.rwidth() += 2 * margin; - opt.rect.setRect(opt.rect.x() + opt.decorationSize.width() + margin, opt.rect.y(), pm.width(), opt.rect.height()); + opt.rect.setRect(opt.rect.x(), opt.rect.y(), pm.width(), opt.rect.height()); drawDecoration(painter, opt, opt.rect, pixmap); -- cgit v1.3.1 From 342d529dd6ad36ecc3455927dbe5a1d10cbb648b Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sat, 9 Jan 2021 20:21:43 +0100 Subject: Do not notifyChange if the new name is identical to the old name. --- src/modlist.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/modlist.cpp b/src/modlist.cpp index 055778f3..f820e4d1 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -555,15 +555,16 @@ bool ModList::renameMod(int index, const QString &newName) m_Profile->cancelModlistWrite(); - if (modInfo->setName(nameFixed)) + if (modInfo->setName(nameFixed)) { // Notice there is a good chance that setName() updated the modinfo indexes // the modRenamed() call will refresh the indexes in the current profile // and update the modlists in all profiles emit modRenamed(oldName, nameFixed); - } + } - // invalidate the currently displayed state of this list - notifyChange(-1); + // invalidate the currently displayed state of this list + notifyChange(-1); + } return true; } -- cgit v1.3.1 From 5a7bd3db677b037191b7e61e52bad682e0faffb9 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sat, 9 Jan 2021 20:47:38 +0100 Subject: Re-add 'Create empty mod' and 'Create separator' to global mod list context menu. --- src/modlistcontextmenu.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/modlistcontextmenu.cpp b/src/modlistcontextmenu.cpp index f5307dc7..78949be3 100644 --- a/src/modlistcontextmenu.cpp +++ b/src/modlistcontextmenu.cpp @@ -27,6 +27,10 @@ ModListGlobalContextMenu::ModListGlobalContextMenu(OrganizerCore& core, ModListV addAction(tr("Create Separator"), [=]() { view->actions().createSeparator(index); }); } } + else { + addAction(tr("Create empty mod"), [=]() { view->actions().createEmptyMod(); }); + addAction(tr("Create Separator"), [=]() { view->actions().createSeparator(); }); + } if (view->hasCollapsibleSeparators()) { addSeparator(); -- cgit v1.3.1 From 5bb48d5e525660ba408d586226754a0f00326bb5 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 10 Jan 2021 19:29:18 +0100 Subject: Small clean. --- src/moapplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/moapplication.cpp b/src/moapplication.cpp index 9de54f2f..9a77c17e 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -102,7 +102,7 @@ public: rect.topLeft() + QPoint(-5, -5) }; painter->drawPolygon(tri, 3); - painter->drawLine(QPoint(rect.topLeft().x(), rect.topLeft().y()), rect.topRight()); + painter->drawLine(rect.topLeft(), rect.topRight()); } else { painter->drawRoundedRect(rect, 5, 5); -- cgit v1.3.1 From 32e441897fb5dc5d49764c8ce2cb8b3475bcdd20 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 10 Jan 2021 19:29:41 +0100 Subject: Request window focus when dropping external folder and scroll to new mod. --- src/modlistview.cpp | 22 ++++++++++++++++------ src/modlistview.h | 7 ++++++- 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index c23cd34b..13c34226 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -390,6 +390,15 @@ void ModListView::setSelected(const QModelIndex& current, const QModelIndexList& } } +void ModListView::scrollToAndSelect(const QModelIndex& index) +{ + // focus, scroll to and select + scrollTo(index); + setCurrentIndex(index); + selectionModel()->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + QTimer::singleShot(0, [=] { setFocus(); }); +} + void ModListView::refreshExpandedItems() { auto* model = m_sortProxy->sourceModel(); @@ -470,11 +479,7 @@ void ModListView::onModInstalled(const QString& modName) setExpanded(qIndex.parent(), true); } - // focus, scroll to and select - setFocus(Qt::OtherFocusReason); - scrollTo(qIndex); - setCurrentIndex(qIndex); - selectionModel()->select(qIndex, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + scrollToAndSelect(qIndex); } void ModListView::onModFilterActive(bool filterActive) @@ -589,6 +594,8 @@ void ModListView::refreshFilters() void ModListView::onExternalFolderDropped(const QUrl& url, int priority) { + setWindowState(Qt::WindowActive); + QFileInfo fileInfo(url.toLocalFile()); GuessedValue name; @@ -624,9 +631,12 @@ void ModListView::onExternalFolderDropped(const QUrl& url, int priority) m_core->refresh(); + const auto index = ModInfo::getIndex(name); if (priority != -1) { - m_core->modList()->changeModPriority(ModInfo::getIndex(name), priority); + m_core->modList()->changeModPriority(index, priority); } + + scrollToAndSelect(indexModelToView(m_core->modList()->index(index, 0))); } bool ModListView::moveSelection(int key) diff --git a/src/modlistview.h b/src/modlistview.h index c9588181..53c71458 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -79,11 +79,16 @@ public: std::optional nextMod(unsigned int index) const; std::optional prevMod(unsigned int index) const; - // check if the given mod is visible + // check if the given mod is visible, i.e. not filtered (returns true + // for collapsed mods) // bool isModVisible(unsigned int index) const; bool isModVisible(ModInfo::Ptr mod) const; + // focus the view, select the given index and scroll to it + // + void scrollToAndSelect(const QModelIndex& index); + // refresh the view (to call when settings have been changed) // void refresh(); -- cgit v1.3.1 From 8115335c55c229b8da741dfb075e240334d2f0ab Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 10 Jan 2021 19:31:29 +0100 Subject: Request window focus when dropping external archive. --- src/modlistview.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 13c34226..2fde97f6 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -820,6 +820,7 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo m_core->installDownload(row, priority); }); connect(m_core->modList(), &ModList::externalArchiveDropped, [=](const QUrl& url, int priority) { + setWindowState(Qt::WindowActive); m_core->installArchive(url.toLocalFile(), priority, false, nullptr); }); connect(m_core->modList(), &ModList::externalFolderDropped, this, &ModListView::onExternalFolderDropped); -- cgit v1.3.1 From a952f51ef75420426e8ed65e8f78d990c10770b0 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 10 Jan 2021 20:08:48 +0100 Subject: Change 'Create empty mod' depending on the currently selected mod. --- src/modlistcontextmenu.cpp | 9 +++++---- src/modlistview.cpp | 2 +- src/modlistviewactions.cpp | 31 ++++++++++++++++++++++++++++--- 3 files changed, 34 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/modlistcontextmenu.cpp b/src/modlistcontextmenu.cpp index 78949be3..97eef0eb 100644 --- a/src/modlistcontextmenu.cpp +++ b/src/modlistcontextmenu.cpp @@ -23,13 +23,14 @@ ModListGlobalContextMenu::ModListGlobalContextMenu(OrganizerCore& core, ModListV if (modIndex.isValid()) { auto info = ModInfo::getByIndex(modIndex.toInt()); if (!info->isBackup()) { - addAction(tr("Create empty mod"), [=]() { view->actions().createEmptyMod(index); }); - addAction(tr("Create Separator"), [=]() { view->actions().createSeparator(index); }); + addAction(info->isSeparator() ? tr("Create empty mod inside") : tr("Create empty mod before"), + [=]() { view->actions().createEmptyMod(index); }); + addAction(tr("Create separator before"), [=]() { view->actions().createSeparator(index); }); } } else { - addAction(tr("Create empty mod"), [=]() { view->actions().createEmptyMod(); }); - addAction(tr("Create Separator"), [=]() { view->actions().createSeparator(); }); + addAction(tr("Create empty mod at the end"), [=]() { view->actions().createEmptyMod(); }); + addAction(tr("Create separator at the end"), [=]() { view->actions().createSeparator(); }); } if (view->hasCollapsibleSeparators()) { diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 2fde97f6..5e3e6b58 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -396,7 +396,7 @@ void ModListView::scrollToAndSelect(const QModelIndex& index) scrollTo(index); setCurrentIndex(index); selectionModel()->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); - QTimer::singleShot(0, [=] { setFocus(); }); + QTimer::singleShot(50, [=] { setFocus(); }); } void ModListView::refreshExpandedItems() diff --git a/src/modlistviewactions.cpp b/src/modlistviewactions.cpp index 9957618a..14c4ab46 100644 --- a/src/modlistviewactions.cpp +++ b/src/modlistviewactions.cpp @@ -97,8 +97,30 @@ void ModListViewActions::createEmptyMod(const QModelIndex& index) const } int newPriority = -1; - if (index.isValid() && m_view->sortColumn() == ModList::COL_PRIORITY) { - newPriority = m_core.currentProfile()->getModPriority(index.data(ModList::IndexRole).toInt()); + if (index.isValid() && index.data(ModList::IndexRole).isValid() + && m_view->sortColumn() == ModList::COL_PRIORITY) { + auto mIndex = index.data(ModList::IndexRole).toInt(); + auto info = ModInfo::getByIndex(mIndex); + newPriority = m_core.currentProfile()->getModPriority(mIndex); + if (info->isSeparator()) { + auto& ibp = m_core.currentProfile()->getAllIndexesByPriority(); + + // start right after the current priority and look for the next + // separator + auto it = ibp.find(newPriority + 1); + for (; it != ibp.end(); ++it) { + auto info = ModInfo::getByIndex(it->second); + if (info->isSeparator()) { + newPriority = it->first; + break; + } + } + + // no separator found, create at the end + if (it == ibp.end()) { + newPriority = -1; + } + } } IModInterface* newMod = m_core.createMod(name); @@ -108,9 +130,12 @@ void ModListViewActions::createEmptyMod(const QModelIndex& index) const m_core.refresh(); + const auto mIndex = ModInfo::getIndex(name); if (newPriority >= 0) { - m_core.modList()->changeModPriority(ModInfo::getIndex(name), newPriority); + m_core.modList()->changeModPriority(mIndex, newPriority); } + + m_view->scrollToAndSelect(m_view->indexModelToView(m_core.modList()->index(mIndex, 0))); } void ModListViewActions::createSeparator(const QModelIndex& index) const -- cgit v1.3.1 From a5059cbe3226f1ebc31b6403eaaa830549d327c9 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 10 Jan 2021 20:11:46 +0100 Subject: Select separator after creation. --- src/modlistviewactions.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/modlistviewactions.cpp b/src/modlistviewactions.cpp index 14c4ab46..cc50f009 100644 --- a/src/modlistviewactions.cpp +++ b/src/modlistviewactions.cpp @@ -123,8 +123,7 @@ void ModListViewActions::createEmptyMod(const QModelIndex& index) const } } - IModInterface* newMod = m_core.createMod(name); - if (newMod == nullptr) { + if (m_core.createMod(name) == nullptr) { return; } @@ -164,16 +163,22 @@ void ModListViewActions::createSeparator(const QModelIndex& index) const newPriority = m_core.currentProfile()->getModPriority(index.data(ModList::IndexRole).toInt()); } - if (m_core.createMod(name) == nullptr) { return; } + if (m_core.createMod(name) == nullptr) { + return; + } + m_core.refresh(); + const auto mIndex = ModInfo::getIndex(name); if (newPriority >= 0) { - m_core.modList()->changeModPriority(ModInfo::getIndex(name), newPriority); + m_core.modList()->changeModPriority(mIndex, newPriority); } if (auto c = m_core.settings().colors().previousSeparatorColor()) { - ModInfo::getByIndex(ModInfo::getIndex(name))->setColor(*c); + ModInfo::getByIndex(mIndex)->setColor(*c); } + + m_view->scrollToAndSelect(m_view->indexModelToView(m_core.modList()->index(mIndex, 0))); } void ModListViewActions::checkModsForUpdates() const -- cgit v1.3.1 From 566441a7067ad0a83173b6652aa4a0c345b93b42 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Mon, 11 Jan 2021 09:36:35 +0100 Subject: Add comment to mousePressEvent(). --- src/modlistview.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 5e3e6b58..8827733b 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -1357,6 +1357,12 @@ void ModListView::timerEvent(QTimerEvent* event) void ModListView::mousePressEvent(QMouseEvent* event) { + // allow alt+click to select all mods inside a separator + // when using collapsible separators + // + // similar code is also present in mouseReleaseEvent to + // avoid missing events + // disable edit if Alt is pressed auto triggers = editTriggers(); if (event->modifiers() & Qt::AltModifier) { -- cgit v1.3.1 From 05efc74e402ca3770d9fdaa2557f4030c31ee198 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Mon, 11 Jan 2021 12:43:28 +0100 Subject: Fix text for new option. --- src/settingsdialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index b09a26de..d5c93c5c 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -277,7 +277,7 @@ If you disable this feature, MO will only display official DLCs this way. Please Save the current filters when closing MO2 and restore them on startup. - Remembers selected filters after restarting MO + Remember selected filters after restarting MO
-- cgit v1.3.1