Added Edit Delegate

Signed-off-by: Tayou <tayou@gmx.net>
This commit is contained in:
Tayou
2023-02-27 23:33:59 +01:00
committed by Tayou
parent a84036a7a3
commit 81435ee082
6 changed files with 255 additions and 3 deletions

View File

@ -248,6 +248,8 @@ set(MINECRAFT_SOURCES
minecraft/gameoptions/GameOptions.cpp
minecraft/gameoptions/GameOptionsSchema.h
minecraft/gameoptions/GameOptionsSchema.cpp
minecraft/gameoptions/GameOptionDelegate.h
minecraft/gameoptions/GameOptionDelegate.cpp
minecraft/update/AssetUpdateTask.h
minecraft/update/AssetUpdateTask.cpp

View File

@ -0,0 +1,199 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2023 Tayou <tayou@gmx.net>
*
* 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 "GameOptionDelegate.h"
#include <QComboBox>
#include <QLineEdit>
#include <QCheckBox>
#include <QPushButton>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QSlider>
#include <QKeySequenceEdit>
QWidget* GameOptionDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
std::shared_ptr<GameOption> knownOption = contents->at(index.row()).knownOption;
switch (contents->at(index.row()).type) {
case OptionType::String: {
if (knownOption != nullptr && !knownOption->validValues.isEmpty()) {
QComboBox* comboBox = new QComboBox(parent);
for (auto value : knownOption->validValues) {
comboBox->addItem(value);
}
comboBox->setGeometry(option.rect);
return comboBox;
} else {
QLineEdit* textField = new QLineEdit(parent);
textField->setGeometry(option.rect);
return textField;
}
}
case OptionType::Int: {
if (knownOption != nullptr && (knownOption->getIntRange().max != 0 || knownOption->getIntRange().min != 0)) {
QSlider* slider = new QSlider(parent);
slider->setMinimum(knownOption->getIntRange().min);
slider->setMaximum(knownOption->getIntRange().max);
slider->setOrientation(Qt::Horizontal);
slider->setGeometry(option.rect);
return slider;
} else {
QSpinBox* intInput = new QSpinBox(parent);
intInput->setGeometry(option.rect);
return intInput;
}
}
case OptionType::Bool: {
QCheckBox* checkBox = new QCheckBox(parent);
checkBox->setGeometry(option.rect);
return checkBox;
}
case OptionType::Float: {
if (knownOption != nullptr && (knownOption->getFloatRange().max != 0 || knownOption->getFloatRange().min != 0)) {
QSlider* slider = new QSlider(parent);
slider->setMinimum(knownOption->getFloatRange().min*100);
slider->setMaximum(knownOption->getFloatRange().max*100);
slider->setOrientation(Qt::Horizontal);
slider->setGeometry(option.rect);
return slider;
} else {
QDoubleSpinBox* floatInput = new QDoubleSpinBox(parent);
floatInput->setGeometry(option.rect);
return floatInput;
}
}
case OptionType::KeyBind: {
QKeySequenceEdit* keySequenceEdit = new QKeySequenceEdit(parent);
keySequenceEdit->setGeometry(option.rect);
return keySequenceEdit;
}
default:
break;
}
};
void GameOptionDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
std::shared_ptr<GameOption> knownOption = contents->at(index.row()).knownOption;
switch (contents->at(index.row()).type) {
case OptionType::String: {
QComboBox* comboBox;
if ((comboBox = dynamic_cast<QComboBox*>(editor)) != nullptr) {
comboBox->setCurrentIndex(comboBox->findText(contents->at(index.row()).value));
} else {
((QLineEdit*)editor)->setText(contents->at(index.row()).value);
}
return;
}
case OptionType::Int: {
QSlider* slider;
if ((slider = dynamic_cast<QSlider*>(editor)) != nullptr) {
slider->setValue(contents->at(index.row()).intValue);
} else {
((QSpinBox*)editor)->setValue(contents->at(index.row()).intValue);
}
return;
}
case OptionType::Bool: {
((QCheckBox*)editor)->setText(contents->at(index.row()).value);
((QCheckBox*)editor)->setChecked(contents->at(index.row()).boolValue);
return;
}
case OptionType::Float: {
QSlider* slider;
if ((slider = dynamic_cast<QSlider*>(editor)) != nullptr) {
slider->setValue(contents->at(index.row()).floatValue*100);
} else {
((QDoubleSpinBox*)editor)->setValue(contents->at(index.row()).floatValue);
}
return;
}
case OptionType::KeyBind: {
// TODO: fall back to QLineEdit if keybind can't be represented, like some mods do (by using another key input API)
// TODO: mouse binding? If not possible, fall back as well maybe?
Qt::Key key;
for (auto& keyBinding : *keybindingOptions) {
// this could become a std::find_if eventually, if someone wants to bother making it that.
if (keyBinding->minecraftKeyCode == contents->at(index.row()).value) {
key = keyBinding->qtKeyCode.keyboardKey;
}
}
((QKeySequenceEdit*)editor)->setKeySequence(QKeySequence(key));
return;
}
default:
return;
}
};
void GameOptionDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const {
editor->setGeometry(option.rect);
};
void GameOptionDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const {
std::shared_ptr<GameOption> knownOption = contents->at(index.row()).knownOption;
switch (contents->at(index.row()).type) {
case OptionType::String: {
QComboBox* comboBox;
if ((comboBox = dynamic_cast<QComboBox*>(editor)) != nullptr) {
contents->at(index.row()).value = comboBox->currentText();
} else {
contents->at(index.row()).value = ((QLineEdit*)editor)->text();
}
return;
}
case OptionType::Int: {
QSlider* slider;
if ((slider = dynamic_cast<QSlider*>(editor)) != nullptr) {
contents->at(index.row()).intValue = slider->value();
} else {
contents->at(index.row()).intValue = ((QSpinBox*)editor)->value();
}
return;
}
case OptionType::Bool: {
((QCheckBox*)editor)->setText(contents->at(index.row()).value);
contents->at(index.row()).boolValue = ((QCheckBox*)editor)->isChecked();
return;
}
case OptionType::Float: {
QSlider* slider;
if ((slider = dynamic_cast<QSlider*>(editor)) != nullptr) {
contents->at(index.row()).floatValue = slider->value()/100.0f;
} else {
contents->at(index.row()).floatValue = ((QDoubleSpinBox*)editor)->value();
}
return;
}
case OptionType::KeyBind: {
QKeySequenceEdit* keySequenceEdit = (QKeySequenceEdit*)editor;
QString minecraftKeyCode;
for (auto& keyBinding : *keybindingOptions) {
// this could become a std::find_if eventually, if someone wants to bother making it that.
if (keyBinding->qtKeyCode.keyboardKey == keySequenceEdit->keySequence()[0].key() ||
keyBinding->qtKeyCode.mouseButton == keySequenceEdit->keySequence()[0].key()) {
minecraftKeyCode = keyBinding->minecraftKeyCode;
}
}
contents->at(index.row()).value = minecraftKeyCode;
return;
}
default:
return;
}
};

