Mercurial > minori
view src/gui/dialog/information.cc @ 187:9613d72b097e
*: multiple performance improvements
like marking `static const` when it makes sense...
date: change old stupid heap-based method to a structure which should
make copying the thing actually make a copy.
also many performance-based changes, like removing the std::tie
dependency and forward-declaring nlohmann json
*: replace every instance of QString::fromUtf8 to Strings::ToQString.
the main difference is that our function will always convert exactly
what is in the string, while some other times it would only convert
up to the nearest NUL byte
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Wed, 06 Dec 2023 13:43:54 -0500 |
parents | 39521c47c7a3 |
children | 4d461ef7d424 |
line wrap: on
line source
#include "gui/dialog/information.h" #include "core/anime.h" #include "core/anime_db.h" #include "core/strings.h" #include "core/session.h" #include "gui/pages/anime_list.h" #include "gui/translate/anime.h" #include "gui/widgets/anime_info.h" #include "gui/widgets/optional_date.h" #include "gui/widgets/poster.h" #include "gui/widgets/text.h" #include "gui/window.h" #include <QCheckBox> #include <QComboBox> #include <QDateEdit> #include <QDebug> #include <QDialogButtonBox> #include <QLabel> #include <QLineEdit> #include <QPlainTextEdit> #include <QSpinBox> #include <QStringList> #include <QTextStream> #include <QVBoxLayout> #include <functional> #ifdef WIN32 #include "sys/win32/dark_theme.h" #endif /* TODO: Taiga disables rendering of the tab widget entirely when the anime is not part of a list, which sucks. Think of a better way to implement this later. */ void InformationDialog::SaveData(Anime::Anime& anime) { anime.SetUserProgress(_progress); anime.SetUserScore(_score); anime.SetUserIsRewatching(_rewatching); anime.SetUserStatus(_status); anime.SetUserNotes(_notes); anime.SetUserDateStarted(_started); anime.SetUserDateCompleted(_completed); } InformationDialog::InformationDialog(Anime::Anime& anime, std::function<void()> accept, enum Pages page, QWidget* parent) : QDialog(parent) { /* ack. lots of brackets here, but MUCH, MUCH MUCH better than what it used to be */ setFixedSize(842, 613); setWindowTitle(tr("Anime Information")); setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); { QPalette pal; pal.setColor(QPalette::Window, pal.color(QPalette::Base)); setPalette(pal); } QVBoxLayout* full_layout = new QVBoxLayout(this); { /* this handles the actual page. */ QWidget* widget = new QWidget(this); QHBoxLayout* layout = new QHBoxLayout(widget); { /* Sidebar */ QWidget* sidebar = new QWidget(widget); QVBoxLayout* sidebar_layout = new QVBoxLayout(sidebar); { /* Poster */ Poster* poster = new Poster(anime, sidebar); sidebar_layout->addWidget(poster); } sidebar_layout->setContentsMargins(0, 0, 0, 0); sidebar_layout->addStretch(); layout->addWidget(sidebar); } { /* ... everything else. */ QWidget* main_widget = new QWidget(widget); QVBoxLayout* main_layout = new QVBoxLayout(main_widget); main_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); { /* Anime title */ TextWidgets::Title* anime_title = new TextWidgets::Title(Strings::ToQString(anime.GetUserPreferredTitle()), main_widget); main_layout->addWidget(anime_title); } { /* Tab widget, contains main info and settings */ QTabWidget* tabbed_widget = new QTabWidget(main_widget); tabbed_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); { /* Main information */ AnimeInfoWidget* main_information_widget = new AnimeInfoWidget(anime, tabbed_widget); tabbed_widget->addTab(main_information_widget, tr("Main information")); } { /* My list and settings */ QWidget* settings_widget = new QWidget(tabbed_widget); settings_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); QVBoxLayout* settings_layout = new QVBoxLayout(settings_widget); settings_layout->addWidget(new TextWidgets::Header(tr("Anime list"), settings_widget)); { /* Anime List */ QWidget* sg_anime_list_content = new QWidget(settings_widget); constexpr int LAYOUT_HORIZ_SPACING = 25; constexpr int LAYOUT_VERT_SPACING = 5; constexpr int LAYOUT_ITEM_WIDTH = 175; QVBoxLayout* al_layout = new QVBoxLayout(sg_anime_list_content); al_layout->setSpacing(LAYOUT_VERT_SPACING); al_layout->setContentsMargins(12, 0, 0, 0); /* Helper function for creating sections, reduces clutter. */ const auto CREATE_SECTION = [](QWidget* parent, std::function<void(QWidget*, QGridLayout*)> x) { QWidget* section = new QWidget(parent); QGridLayout* layout = new QGridLayout(section); layout->setHorizontalSpacing(LAYOUT_HORIZ_SPACING); layout->setVerticalSpacing(LAYOUT_VERT_SPACING); layout->setContentsMargins(0, 0, 0, 0); x(section, layout); parent->layout()->addWidget(section); }; CREATE_SECTION(sg_anime_list_content, [this, &anime](QWidget* section, QGridLayout* layout){ { /* Episodes watched... */ layout->addWidget(new QLabel(tr("Episodes watched:"), section), 0, 0); QSpinBox* spin_box = new QSpinBox(section); connect(spin_box, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int i) { _progress = i; }); spin_box->setRange(0, anime.GetEpisodes()); spin_box->setSingleStep(1); spin_box->setValue(_progress = anime.GetUserProgress()); spin_box->setFixedWidth(LAYOUT_ITEM_WIDTH); layout->addWidget(spin_box, 1, 0); } { /* Rewatching? */ QCheckBox* checkbox = new QCheckBox(tr("Rewatching")); connect(checkbox, QOverload<int>::of(&QCheckBox::stateChanged), this, [this](int state) { _rewatching = (state == Qt::Checked); }); checkbox->setCheckState((_rewatching = anime.GetUserIsRewatching()) ? Qt::Checked : Qt::Unchecked); checkbox->setFixedWidth(LAYOUT_ITEM_WIDTH); layout->addWidget(checkbox, 1, 1); } layout->setColumnStretch(layout->columnCount(), 1); }); CREATE_SECTION(sg_anime_list_content, [this, &anime](QWidget* section, QGridLayout* layout){ { /* Status */ layout->addWidget(new QLabel(tr("Status:"), section), 0, 0); QComboBox* combo_box = new QComboBox(section); for (unsigned int i = 0; i < Anime::ListStatuses.size(); i++) combo_box->addItem(Strings::ToQString(Translate::ToString(Anime::ListStatuses[i])), static_cast<int>(Anime::ListStatuses[i])); connect(combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this, combo_box](int) { _status = static_cast<Anime::ListStatus>(combo_box->currentData().toInt()); }); /* this should NEVER, EVER, be NOT_IN_LIST */ combo_box->setCurrentIndex(static_cast<int>(_status = anime.GetUserStatus()) - 1); combo_box->setFixedWidth(LAYOUT_ITEM_WIDTH); layout->addWidget(combo_box, 1, 0); } { /* Score */ layout->addWidget(new QLabel(tr("Score:"), section), 0, 1); QSpinBox* spin_box = new QSpinBox(section); connect(spin_box, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int i) { _score = i; }); spin_box->setRange(0, 100); spin_box->setSingleStep(5); spin_box->setValue(_score = anime.GetUserScore()); spin_box->setFixedWidth(LAYOUT_ITEM_WIDTH); layout->addWidget(spin_box, 1, 1); } layout->setColumnStretch(layout->columnCount(), 1); }); CREATE_SECTION(sg_anime_list_content, [this, &anime](QWidget* section, QGridLayout* layout){ layout->addWidget(new QLabel(tr("Notes:"), section), 0, 0); QLineEdit* line_edit = new QLineEdit(section); connect(line_edit, &QLineEdit::textChanged, this, [this](const QString& text) { /* this sucks but I don't really want to implement anything smarter :) */ _notes = Strings::ToUtf8String(text); }); line_edit->setText(Strings::ToQString(_notes = anime.GetUserNotes())); line_edit->setPlaceholderText(tr("Enter your notes about this anime")); layout->addWidget(line_edit, 1, 0); }); CREATE_SECTION(sg_anime_list_content, [this, &anime](QWidget* section, QGridLayout* layout){ /* Started */ { layout->addWidget(new QLabel(tr("Date started:"), section), 0, 0); OptionalDate* date = new OptionalDate(true, section); connect(date, &OptionalDate::DataChanged, this, [this](bool enabled, Date date) { _started = enabled ? date : Date(); }); date->setFixedWidth(LAYOUT_ITEM_WIDTH); _started = anime.GetUserDateStarted(); if (!_started.IsValid()) { date->SetEnabled(false); _started = anime.GetAirDate(); } date->SetDate(_started); layout->addWidget(date, 1, 0); } /* Completed */ { layout->addWidget(new QLabel(tr("Date completed:"), section), 0, 1); OptionalDate* date = new OptionalDate(true, section); connect(date, &OptionalDate::DataChanged, this, [this](bool enabled, Date date) { _completed = enabled ? date : Date(); }); date->setFixedWidth(LAYOUT_ITEM_WIDTH); _completed = anime.GetUserDateCompleted(); if (!_completed.IsValid()) { date->SetEnabled(false); _completed = anime.GetAirDate(); } date->SetDate(_completed); layout->addWidget(date, 1, 1); } layout->setColumnStretch(layout->columnCount(), 1); }); settings_layout->addWidget(sg_anime_list_content); } /* { // commenting this out until it actually gets implemented :) settings_layout->addWidget(new TextWidgets::Header(tr("Local settings"), settings_widget)); QWidget* sg_local_content = new QWidget(settings_widget); QVBoxLayout* sg_local_layout = new QVBoxLayout(sg_local_content); sg_local_layout->setSpacing(5); sg_local_layout->setContentsMargins(12, 0, 0, 0); CREATE_SECTION(sg_local_content, [this, &anime](QWidget* section, QGridLayout* layout){ layout->addWidget(new QLabel(tr("Alternative titles:"), section), 0, 0); QLineEdit* line_edit = new QLineEdit("", section); line_edit->setPlaceholderText( tr("Enter alternative titles here, separated by a semicolon (i.e. Title 1; Title 2)")); layout->addWidget(line_edit, 1, 0); QCheckBox* checkbox = new QCheckBox(tr("Use the first alternative title to search for torrents")); layout->addWidget(checkbox, 2, 0); }); settings_layout->addWidget(sg_local_content); } */ settings_layout->addStretch(); tabbed_widget->addTab(settings_widget, tr("My list and settings")); } tabbed_widget->setCurrentIndex(static_cast<int>(page)); main_layout->addWidget(tabbed_widget); main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setSpacing(12); } layout->addWidget(main_widget); } layout->setSpacing(12); full_layout->addWidget(widget); } { /* Dialog box buttons */ QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(button_box, &QDialogButtonBox::accepted, this, [this, accept, &anime] { SaveData(anime); accept(); QDialog::accept(); }); connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); full_layout->addWidget(button_box, 0, Qt::AlignBottom); } } void InformationDialog::showEvent(QShowEvent* event) { QDialog::showEvent(event); #ifdef WIN32 win32::SetTitleBarsToBlack(session.config.theme.IsInDarkTheme()); #endif } #include "gui/dialog/moc_information.cpp"