1
0
forked from BRT/arc
arc/views/widget/common/CollapsibleSection.cpp

112 lines
4.1 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "CollapsibleSection.h"
#include <QVBoxLayout>
#include <QTextBrowser>
#include <QEvent>
#include <QCoreApplication>
#include <QDesktopServices>
#include <QRegularExpression>
#include <QApplication>
CollapsibleSection::CollapsibleSection(
const QString &title,
const QString &markdownContent,
QWidget *parent,
const bool expanded
): QWidget(parent) {
QColor bg = qApp->palette().color(QPalette::Window);
bool dark = bg.lightness() < 128;
// Кнопка заголовка с стрелкой
m_toggleButton = new QToolButton(this);
m_toggleButton->setText(title);
m_toggleButton->setCheckable(true);
m_toggleButton->setChecked(expanded);
m_toggleButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
m_toggleButton->setArrowType(expanded ? Qt::DownArrow : Qt::RightArrow);
connect(m_toggleButton, &QToolButton::toggled, this, &CollapsibleSection::onToggled);
// Контент без собственного скрола, займёт доступное пространство
m_contentBrowser = new QTextBrowser(this);
m_contentBrowser->setSearchPaths({QCoreApplication::applicationDirPath() + "/tutorials"});
if (markdownContent.contains("<table") || markdownContent.contains("<img")) {
// Контент с HTML — конвертируем markdown-элементы вручную
QString html = markdownContent;
// ## заголовок → <h2>
html.replace(QRegularExpression(R"(^## (.+)$)", QRegularExpression::MultilineOption), R"(<h3>\1</h3>)");
// --- → <hr>
html.replace(QRegularExpression(R"(^---$)", QRegularExpression::MultilineOption), "<hr>");
// **text** → <b>text</b>
html.replace(QRegularExpression(R"(\*\*([^*]+)\*\*)"), R"(<b>\1</b>)");
m_contentBrowser->setHtml(html);
} else {
m_contentBrowser->setMarkdown(markdownContent);
}
m_contentBrowser->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_contentBrowser->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_contentBrowser->setFrameShape(QFrame::NoFrame);
m_contentBrowser->setVisible(expanded);
m_contentBrowser->document()->adjustSize();
m_contentBrowser->setReadOnly(true);
m_contentBrowser->setOpenLinks(false);
// 2) Подключаемся к клику по ссылке
connect(m_contentBrowser, &QTextBrowser::anchorClicked,
this, [](const QUrl &url) {
QDesktopServices::openUrl(url);
});
if (dark) {
m_contentBrowser->setStyleSheet(R"(
QTextBrowser {
background-color: #2b2b2b;
border: 1px solid #ccc;
color: #dddddd;
border-radius:3px;
}
)");
} else {
m_contentBrowser->setStyleSheet(R"(
QTextBrowser {
background-color: white;
border: 1px solid #ccc;
color: black;
border-radius: 3px;
}
)");
}
updateContentHeight();
m_contentBrowser->viewport()->installEventFilter(this);
auto *layout = new QVBoxLayout(this);
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_toggleButton);
layout->addSpacing(5);
layout->addWidget(m_contentBrowser);
}
bool CollapsibleSection::eventFilter(QObject *watched, QEvent *event) {
if (watched == m_contentBrowser->viewport() && event->type() == QEvent::Resize) {
updateContentHeight();
}
return QWidget::eventFilter(watched, event);
}
void CollapsibleSection::updateContentHeight() const {
const qreal w = m_contentBrowser->viewport()->width();
m_contentBrowser->document()->setTextWidth(w);
const qreal h = m_contentBrowser->document()->size().height();
// Можно добавить +1 пиксел на погрешность:
m_contentBrowser->setFixedHeight(static_cast<int>(h) + 5);
}
void CollapsibleSection::onToggled(const bool checked) const {
m_toggleButton->setArrowType(checked ? Qt::DownArrow : Qt::RightArrow);
m_contentBrowser->setVisible(checked);
if (checked) {
updateContentHeight();
}
}