Pith - wedge
#include "WedgeHeader.h"
#include "WedgeSettings.h"
#include "WedgeStyle.h"
#include <QColorDialog>
#include <QDesktopServices>
#include <QFormLayout>
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
#include <QButtonGroup>

// version
static const QString kVersionRemote = "210.026.1";

static QSpacerItem* makeSpacer(int height) {
	return new QSpacerItem(0, height, QSizePolicy::Minimum, QSizePolicy::Fixed);
}

// radio buttons
static QWidget* makeSegmentRow(QButtonGroup *group, const QString &opt0, const QString &opt1,
	int currentIndex, QWidget *parent) {
	auto *w = new QWidget(parent);
	auto *h = new QHBoxLayout(w);
	h->setContentsMargins(0, 0, 0, 0);
	h->setSpacing(0);
	auto *b0 = new QPushButton(opt0, w);
	auto *b1 = new QPushButton(opt1, w);
	b0->setProperty("segment", "left");
	b1->setProperty("segment", "right");
	for (QPushButton *b : {b0, b1}) {
		b->setCheckable(true);
		b->setCursor(Qt::PointingHandCursor);
		b->setFocusPolicy(Qt::NoFocus);
	}
	group->addButton(b0, 0);
	group->addButton(b1, 1);
	group->setExclusive(true);
	(currentIndex == 1 ? b1 : b0)->setChecked(true);
	h->addWidget(b0);
	h->addWidget(b1);
	h->addStretch(1);
	return w;
}

