first attempt at a combobox
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
parent
fea4c4eba8
commit
55946c8923
@ -1035,6 +1035,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/dialogs/InstallLoaderDialog.h
|
||||
|
||||
# GUI - widgets
|
||||
ui/widgets/CheckComboBox.cpp
|
||||
ui/widgets/CheckComboBox.h
|
||||
ui/widgets/Common.cpp
|
||||
ui/widgets/Common.h
|
||||
ui/widgets/CustomCommands.cpp
|
||||
|
205
launcher/ui/widgets/CheckComboBox.cpp
Normal file
205
launcher/ui/widgets/CheckComboBox.cpp
Normal file
@ -0,0 +1,205 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CheckComboBox.h"
|
||||
#include <qboxlayout.h>
|
||||
#include <qcontainerfwd.h>
|
||||
#include <qlistview.h>
|
||||
|
||||
#include <QAbstractItemView>
|
||||
#include <QEvent>
|
||||
#include <QIdentityProxyModel>
|
||||
#include <QKeyEvent>
|
||||
#include <QLineEdit>
|
||||
#include <QStringList>
|
||||
#include "BaseVersionList.h"
|
||||
|
||||
class CheckComboModel : public QIdentityProxyModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CheckComboModel(QObject* parent = nullptr) : QIdentityProxyModel(parent) {}
|
||||
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const { return QIdentityProxyModel::flags(index) | Qt::ItemIsUserCheckable; }
|
||||
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const
|
||||
{
|
||||
if (role == Qt::CheckStateRole) {
|
||||
auto txt = QIdentityProxyModel::data(index, BaseVersionList::VersionIdRole).toString();
|
||||
return checked.contains(txt) ? Qt::Checked : Qt::Unchecked;
|
||||
}
|
||||
if (role == Qt::DisplayRole)
|
||||
return QIdentityProxyModel::data(index, BaseVersionList::VersionIdRole);
|
||||
return {};
|
||||
}
|
||||
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole)
|
||||
{
|
||||
if (role == Qt::CheckStateRole) {
|
||||
auto txt = QIdentityProxyModel::data(index, BaseVersionList::VersionIdRole).toString();
|
||||
if (checked.contains(txt)) {
|
||||
checked.removeOne(txt);
|
||||
} else {
|
||||
checked.push_back(txt);
|
||||
}
|
||||
emit dataChanged(index, index);
|
||||
emit checkStateChanged();
|
||||
return true;
|
||||
}
|
||||
return QIdentityProxyModel::setData(index, value, role);
|
||||
}
|
||||
QStringList getChecked() { return checked; }
|
||||
|
||||
signals:
|
||||
void checkStateChanged();
|
||||
|
||||
private:
|
||||
QStringList checked;
|
||||
};
|
||||
|
||||
CheckComboBox::CheckComboBox(QWidget* parent) : QComboBox(parent), m_separator(",")
|
||||
{
|
||||
// read-only contents
|
||||
// QLineEdit* lineEdit = new QLineEdit(this);
|
||||
// lineEdit->setReadOnly(false);
|
||||
// setLineEdit(lineEdit);
|
||||
// lineEdit->disconnect(this);
|
||||
setInsertPolicy(QComboBox::NoInsert);
|
||||
|
||||
view()->installEventFilter(this);
|
||||
view()->window()->installEventFilter(this);
|
||||
view()->viewport()->installEventFilter(this);
|
||||
this->installEventFilter(this);
|
||||
}
|
||||
|
||||
void CheckComboBox::setModel(QAbstractItemModel* new_model)
|
||||
{
|
||||
auto proxy = new CheckComboModel(this);
|
||||
proxy->setSourceModel(new_model);
|
||||
model()->disconnect(this);
|
||||
QComboBox::setModel(proxy);
|
||||
connect(this, QOverload<int>::of(&QComboBox::activated), this, &CheckComboBox::toggleCheckState);
|
||||
connect(proxy, &CheckComboModel::checkStateChanged, this, &CheckComboBox::updateCheckedItems);
|
||||
connect(model(), &CheckComboModel::rowsInserted, this, &CheckComboBox::updateCheckedItems);
|
||||
connect(model(), &CheckComboModel::rowsRemoved, this, &CheckComboBox::updateCheckedItems);
|
||||
}
|
||||
|
||||
void CheckComboBox::hidePopup()
|
||||
{
|
||||
if (containerMousePress)
|
||||
QComboBox::hidePopup();
|
||||
}
|
||||
|
||||
void CheckComboBox::updateCheckedItems()
|
||||
{
|
||||
QStringList items = checkedItems();
|
||||
if (items.isEmpty())
|
||||
setEditText(defaultText());
|
||||
else
|
||||
setEditText(items.join(separator()));
|
||||
|
||||
emit checkedItemsChanged(items);
|
||||
}
|
||||
|
||||
QString CheckComboBox::defaultText() const
|
||||
{
|
||||
return m_default_text;
|
||||
}
|
||||
|
||||
void CheckComboBox::setDefaultText(const QString& text)
|
||||
{
|
||||
if (m_default_text != text) {
|
||||
m_default_text = text;
|
||||
updateCheckedItems();
|
||||
}
|
||||
}
|
||||
|
||||
QString CheckComboBox::separator() const
|
||||
{
|
||||
return m_separator;
|
||||
}
|
||||
|
||||
void CheckComboBox::setSeparator(const QString& separator)
|
||||
{
|
||||
if (m_separator != separator) {
|
||||
m_separator = separator;
|
||||
updateCheckedItems();
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckComboBox::eventFilter(QObject* receiver, QEvent* event)
|
||||
{
|
||||
switch (event->type()) {
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease: {
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (receiver == this && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) {
|
||||
showPopup();
|
||||
return true;
|
||||
} else if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Escape) {
|
||||
// it is important to call QComboBox implementation
|
||||
QComboBox::hidePopup();
|
||||
return (keyEvent->key() != Qt::Key_Escape);
|
||||
}
|
||||
}
|
||||
case QEvent::MouseButtonPress:
|
||||
containerMousePress = (receiver == view()->window());
|
||||
break;
|
||||
case QEvent::MouseButtonRelease:
|
||||
containerMousePress = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CheckComboBox::toggleCheckState(int index)
|
||||
{
|
||||
QVariant value = itemData(index, Qt::CheckStateRole);
|
||||
if (value.isValid()) {
|
||||
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
|
||||
setItemData(index, (state == Qt::Unchecked ? Qt::Checked : Qt::Unchecked), Qt::CheckStateRole);
|
||||
}
|
||||
updateCheckedItems();
|
||||
}
|
||||
|
||||
Qt::CheckState CheckComboBox::itemCheckState(int index) const
|
||||
{
|
||||
return static_cast<Qt::CheckState>(itemData(index, Qt::CheckStateRole).toInt());
|
||||
}
|
||||
|
||||
void CheckComboBox::setItemCheckState(int index, Qt::CheckState state)
|
||||
{
|
||||
setItemData(index, state, Qt::CheckStateRole);
|
||||
}
|
||||
|
||||
QStringList CheckComboBox::checkedItems() const
|
||||
{
|
||||
if (model())
|
||||
return dynamic_cast<CheckComboModel*>(model())->getChecked();
|
||||
return {};
|
||||
}
|
||||
|
||||
void CheckComboBox::setCheckedItems(const QStringList& items)
|
||||
{
|
||||
foreach (auto text, items) {
|
||||
auto index = findText(text);
|
||||
setItemCheckState(index, index != -1 ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
|
||||
#include "CheckComboBox.moc"
|
61
launcher/ui/widgets/CheckComboBox.h
Normal file
61
launcher/ui/widgets/CheckComboBox.h
Normal file
@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <qlineedit.h>
|
||||
#include <QComboBox>
|
||||
|
||||
class CheckComboBox : public QComboBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CheckComboBox(QWidget* parent = nullptr);
|
||||
virtual ~CheckComboBox() = default;
|
||||
|
||||
virtual void hidePopup() override;
|
||||
|
||||
QString defaultText() const;
|
||||
void setDefaultText(const QString& text);
|
||||
|
||||
Qt::CheckState itemCheckState(int index) const;
|
||||
void setItemCheckState(int index, Qt::CheckState state);
|
||||
|
||||
QString separator() const;
|
||||
void setSeparator(const QString& separator);
|
||||
|
||||
QStringList checkedItems() const;
|
||||
|
||||
virtual void setModel(QAbstractItemModel* model) override;
|
||||
|
||||
public slots:
|
||||
void setCheckedItems(const QStringList& items);
|
||||
|
||||
signals:
|
||||
void checkedItemsChanged(const QStringList& items);
|
||||
|
||||
private:
|
||||
void updateCheckedItems();
|
||||
bool eventFilter(QObject* receiver, QEvent* event) override;
|
||||
void toggleCheckState(int index);
|
||||
|
||||
private:
|
||||
QString m_default_text;
|
||||
QString m_separator;
|
||||
bool containerMousePress;
|
||||
};
|
@ -105,8 +105,7 @@ void ModFilterWidget::prepareBasicFilter()
|
||||
m_filter->loaders = loaders;
|
||||
auto def = m_instance->getPackProfile()->getComponentVersion("net.minecraft");
|
||||
m_filter->versions.push_front(Version{ def });
|
||||
m_versions_proxy->setCurrentVersion(def);
|
||||
ui->versionsCb->setCurrentIndex(m_versions_proxy->getVersion(def).row());
|
||||
ui->versionsCb->setCheckedItems({ def });
|
||||
}
|
||||
|
||||
void ModFilterWidget::onIncludeSnapshotsChanged()
|
||||
@ -119,9 +118,10 @@ void ModFilterWidget::onIncludeSnapshotsChanged()
|
||||
|
||||
void ModFilterWidget::onVersionFilterChanged()
|
||||
{
|
||||
auto version = ui->versionsCb->currentData(BaseVersionList::VersionIdRole).toString();
|
||||
auto versions = ui->versionsCb->checkedItems();
|
||||
m_filter->versions.clear();
|
||||
m_filter->versions.push_front(version);
|
||||
for (auto version : versions)
|
||||
m_filter->versions.push_back(version);
|
||||
m_filter_changed = true;
|
||||
emit filterChanged();
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QComboBox" name="versionsCb">
|
||||
<widget class="CheckComboBox" name="versionsCb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@ -157,6 +157,13 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CheckComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>ui/widgets/CheckComboBox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
Loading…
Reference in New Issue
Block a user