view src/gui/dialog/information.cc @ 88:1b19d80b3f8c

dialog/information.cc: fix QGridLayout :)
author Paper <mrpapersonic@gmail.com>
date Tue, 31 Oct 2023 16:18:26 -0400
parents 4aef97f4d998
children e6fab256ddc4
line wrap: on
line source

#include "gui/dialog/information.h"
#include "core/anime.h"
#include "core/anime_db.h"
#include "core/strings.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>

/* 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, QWidget* parent)
    : QDialog(parent) {
	setFixedSize(842, 613);
	setWindowTitle(tr("Anime Information"));
	setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);

	{
		QPalette pal(palette());
		pal.setColor(QPalette::Window, pal.color(QPalette::Base));
		setPalette(pal);
	}

	QWidget* widget = new QWidget(this);

	/* "sidebar", includes... just the anime image :) */
	QWidget* sidebar = new QWidget(widget);
	QVBoxLayout* sidebar_layout = new QVBoxLayout(sidebar);
	Poster* poster = new Poster(anime, sidebar);
	sidebar_layout->addWidget(poster);
	sidebar_layout->setContentsMargins(0, 0, 0, 0);
	sidebar_layout->addStretch();

	/* main widget */
	QWidget* main_widget = new QWidget(widget);

	main_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

	/* anime title header text */
	TextWidgets::Title* anime_title =
	    new TextWidgets::Title(Strings::ToQString(anime.GetUserPreferredTitle()), main_widget);

	/* tabbed widget */
	QTabWidget* tabbed_widget = new QTabWidget(main_widget);
	tabbed_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

	/* main info tab */
	AnimeInfoWidget* main_information_widget = new AnimeInfoWidget(anime, tabbed_widget);

	{
		QPalette pal(main_information_widget->palette());
		pal.setColor(QPalette::Base, pal.color(QPalette::Window));
		main_information_widget->setPalette(pal);
	}

	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));

	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);

	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);
	};

	const auto GRID_ADD_STRETCH = [](QGridLayout* layout) {
		layout->setRowStretch(layout->rowCount(), 1);
		layout->setColumnStretch(layout->columnCount(), 1);
	};

	CREATE_SECTION(sg_anime_list_content, [this, &anime, &GRID_ADD_STRETCH](QWidget* section, QGridLayout* layout){
		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);

		layout->addWidget(new QLabel(tr(" "), section), 0, 1);

		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);
		GRID_ADD_STRETCH(layout);
	});

	CREATE_SECTION(sg_anime_list_content, [this, &anime, &GRID_ADD_STRETCH](QWidget* section, QGridLayout* layout){
		/* Status & score section */
		layout->addWidget(new QLabel(tr("Status:"), section), 0, 0);

		/* FIXME: this sucks */
		QStringList string_list;
		for (unsigned int i = 0; i < Anime::ListStatuses.size(); i++)
			string_list.append(Strings::ToQString(Translate::ToString(Anime::ListStatuses[i])));

		QComboBox* combo_box = new QComboBox(section);
		combo_box->addItems(string_list);
		connect(combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
		        [this](int i) { _status = Anime::ListStatuses[i]; });
		combo_box->setCurrentIndex(static_cast<int>(_status = anime.GetUserStatus()) - 1);
		combo_box->setFixedWidth(LAYOUT_ITEM_WIDTH);
		layout->addWidget(combo_box, 1, 0);
	
		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);
		GRID_ADD_STRETCH(layout);
	});

	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, &GRID_ADD_STRETCH](QWidget* section, QGridLayout* layout){
		/* Dates section */
		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);

		layout->addWidget(new QLabel(tr("Date completed:"), section), 0, 1);

		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);
		GRID_ADD_STRETCH(layout);
	});

	settings_layout->addWidget(sg_anime_list_content);

	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);
	});
#undef CREATE_SECTION
#undef CREATE_FULL_WIDTH_SECTION

	settings_layout->addWidget(sg_local_content);
	settings_layout->addStretch();

	tabbed_widget->addTab(main_information_widget, tr("Main information"));
	tabbed_widget->addTab(settings_widget, tr("My list and settings"));

	QVBoxLayout* main_layout = new QVBoxLayout(main_widget);
	main_layout->addWidget(anime_title);
	main_layout->addWidget(tabbed_widget);
	main_layout->setContentsMargins(0, 0, 0, 0);
	main_layout->setSpacing(12);

	QHBoxLayout* layout = new QHBoxLayout(widget);
	layout->addWidget(sidebar);
	layout->addWidget(main_widget);
	layout->setSpacing(12);

	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);

	QVBoxLayout* buttons_layout = new QVBoxLayout(this);
	buttons_layout->addWidget(widget);
	buttons_layout->addWidget(button_box, 0, Qt::AlignBottom);
}

#include "gui/dialog/moc_information.cpp"