summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikaël Capelle <capelle.mikael@gmail.com>2021-01-01 13:51:36 +0100
committerMikaël Capelle <capelle.mikael@gmail.com>2021-01-02 15:38:19 +0100
commite5f43788e874e638e1d4dbab20451c36e52df10d (patch)
tree9191bae2dce4cb69bd9c5bfa0099a4f8981a50d1
parentf36c68332019ec68a713b21519c0439039845fa1 (diff)
Visual fixes for the modlist.
- Fix invalid positions of markers in the scrollbar. - Use color from children for collapsed elements (background and markers).
-rw-r--r--src/icondelegate.cpp9
-rw-r--r--src/modelutils.cpp58
-rw-r--r--src/modelutils.h12
-rw-r--r--src/modlistbypriorityproxy.cpp46
-rw-r--r--src/modlistbypriorityproxy.h1
-rw-r--r--src/modlistview.cpp17
-rw-r--r--src/modlistview.h1
-rw-r--r--src/pluginlistview.cpp16
-rw-r--r--src/pluginlistview.h1
-rw-r--r--src/settings.cpp1
-rw-r--r--src/viewmarkingscrollbar.cpp30
-rw-r--r--src/viewmarkingscrollbar.h6
12 files changed, 163 insertions, 35 deletions
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 <http://www.gnu.org/licenses/>.
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<QAbstractItemView*>(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 <QAbstractProxyModel>
+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<QColor> 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<QColor>()) {
+ colors.push_back(childData.value<QColor>());
+ }
+ }
+
+ 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 <QAbstractItemView>
#include <QAbstractItemModel>
+#include <QColor>
+
+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<QColor> 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<QColor>()) {
+ colors.push_back(childData.value<QColor>());
+ }
+ }
+
+ 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 <http://www.gnu.org/licenses/>.
#include <iplugingame.h>
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 <QStyleOptionSlider>
#include <QPainter>
-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<qreal>(innerRect.height() - 3) / static_cast<qreal>(indices.size());
for (int i = 0; i < indices.size(); ++i) {
QVariant data = indices[i].data(m_role);
- if (data.isValid()) {
- QColor col = data.value<QColor>();
- painter.setPen(col);
- painter.setBrush(col);
+ QColor color;
+
+ if (data.canConvert<QColor>()) {
+ color = data.value<QColor>();
+ }
+
+ 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 <QAbstractItemModel>
+#include <QTreeView>
#include <QScrollBar>
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;
};