141 lines
4.9 KiB
C++
141 lines
4.9 KiB
C++
#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
|