SettingsDialog::SettingsDialog(const NoteData &data, QWidget *parent) 
: QDialog(parent), originalData(data) {

	setWindowTitle("");
	setFixedWidth(333);
	setStyleSheet(WedgeStyle::sheet());

	auto *layout = new QVBoxLayout(this);
	layout->setContentsMargins(16, 14, 16, 14);
	auto *form = new QFormLayout();

	form->setVerticalSpacing(7);
	form->setHorizontalSpacing(15);

// aesthetics

	form->addItem(makeSpacer(3));

	currentBg = data.bgColor;
	currentText = data.textColor;
	currentFocus = data.focusColor;
	currentHighlight = data.highlightColor;

	fontCombo = new QFontComboBox();
	fontCombo->setCurrentFont(QFont(data.fontFamily));

	sizeSpin = new QSpinBox();
	sizeSpin->setRange(8, 47);
	sizeSpin->setValue(data.fontSize);

	bgColorBtn = new QPushButton("Ground Color");
	textColorBtn = new QPushButton("Text Color");
	focusColorBtn = new QPushButton("Focus Color");
	highlightColorBtn = new QPushButton("Next Color");

	QFrame *bgPreview = new QFrame();
	bgPreview->setFixedSize(27, 27);
	QFrame *textPreview = new QFrame();
	textPreview->setFixedSize(27, 27);
	QFrame *focusPreview = new QFrame();
	focusPreview->setFixedSize(27, 27);
	QFrame *highlightPreview = new QFrame();
	highlightPreview->setFixedSize(27, 27);

	auto updateButtonColors = [this, bgPreview, textPreview, focusPreview, highlightPreview]() {
		bgPreview->setStyleSheet(QString("background-color: %1; border: 1px solid #d5d5d5; border-radius: 4px;").arg(currentBg.name()));
		textPreview->setStyleSheet(QString("background-color: %1; border: 1px solid #d5d5d5; border-radius: 4px;").arg(currentText.name()));
		focusPreview->setStyleSheet(QString("background-color: %1; border: 1px solid #d5d5d5; border-radius: 4px;").arg(currentFocus.name()));
		highlightPreview->setStyleSheet(QString("background-color: %1; border: 1px solid #d5d5d5; border-radius: 4px;").arg(currentHighlight.name()));
	};

	QHBoxLayout *bgLayout = new QHBoxLayout(); bgLayout->setSpacing(8); bgLayout->addWidget(bgPreview); bgLayout->addWidget(bgColorBtn);
	QHBoxLayout *textLayout = new QHBoxLayout(); textLayout->setSpacing(8); textLayout->addWidget(textPreview); textLayout->addWidget(textColorBtn);
	QHBoxLayout *focusLayout = new QHBoxLayout(); focusLayout->setSpacing(8); focusLayout->addWidget(focusPreview); focusLayout->addWidget(focusColorBtn);
	QHBoxLayout *highlightLayout = new QHBoxLayout(); highlightLayout->setSpacing(8); highlightLayout->addWidget(highlightPreview); highlightLayout->addWidget(highlightColorBtn);
	updateButtonColors();

	connect(bgColorBtn, &QPushButton::clicked, [this, updateButtonColors]() {
		QColor c = QColorDialog::getColor(currentBg, this, "Select Ground Color");
		if (c.isValid()) { currentBg = c; updateButtonColors(); emitChange(); }
	});

	connect(textColorBtn, &QPushButton::clicked, [this, updateButtonColors]() {
		QColor c = QColorDialog::getColor(currentText, this, "Select Text Color");
		if (c.isValid()) { currentText = c; updateButtonColors(); emitChange(); }
	});

	connect(focusColorBtn, &QPushButton::clicked, [this, updateButtonColors]() {
		QColor c = QColorDialog::getColor(currentFocus, this, "Select Focus Color");
		if (c.isValid()) { currentFocus = c; updateButtonColors(); emitChange(); }
	});

	connect(highlightColorBtn, &QPushButton::clicked, this, [this, updateButtonColors]() {
		QColor col = QColorDialog::getColor(currentHighlight, this, "Select Next Color");
		if (col.isValid()) { currentHighlight = col; updateButtonColors(); emitChange(); }
	});

	autoStartGroup = new QButtonGroup(this);
	QWidget *autoStartRow = makeSegmentRow(autoStartGroup, "False", "True", data.autoStart ? 1 : 0, this);

	hideTaskbarGroup = new QButtonGroup(this);
	QWidget *hideTaskbarRow = makeSegmentRow(hideTaskbarGroup, "False", "True", data.hideTaskbar ? 1 : 0, this);

	form->addRow("Font Family", fontCombo);
	form->addRow("Font Size", sizeSpin);
	form->addRow("Font Color", textLayout);
	form->addRow("Focus Color", focusLayout);
	form->addRow("Next Color", highlightLayout);
	form->addRow("Ground Color", bgLayout);

	form->addItem(makeSpacer(4));

// calendar

	headerEdit = new QLineEdit(this);
	headerEdit->setText(data.headerFormat.isEmpty() ? "otcDay EEE dd MMM*" : data.headerFormat);

	form->addRow("Header", headerEdit);

	QLabel *headerPreviewLabel = new QLabel(this);
	headerPreviewLabel->setStyleSheet("font-family: monospace; font-size: 8pt; padding-top: 2px; padding-bottom: 2px;");

	auto updateHeaderPreview = [headerPreviewLabel](const QString &fmt) {
		headerPreviewLabel->setText(fmt.isEmpty() ? QString() : WedgeHeader::render(fmt, QDate::currentDate()));
	};
	updateHeaderPreview(headerEdit->text());

	connect(headerEdit, &QLineEdit::textChanged, this, updateHeaderPreview);

	form->addRow("Print", headerPreviewLabel);

	form->addItem(makeSpacer(3));

// system

	form->addRow("Auto Start", autoStartRow);
	form->addRow("Hide Task Bar", hideTaskbarRow);

	form->addItem(makeSpacer(1));

// data

	qint64 backupTime = ConfigManager::lastBackupTime();
	QString archivedStr = (backupTime > 0)
	? QString("<a style='text-decoration: none; color: #000000; font-family: monospace; font-size: 8pt;' href='bk'>%1</a>").arg(ConfigManager::formatOtc(backupTime))
	: "n/a";
	QLabel *archiveLabel = new QLabel(archivedStr, this);
	archiveLabel->setStyleSheet("font-family: monospace; font-size: 8pt; padding-top: 2px; padding-bottom: 2px;");
	archiveLabel->setOpenExternalLinks(false);

	connect(archiveLabel, &QLabel::linkActivated, this, [](const QString &link) {
		if (link == "bk") {
			QDesktopServices::openUrl(QUrl::fromLocalFile(ConfigManager::getConfigPath() + "/wedge.conf.bk"));
		}
	});

	QLabel *dataLabel = new QLabel("<a style='text-decoration: none; color: #000000; font-family: monospace; font-size: 8pt;' href='conf'>wedge.conf</a>", this);
	dataLabel->setOpenExternalLinks(false);
	dataLabel->setStyleSheet("padding-top: 2px; padding-bottom: 2px;");

	connect(dataLabel, &QLabel::linkActivated, this, [](const QString &link) {
		if (link == "conf") {
			QDesktopServices::openUrl(QUrl::fromLocalFile(ConfigManager::getConfigPath() + "/wedge.conf"));
		}
	});

	QLabel *versionLabel = new QLabel(
		QString("%1 <a style='text-decoration: none; color: #888888; font-family: monospace; font-size: 8pt;' href='https://vgmlr.com/?t=Wedge'>[update]</a>").arg(kVersionRemote),
		this);
	versionLabel->setStyleSheet("font-family: monospace; font-size: 8pt; padding-top: 2px; padding-bottom: 2px;");
	versionLabel->setOpenExternalLinks(true);
	versionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);

	QLabel *sourceLabel = new QLabel("<a style='text-decoration: none; color: #000000; font-family: monospace; font-size: 8pt;' href='https://vgmlr.com/mlwrk'>vgmlr.com/mlwrk</a>", this);
	sourceLabel->setOpenExternalLinks(true);
	sourceLabel->setStyleSheet("padding-top: 2px; padding-bottom: 2px;");

	form->addRow("Storage", dataLabel);
	form->addRow("Archived", archiveLabel);
	form->addRow("Version", versionLabel);
	form->addRow("Source", sourceLabel);

	form->addItem(makeSpacer(6));

	layout->addLayout(form);

	connect(fontCombo, &QFontComboBox::currentFontChanged, this, [this](const QFont &) { emitChange(); });
	connect(sizeSpin, &QSpinBox::valueChanged, this, [this](int) { emitChange(); });
	connect(autoStartGroup, &QButtonGroup::idClicked, this, [this](int) { emitChange(); });
	connect(hideTaskbarGroup, &QButtonGroup::idClicked, this, [this](int) { emitChange(); });
	connect(headerEdit, &QLineEdit::textChanged, this, [this](const QString &) { emitChange(); });
}

void SettingsDialog::emitChange() {
	emit settingsChanged(getUpdatedData());
}

NoteData SettingsDialog::getUpdatedData() const {
	NoteData data = originalData;
	data.autoStart = (autoStartGroup->checkedId() == 1);
	data.bgColor = currentBg;
	data.focusColor = currentFocus;
	data.fontFamily = fontCombo->currentFont().family();
	data.fontSize = sizeSpin->value();
	data.headerFormat = headerEdit->text();
	data.hideTaskbar = (hideTaskbarGroup->checkedId() == 1);
	data.highlightColor = currentHighlight;
	data.textColor = currentText;
	return data;
}