cleaned up and improved GameOptions Model & Page
- added array support - cleaned up logic - ran clang-format - added description & default value columns - added basic editing support (bools only) - no saving Co-authored-by: TheLastRar <TheLastRar@users.noreply.github.com> Signed-off-by: Tayou <tayou@gmx.net>
This commit is contained in:
parent
564567a568
commit
511076d3ba
@ -1,8 +1,51 @@
|
|||||||
#include "GameOptions.h"
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2023 Tayou <tayou@gmx.net>
|
||||||
|
* Copyright (C) 2023 TheLastRar <TheLastRar@users.noreply.github.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/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
|
#include "FileSystem.h"
|
||||||
|
#include "GameOptions.h"
|
||||||
|
|
||||||
|
static Qt::CheckState boolToState(bool b)
|
||||||
|
{
|
||||||
|
return b ? Qt::Checked : Qt::Unchecked;
|
||||||
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool load(const QString& path, std::vector<GameOptionItem>& contents, int& version)
|
bool load(const QString& path, std::vector<GameOptionItem>& contents, int& version)
|
||||||
{
|
{
|
||||||
@ -12,24 +55,54 @@ bool load(const QString& path, std::vector<GameOptionItem>& contents, int& versi
|
|||||||
qWarning() << "Failed to read options file.";
|
qWarning() << "Failed to read options file.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
version = 0;
|
version = 0;
|
||||||
while (!file.atEnd()) {
|
while (!file.atEnd()) {
|
||||||
auto line = file.readLine();
|
// This should be handled by toml++ or some other toml parser rather than this manual parsing
|
||||||
|
QString line = QString::fromUtf8(file.readLine());
|
||||||
if (line.endsWith('\n')) {
|
if (line.endsWith('\n')) {
|
||||||
line.chop(1);
|
line.chop(1);
|
||||||
}
|
}
|
||||||
auto separatorIndex = line.indexOf(':');
|
if (line.endsWith('\r')) {
|
||||||
if (separatorIndex == -1) {
|
line.chop(1);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
auto key = QString::fromUtf8(line.data(), separatorIndex);
|
GameOptionItem item = GameOptionItem();
|
||||||
auto value = QString::fromUtf8(line.data() + separatorIndex + 1, line.size() - 1 - separatorIndex);
|
|
||||||
qDebug() << "!!" << key << "!!";
|
auto parts = line.split(':');
|
||||||
if (key == "version") {
|
|
||||||
version = value.toInt();
|
item.key = parts[0];
|
||||||
|
item.value = parts[1];
|
||||||
|
item.type = OptionType::String;
|
||||||
|
qDebug() << "Reading Game Options Key:" << item.key;
|
||||||
|
|
||||||
|
if (item.key == "version") {
|
||||||
|
version = item.value.toInt();
|
||||||
continue;
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isInt = false;
|
||||||
|
bool isFloat = false;
|
||||||
|
item.intValue = item.value.toInt(&isInt);
|
||||||
|
item.floatValue = item.value.toFloat(&isFloat);
|
||||||
|
if (isInt) {
|
||||||
|
item.type = OptionType::Int;
|
||||||
|
// qDebug() << "The value" << value << "is a int";
|
||||||
|
} else if (isFloat) {
|
||||||
|
item.type = OptionType::Float;
|
||||||
|
// qDebug() << "The value" << value << "is a float";
|
||||||
|
} else if (item.value == "true" || item.value == "false") {
|
||||||
|
item.boolValue = item.value == "true" ? true : false;
|
||||||
|
item.type = OptionType::Bool;
|
||||||
|
qDebug() << "The value" << item.value << "is a bool";
|
||||||
|
} else if (item.value.endsWith("]") && item.value.startsWith("[")) {
|
||||||
|
qDebug() << "The value" << item.value << "is an array";
|
||||||
|
for (QString part : item.value.mid(1, item.value.size() - 2).split(",")) {
|
||||||
|
GameOptionChildItem child{ part, static_cast<int>(contents.size()) };
|
||||||
|
qDebug() << "Array has entry" << part;
|
||||||
|
item.children.append(child);
|
||||||
}
|
}
|
||||||
contents.emplace_back(GameOptionItem{ key, value });
|
}
|
||||||
|
contents.emplace_back(item);
|
||||||
}
|
}
|
||||||
qDebug() << "Loaded" << path << "with version:" << version;
|
qDebug() << "Loaded" << path << "with version:" << version;
|
||||||
return true;
|
return true;
|
||||||
@ -64,17 +137,76 @@ GameOptions::GameOptions(const QString& path) : path(path)
|
|||||||
QVariant GameOptions::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant GameOptions::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if (role != Qt::DisplayRole) {
|
if (role != Qt::DisplayRole) {
|
||||||
return QAbstractListModel::headerData(section, orientation, role);
|
return QAbstractItemModel::headerData(section, orientation, role);
|
||||||
}
|
}
|
||||||
switch (section) {
|
switch (section) {
|
||||||
case 0:
|
case 0:
|
||||||
return tr("Key");
|
return tr("Key");
|
||||||
case 1:
|
case 1:
|
||||||
|
return tr("Description");
|
||||||
|
case 2:
|
||||||
return tr("Value");
|
return tr("Value");
|
||||||
|
case 3:
|
||||||
|
return tr("Default Value");
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool GameOptions::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||||
|
{
|
||||||
|
auto row = index.row();
|
||||||
|
auto column = (Column)index.column();
|
||||||
|
if (column == Column::Value) {
|
||||||
|
switch (contents[row].type) {
|
||||||
|
case OptionType::String: {
|
||||||
|
contents[row].value = value.toString();
|
||||||
|
}
|
||||||
|
case OptionType::Int: {
|
||||||
|
contents[row].intValue = value.toInt();
|
||||||
|
}
|
||||||
|
case OptionType::Bool: {
|
||||||
|
contents[row].boolValue = value.toBool();
|
||||||
|
}
|
||||||
|
case OptionType::Float: {
|
||||||
|
contents[row].floatValue = value.toFloat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags GameOptions::flags(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
|
||||||
|
|
||||||
|
if (!index.isValid())
|
||||||
|
return flags;
|
||||||
|
|
||||||
|
Column column = (Column)index.column();
|
||||||
|
|
||||||
|
if (column == Column::Key) {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index.parent().isValid()) {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contents[index.row()].children.count() > 0) {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = flags | Qt::ItemFlag::ItemIsEditable;
|
||||||
|
if (column == Column::Value || column == Column::DefaultValue) {
|
||||||
|
flags = flags | Qt::ItemFlag::ItemIsUserCheckable;
|
||||||
|
}
|
||||||
|
if (column == Column::DefaultValue) {
|
||||||
|
flags = flags & ~Qt::ItemFlag::ItemIsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant GameOptions::data(const QModelIndex& index, int role) const
|
QVariant GameOptions::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
@ -82,32 +214,171 @@ QVariant GameOptions::data(const QModelIndex& index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
int column = index.column();
|
Column column = (Column)index.column();
|
||||||
|
|
||||||
if (row < 0 || row >= int(contents.size()))
|
if (row < 0 || row >= int(contents.size()))
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
|
if (index.parent().isValid()) {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole: {
|
||||||
if (column == 0) {
|
if (column == Column::Value) {
|
||||||
return contents[row].key;
|
GameOptionChildItem* item = static_cast<GameOptionChildItem*>(index.internalPointer());
|
||||||
|
return item->value;
|
||||||
} else {
|
} else {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole: {
|
||||||
|
switch (column) {
|
||||||
|
case Column::Key: {
|
||||||
|
return contents[row].key;
|
||||||
|
}
|
||||||
|
case Column::Description: {
|
||||||
|
return "Description goes here!";
|
||||||
|
}
|
||||||
|
case Column::Value: {
|
||||||
|
switch (contents[row].type) {
|
||||||
|
case OptionType::String: {
|
||||||
return contents[row].value;
|
return contents[row].value;
|
||||||
}
|
}
|
||||||
default:
|
case OptionType::Int: {
|
||||||
|
return contents[row].intValue;
|
||||||
|
}
|
||||||
|
case OptionType::Bool: {
|
||||||
|
return contents[row].boolValue;
|
||||||
|
}
|
||||||
|
case OptionType::Float: {
|
||||||
|
return contents[row].floatValue;
|
||||||
|
}
|
||||||
|
case OptionType::KeyBind: {
|
||||||
|
return contents[row].value;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Column::DefaultValue: {
|
||||||
|
switch (contents[row].type) {
|
||||||
|
case OptionType::String: {
|
||||||
|
return contents[row].value;
|
||||||
|
}
|
||||||
|
case OptionType::Int: {
|
||||||
|
return contents[row].intValue;
|
||||||
|
}
|
||||||
|
case OptionType::Bool: {
|
||||||
|
return contents[row].boolValue;
|
||||||
|
}
|
||||||
|
case OptionType::Float: {
|
||||||
|
return contents[row].floatValue;
|
||||||
|
}
|
||||||
|
case OptionType::KeyBind: {
|
||||||
|
return contents[row].value;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Qt::CheckStateRole: {
|
||||||
|
switch (column) {
|
||||||
|
case Column::Value: {
|
||||||
|
if (contents[row].type == OptionType::Bool) {
|
||||||
|
return boolToState(contents[row].boolValue);
|
||||||
|
} else {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Column::DefaultValue: {
|
||||||
|
return boolToState(contents[row].boolValue);
|
||||||
|
} else {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
int GameOptions::rowCount(const QModelIndex&) const
|
QModelIndex GameOptions::index(int row, int column, const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
return contents.size();
|
if (!hasIndex(row, column, parent))
|
||||||
|
return QModelIndex();
|
||||||
|
|
||||||
|
if (parent.isValid()) {
|
||||||
|
if (parent.parent().isValid())
|
||||||
|
return QModelIndex();
|
||||||
|
|
||||||
|
GameOptionItem* item = static_cast<GameOptionItem*>(parent.internalPointer());
|
||||||
|
return createIndex(row, column, &item->children[row]);
|
||||||
|
} else {
|
||||||
|
return createIndex(row, column, &contents[row]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GameOptions::columnCount(const QModelIndex&) const
|
QModelIndex GameOptions::parent(const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
return 2;
|
if (!index.isValid())
|
||||||
|
return QModelIndex();
|
||||||
|
|
||||||
|
const void* childItem = index.internalPointer();
|
||||||
|
|
||||||
|
// Determine where childItem points to
|
||||||
|
if (childItem >= &contents[0] && childItem <= &contents.back()) {
|
||||||
|
// Parent is root/contents
|
||||||
|
return QModelIndex();
|
||||||
|
} else {
|
||||||
|
GameOptionChildItem* child = static_cast<GameOptionChildItem*>(index.internalPointer());
|
||||||
|
return createIndex(child->parentRow, 0, &contents[child->parentRow]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GameOptions::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (!parent.isValid()) {
|
||||||
|
return static_cast<int>(contents.size());
|
||||||
|
} else {
|
||||||
|
if (parent.column() > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Our tree model is only one layer deep
|
||||||
|
// If we have parent, we can't go deeper
|
||||||
|
if (parent.parent().isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
GameOptionItem* item = static_cast<GameOptionItem*>(parent.internalPointer());
|
||||||
|
return item->children.count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GameOptions::columnCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
// Our tree model is only one layer deep
|
||||||
|
// If we have parent, we can't go deeper
|
||||||
|
if (parent.parent().isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameOptions::isLoaded() const
|
bool GameOptions::isLoaded() const
|
||||||
|
@ -1,24 +1,77 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2023 Tayou <tayou@gmx.net>
|
||||||
|
* Copyright (C) 2023 TheLastRar <TheLastRar@users.noreply.github.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/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
struct GameOptionItem {
|
enum class OptionType { String, Int, Float, Bool, KeyBind };
|
||||||
QString key;
|
|
||||||
|
struct GameOptionChildItem {
|
||||||
QString value;
|
QString value;
|
||||||
|
int parentRow;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GameOptions : public QAbstractListModel {
|
struct GameOptionItem {
|
||||||
|
QString key;
|
||||||
|
bool boolValue;
|
||||||
|
int intValue;
|
||||||
|
float floatValue;
|
||||||
|
QString value;
|
||||||
|
OptionType type;
|
||||||
|
QList<GameOptionChildItem> children;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GameOptions : public QAbstractItemModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
enum class Column { Key, Description, Value, DefaultValue };
|
||||||
explicit GameOptions(const QString& path);
|
explicit GameOptions(const QString& path);
|
||||||
virtual ~GameOptions() = default;
|
virtual ~GameOptions() = default;
|
||||||
|
|
||||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex& parent) const override;
|
int columnCount(const QModelIndex& parent) const override;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
|
||||||
|
QModelIndex parent(const QModelIndex& index) const override;
|
||||||
|
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
|
||||||
|
|
||||||
bool isLoaded() const;
|
bool isLoaded() const;
|
||||||
bool reload();
|
bool reload();
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
|
* Copyright (C) 2023 Tayou <tayou@gmx.net>
|
||||||
|
* Copyright (C) 2023 TheLastRar <TheLastRar@users.noreply.github.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -45,12 +47,14 @@ GameOptionsPage::GameOptionsPage(MinecraftInstance* inst, QWidget* parent) : QWi
|
|||||||
m_model = inst->gameOptionsModel();
|
m_model = inst->gameOptionsModel();
|
||||||
ui->optionsView->setModel(m_model.get());
|
ui->optionsView->setModel(m_model.get());
|
||||||
auto head = ui->optionsView->header();
|
auto head = ui->optionsView->header();
|
||||||
|
head->setDefaultSectionSize(250);
|
||||||
if (head->count()) {
|
if (head->count()) {
|
||||||
head->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
|
||||||
for (int i = 1; i < head->count(); i++) {
|
for (int i = 1; i < head->count(); i++) {
|
||||||
head->setSectionResizeMode(i, QHeaderView::Stretch);
|
head->setSectionResizeMode(i, QHeaderView::Stretch);
|
||||||
}
|
}
|
||||||
|
head->setSectionResizeMode(head->count() -1, QHeaderView::Stretch);
|
||||||
}
|
}
|
||||||
|
connect(ui->optionsView, &QTreeView::doubleClicked, this, &GameOptionsPage::OptionDoubleClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameOptionsPage::~GameOptionsPage()
|
GameOptionsPage::~GameOptionsPage()
|
||||||
@ -72,3 +76,21 @@ void GameOptionsPage::retranslate()
|
|||||||
{
|
{
|
||||||
ui->retranslateUi(this);
|
ui->retranslateUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QTreeView's double click checks if the cell clicked on has children
|
||||||
|
// but a typical tree model would only have children in the first column
|
||||||
|
// Workaround this by calling expand ourself
|
||||||
|
void GameOptionsPage::OptionDoubleClicked(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if (!index.isValid() || index.column() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QModelIndex firstColumn = ui->optionsView->model()->index(index.row(), 0, index.parent());
|
||||||
|
if (!ui->optionsView->model()->hasChildren(firstColumn))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ui->optionsView->isExpanded(firstColumn))
|
||||||
|
ui->optionsView->collapse(firstColumn);
|
||||||
|
else
|
||||||
|
ui->optionsView->expand(firstColumn);
|
||||||
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
|
* Copyright (C) 2023 Tayou <tayou@gmx.net>
|
||||||
|
* Copyright (C) 2023 TheLastRar <TheLastRar@users.noreply.github.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -67,4 +69,7 @@ class GameOptionsPage : public QWidget, public BasePage {
|
|||||||
private: // data
|
private: // data
|
||||||
Ui::GameOptionsPage* ui = nullptr;
|
Ui::GameOptionsPage* ui = nullptr;
|
||||||
std::shared_ptr<GameOptions> m_model;
|
std::shared_ptr<GameOptions> m_model;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void OptionDoubleClicked(const QModelIndex& index);
|
||||||
};
|
};
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="rootIsDecorated">
|
<property name="rootIsDecorated">
|
||||||
<bool>false</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="headerStretchLastSection">
|
<attribute name="headerStretchLastSection">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user