geopro/src/app/panels/DescriptionPanel.cpp

141 lines
4.9 KiB
C++
Raw 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 "panels/DescriptionPanel.hpp"
#include <QColorDialog>
#include <QComboBox>
#include <QHBoxLayout>
#include <QPushButton>
#include <QTextCharFormat>
#include <QTextEdit>
#include <QTextListFormat>
#include <QToolBar>
#include <QToolButton>
#include <QVBoxLayout>
#include "Theme.hpp"
#include "panels/QuillDelta.hpp"
namespace geopro::app {
namespace {
// 字号下拉选项px——对照原版 ql-size 的 12~32px。
const int kFontSizesPx[] = {12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32};
} // namespace
DescriptionPanel::DescriptionPanel(QWidget* parent) : QWidget(parent) {
auto* lay = new QVBoxLayout(this);
lay->setContentsMargins(geopro::app::space::kMd, geopro::app::space::kMd,
geopro::app::space::kMd, geopro::app::space::kMd);
lay->setSpacing(geopro::app::space::kSm);
auto* tb = new QToolBar(this);
buildToolbar(tb);
lay->addWidget(tb);
edit_ = new QTextEdit(this);
edit_->setAcceptRichText(true);
edit_->setPlaceholderText(QStringLiteral("暂无描述"));
lay->addWidget(edit_, 1);
auto* btnLay = new QHBoxLayout();
btnLay->addStretch();
saveBtn_ = new QPushButton(QStringLiteral("保存"), this);
saveBtn_->setEnabled(false); // 注入 cmdRepo 后启用
btnLay->addWidget(saveBtn_);
lay->addLayout(btnLay);
connect(saveBtn_, &QPushButton::clicked, this, [this]() { emit saveRequested(); });
}
void DescriptionPanel::buildToolbar(QToolBar* tb) {
// 粗体 / 斜体 / 下划线:可勾选按钮,作用于选区当前字符格式。
auto addToggle = [this, tb](const QString& label, auto applier) {
auto* btn = new QToolButton(tb);
btn->setText(label);
btn->setCheckable(true);
tb->addWidget(btn);
connect(btn, &QToolButton::toggled, this, applier);
return btn;
};
addToggle(QStringLiteral("B"), [this](bool on) {
QTextCharFormat f;
f.setFontWeight(on ? QFont::Bold : QFont::Normal);
edit_->mergeCurrentCharFormat(f);
});
addToggle(QStringLiteral("I"), [this](bool on) {
QTextCharFormat f;
f.setFontItalic(on);
edit_->mergeCurrentCharFormat(f);
});
addToggle(QStringLiteral("U"), [this](bool on) {
QTextCharFormat f;
f.setFontUnderline(on);
edit_->mergeCurrentCharFormat(f);
});
// 字色:弹色板,作用于选区前景色。
auto* colorBtn = new QToolButton(tb);
colorBtn->setText(QStringLiteral("A"));
tb->addWidget(colorBtn);
connect(colorBtn, &QToolButton::clicked, this, [this]() {
const QColor c = QColorDialog::getColor(Qt::black, this, QStringLiteral("字体颜色"));
if (!c.isValid()) return;
QTextCharFormat f;
f.setForeground(c);
edit_->mergeCurrentCharFormat(f);
});
// 字号下拉px
auto* sizeBox = new QComboBox(tb);
for (int px : kFontSizesPx) sizeBox->addItem(QStringLiteral("%1px").arg(px), px);
sizeBox->setCurrentIndex(2); // 默认 16px与原版一致
tb->addWidget(sizeBox);
connect(sizeBox, &QComboBox::currentIndexChanged, this, [this, sizeBox](int) {
const int px = sizeBox->currentData().toInt();
QTextCharFormat f;
f.setFontPointSize(px * 3.0 / 4.0); // px→pt。
edit_->mergeCurrentCharFormat(f);
});
// 标题下拉(正文 / H1~H4——块级作用于当前段。
auto* headerBox = new QComboBox(tb);
headerBox->addItem(QStringLiteral("正文"), 0);
for (int h = 1; h <= 4; ++h) headerBox->addItem(QStringLiteral("标题%1").arg(h), h);
tb->addWidget(headerBox);
connect(headerBox, &QComboBox::currentIndexChanged, this, [this, headerBox](int) {
const int h = headerBox->currentData().toInt();
QTextCursor cur = edit_->textCursor();
QTextBlockFormat bf = cur.blockFormat();
bf.setHeadingLevel(h); // 0 表示正文。
cur.mergeBlockFormat(bf);
edit_->setTextCursor(cur);
});
// 有序 / 无序列表——块级。
auto addListBtn = [this, tb](const QString& label, QTextListFormat::Style style) {
auto* btn = new QToolButton(tb);
btn->setText(label);
tb->addWidget(btn);
connect(btn, &QToolButton::clicked, this, [this, style]() {
edit_->textCursor().createList(style);
});
};
addListBtn(QStringLiteral("1."), QTextListFormat::ListDecimal);
addListBtn(QStringLiteral(""), QTextListFormat::ListDisc);
}
void DescriptionPanel::setDelta(const QJsonArray& ops) {
if (ops.isEmpty()) return;
deltaToDocument(ops, *edit_->document());
}
void DescriptionPanel::setPlainText(const QString& text) { edit_->setPlainText(text); }
QJsonArray DescriptionPanel::delta() const { return documentToDelta(*edit_->document()); }
QString DescriptionPanel::plainText() const { return edit_->toPlainText(); }
void DescriptionPanel::setSaveEnabled(bool on) { saveBtn_->setEnabled(on); }
} // namespace geopro::app