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
|
ui/dialogs/InstallLoaderDialog.h
|
||||||
|
|
||||||
# GUI - widgets
|
# GUI - widgets
|
||||||
|
ui/widgets/CheckComboBox.cpp
|
||||||
|
ui/widgets/CheckComboBox.h
|
||||||
ui/widgets/Common.cpp
|
ui/widgets/Common.cpp
|
||||||
ui/widgets/Common.h
|
ui/widgets/Common.h
|
||||||
ui/widgets/CustomCommands.cpp
|
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;
|
m_filter->loaders = loaders;
|
||||||
auto def = m_instance->getPackProfile()->getComponentVersion("net.minecraft");
|
auto def = m_instance->getPackProfile()->getComponentVersion("net.minecraft");
|
||||||
m_filter->versions.push_front(Version{ def });
|
m_filter->versions.push_front(Version{ def });
|
||||||
m_versions_proxy->setCurrentVersion(def);
|
ui->versionsCb->setCheckedItems({ def });
|
||||||
ui->versionsCb->setCurrentIndex(m_versions_proxy->getVersion(def).row());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModFilterWidget::onIncludeSnapshotsChanged()
|
void ModFilterWidget::onIncludeSnapshotsChanged()
|
||||||
@ -119,9 +118,10 @@ void ModFilterWidget::onIncludeSnapshotsChanged()
|
|||||||
|
|
||||||
void ModFilterWidget::onVersionFilterChanged()
|
void ModFilterWidget::onVersionFilterChanged()
|
||||||
{
|
{
|
||||||
auto version = ui->versionsCb->currentData(BaseVersionList::VersionIdRole).toString();
|
auto versions = ui->versionsCb->checkedItems();
|
||||||
m_filter->versions.clear();
|
m_filter->versions.clear();
|
||||||
m_filter->versions.push_front(version);
|
for (auto version : versions)
|
||||||
|
m_filter->versions.push_back(version);
|
||||||
m_filter_changed = true;
|
m_filter_changed = true;
|
||||||
emit filterChanged();
|
emit filterChanged();
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QComboBox" name="versionsCb">
|
<widget class="CheckComboBox" name="versionsCb">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@ -157,6 +157,13 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>CheckComboBox</class>
|
||||||
|
<extends>QComboBox</extends>
|
||||||
|
<header>ui/widgets/CheckComboBox.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
Loading…
Reference in New Issue
Block a user