From 9db6a9d7931edbb08e74cd1e110794f47d46df3e Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Mon, 28 Dec 2020 14:25:47 +0100 Subject: Save collapse state of separator. --- src/settings.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'src/settings.cpp') diff --git a/src/settings.cpp b/src/settings.cpp index f5ad83a7..04cfafc9 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1063,6 +1063,41 @@ WidgetSettings::WidgetSettings(QSettings& s, bool globalInstance) } } +std::vector WidgetSettings::allIndex(const QAbstractItemModel* model, int column, const QModelIndex& parent) const +{ + std::vector index; + for (std::size_t i = 0; i < model->rowCount(parent); ++i) { + index.push_back(model->index(i, column, parent)); + + auto cindex = allIndex(model, column, index.back()); + index.insert(index.end(), cindex.begin(), cindex.end()); + } + return index; +} + +void WidgetSettings::saveTreeState(const QTreeView* tv, int role) +{ + QVariantList expanded; + for (auto index : allIndex(tv->model())) { + if (tv->isExpanded(index)) { + expanded.append(index.data(role)); + } + } + set(m_Settings, "Widgets", indexSettingName(tv), expanded); +} + +void WidgetSettings::restoreTreeState(QTreeView* tv, int role) const +{ + if (auto expanded = getOptional(m_Settings, "Widgets", indexSettingName(tv))) { + tv->collapseAll(); + for (auto index : allIndex(tv->model())) { + if (expanded->contains(index.data(role))) { + tv->expand(index); + } + } + } +} + std::optional WidgetSettings::index(const QComboBox* cb) const { return getOptional(m_Settings, "Widgets", indexSettingName(cb)); -- cgit v1.3.1 From 095348c16f58d757f2d9549d06fd12d5ed14a1d2 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Tue, 29 Dec 2020 21:40:22 +0100 Subject: Add option to disable collapsible separators. --- src/mainwindow.cpp | 2 +- src/modlistview.cpp | 7 +++++-- src/modlistview.h | 5 ++--- src/settings.cpp | 10 ++++++++++ src/settings.h | 5 +++++ src/settingsdialog.ui | 37 +++++++++++++++++++++++++++++++++++++ src/settingsdialoggeneral.cpp | 2 ++ 7 files changed, 62 insertions(+), 6 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e54c24e1..63c9a8be 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -692,7 +692,6 @@ void MainWindow::allowListResize() void MainWindow::updateStyle(const QString&) { resetActionIcons(); - ui->modList->refreshStyle(); } void MainWindow::resizeEvent(QResizeEvent *event) @@ -4619,6 +4618,7 @@ void MainWindow::on_actionSettings_triggered() fixCategories(); refreshFilters(); + ui->modList->refresh(); if (settings.paths().profiles() != oldProfilesDirectory) { refreshProfiles(); diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 643b1971..dbd09884 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -76,8 +76,10 @@ ModListView::ModListView(QWidget* parent) setItemDelegate(new ModListStyledItemDelegated(this)); } -void ModListView::refreshStyle() +void ModListView::refresh() { + updateGroupByProxy(-1); + // maybe there is a better way but I did not find one QString sheet = styleSheet(); setStyleSheet("QTreeView { }"); @@ -496,7 +498,8 @@ void ModListView::updateGroupByProxy(int groupIndex) m_byNexusIdProxy->setGroupedColumn(ModList::COL_MODID); m_sortProxy->setSourceModel(m_byNexusIdProxy); } - else if (m_sortProxy->sortColumn() == ModList::COL_PRIORITY + else if (m_core->settings().interface().collapsibleSeparators() + && m_sortProxy->sortColumn() == ModList::COL_PRIORITY && m_sortProxy->sortOrder() == Qt::AscendingOrder) { m_sortProxy->setSourceModel(m_byPriorityProxy); m_byPriorityProxy->refresh(); diff --git a/src/modlistview.h b/src/modlistview.h index 3520bfc4..2ea5891c 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -65,10 +65,9 @@ public: // QRect visualRect(const QModelIndex& index) const override; - // refresh the style of the mod list, this needs to be called when the - // stylesheet is changed + // refresh the view (to call when settings have been changed) // - void refreshStyle(); + void refresh(); signals: diff --git a/src/settings.cpp b/src/settings.cpp index 04cfafc9..b6961807 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2162,6 +2162,16 @@ void InterfaceSettings::setStyleName(const QString& name) set(m_Settings, "Settings", "style", name); } +bool InterfaceSettings::collapsibleSeparators() const +{ + return get(m_Settings, "Settings", "collapsible_separators", true); +} + +void InterfaceSettings::setCollapsibleSeparators(bool b) +{ + set(m_Settings, "Settings", "collapsible_separators", b); +} + bool InterfaceSettings::compactDownloads() const { return get(m_Settings, "Settings", "compact_downloads", false); diff --git a/src/settings.h b/src/settings.h index 3f60fc7b..5506bbf8 100644 --- a/src/settings.h +++ b/src/settings.h @@ -617,6 +617,11 @@ public: std::optional styleName() const; void setStyleName(const QString& name); + // whether to use collapsible separators when possible + // + bool collapsibleSeparators() const; + void setCollapsibleSeparators(bool b); + // whether to show compact downloads // bool compactDownloads() const; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 43af5e9f..6d62228d 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -338,6 +338,43 @@ + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Use collapsible separators + + + true + + + false + + + + + + diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp index f29e1d24..47388c96 100644 --- a/src/settingsdialoggeneral.cpp +++ b/src/settingsdialoggeneral.cpp @@ -27,6 +27,7 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) ui->checkForUpdates->setChecked(settings().checkForUpdates()); ui->usePrereleaseBox->setChecked(settings().usePrereleases()); ui->colorSeparatorsBox->setChecked(settings().colors().colorSeparatorScrollbar()); + ui->collapsibleSeparatorsBox->setChecked(settings().interface().collapsibleSeparators()); QObject::connect(ui->exploreStyles, &QPushButton::clicked, [&]{ onExploreStyles(); }); @@ -70,6 +71,7 @@ void GeneralSettingsTab::update() settings().setCheckForUpdates(ui->checkForUpdates->isChecked()); settings().setUsePrereleases(ui->usePrereleaseBox->isChecked()); settings().colors().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked()); + settings().interface().setCollapsibleSeparators(ui->collapsibleSeparatorsBox->isChecked()); } void GeneralSettingsTab::addLanguages() -- cgit v1.3.1 From 87dac464d9ec488737b16839b0f06586eadb837e Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 31 Dec 2020 23:36:14 +0100 Subject: Fix position of markers in scrollbar for non-flat models. --- src/modelutils.cpp | 11 +++++++++++ src/modelutils.h | 4 ++++ src/modlistview.cpp | 15 ++------------- src/modlistview.h | 5 ----- src/settings.cpp | 17 +++-------------- src/viewmarkingscrollbar.cpp | 9 ++++++--- 6 files changed, 26 insertions(+), 35 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/modelutils.cpp b/src/modelutils.cpp index 43aa6b99..d464bb91 100644 --- a/src/modelutils.cpp +++ b/src/modelutils.cpp @@ -2,6 +2,17 @@ #include +QModelIndexList flatIndex( + const QAbstractItemModel* model, int column, const QModelIndex& parent) +{ + QModelIndexList index; + for (std::size_t i = 0; i < model->rowCount(parent); ++i) { + index.append(model->index(i, column, parent)); + index.append(flatIndex(model, column, index.back())); + } + return index; +} + QModelIndex indexModelToView(const QModelIndex& index, const QAbstractItemView* view) { // we need to stack the proxy diff --git a/src/modelutils.h b/src/modelutils.h index f355c0d6..b5becb6c 100644 --- a/src/modelutils.h +++ b/src/modelutils.h @@ -4,6 +4,10 @@ #include #include +// retrieve all the row index under the given parent +QModelIndexList flatIndex( + const QAbstractItemModel* model, int column = 0, const QModelIndex& parent = QModelIndex()); + // convert back-and-forth through model proxies QModelIndex indexModelToView(const QModelIndex& index, const QAbstractItemView* view); QModelIndexList indexModelToView(const QModelIndexList& index, const QAbstractItemView* view); diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 42627e3f..c92b65ef 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -169,12 +169,12 @@ std::optional ModListView::prevMod(unsigned int modIndex) const void ModListView::enableAllVisible() { - m_core->modList()->setActive(indexViewToModel(allIndex(model())), true); + m_core->modList()->setActive(indexViewToModel(flatIndex(model())), true); } void ModListView::disableAllVisible() { - m_core->modList()->setActive(indexViewToModel(allIndex(model())), false); + m_core->modList()->setActive(indexViewToModel(flatIndex(model())), false); } void ModListView::setFilterCriteria(const std::vector& criteria) @@ -254,17 +254,6 @@ QModelIndex ModListView::prevIndex(const QModelIndex& index) const return prev; } -QModelIndexList ModListView::allIndex( - const QAbstractItemModel* model, int column, const QModelIndex& parent) const -{ - QModelIndexList index; - for (std::size_t i = 0; i < model->rowCount(parent); ++i) { - index.append(model->index(i, column, parent)); - index.append(allIndex(model, column, index.back())); - } - return index; -} - std::pair ModListView::selected() const { return { indexViewToModel(currentIndex()), indexViewToModel(selectionModel()->selectedRows()) }; diff --git a/src/modlistview.h b/src/modlistview.h index 098466bc..c0d96f3f 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -124,11 +124,6 @@ protected: QModelIndex nextIndex(const QModelIndex& index) const; QModelIndex prevIndex(const QModelIndex& index) const; - // all index for the given model under the given index, recursively - // - QModelIndexList allIndex( - const QAbstractItemModel* model, int column = 0, const QModelIndex& index = QModelIndex()) const; - // re-implemented to fake the return value to allow drag-and-drop on // itself for separators // diff --git a/src/settings.cpp b/src/settings.cpp index b6961807..0e2de9d7 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -24,6 +24,7 @@ along with Mod Organizer. If not, see . #include "instancemanager.h" #include "shared/appconfig.h" #include "env.h" +#include "modelutils.h" #include "envmetrics.h" #include #include @@ -1063,22 +1064,10 @@ WidgetSettings::WidgetSettings(QSettings& s, bool globalInstance) } } -std::vector WidgetSettings::allIndex(const QAbstractItemModel* model, int column, const QModelIndex& parent) const -{ - std::vector index; - for (std::size_t i = 0; i < model->rowCount(parent); ++i) { - index.push_back(model->index(i, column, parent)); - - auto cindex = allIndex(model, column, index.back()); - index.insert(index.end(), cindex.begin(), cindex.end()); - } - return index; -} - void WidgetSettings::saveTreeState(const QTreeView* tv, int role) { QVariantList expanded; - for (auto index : allIndex(tv->model())) { + for (auto index : flatIndex(tv->model())) { if (tv->isExpanded(index)) { expanded.append(index.data(role)); } @@ -1090,7 +1079,7 @@ void WidgetSettings::restoreTreeState(QTreeView* tv, int role) const { if (auto expanded = getOptional(m_Settings, "Widgets", indexSettingName(tv))) { tv->collapseAll(); - for (auto index : allIndex(tv->model())) { + for (auto index : flatIndex(tv->model())) { if (expanded->contains(index.data(role))) { tv->expand(index); } diff --git a/src/viewmarkingscrollbar.cpp b/src/viewmarkingscrollbar.cpp index 2452d0e3..ed17120b 100644 --- a/src/viewmarkingscrollbar.cpp +++ b/src/viewmarkingscrollbar.cpp @@ -1,4 +1,5 @@ #include "viewmarkingscrollbar.h" +#include "modelutils.h" #include #include #include @@ -27,11 +28,13 @@ void ViewMarkingScrollBar::paintEvent(QPaintEvent *event) QRect handleRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarSlider, this); QRect innerRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarGroove, this); + auto indices = flatIndex(m_Model, 0, QModelIndex()); + painter.translate(innerRect.topLeft() + QPoint(0, 3)); - qreal scale = static_cast(innerRect.height() - 3) / static_cast(m_Model->rowCount()); + qreal scale = static_cast(innerRect.height() - 3) / static_cast(indices.size()); - for (int i = 0; i < m_Model->rowCount(); ++i) { - QVariant data = m_Model->data(m_Model->index(i, 0), m_Role); + for (int i = 0; i < indices.size(); ++i) { + QVariant data = indices[i].data(m_Role); if (data.isValid()) { QColor col = data.value(); painter.setPen(col); -- cgit v1.3.1 From e5f43788e874e638e1d4dbab20451c36e52df10d Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 1 Jan 2021 13:51:36 +0100 Subject: Visual fixes for the modlist. - Fix invalid positions of markers in the scrollbar. - Use color from children for collapsed elements (background and markers). --- src/icondelegate.cpp | 9 +++++-- src/modelutils.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++ src/modelutils.h | 12 +++++++++ src/modlistbypriorityproxy.cpp | 46 +++++++++++++++++++++++++++++++++ src/modlistbypriorityproxy.h | 1 + src/modlistview.cpp | 17 +++++++------ src/modlistview.h | 1 - src/pluginlistview.cpp | 16 ++++-------- src/pluginlistview.h | 1 - src/settings.cpp | 1 + src/viewmarkingscrollbar.cpp | 30 +++++++++++++++------- src/viewmarkingscrollbar.h | 6 ++--- 12 files changed, 163 insertions(+), 35 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/icondelegate.cpp b/src/icondelegate.cpp index 03964263..901b5731 100644 --- a/src/icondelegate.cpp +++ b/src/icondelegate.cpp @@ -27,7 +27,7 @@ along with Mod Organizer. If not, see . using namespace MOBase; -IconDelegate::IconDelegate(QObject *parent) +IconDelegate::IconDelegate(QObject* parent) : QStyledItemDelegate(parent) { } @@ -66,7 +66,12 @@ void IconDelegate::paintIcons( void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - QStyledItemDelegate::paint(painter, option, index); + if (auto* w = qobject_cast(parent())) { + w->itemDelegate()->paint(painter, option, index); + } + else { + QStyledItemDelegate::paint(painter, option, index); + } paintIcons(painter, option, index, getIcons(index)); } diff --git a/src/modelutils.cpp b/src/modelutils.cpp index d464bb91..7b54d258 100644 --- a/src/modelutils.cpp +++ b/src/modelutils.cpp @@ -2,6 +2,8 @@ #include +namespace MOShared { + QModelIndexList flatIndex( const QAbstractItemModel* model, int column, const QModelIndex& parent) { @@ -13,6 +15,26 @@ QModelIndexList flatIndex( return index; } +static QModelIndexList visibleIndexImpl(QTreeView* view, int column, const QModelIndex& parent) +{ + if (parent.isValid() && !view->isExpanded(parent)) { + return {}; + } + + auto* model = view->model(); + QModelIndexList index; + for (std::size_t i = 0; i < model->rowCount(parent); ++i) { + index.append(model->index(i, column, parent)); + index.append(visibleIndexImpl(view, column, index.back())); + } + return index; +} + +QModelIndexList visibleIndex(QTreeView* view, int column) +{ + return visibleIndexImpl(view, column, QModelIndex()); +} + QModelIndex indexModelToView(const QModelIndex& index, const QAbstractItemView* view) { // we need to stack the proxy @@ -67,3 +89,39 @@ QModelIndexList indexViewToModel(const QModelIndexList& index, const QAbstractIt } return result; } + +QColor childrenColor(const QModelIndex& index, QTreeView* view, int role) +{ + auto* model = view->model(); + auto rowIndex = index.sibling(index.row(), 0); + + if (model->hasChildren(rowIndex) && !view->isExpanded(rowIndex)) { + + // this is a non-expanded item + std::vector colors; + for (int i = 0; i < model->rowCount(rowIndex); ++i) { + auto childData = model->data(model->index(i, index.column(), rowIndex), role); + if (childData.isValid() && childData.canConvert()) { + colors.push_back(childData.value()); + } + } + + if (colors.empty()) { + return QColor(); + } + + int r = 0, g = 0, b = 0, a = 0; + for (auto& color : colors) { + r += color.red(); + g += color.green(); + b += color.blue(); + a += color.alpha(); + } + + return QColor(r / colors.size(), g / colors.size(), b / colors.size(), a / colors.size()); + } + + return QColor(); +} + +} diff --git a/src/modelutils.h b/src/modelutils.h index b5becb6c..cb7c9394 100644 --- a/src/modelutils.h +++ b/src/modelutils.h @@ -3,16 +3,28 @@ #include #include +#include + +namespace MOShared { // retrieve all the row index under the given parent QModelIndexList flatIndex( const QAbstractItemModel* model, int column = 0, const QModelIndex& parent = QModelIndex()); +// retrieve all the visible index in the given view +QModelIndexList visibleIndex(QTreeView* view, int column = 0); + // convert back-and-forth through model proxies QModelIndex indexModelToView(const QModelIndex& index, const QAbstractItemView* view); QModelIndexList indexModelToView(const QModelIndexList& index, const QAbstractItemView* view); QModelIndex indexViewToModel(const QModelIndex& index, const QAbstractItemModel* model); QModelIndexList indexViewToModel(const QModelIndexList& index, const QAbstractItemModel* model); +// retrieve the color of the children of the given index for the given, or an invalid +// color if the item is expanded or the children do not have colors for the given role +// +QColor childrenColor(const QModelIndex& index, QTreeView* view, int role); + +} #endif diff --git a/src/modlistbypriorityproxy.cpp b/src/modlistbypriorityproxy.cpp index 749991d0..7ef540b0 100644 --- a/src/modlistbypriorityproxy.cpp +++ b/src/modlistbypriorityproxy.cpp @@ -181,6 +181,52 @@ bool ModListByPriorityProxy::hasChildren(const QModelIndex& parent) const return item->children.size() > 0; } +QVariant ModListByPriorityProxy::data(const QModelIndex& index, int role) const +{ + auto sourceIndex = mapToSource(index); + if (!sourceIndex.isValid()) { + return QVariant(); + } + + auto sourceData = sourceModel()->data(sourceIndex, role); + if (role != Qt::BackgroundRole && role != ModList::ScrollMarkRole) { + return sourceData; + } + + if (!hasChildren(index)) { + return sourceData; + } + + bool expanded = !m_CollapsedItems.contains(index.sibling(index.row(), 0).data(Qt::DisplayRole).toString()); + + if (expanded) { + return sourceData; + } + + // this is a non-expanded item + std::vector colors; + for (int i = 0; i < rowCount(index); ++i) { + auto childData = sourceModel()->data(mapToSource(this->index(i, index.column(), index)), role); + if (childData.isValid() && childData.canConvert()) { + colors.push_back(childData.value()); + } + } + + if (true || colors.empty()) { + return sourceData; + } + + int r = 0, g = 0, b = 0, a = 0; + for (auto& color : colors) { + r += color.red(); + g += color.green(); + b += color.blue(); + a += color.alpha(); + } + + return QColor(r / colors.size(), g / colors.size(), b / colors.size(), a / colors.size()); +} + bool ModListByPriorityProxy::setData(const QModelIndex& index, const QVariant& value, int role) { // only care about the "name" column diff --git a/src/modlistbypriorityproxy.h b/src/modlistbypriorityproxy.h index e5a8adff..5149b7a2 100644 --- a/src/modlistbypriorityproxy.h +++ b/src/modlistbypriorityproxy.h @@ -37,6 +37,7 @@ public: int columnCount(const QModelIndex& index) const override; bool hasChildren(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role) const override; bool setData(const QModelIndex& index, const QVariant& value, int role) override; bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const override; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 80aa6495..da4d79cf 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -28,6 +28,7 @@ #include "modelutils.h" using namespace MOBase; +using namespace MOShared; // delegate to remove indentation for mods when using collapsible // separator @@ -57,6 +58,13 @@ public: } } QStyledItemDelegate::paint(painter, opt, index); + + auto color = childrenColor(index, m_view, Qt::BackgroundRole); + if (color.isValid()) { + // int shift = 3 * opt.rect.height() / 4; + // opt.rect.adjust(0, shift, 0, 0); + painter->fillRect(opt.rect, color); + } } }; @@ -67,7 +75,7 @@ ModListView::ModListView(QWidget* parent) , m_byPriorityProxy(nullptr) , m_byCategoryProxy(nullptr) , m_byNexusIdProxy(nullptr) - , m_scrollbar(new ViewMarkingScrollBar(this->model(), ModList::ScrollMarkRole, this)) + , m_scrollbar(new ViewMarkingScrollBar(this, ModList::ScrollMarkRole)) { setVerticalScrollBar(m_scrollbar); MOBase::setCustomizableColumns(this); @@ -79,13 +87,6 @@ ModListView::ModListView(QWidget* parent) connect(this, &ModListView::customContextMenuRequested, this, &ModListView::onCustomContextMenuRequested); } -void ModListView::setModel(QAbstractItemModel* model) -{ - QTreeView::setModel(model); - setVerticalScrollBar(new ViewMarkingScrollBar(model, ModList::ScrollMarkRole, this)); -} - - void ModListView::refresh() { updateGroupByProxy(-1); diff --git a/src/modlistview.h b/src/modlistview.h index c0d96f3f..dac96822 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -38,7 +38,6 @@ public: public: explicit ModListView(QWidget* parent = 0); - void setModel(QAbstractItemModel* model) override; void setup(OrganizerCore& core, CategoryFactory& factory, MainWindow* mw, Ui::MainWindow* mwui); diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index 589c5737..d17b4a2f 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -21,19 +21,13 @@ using namespace MOBase; PluginListView::PluginListView(QWidget *parent) : QTreeView(parent) , m_sortProxy(nullptr) - , m_Scrollbar(new ViewMarkingScrollBar(this->model(), Qt::BackgroundRole, this)) + , m_Scrollbar(new ViewMarkingScrollBar(this, Qt::BackgroundRole)) , m_didUpdateMasterList(false) { setVerticalScrollBar(m_Scrollbar); MOBase::setCustomizableColumns(this); } -void PluginListView::setModel(QAbstractItemModel *model) -{ - QTreeView::setModel(model); - setVerticalScrollBar(new ViewMarkingScrollBar(model, Qt::BackgroundRole, this)); -} - int PluginListView::sortColumn() const { return m_sortProxy ? m_sortProxy->sortColumn() : -1; @@ -41,22 +35,22 @@ int PluginListView::sortColumn() const QModelIndex PluginListView::indexModelToView(const QModelIndex& index) const { - return ::indexModelToView(index, this); + return MOShared::indexModelToView(index, this); } QModelIndexList PluginListView::indexModelToView(const QModelIndexList& index) const { - return ::indexModelToView(index, this); + return MOShared::indexModelToView(index, this); } QModelIndex PluginListView::indexViewToModel(const QModelIndex& index) const { - return ::indexViewToModel(index, m_core->pluginList()); + return MOShared::indexViewToModel(index, m_core->pluginList()); } QModelIndexList PluginListView::indexViewToModel(const QModelIndexList& index) const { - return ::indexViewToModel(index, m_core->pluginList()); + return MOShared::indexViewToModel(index, m_core->pluginList()); } void PluginListView::updatePluginCount() diff --git a/src/pluginlistview.h b/src/pluginlistview.h index e5dc15e7..6470ced9 100644 --- a/src/pluginlistview.h +++ b/src/pluginlistview.h @@ -19,7 +19,6 @@ class PluginListView : public QTreeView Q_OBJECT public: explicit PluginListView(QWidget* parent = nullptr); - void setModel(QAbstractItemModel* model) override; void setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* mwui); diff --git a/src/settings.cpp b/src/settings.cpp index 0e2de9d7..e379a819 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -31,6 +31,7 @@ along with Mod Organizer. If not, see . #include using namespace MOBase; +using namespace MOShared; EndorsementState endorsementStateFromString(const QString& s) diff --git a/src/viewmarkingscrollbar.cpp b/src/viewmarkingscrollbar.cpp index 0991f171..fb165922 100644 --- a/src/viewmarkingscrollbar.cpp +++ b/src/viewmarkingscrollbar.cpp @@ -4,9 +4,11 @@ #include #include -ViewMarkingScrollBar::ViewMarkingScrollBar(QAbstractItemModel* model, int role, QWidget *parent) - : QScrollBar(parent) - , m_model(model) +using namespace MOShared; + +ViewMarkingScrollBar::ViewMarkingScrollBar(QTreeView* view, int role) + : QScrollBar(view) + , m_view(view) , m_role(role) { // not implemented for horizontal sliders @@ -15,7 +17,7 @@ ViewMarkingScrollBar::ViewMarkingScrollBar(QAbstractItemModel* model, int role, void ViewMarkingScrollBar::paintEvent(QPaintEvent* event) { - if (m_model == nullptr) { + if (m_view->model() == nullptr) { return; } QScrollBar::paintEvent(event); @@ -28,17 +30,27 @@ void ViewMarkingScrollBar::paintEvent(QPaintEvent* event) QRect handleRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarSlider, this); QRect innerRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarGroove, this); - auto indices = flatIndex(m_model, 0, QModelIndex()); + auto indices = visibleIndex(m_view, 0); painter.translate(innerRect.topLeft() + QPoint(0, 3)); qreal scale = static_cast(innerRect.height() - 3) / static_cast(indices.size()); for (int i = 0; i < indices.size(); ++i) { QVariant data = indices[i].data(m_role); - if (data.isValid()) { - QColor col = data.value(); - painter.setPen(col); - painter.setBrush(col); + QColor color; + + if (data.canConvert()) { + color = data.value(); + } + + auto childrenColor = MOShared::childrenColor(indices[i], m_view, m_role); + if (childrenColor.isValid()) { + color = childrenColor; + } + + if (color.isValid()) { + painter.setPen(color); + painter.setBrush(color); painter.drawRect(QRect(2, i * scale - 2, handleRect.width() - 5, 3)); } } diff --git a/src/viewmarkingscrollbar.h b/src/viewmarkingscrollbar.h index 88d77039..6947a018 100644 --- a/src/viewmarkingscrollbar.h +++ b/src/viewmarkingscrollbar.h @@ -1,20 +1,20 @@ #ifndef VIEWMARKINGSCROLLBAR_H #define VIEWMARKINGSCROLLBAR_H -#include +#include #include class ViewMarkingScrollBar : public QScrollBar { public: - ViewMarkingScrollBar(QAbstractItemModel *model, int role, QWidget* parent = nullptr); + ViewMarkingScrollBar(QTreeView* view, int role); protected: void paintEvent(QPaintEvent *event) override; private: - QAbstractItemModel* m_model; + QTreeView* m_view; int m_role; }; -- cgit v1.3.1 From 071974c243d97a19e5a73f368ce25f8decd00183 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sat, 2 Jan 2021 17:14:09 +0100 Subject: Save/restore filter list state between run. --- src/filterlist.cpp | 50 +++++++++++++++++++++++++++++++++++++++----------- src/mainwindow.cpp | 2 +- src/modlistview.cpp | 4 ++-- src/settings.cpp | 27 +++++++++++++++++++++++++-- src/settings.h | 10 +++++++--- 5 files changed, 74 insertions(+), 19 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/filterlist.cpp b/src/filterlist.cpp index c3f169a6..14813312 100644 --- a/src/filterlist.cpp +++ b/src/filterlist.cpp @@ -12,7 +12,14 @@ using Criteria = ModListSortProxy::Criteria; class FilterList::CriteriaItem : public QTreeWidgetItem { + + static constexpr int IDRole = Qt::UserRole; + static constexpr int TypeRole = Qt::UserRole + 1; + public: + + static constexpr int StateRole = Qt::UserRole + 2; + enum States { FirstState = 0, @@ -58,27 +65,41 @@ public: void nextState() { - m_state = static_cast(m_state + 1); - if (m_state > LastState) { - m_state = FirstState; + auto s = static_cast(m_state + 1); + if (s > LastState) { + s = FirstState; } - - updateState(); + setState(s); } void previousState() { - m_state = static_cast(m_state - 1); - if (m_state < FirstState) { - m_state = LastState; + auto s = static_cast(m_state - 1); + if (s < FirstState) { + s = LastState; } + setState(s); + } - updateState(); + QVariant data(int column, int role) const + { + if (role == StateRole) { + return m_state; + } + return QTreeWidgetItem::data(column, role); + } + + void setData(int column, int role, const QVariant& value) { + if (role == StateRole) { + MOBase::log::debug("setData: {}, {}, {}", column, role, value.toInt()); + setState(static_cast(value.toInt())); + } + else { + QTreeWidgetItem::setData(column, role, value); + } } private: - const int IDRole = Qt::UserRole; - const int TypeRole = Qt::UserRole + 1; FilterList* m_list; States m_state; @@ -212,10 +233,17 @@ FilterList::FilterList(Ui::MainWindow* ui, OrganizerCore& core, CategoryFactory& 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); + checkCriteria(); } void FilterList::saveState(Settings& s) const { + s.widgets().saveTreeCheckState(ui->filters, CriteriaItem::StateRole); + s.widgets().saveChecked(ui->filtersAnd); + s.widgets().saveChecked(ui->filtersOr); s.widgets().saveIndex(ui->filtersSeparators); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6929a009..2b2685c4 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1170,8 +1170,8 @@ void MainWindow::showEvent(QShowEvent *event) QMainWindow::showEvent(event); if (!m_WasVisible) { - readSettings(); ui->modList->refreshFilters(); + readSettings(); // this needs to be connected here instead of in the constructor because the // actual changing of the stylesheet is done by MOApplication, which diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 0898fe3c..a460e4a4 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -804,7 +804,7 @@ void ModListView::restoreState(const Settings& s) s.geometry().restoreState(header()); s.widgets().restoreIndex(ui.groupBy); - s.widgets().restoreTreeState(this); + s.widgets().restoreTreeExpandState(this); m_filters->restoreState(s); } @@ -814,7 +814,7 @@ void ModListView::saveState(Settings& s) const s.geometry().saveState(header()); s.widgets().saveIndex(ui.groupBy); - s.widgets().saveTreeState(this); + s.widgets().saveTreeExpandState(this); m_filters->saveState(s); } diff --git a/src/settings.cpp b/src/settings.cpp index e379a819..3cc026cf 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1065,7 +1065,30 @@ WidgetSettings::WidgetSettings(QSettings& s, bool globalInstance) } } -void WidgetSettings::saveTreeState(const QTreeView* tv, int role) +void WidgetSettings::saveTreeCheckState(const QTreeView* tv, int role) +{ + QVariantList data; + for (auto index : flatIndex(tv->model())) { + data.append(index.data(role)); + } + set(m_Settings, "Widgets", indexSettingName(tv), data); +} + +void WidgetSettings::restoreTreeCheckState(QTreeView* tv, int role) const +{ + if (auto states = getOptional(m_Settings, "Widgets", indexSettingName(tv))) { + auto allIndex = flatIndex(tv->model()); + MOBase::log::debug("restoreTreeCheckState: {}, {}", states->size(), allIndex.size()); + if (states->size() != allIndex.size()) { + return; + } + for (int i = 0; i < states->size(); ++i) { + tv->model()->setData(allIndex[i], states->at(i), role); + } + } +} + +void WidgetSettings::saveTreeExpandState(const QTreeView* tv, int role) { QVariantList expanded; for (auto index : flatIndex(tv->model())) { @@ -1076,7 +1099,7 @@ void WidgetSettings::saveTreeState(const QTreeView* tv, int role) set(m_Settings, "Widgets", indexSettingName(tv), expanded); } -void WidgetSettings::restoreTreeState(QTreeView* tv, int role) const +void WidgetSettings::restoreTreeExpandState(QTreeView* tv, int role) const { if (auto expanded = getOptional(m_Settings, "Widgets", indexSettingName(tv))) { tv->collapseAll(); diff --git a/src/settings.h b/src/settings.h index 5506bbf8..9c3765c2 100644 --- a/src/settings.h +++ b/src/settings.h @@ -202,11 +202,15 @@ public: // WidgetSettings(QSettings& s, bool globalInstance); + // tree item check - this saves the list of expanded items based on the given role + // + void saveTreeCheckState(const QTreeView* tv, int role = Qt::CheckStateRole); + void restoreTreeCheckState(QTreeView* tv, int role = Qt::CheckStateRole) const; + // tree state - this saves the list of expanded items based on the given role // - std::vector allIndex(const QAbstractItemModel* model, int column = 0, const QModelIndex& parent = QModelIndex()) const; - void saveTreeState(const QTreeView* tv, int role = Qt::DisplayRole); - void restoreTreeState(QTreeView* tv, int role = Qt::DisplayRole) const; + void saveTreeExpandState(const QTreeView* tv, int role = Qt::DisplayRole); + void restoreTreeExpandState(QTreeView* tv, int role = Qt::DisplayRole) const; // selected index for a combobox // -- cgit v1.3.1 From fbd7e777d76c2032d8c4df418e5550b14b9c2943 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 3 Jan 2021 16:30:35 +0100 Subject: Add option to enable/disable displaying conflicts on collapsed separators. --- src/modconflicticondelegate.cpp | 25 +++---------------------- src/modlistview.cpp | 35 ++++++++++++++++++++++++++++++++++- src/modlistview.h | 6 ++++++ src/settings.cpp | 10 ++++++++++ src/settings.h | 5 +++++ src/settingsdialog.ui | 19 +++++++++++++++++++ src/settingsdialoggeneral.cpp | 7 +++++++ 7 files changed, 84 insertions(+), 23 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/modconflicticondelegate.cpp b/src/modconflicticondelegate.cpp index cbc32037..73c47a03 100644 --- a/src/modconflicticondelegate.cpp +++ b/src/modconflicticondelegate.cpp @@ -93,28 +93,9 @@ QList ModConflictIconDelegate::getIcons(const QModelIndex &index) const return {}; } - ModInfo::Ptr info = ModInfo::getByIndex(modIndex.toInt()); - - auto flags = info->getConflictFlags(); - bool compact = m_Compact; - if (info->isSeparator() - && m_View->hasCollapsibleSeparators() - && !m_View->isExpanded(index.sibling(index.row(), 0))) { - - // combine the child conflicts - std::set eFlags(flags.begin(), flags.end()); - for (int i = 0; i < m_View->model()->rowCount(index); ++i) { - auto cIndex = m_View->model()->index(i, index.column(), index).data(ModList::IndexRole).toInt(); - auto cFlags = ModInfo::getByIndex(cIndex)->getConflictFlags(); - eFlags.insert(cFlags.begin(), cFlags.end()); - } - flags = { eFlags.begin(), eFlags.end() }; - - // force compact because there can be a lots of flags here - compact = true; - } - - return getIconsForFlags(flags, compact); + bool compact; + auto flags = m_View->conflictFlags(index, &compact); + return getIconsForFlags(flags, compact || m_Compact); } QString ModConflictIconDelegate::getFlagIcon(ModInfo::EConflictFlag flag) diff --git a/src/modlistview.cpp b/src/modlistview.cpp index e6d78bab..531a8d43 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -1045,7 +1045,9 @@ QColor ModListView::markerColor(const QModelIndex& index) const // collapsed separator auto rowIndex = index.sibling(index.row(), 0); - if (hasCollapsibleSeparators() && model()->hasChildren(rowIndex) && !isExpanded(rowIndex)) { + if (hasCollapsibleSeparators() + && m_core->settings().interface().collapsibleSeparatorsConflicts() + && model()->hasChildren(rowIndex) && !isExpanded(rowIndex)) { std::vector colors; for (int i = 0; i < model()->rowCount(rowIndex); ++i) { @@ -1073,6 +1075,37 @@ QColor ModListView::markerColor(const QModelIndex& index) const return QColor(); } +std::vector ModListView::conflictFlags(const QModelIndex& index, bool* forceCompact) const +{ + ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); + + auto flags = info->getConflictFlags(); + 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)->getConflictFlags(); + 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; +} + void ModListView::onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { if (hasCollapsibleSeparators()) { diff --git a/src/modlistview.h b/src/modlistview.h index 9712deab..faa33b6a 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -170,6 +170,7 @@ protected slots: private: + friend class ModConflictIconDelegate; friend class ModListStyledItemDelegated; friend class ModListViewMarkingScrollBar; @@ -191,6 +192,11 @@ private: // QColor markerColor(const QModelIndex& index) const; + // retrieve the conflicts flags for the given index + // + std::vector conflictFlags( + const QModelIndex& index, bool* forceCompact = nullptr) 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 // diff --git a/src/settings.cpp b/src/settings.cpp index 3cc026cf..e04cd0c1 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2185,6 +2185,16 @@ void InterfaceSettings::setCollapsibleSeparators(bool b) set(m_Settings, "Settings", "collapsible_separators", b); } +bool InterfaceSettings::collapsibleSeparatorsConflicts() const +{ + return get(m_Settings, "Settings", "collapsible_separators_conflicts", true); +} + +void InterfaceSettings::setCollapsibleSeparatorsConflicts(bool b) +{ + set(m_Settings, "Settings", "collapsible_separators_conflicts", b); +} + bool InterfaceSettings::compactDownloads() const { return get(m_Settings, "Settings", "compact_downloads", false); diff --git a/src/settings.h b/src/settings.h index 9c3765c2..043b22a4 100644 --- a/src/settings.h +++ b/src/settings.h @@ -626,6 +626,11 @@ public: bool collapsibleSeparators() const; void setCollapsibleSeparators(bool b); + // whether to display mod conflicts on separators when collapsed + // + bool collapsibleSeparatorsConflicts() const; + void setCollapsibleSeparatorsConflicts(bool b); + // whether to show compact downloads // bool compactDownloads() const; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 6655ca97..ae4f4f34 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -403,6 +403,9 @@ + + Allow collapsing separators when sorting by ascending priority. + Use collapsible separators @@ -414,6 +417,22 @@ + + + + Display mod conflicts on separator when collapsed. + + + Display mod conflicts on separator when collapsed. + + + Show conflicts on separators + + + true + + + diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp index 47388c96..7b854260 100644 --- a/src/settingsdialoggeneral.cpp +++ b/src/settingsdialoggeneral.cpp @@ -19,6 +19,11 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) 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()); @@ -27,6 +32,7 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) 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(); }); @@ -72,6 +78,7 @@ void GeneralSettingsTab::update() 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() -- cgit v1.3.1