view src/gui/widgets/text.cc @ 365:f81bed4e04ac

*: megacommit that probably breaks things
author Paper <paper@paper.us.eu.org>
date Wed, 02 Oct 2024 23:06:43 -0400
parents 6b0768158dcd
children
line wrap: on
line source

#include "gui/widgets/text.h"
#include "core/session.h"
#include "core/strings.h"

#include <QDebug>
#include <QFrame>
#include <QLabel>
#include <QTextBlock>
#include <QVBoxLayout>
#include <QScrollArea>
#include <QDebug>
#include <QPainter>

namespace TextWidgets {

/* Generic header meant to be used in conjunction with Section<T> */

Header::Header(QWidget* parent)
	: QWidget(parent)
	, title_(new QLabel)
	, separator_(new QFrame) {
	QVBoxLayout* layout = new QVBoxLayout(this);
	setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);

	title_->setTextFormat(Qt::PlainText);

	{
		QFont font = title_->font();
		font.setWeight(QFont::Bold);
		title_->setFont(font);
	}

	separator_->setFrameShape(QFrame::HLine);
	separator_->setFrameShadow(QFrame::Sunken);
	separator_->setFixedHeight(2);

	layout->addWidget(title_.data());
	layout->addWidget(separator_.data());
	layout->setSpacing(0);
	layout->setContentsMargins(0, 0, 0, 0);
}

void Header::SetText(const std::string& text) {
	title_->setText(Strings::ToQString(text));
	updateGeometry();
}

Label::Label(QWidget *parent) : QLabel(parent) {}
Label::Label(const QString &string, QWidget *parent) : QLabel(string, parent) {}

void Label::SetElidingMode(bool elide) {
	elide_ = elide;
	update();
}

void Label::paintEvent(QPaintEvent *event) {
	if (elide_) {
		/* bruh */
		if (wordWrap()) {
			QFrame::paintEvent(event);

			const QString content = text();

		    QPainter painter(this);
		    QFontMetrics fontMetrics = painter.fontMetrics();

		    bool didElide = false;
		    int lineSpacing = fontMetrics.lineSpacing();
		    int y = 0;

		    QTextLayout textLayout(content, painter.font());
		    textLayout.beginLayout();
		    for (;;) {
		        QTextLine line = textLayout.createLine();

		        if (!line.isValid())
		            break;

		        line.setLineWidth(width());
		        int nextLineY = y + lineSpacing;

		        if (height() >= nextLineY + lineSpacing) {
		            line.draw(&painter, QPoint(0, y));
		            y = nextLineY;
				} else {
					QString lastLine = content.mid(line.textStart());
					QString elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, width());
					painter.drawText(QPoint(0, y + fontMetrics.ascent()), elidedLastLine);
					line = textLayout.createLine();
					didElide = line.isValid();
					break;
				}
			}
			textLayout.endLayout();
		} else {
			QString backup_text = QLabel::text();

			QFontMetrics metric(fontMetrics());
			QString elided_text = metric.elidedText(backup_text, Qt::ElideRight, width());

			QLabel::setText(elided_text);
			QLabel::paintEvent(event);
			QLabel::setText(backup_text);
		}
	} else {
		/* QLabel can handle everything... */
		QLabel::paintEvent(event);
	}
}

/* ---------------------------------------------------------------------------------- */
/* "Paragraph" widgets, as in widgets meant to hold a bunch of text. */

Paragraph::Paragraph(QWidget *parent) : QWidget(parent), label_(new QLabel) {
	QVBoxLayout *layout = new QVBoxLayout(this);
	layout->setSpacing(0);
	layout->setContentsMargins(0, 0, 0, 0);

	label_->setTextInteractionFlags(Qt::TextBrowserInteraction);

	/* defaults */
	SetWordWrap(true);
	SetSelectable(true);

	layout->addWidget(label_.data());
}

void Paragraph::SetText(const std::string& text) {
	label_->setText(Strings::ToQString(text));
}

void Paragraph::SetSelectable(bool enable) {
	label_->setAttribute(Qt::WidgetAttribute::WA_TransparentForMouseEvents, !enable);
	label_->setCursor(enable ? Qt::IBeamCursor : Qt::ArrowCursor);
}

void Paragraph::SetWordWrap(bool enable) {
	label_->setWordWrap(enable);
}

/* LabelledParagraph implementation */

LabelledParagraph::LabelledParagraph(QWidget* parent)
	: QWidget(parent)
	, contents_(new QWidget)
	, contents_layout_(new QGridLayout) {
	QHBoxLayout* ly = new QHBoxLayout(this);

	contents_layout_->setVerticalSpacing(1);
	contents_layout_->setHorizontalSpacing(20);
	contents_layout_->setContentsMargins(0, 0, 0, 0);
	contents_layout_->setColumnStretch(1, 0);

	contents_->setLayout(contents_layout_.data());

	ly->addWidget(contents_.data());
	ly->setContentsMargins(0, 0, 0, 0);
}

LabelledParagraph::~LabelledParagraph() {
	data_.clear();
}

void LabelledParagraph::Clear(void) {
	for (auto& [label, data] : data_) {
		contents_layout_->removeWidget(label.data());
		contents_layout_->removeWidget(data.data());
	}

	data_.clear();
}

void LabelledParagraph::SetData(const std::vector<std::pair<std::string, std::string>>& data) {
	Clear();

	data_.reserve(data.size());
	for (std::size_t i = 0; i < data.size(); i++) {
		QSharedPointer<Label> first(new Label);
		QSharedPointer<Label> second(new Label);

		first->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);

		first->setText(Strings::ToQString(data[i].first));
		second->setText(Strings::ToQString(data[i].second));

		data_.push_back({first, second});

		contents_layout_->addWidget(first.data(),  i, 0);
		contents_layout_->addWidget(second.data(), i, 1);
	}
}

void LabelledParagraph::SetStyle(int style) {
	const QString style_sheet = (style & LabelledParagraph::BoldedLabels) ? "font-weight: bold;" : "";
	for (auto& [label, data] : data_)
		label->setStyleSheet(style_sheet);

	if (style & LabelledParagraph::ElidedData) {
		for (auto& [label, data] : data_) {
			data->setWordWrap(false);
			data->SetElidingMode(true);
		}
	}
}

} // namespace TextWidgets