summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/filterlist.cpp232
-rw-r--r--src/filterlist.h8
-rw-r--r--src/mainwindow.ui64
-rw-r--r--src/modlistsortproxy.cpp26
-rw-r--r--src/modlistsortproxy.h3
5 files changed, 204 insertions, 129 deletions
diff --git a/src/filterlist.cpp b/src/filterlist.cpp
index 81f8b670..0dee8544 100644
--- a/src/filterlist.cpp
+++ b/src/filterlist.cpp
@@ -11,28 +11,23 @@ using Criteria = ModListSortProxy::Criteria;
class FilterList::CriteriaItem : public QTreeWidgetItem
{
public:
- CriteriaItem(FilterList* list, QString name, CriteriaType type, int id)
- : QTreeWidgetItem({name}), m_list(list), m_widget(nullptr), m_checkbox(nullptr)
+ enum States : int
{
- setData(0, Qt::ToolTipRole, name);
- setData(0, TypeRole, type);
- setData(0, IDRole, id);
-
- m_widget = new QWidget;
- m_widget->setStyleSheet("background-color: rgba(0,0,0,0)");
+ FirstState = 0,
- auto* ly = new QVBoxLayout(m_widget);
- ly->setAlignment(Qt::AlignCenter);
- ly->setContentsMargins(0, 0, 0, 0);
+ Inactive = FirstState,
+ Active,
+ Inverted,
- m_checkbox = new QCheckBox;
- QObject::connect(m_checkbox, &QCheckBox::toggled, [&]{ m_list->onSelection(); });
- ly->addWidget(m_checkbox);
- }
+ LastState = Inverted
+ };
- QWidget* widget()
+ CriteriaItem(FilterList* list, QString name, CriteriaType type, int id)
+ : QTreeWidgetItem({"", name}), m_list(list), m_state(Inactive)
{
- return m_widget;
+ setData(0, Qt::ToolTipRole, name);
+ setData(0, TypeRole, type);
+ setData(0, IDRole, id);
}
CriteriaType type() const
@@ -45,14 +40,37 @@ public:
return data(0, IDRole).toInt();
}
- bool inverse() const
+ States state() const
+ {
+ return m_state;
+ }
+
+ void setState(States s)
{
- return m_checkbox->isChecked();
+ if (m_state != s) {
+ m_state = s;
+ updateState();
+ }
}
- void setInverted(bool b)
+ void nextState()
{
- m_checkbox->setChecked(b);
+ m_state = static_cast<States>(m_state + 1);
+ if (m_state > LastState) {
+ m_state = FirstState;
+ }
+
+ updateState();
+ }
+
+ void previousState()
+ {
+ m_state = static_cast<States>(m_state - 1);
+ if (m_state < FirstState) {
+ m_state = LastState;
+ }
+
+ updateState();
}
private:
@@ -60,40 +78,91 @@ private:
const int TypeRole = Qt::UserRole + 1;
FilterList* m_list;
- QWidget* m_widget;
- QCheckBox* m_checkbox;
+ States m_state;
+
+ void updateState()
+ {
+ QString s;
+
+ switch (m_state)
+ {
+ case Inactive:
+ {
+ break;
+ }
+
+ case Active:
+ {
+ // U+2713 CHECK MARK
+ s = QString::fromUtf8("\xe2\x9c\x93");
+ break;
+ }
+
+ case Inverted:
+ {
+ s = tr("Not");
+ break;
+ }
+ }
+
+ setText(0, s);
+ }
+};
+
+
+class ClickFilter : public QObject
+{
+public:
+ ClickFilter(std::function<bool (QMouseEvent*)> f)
+ : m_f(std::move(f))
+ {
+ }
+
+ bool eventFilter(QObject* o, QEvent* e) override
+ {
+ if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) {
+ if (m_f) {
+ return m_f(static_cast<QMouseEvent*>(e));
+ }
+ }
+
+ return QObject::eventFilter(o, e);;
+ }
+
+private:
+ std::function<bool (QMouseEvent*)> m_f;
};
FilterList::FilterList(Ui::MainWindow* ui, CategoryFactory& factory)
: ui(ui), m_factory(factory)
{
- connect(
- ui->filters, &QTreeWidget::customContextMenuRequested,
- [&](auto&& pos){ onContextMenu(pos); });
+ ui->filters->viewport()->installEventFilter(
+ new ClickFilter([&](auto* e){ return onClick(e); }));
connect(
- ui->filters, &QTreeWidget::itemSelectionChanged,
- [&]{ onSelection(); });
+ ui->filtersClear, &QPushButton::clicked,
+ [&]{ clearSelection(); });
connect(
- ui->filtersClear, &QPushButton::clicked,
- [&]{ clear(); });
+ ui->filtersEdit, &QPushButton::clicked,
+ [&]{ editCategories(); });
connect(
ui->filtersAnd, &QCheckBox::toggled,
- [&]{ onCriteriaChanged(); });
+ [&]{ onOptionsChanged(); });
connect(
ui->filtersOr, &QCheckBox::toggled,
- [&]{ onCriteriaChanged(); });
+ [&]{ onOptionsChanged(); });
connect(
ui->filtersSeparators, &QCheckBox::toggled,
- [&]{ onCriteriaChanged(); });
+ [&]{ onOptionsChanged(); });
- ui->filters->header()->setSectionResizeMode(0, QHeaderView::Stretch);
- ui->filters->header()->resizeSection(1, 50);
+ ui->filters->header()->setMinimumSectionSize(0);
+ ui->filters->header()->setSectionResizeMode(0, QHeaderView::Fixed);
+ ui->filters->header()->resizeSection(0, 30);
ui->categoriesSplitter->setCollapsible(0, false);
ui->categoriesSplitter->setCollapsible(1, false);
}
@@ -110,7 +179,7 @@ QTreeWidgetItem* FilterList::addCriteriaItem(
ui->filters->addTopLevelItem(item);
}
- ui->filters->setItemWidget(item, 1, item->widget());
+ item->setTextAlignment(0, Qt::AlignCenter);
return item;
}
@@ -224,91 +293,72 @@ void FilterList::setSelection(const std::vector<Criteria>& criteria)
void FilterList::clearSelection()
{
- ui->filters->clearSelection();
-}
-
-void FilterList::onSelection()
-{
- const QModelIndexList indices = ui->filters->selectionModel()->selectedRows();
- std::vector<Criteria> criteria;
-
- for (auto* item : ui->filters->selectedItems()) {
- const auto* ci = dynamic_cast<CriteriaItem*>(item);
+ for (int i=0; i<ui->filters->topLevelItemCount(); ++i) {
+ auto* ci = dynamic_cast<CriteriaItem*>(ui->filters->topLevelItem(i));
if (!ci) {
continue;
}
- criteria.push_back({
- ci->type(), ci->id(), ci->inverse()
- });
+ ci->setState(CriteriaItem::Inactive);
}
- emit criteriaChanged(criteria);
+ checkCriteria();
}
-void FilterList::onContextMenu(const QPoint &pos)
+bool FilterList::onClick(QMouseEvent* e)
{
- QMenu menu;
+ auto* item = ui->filters->itemAt(e->pos());
+ if (!item) {
+ return false;
+ }
- QAction* set = menu.addAction(tr("Set inverted"), [&]{ toggleInverted(true); });
- QAction* unset = menu.addAction(tr("Unset inverted"), [&]{ toggleInverted(false); });
- menu.addSeparator();
- menu.addAction(tr("Edit Categories..."), [&]{ editCategories(); });
+ auto* ci = dynamic_cast<CriteriaItem*>(item);
+ if (!ci) {
+ return false;
+ }
- if (ui->filters->selectedItems().empty()) {
- set->setEnabled(false);
- unset->setEnabled(false);
+ if (e->button() == Qt::LeftButton) {
+ ci->nextState();
+ } else if (e->button() == Qt::RightButton) {
+ ci->previousState();
+ } else {
+ return false;
}
- menu.exec(ui->filters->viewport()->mapToGlobal(pos));
+ checkCriteria();
+ return true;
}
-void FilterList::editCategories()
+void FilterList::checkCriteria()
{
- CategoriesDialog dialog(qApp->activeWindow());
-
- if (dialog.exec() == QDialog::Accepted) {
- dialog.commitChanges();
- }
-}
+ std::vector<Criteria> criteria;
-void FilterList::clear()
-{
- const auto count = ui->filters->topLevelItemCount();
- for (int i=0; i<count; ++i) {
- auto* ci = dynamic_cast<CriteriaItem*>(ui->filters->topLevelItem(i));
+ for (int i=0; i<ui->filters->topLevelItemCount(); ++i) {
+ const auto* ci = dynamic_cast<CriteriaItem*>(ui->filters->topLevelItem(i));
if (!ci) {
continue;
}
- ci->setInverted(false);
+ if (ci->state() != CriteriaItem::Inactive) {
+ criteria.push_back({
+ ci->type(), ci->id(), (ci->state() == CriteriaItem::Inverted)
+ });
+ }
}
- clearSelection();
+ emit criteriaChanged(criteria);
}
-void FilterList::toggleInverted(bool b)
+void FilterList::editCategories()
{
- bool changed = false;
-
- for (auto* item : ui->filters->selectedItems()) {
- auto* ci = dynamic_cast<CriteriaItem*>(item);
- if (!ci) {
- continue;
- }
-
- if (ci->inverse() != b) {
- ci->setInverted(b);
- changed = true;
- }
- }
+ CategoriesDialog dialog(qApp->activeWindow());
- if (changed) {
- onSelection();
+ if (dialog.exec() == QDialog::Accepted) {
+ dialog.commitChanges();
}
}
-void FilterList::onCriteriaChanged()
+void FilterList::onOptionsChanged()
{
const auto mode = ui->filtersAnd->isChecked() ?
ModListSortProxy::FILTER_AND : ModListSortProxy::FILTER_OR;
diff --git a/src/filterlist.h b/src/filterlist.h
index 52b90ea7..fac1d683 100644
--- a/src/filterlist.h
+++ b/src/filterlist.h
@@ -28,13 +28,11 @@ private:
Ui::MainWindow* ui;
CategoryFactory& m_factory;
- void onContextMenu(const QPoint &pos);
- void onSelection();
- void onCriteriaChanged();
+ bool onClick(QMouseEvent* e);
+ void onOptionsChanged();
- void clear();
- void toggleInverted(bool b);
void editCategories();
+ void checkCriteria();
QTreeWidgetItem* addCriteriaItem(
QTreeWidgetItem *root, const QString &name, int categoryID,
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index 5206d797..1a64dfdd 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -76,59 +76,69 @@
<height>0</height>
</size>
</property>
- <property name="contextMenuPolicy">
- <enum>Qt::CustomContextMenu</enum>
- </property>
<property name="selectionMode">
- <enum>QAbstractItemView::ExtendedSelection</enum>
+ <enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="indentation">
<number>0</number>
</property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="headerHidden">
- <bool>false</bool>
+ <bool>true</bool>
</property>
<attribute name="headerVisible">
- <bool>true</bool>
+ <bool>false</bool>
</attribute>
<attribute name="headerCascadingSectionResizes">
- <bool>true</bool>
- </attribute>
- <attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
<column>
<property name="text">
- <string notr="true">Category</string>
+ <string/>
</property>
</column>
<column>
<property name="text">
- <string>Invert</string>
+ <string notr="true">Category</string>
</property>
</column>
</widget>
</item>
<item>
- <widget class="QPushButton" name="filtersClear">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>25</height>
- </size>
- </property>
- <property name="text">
- <string>Clear</string>
- </property>
+ <widget class="QWidget" name="widget_2" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="filtersClear">
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="filtersEdit">
+ <property name="text">
+ <string>Edit...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
</item>
<item>
diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp
index 36dcae59..e6bed49c 100644
--- a/src/modlistsortproxy.cpp
+++ b/src/modlistsortproxy.cpp
@@ -269,12 +269,12 @@ bool ModListSortProxy::hasConflictFlag(const std::vector<ModInfo::EFlag> &flags)
bool ModListSortProxy::filterMatchesModAnd(ModInfo::Ptr info, bool enabled) const
{
- if (info->hasFlag(ModInfo::FLAG_SEPARATOR) && !m_FilterSeparators) {
+ if (!optionsMatchMod(info, enabled)) {
return false;
}
for (auto&& c : m_Criteria) {
- if (!criteriaMatchesMod(info, enabled, c)) {
+ if (!criteriaMatchMod(info, enabled, c)) {
return false;
}
}
@@ -284,12 +284,12 @@ bool ModListSortProxy::filterMatchesModAnd(ModInfo::Ptr info, bool enabled) cons
bool ModListSortProxy::filterMatchesModOr(ModInfo::Ptr info, bool enabled) const
{
- if (info->hasFlag(ModInfo::FLAG_SEPARATOR) && !m_FilterSeparators) {
+ if (!optionsMatchMod(info, enabled)) {
return false;
}
for (auto&& c : m_Criteria) {
- if (criteriaMatchesMod(info, enabled, c)) {
+ if (criteriaMatchMod(info, enabled, c)) {
return true;
}
}
@@ -302,7 +302,23 @@ bool ModListSortProxy::filterMatchesModOr(ModInfo::Ptr info, bool enabled) const
return true;
}
-bool ModListSortProxy::criteriaMatchesMod(
+bool ModListSortProxy::optionsMatchMod(ModInfo::Ptr info, bool) const
+{
+ // don't check options if there are no filters selected
+ if (!m_FilterActive) {
+ return true;
+ }
+
+ if (!m_FilterSeparators) {
+ if (info->hasFlag(ModInfo::FLAG_SEPARATOR)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ModListSortProxy::criteriaMatchMod(
ModInfo::Ptr info, bool enabled, const Criteria& c) const
{
bool b = false;
diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h
index 5aeaccce..9b533492 100644
--- a/src/modlistsortproxy.h
+++ b/src/modlistsortproxy.h
@@ -157,7 +157,8 @@ private:
std::vector<Criteria> m_PreChangeCriteria;
- bool criteriaMatchesMod(ModInfo::Ptr info, bool enabled, const Criteria& c) const;
+ bool optionsMatchMod(ModInfo::Ptr info, bool enabled) const;
+ bool criteriaMatchMod(ModInfo::Ptr info, bool enabled, const Criteria& c) const;
bool categoryMatchesMod(ModInfo::Ptr info, bool enabled, int category) const;
bool contentMatchesMod(ModInfo::Ptr info, bool enabled, int content) const;
};