View File

@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2023 Tayou <tayou@gmx.net>
*
* 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 <QStyledItemDelegate>
#include <QString>
#include <QWidget>
#include "GameOptions.h"
class GameOptionDelegate : public QStyledItemDelegate {
public:
GameOptionDelegate(QObject* parent, std::vector<GameOptionItem>* contents) : contents(contents), QStyledItemDelegate(parent)
{
keybindingOptions = GameOptionsSchema::getKeyBindOptions();
};
QWidget* createEditor(QWidget* parent,
const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
void updateEditorGeometry(QWidget* editor,
const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override;
private:
std::vector<GameOptionItem>* contents;
QList<std::shared_ptr<KeyBindData>>* keybindingOptions;
};

View File

@ -110,6 +110,9 @@ bool load(const QString& path,
}
} else if (item.key.startsWith("key_")) {
item.type = OptionType::KeyBind;
} else {
// this is really ugly, please suggest how to truncate the start and end
item.value = item.value.remove(item.value.length()-1, 1).remove(0, 1);
}
// adds reference to known option from gameOptionsSchema if avaiable to get display name and other metadata
@ -210,9 +213,9 @@ Qt::ItemFlags GameOptions::flags(const QModelIndex& index) const
}
flags = flags | Qt::ItemFlag::ItemIsEditable;
if (column == Column::Value || column == Column::DefaultValue) {
/*if (column == Column::Value || column == Column::DefaultValue) {
flags = flags | Qt::ItemFlag::ItemIsUserCheckable;
}
}*/
if (column == Column::DefaultValue) {
flags = flags & ~Qt::ItemFlag::ItemIsEnabled;
}

View File

@ -78,6 +78,8 @@ class GameOptions : public QAbstractItemModel {
bool reload();
bool save();
std::vector<GameOptionItem>* getContents(){ return &contents; };
private:
std::vector<GameOptionItem> contents;
bool loaded = false;

View File

@ -38,7 +38,7 @@
#include "GameOptionsPage.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/gameoptions/GameOptions.h"
#include "ui_GameOptionsPage.h"
#include "minecraft/gameoptions/GameOptionDelegate.h"
GameOptionsPage::GameOptionsPage(MinecraftInstance* inst, QWidget* parent) : QWidget(parent), ui(new Ui::GameOptionsPage)
{
@ -46,6 +46,8 @@ GameOptionsPage::GameOptionsPage(MinecraftInstance* inst, QWidget* parent) : QWi
ui->tabWidget->tabBar()->hide();
m_model = inst->gameOptionsModel();
ui->optionsView->setModel(m_model.get());
ui->optionsView->setItemDelegateForColumn(2, new GameOptionDelegate(ui->optionsView, m_model->getContents()));
ui->optionsView->setEditTriggers(QAbstractItemView::AllEditTriggers);
auto head = ui->optionsView->header();
head->setDefaultSectionSize(250);
if (head->count()) {