From 729ebffa12336a99af9eac6572742771c4f961ce Mon Sep 17 00:00:00 2001 From: Reinder Feenstra Date: Mon, 24 Mar 2025 22:41:29 +0100 Subject: [PATCH] Restyled load world dialog and added search bar --- client/src/dialog/worldlistdialog.cpp | 92 +++++++++++++++++++++++---- client/src/dialog/worldlistdialog.hpp | 10 ++- shared/translations/en-us.json | 4 ++ 3 files changed, 91 insertions(+), 15 deletions(-) diff --git a/client/src/dialog/worldlistdialog.cpp b/client/src/dialog/worldlistdialog.cpp index b1626482..b3f7b452 100644 --- a/client/src/dialog/worldlistdialog.cpp +++ b/client/src/dialog/worldlistdialog.cpp @@ -3,7 +3,7 @@ * * This file is part of the traintastic source code. * - * Copyright (C) 2019-2020,2023 Reinder Feenstra + * Copyright (C) 2019-2020,2023,2025 Reinder Feenstra * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,8 +25,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include -#include "../widget/tablewidget.hpp" #include "../network/connection.hpp" #include "../network/object.hpp" #include "../network/tablemodel.hpp" @@ -35,14 +40,70 @@ #include "../widget/alertwidget.hpp" #include +constexpr int columnUUID = 1; + +class WorldListItemDelegate : public QItemDelegate +{ +public: + inline WorldListItemDelegate(QListView* parent) + : QItemDelegate(parent) + { + } + + inline void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const final + { + static const QSize iconSize{40, 40}; + + auto* model = qobject_cast(parent())->model(); + const auto name = model->data(model->index(index.row(), 0)).toString(); + const auto uuid = model->data(model->index(index.row(), 1)).toString(); + + const auto r = option.rect.adjusted(5, 5, -5, -5); + const int iconOffset = (r.height() - iconSize.height()) / 2; + + const auto palette = QApplication::palette(); + + if((option.state & QStyle::State_Selected) != 0) + { + painter->fillRect(option.rect, palette.brush(QPalette::Highlight)); + } + + QTextOption textOption; + textOption.setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + + const auto classIcon = Theme::getIcon("world"); + painter->drawPixmap(r.topLeft() + QPoint(iconOffset, iconOffset), classIcon.pixmap(iconSize)); + + painter->setPen(palette.color(QPalette::Disabled, QPalette::Text)); + painter->drawText(r.adjusted(r.height() + 10, r.height() / 2, 0, 0), uuid, textOption); + + painter->setPen(palette.color(QPalette::Active, QPalette::Text)); + painter->drawText(r.adjusted(r.height() + 10, 0, 0, -r.height() / 2), name, textOption); + + painter->setPen(QColor(0x80, 0x80, 0x80, 0x30)); + painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight()); + } + + inline QSize sizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const final + { + return QSize(-1, 50); + } +}; + WorldListDialog::WorldListDialog(std::shared_ptr connection, QWidget* parent) : QDialog(parent, Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), m_connection{std::move(connection)}, m_buttons{new QDialogButtonBox(this)}, - m_tableWidget{new TableWidget()} + m_search{new QLineEdit(this)}, + m_list{new QListView(this)} { setWindowTitle(Locale::tr("qtapp.world_list_dialog:world_list")); setWindowIcon(Theme::getIcon("world_load")); + resize(500, 400); + + m_search->setPlaceholderText(Locale::tr("qtapp.world_list_dialog:search")); + + m_list->setItemDelegate(new WorldListItemDelegate(m_list)); m_buttons->setStandardButtons(QDialogButtonBox::Open | QDialogButtonBox::Cancel); m_buttons->button(QDialogButtonBox::Open)->setText(Locale::tr("qtapp.world_list_dialog:load")); @@ -50,14 +111,15 @@ WorldListDialog::WorldListDialog(std::shared_ptr connection, QWidget connect(m_buttons->button(QDialogButtonBox::Open), &QPushButton::clicked, this, [this]() { - m_uuid = m_tableWidget->getRowObjectId(m_tableWidget->selectionModel()->selectedIndexes().first().row()); + m_uuid = m_list->model()->data(m_list->model()->index(m_list->selectionModel()->selectedIndexes().first().row(), columnUUID)).toString(); accept(); }); m_buttons->button(QDialogButtonBox::Cancel)->setText(Locale::tr("qtapp.world_list_dialog:cancel")); connect(m_buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &WorldListDialog::reject); QVBoxLayout* layout = new QVBoxLayout(); - layout->addWidget(m_tableWidget); + layout->addWidget(m_search); + layout->addWidget(m_list); layout->addWidget(m_buttons); setLayout(layout); @@ -78,20 +140,26 @@ WorldListDialog::WorldListDialog(std::shared_ptr connection, QWidget { m_requestId = Connection::invalidRequestId; - m_tableWidget->setTableModel(tableModel); - m_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); - connect(m_tableWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, + m_tableModel = tableModel; + m_tableModel->setRegionAll(true); + auto* filter = new QSortFilterProxyModel(this); + filter->setSourceModel(m_tableModel.get()); + filter->setFilterCaseSensitivity(Qt::CaseInsensitive); + connect(m_search, &QLineEdit::textChanged, filter, &QSortFilterProxyModel::setFilterFixedString); + filter->setFilterFixedString(m_search->text()); + m_list->setModel(filter); + m_list->setSelectionBehavior(QAbstractItemView::SelectRows); + connect(m_list->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this](const QItemSelection&, const QItemSelection&) { - m_buttons->button(QDialogButtonBox::Open)->setEnabled(m_tableWidget->selectionModel()->selectedRows().count() == 1); + m_buttons->button(QDialogButtonBox::Open)->setEnabled(m_list->selectionModel()->selectedRows().count() == 1); }); - connect(m_tableWidget, &TableWidget::doubleClicked, this, + connect(m_list, &QListView::doubleClicked, this, [this](const QModelIndex& index) { - m_uuid = m_tableWidget->getRowObjectId(index.row()); + m_uuid = m_list->model()->data(m_list->model()->index(index.row(), columnUUID)).toString(); accept(); }); - delete spinner; } else if(err) diff --git a/client/src/dialog/worldlistdialog.hpp b/client/src/dialog/worldlistdialog.hpp index 5f0798b5..fc3257e2 100644 --- a/client/src/dialog/worldlistdialog.hpp +++ b/client/src/dialog/worldlistdialog.hpp @@ -3,7 +3,7 @@ * * This file is part of the traintastic source code. * - * Copyright (C) 2019-2020 Reinder Feenstra + * Copyright (C) 2019-2020,2025 Reinder Feenstra * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,9 +25,11 @@ #include #include "../network/objectptr.hpp" +#include "../network/tablemodelptr.hpp" class QDialogButtonBox; -class TableWidget; +class QLineEdit; +class QListView; class Connection; class WorldListDialog final : public QDialog @@ -39,8 +41,10 @@ class WorldListDialog final : public QDialog int m_requestId; ObjectPtr m_object; QDialogButtonBox* m_buttons; // TODO: m_buttonLoad; - TableWidget* m_tableWidget; + QLineEdit* m_search; + QListView* m_list; QString m_uuid; + TableModelPtr m_tableModel; public: explicit WorldListDialog(std::shared_ptr connection, QWidget* parent = nullptr); diff --git a/shared/translations/en-us.json b/shared/translations/en-us.json index cf3730f9..f0441931 100644 --- a/shared/translations/en-us.json +++ b/shared/translations/en-us.json @@ -6733,5 +6733,9 @@ { "term": "interface_list:create", "definition": "Create a new interface." + }, + { + "term": "qtapp.world_list_dialog:search", + "definition": "Search" } ]