qt/LedOK/program/etext.cpp
2023-05-18 18:24:40 +08:00

821 lines
30 KiB
C++

#include "base/locolorselector.h"
#include "etext.h"
#include "globaldefine.h"
#include "tools.h"
#include <QBoxLayout>
#include <QButtonGroup>
#include <QFontComboBox>
#include <QJsonArray>
#include <QMessageBox>
#include <QRadioButton>
#include <QSpinBox>
#include <QStackedLayout>
#include <QTextBlock>
#include <QTextCodec>
#include <QTimeEdit>
#include <QToolButton>
#include <QPainter>
#include <QLabel>
static QColor charColors[]{"#fff","#f00","#f00","#f0f","#c0c","#ff0","#f80","#0f0","#0f0","#0a0","#0a0","#7b0","#00f","#00f","#0af","#0ef"};
EText::EText(EBase *multiWin) : EBase(multiWin) {
mType = EBase::Text;
m_attr.text = "<body>"+tr("Enter your text")+"</body>";
connect(this, &EText::sizeChanged, this, &EText::updImg);
updImg();
}
EText::EText(const QJsonObject &json, EBase *multiWin) : EBase(multiWin) {
mType = EBase::Text;
setBaseAttr(json);
setElement(json, m_attr);
connect(this, &EText::sizeChanged, this, &EText::updImg);
updImg();
}
void EText::setElement(const QJsonObject &json, Data &attr) {
auto widget = json["widget"];
attr.text = widget["text"].toString();
attr.align = static_cast<Qt::Alignment>(widget["align"].toInt());
auto backColor = widget["backColor"].toString();
attr.backColor = backColor.isEmpty() ? QColor(0,0,0,0) : QColor(backColor);
auto play = json["play"];
attr.playMode = play["style"].toInt();
auto turning = play["turning"];
attr.flip.effect = turning["strEffect"].toString();
attr.flip.pageDuration = turning["iEffectTime"].toInt();
attr.flip.effectDuration = turning["iEffectSpeed"].toInt();
auto rolling = play["rolling"];
attr.scroll.effect = rolling["rollingStyle"].toInt();
attr.scroll.effectSpeed = rolling["rollingSpeed"].toInt();
attr.scroll.headTailSpacing = rolling["headTailSpacing"].toInt();
attr.scroll.duration = rolling["playDuration"].toInt();
attr.duration = play["static"]["playDuration"].toInt();
}
class TTextEdit : public QTextEdit {
public:
TTextEdit() {}
explicit TTextEdit(const QString &text) : QTextEdit(text){}
QSize minimumSizeHint() const override {
return sizeHint();
};
QSize sizeHint() const override {
auto size = QTextEdit::sizeHint();
auto minH = minimumHeight();
if(minH > 0) size.setHeight(minH+0xfff);
return size;
};
};
QWidget* EText::attrWgt() {
auto wgtAttr = new QWidget;
auto vBox = new QVBoxLayout(wgtAttr);
vBox->setContentsMargins(4, 0, 4, 0);
vBox->setSpacing(3);
addBaseAttrWgt(vBox);
auto hBox = new QHBoxLayout;
hBox->addWidget(new QLabel(tr("Basic Properties")));
auto line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
hBox->addWidget(line, 1);
vBox->addLayout(hBox);
hBox = new QHBoxLayout;
auto fdText = new TTextEdit("");
auto fdFontFamily = new QFontComboBox;
fdFontFamily->setEditable(false);
fdFontFamily->setCurrentFont(QFont("黑体"));
connect(fdFontFamily, &QFontComboBox::currentFontChanged, fdText, [fdText](const QFont &f) {
QTextCharFormat fmt;
fmt.setFontFamilies({f.family()});
QTextCursor cursor = fdText->textCursor();
if(! cursor.hasSelection()) cursor.select(QTextCursor::WordUnderCursor);
cursor.mergeCharFormat(fmt);
});
hBox->addWidget(fdFontFamily);
hBox->addStretch();
auto fdFontSize = new QSpinBox;
fdFontSize->setRange(4, 9999);
fdFontSize->setValue(16);
connect(fdFontSize, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, fdText, [fdText](int value) {
if(value <= 0) return;
QTextCharFormat fmt;
fmt.setProperty(QTextFormat::FontPixelSize, value);
QTextCursor cursor = fdText->textCursor();
if(! cursor.hasSelection()) cursor.select(QTextCursor::WordUnderCursor);
cursor.mergeCharFormat(fmt);
});
hBox->addWidget(fdFontSize);
vBox->addLayout(hBox);
hBox = new QHBoxLayout;
hBox->setSpacing(3);
auto wTextAlignHL = new QPushButton(QIcon(":/res/program/TextAlignHL.png"), "");
wTextAlignHL->setStyleSheet("QPushButton{border: none; background: #bbb;} QPushButton:checked{background: #29c;}");
wTextAlignHL->setFixedSize(30, 30);
wTextAlignHL->setIconSize(QSize(30, 30));
wTextAlignHL->setCheckable(true);
wTextAlignHL->setChecked(true);
hBox->addWidget(wTextAlignHL);
auto wTextAlignHC = new QPushButton(QIcon(":/res/program/TextAlignHC.png"), "");
wTextAlignHC->setStyleSheet("QPushButton{border: none; background: #bbb;} QPushButton:checked{background: #29c;}");
wTextAlignHC->setFixedSize(30, 30);
wTextAlignHC->setIconSize(QSize(30, 30));
wTextAlignHC->setCheckable(true);
hBox->addWidget(wTextAlignHC);
auto wTextAlignHR = new QPushButton(QIcon(":/res/program/TextAlignHR.png"), "");
wTextAlignHR->setStyleSheet("QPushButton{border: none; background: #bbb;} QPushButton:checked{background: #29c;}");
wTextAlignHR->setFixedSize(30, 30);
wTextAlignHR->setIconSize(QSize(30, 30));
wTextAlignHR->setCheckable(true);
hBox->addWidget(wTextAlignHR);
hBox->addStretch();
auto fdFontBold = new QPushButton("B");
fdFontBold->setStyleSheet("QPushButton{background: #bbb; color: #888; font-size: 20px; font-weight: bold;} QPushButton:checked{background: #29c; color: #fff;}");
fdFontBold->setFixedSize(30, 30);
fdFontBold->setCheckable(true);
connect(fdFontBold, &QToolButton::toggled, fdText, [fdText](bool checked) {
QTextCharFormat fmt;
fmt.setFontWeight(checked ? QFont::Bold : QFont::Normal);
Tools::mergeFormat(fdText, fmt);
});
hBox->addWidget(fdFontBold);
auto fdFontItalic = new QPushButton("I");
fdFontItalic->setStyleSheet("QPushButton{background: #bbb; color: #888; font-size: 20px; font-style: italic;} QPushButton:checked{background: #29c; color: #fff;}");
fdFontItalic->setFixedSize(30, 30);
fdFontItalic->setCheckable(true);
connect(fdFontItalic, &QToolButton::toggled, fdText, [fdText](bool checked) {
QTextCharFormat fmt;
fmt.setFontItalic(checked);
Tools::mergeFormat(fdText, fmt);
});
hBox->addWidget(fdFontItalic);
auto fdFontUnderline = new QPushButton("U");
fdFontUnderline->setStyleSheet("QPushButton{background: #bbb; color: #888; font-size: 20px; text-decoration: underline;} QPushButton:checked{background: #29c; color: #fff;}");
fdFontUnderline->setFixedSize(30, 30);
fdFontUnderline->setCheckable(true);
connect(fdFontUnderline, &QToolButton::toggled, fdText, [fdText](bool checked) {
QTextCharFormat fmt;
fmt.setFontUnderline(checked);
Tools::mergeFormat(fdText, fmt);
});
hBox->addWidget(fdFontUnderline);
hBox->addStretch();
auto fdTextColor = new LoColorSelector("T", Qt::white);
fdTextColor->setToolTip(tr("Text Color"));
fdTextColor->setFixedSize(30, 30);
connect(fdTextColor, &LoColorSelector::sColorChanged, fdText, [fdText](const QColor &color) {
if(! color.isValid()) return;
QTextCharFormat fmt;
fmt.setForeground(color);
Tools::mergeFormat(fdText, fmt);
});
hBox->addWidget(fdTextColor);
auto fdBackColor = new LoColorSelector("B", m_attr.backColor);
fdBackColor->setToolTip(tr("Back Color"));
fdBackColor->setFixedSize(30, 30);
connect(fdBackColor, &LoColorSelector::sColorChanged, this, [this](const QColor &color) {
if(! color.isValid()) return;
m_attr.backColor = color;
updImg();
});
hBox->addWidget(fdBackColor);
auto fdRandomColor = new QPushButton(QIcon(":/res/random.png"), "");
fdRandomColor->setToolTip(tr("Colorful Text"));
fdRandomColor->setFixedSize(30, 30);
fdRandomColor->setIconSize(QSize(30, 30));
connect(fdRandomColor, &QPushButton::clicked, fdText, [fdText] {
auto cursor = fdText->textCursor();
auto len = fdText->document()->characterCount();
QTextCharFormat fmt;
int last = -1, idx;
for(int i=0; i<len; i++) {
cursor.setPosition(i, QTextCursor::MoveAnchor);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
while((idx = rand()%(sizeof(charColors)/sizeof(charColors[0])))==last) ;
last = idx;
fmt.setForeground(charColors[idx]);
cursor.mergeCharFormat(fmt);
}
});
hBox->addWidget(fdRandomColor);
vBox->addLayout(hBox);
hBox = new QHBoxLayout;
hBox->setSpacing(3);
auto wTextAlignVT = new QPushButton(QIcon(":/res/program/TextAlignVT.png"), "");
wTextAlignVT->setStyleSheet("QPushButton{border: none; background: #bbb;} QPushButton:checked{background: #29c;}");
wTextAlignVT->setFixedSize(30, 30);
wTextAlignVT->setIconSize(QSize(30, 30));
wTextAlignVT->setCheckable(true);
hBox->addWidget(wTextAlignVT);
auto wTextAlignVC = new QPushButton(QIcon(":/res/program/TextAlignVC.png"), "");
wTextAlignVC->setStyleSheet("QPushButton{border: none; background: #bbb;} QPushButton:checked{background: #29c;}");
wTextAlignVC->setFixedSize(30, 30);
wTextAlignVC->setIconSize(QSize(30, 30));
wTextAlignVC->setCheckable(true);
hBox->addWidget(wTextAlignVC);
auto wTextAlignVB = new QPushButton(QIcon(":/res/program/TextAlignVB.png"), "");
wTextAlignVB->setStyleSheet("QPushButton{border: none; background: #bbb;} QPushButton:checked{background: #29c;}");
wTextAlignVB->setFixedSize(30, 30);
wTextAlignVB->setIconSize(QSize(30, 30));
wTextAlignVB->setCheckable(true);
hBox->addWidget(wTextAlignVB);
hBox->addStretch();
auto lb = new QLabel(tr("Kerning"));
lb->setToolTip(lb->text());
hBox->addWidget(lb);
auto fdLetterSpacing = new QSpinBox();
fdLetterSpacing->setMaximum(999);
connect(fdLetterSpacing, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this, fdText](int value) {
QTextCharFormat fmt;
fmt.setFontLetterSpacing(value);
QTextCursor cursor = fdText->textCursor();
if(! cursor.hasSelection()) cursor.select(QTextCursor::WordUnderCursor);
cursor.mergeCharFormat(fmt);
updImg();
});
hBox->addWidget(fdLetterSpacing);
lb = new QLabel(tr("Line Spacing"));
lb->setToolTip(lb->text());
hBox->addWidget(lb);
auto fdLineSpacing = new QSpinBox();
fdLineSpacing->setRange(-99, 999);
connect(fdLineSpacing, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this, fdText](int value) {
QTextBlockFormat fmt;
fmt.setLineHeight(value, QTextBlockFormat::LineDistanceHeight);
QTextCursor cursor = fdText->textCursor();
if(! cursor.hasSelection()) cursor.select(QTextCursor::WordUnderCursor);
cursor.mergeBlockFormat(fmt);
updImg();
});
hBox->addWidget(fdLineSpacing);
vBox->addLayout(hBox);
auto wTextAlignH = new QButtonGroup(wgtAttr);
wTextAlignH->addButton(wTextAlignHL, Qt::AlignLeft);
wTextAlignH->addButton(wTextAlignHC, Qt::AlignHCenter);
wTextAlignH->addButton(wTextAlignHR, Qt::AlignRight);
connect(wTextAlignH, &QButtonGroup::idClicked, this, [this, fdText](int value) {
QTextBlockFormat fmt;
fmt.setAlignment((Qt::Alignment) value);
QTextCursor cursor = fdText->textCursor();
cursor.mergeBlockFormat(fmt);
updImg();
});
auto wTextAlignV = new QButtonGroup(wgtAttr);
wTextAlignV->addButton(wTextAlignVT, Qt::AlignTop);
wTextAlignV->addButton(wTextAlignVC, Qt::AlignVCenter);
wTextAlignV->addButton(wTextAlignVB, Qt::AlignBottom);
connect(wTextAlignV, &QButtonGroup::idClicked, this, [this](int value) {
m_attr.align = (Qt::Alignment) value;
updImg();
});
auto v_align = m_attr.align & Qt::AlignVertical_Mask;
if(v_align==Qt::AlignTop) wTextAlignVT->setChecked(true);
if(v_align==Qt::AlignVCenter) wTextAlignVC->setChecked(true);
if(v_align==Qt::AlignBottom) wTextAlignVB->setChecked(true);
fdText->setMinimumHeight(160);
auto doc = fdText->document();
if(doc) doc->setDocumentMargin(2);
auto font = fdText->font();
font.setFamilies({"Arial","黑体"});
font.setPixelSize(16);
if(! gTextAntialiasing) font.setStyleStrategy(QFont::NoAntialias);
fdText->setFont(font);
auto pal = fdText->palette();
pal.setColor(QPalette::Base, Qt::black);
pal.setColor(QPalette::Text, Qt::white);
fdText->setPalette(pal);
fdText->setFrameShape(QFrame::NoFrame);
fdText->setAcceptRichText(false);
fdText->setHtml(m_attr.text);
connect(fdText, &QTextEdit::textChanged, this, [this, fdText] {
m_attr.text = fdText->toHtml();
updImg();
});
vBox->addWidget(fdText);
hBox = new QHBoxLayout;
hBox->addStretch();
auto pageInfoWgt = new QWidget;
auto hhh = new QHBoxLayout(pageInfoWgt);
hhh->setContentsMargins(0,0,0,0);
hhh->addWidget(new QLabel(tr("PageCount:")));
auto fdPageCnt = new QLabel(QString::number(mImgs.size()));
hhh->addWidget(fdPageCnt);
hhh->addSpacing(20);
hhh->addWidget(new QLabel(tr("page")));
auto fdPageIdx = new QSpinBox();
fdPageIdx->setRange(1, mImgs.size());
connect(fdPageIdx, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int idx) {
curIdx = idx - 1;
update();
});
hhh->addWidget(fdPageIdx);
hBox->addWidget(pageInfoWgt);
hBox->addStretch();
auto btnImport = new QPushButton(tr("Import txt File"));
btnImport->setProperty("ssType", "progManageTool");
connect(btnImport, &QPushButton::clicked, fdText, [=] {
auto filePath = QFileDialog::getOpenFileName(wgtAttr, tr("Select File"), gFileHome, "Txt(*.txt)");
if(filePath.isEmpty()) return;
QFile qFile(filePath);
if(! qFile.open(QFile::ReadOnly)) {
QMessageBox::critical(wgtAttr, tr("Fail"), tr("Cannot Open File")+": "+qFile.errorString()+"\n"+filePath);
return;
}
auto data = qFile.readAll();
qFile.close();
QTextCodec::ConverterState state;
QString text = QTextCodec::codecForName("UTF-8")->toUnicode(data.constData(), data.size(), &state);
if(state.invalidChars > 0) text = QString::fromLocal8Bit(data);
fdText->setText(text);
});
hBox->addWidget(btnImport);
vBox->addLayout(hBox);
hBox = new QHBoxLayout;
hBox->addWidget(new QLabel(tr("Play Properties")));
line = new QFrame();
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
hBox->addWidget(line, 1);
vBox->addLayout(hBox);
hBox = new QHBoxLayout;
hBox->addStretch();
auto fdFlip = new QRadioButton(tr("Flip"));
hBox->addWidget(fdFlip);
hBox->addStretch();
auto fdScroll = new QRadioButton(tr("Scroll"));
hBox->addWidget(fdScroll);
hBox->addStretch();
auto fdStatic = new QRadioButton(tr("Static"));
hBox->addWidget(fdStatic);
hBox->addStretch();
vBox->addLayout(hBox);
auto fdPlayStyle = new QButtonGroup(wgtAttr);
fdPlayStyle->addButton(fdFlip, EText::Flip);
fdPlayStyle->addButton(fdScroll, EText::Scroll);
fdPlayStyle->addButton(fdStatic, EText::Static);
if(m_attr.playMode==EText::Flip) fdFlip->setChecked(true);
else if(m_attr.playMode==EText::Scroll) fdScroll->setChecked(true);
else if(m_attr.playMode==EText::Static) fdStatic->setChecked(true);
auto wgtAttrFlip = new QWidget();
auto fdDur = new QTimeEdit(QTime::fromMSecsSinceStartOfDay(m_attr.flip.pageDuration * mImgs.size() * 1000));
auto fdPageDur = new QTimeEdit(QTime::fromMSecsSinceStartOfDay(m_attr.flip.pageDuration * 1000));
{
auto vBox = new QVBoxLayout(wgtAttrFlip);
vBox->setContentsMargins(2, 0, 2, 0);
vBox->setSpacing(3);
hBox = new QHBoxLayout;
auto label = new QLabel(tr("Play Duration"));
label->setMinimumWidth(100);
hBox->addWidget(label);
fdDur->setReadOnly(true);
fdDur->setButtonSymbols(QAbstractSpinBox::NoButtons);
fdDur->setDisplayFormat("H:mm:ss");
fdDur->setStyleSheet("QTimeEdit{background-color:#ddd;}");
hBox->addWidget(fdDur);
hBox->addStretch();
vBox->addLayout(hBox);
hBox = new QHBoxLayout();
label = new QLabel(tr("Duration/Page"));
label->setMinimumWidth(100);
hBox->addWidget(label);
fdPageDur->setDisplayFormat("H:mm:ss");
fdPageDur->setCurrentSection(QTimeEdit::SecondSection);
hBox->addWidget(fdPageDur);
hBox->addStretch();
vBox->addLayout(hBox);
hBox = new QHBoxLayout();
label = new QLabel(tr("Entrance Effect"));
label->setMinimumWidth(100);
hBox->addWidget(label);
auto fdEff = new QComboBox();
fdEff->addItem(tr("no"), "no");
fdEff->addItem(tr("random"), "random");
fdEff->addItem(tr("right to left"), "right to left");
fdEff->addItem(tr("bottom to top"), "bottom to top");
fdEff->addItem(tr("left to right"), "left to right");
fdEff->addItem(tr("top to bottom"), "top to bottom");
int idx = fdEff->findData(m_attr.flip.effect);
if(idx!=-1) fdEff->setCurrentIndex(idx);
connect(fdEff, (void(QComboBox::*)(int))&QComboBox::currentIndexChanged, this, [this, fdEff] {
m_attr.flip.effect = fdEff->currentData().toString();
update();
});
hBox->addWidget(fdEff);
hBox->addStretch();
vBox->addLayout(hBox);
hBox = new QHBoxLayout();
label = new QLabel(tr("Effect time"));
label->setMinimumWidth(100);
hBox->addWidget(label);
auto wEffectSpeed = new QSpinBox();
wEffectSpeed->setValue(m_attr.flip.effectDuration);
hBox->addWidget(wEffectSpeed);
hBox->addWidget(new QLabel(tr("s")));
hBox->addStretch();
vBox->addLayout(hBox);
vBox->addStretch();
connect(fdPageDur, &QTimeEdit::timeChanged, this, [=](const QTime &time) {
int effDur = wEffectSpeed->value();
int pageDur = time.msecsSinceStartOfDay()/1000;
if(pageDur < effDur) {
QMessageBox::warning(wgtAttr, tr("Tip Info"), tr("Effect time cannot be longer than duration time"));
pageDur = effDur;
fdPageDur->setTime(QTime::fromMSecsSinceStartOfDay(pageDur*1000));
fdPageDur->setFocus();
}
m_attr.flip.pageDuration = pageDur;
fdDur->setTime(QTime::fromMSecsSinceStartOfDay(pageDur * mImgs.size() * 1000));
});
connect(wEffectSpeed, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [=](int value) {
int pageDur = fdPageDur->time().msecsSinceStartOfDay()/1000;
if(value > pageDur) {
QMessageBox::warning(wgtAttr, tr("Tip Info"), tr("Effect time cannot be longer than duration time"));
if(pageDur>1) value = pageDur-1;
else value = 0;
wEffectSpeed->setValue(value);
wEffectSpeed->setFocus();
}
m_attr.flip.effectDuration = value;
});
}
auto wgtAttrScroll = new QWidget();
{
auto vBox = new QVBoxLayout(wgtAttrScroll);
vBox->setContentsMargins(2, 0, 2, 0);
vBox->setSpacing(3);
auto hBox = new QHBoxLayout();
auto label = new QLabel(tr("Play Duration"));
label->setMinimumWidth(100);
hBox->addWidget(label);
auto timeEdit = new QTimeEdit(QTime::fromMSecsSinceStartOfDay(m_attr.scroll.duration*1000));
timeEdit->setDisplayFormat("H:mm:ss");
timeEdit->setCurrentSectionIndex(2);
connect(timeEdit, &QTimeEdit::timeChanged, this, [this](const QTime &time) {
m_attr.scroll.duration = time.msecsSinceStartOfDay()/1000;
});
hBox->addWidget(timeEdit);
hBox->addStretch();
vBox->addLayout(hBox);
hBox = new QHBoxLayout();
label = new QLabel(tr("Head-Tail Spacing"));
label->setMinimumWidth(100);
hBox->addWidget(label);
auto wHeadTailSpacing = new QSpinBox;
wHeadTailSpacing->setRange(0, 9999);
wHeadTailSpacing->setValue(m_attr.scroll.headTailSpacing);
connect(wHeadTailSpacing, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
m_attr.scroll.headTailSpacing = value;
});
hBox->addWidget(wHeadTailSpacing);
hBox->addStretch();
vBox->addLayout(hBox);
hBox = new QHBoxLayout();
label = new QLabel(tr("Scroll Style"));
label->setMinimumWidth(100);
hBox->addWidget(label);
auto wRollingStyle = new QComboBox;
wRollingStyle->addItem(tr("Right -> Left"));
wRollingStyle->addItem(tr("Bottom -> Top"));
wRollingStyle->addItem(tr("Left -> Right"));
wRollingStyle->addItem(tr("Top -> Bottom"));
wRollingStyle->setCurrentIndex(m_attr.scroll.effect);
connect(wRollingStyle, (void(QComboBox::*)(int))&QComboBox::currentIndexChanged, this, [this](int index) {
m_attr.scroll.effect = index;
updImg();
});
hBox->addWidget(wRollingStyle);
hBox->addStretch();
vBox->addLayout(hBox);
hBox = new QHBoxLayout();
label = new QLabel(tr("Scroll Speed"));
label->setMinimumWidth(100);
hBox->addWidget(label);
auto wRollingSpeed = new QSpinBox();
wRollingSpeed->setMaximum(9999);
wRollingSpeed->setValue(m_attr.scroll.effectSpeed);
connect(wRollingSpeed, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
m_attr.scroll.effectSpeed = value;
});
hBox->addWidget(wRollingSpeed);
hBox->addStretch();
vBox->addLayout(hBox);
vBox->addStretch();
}
auto wgtAttrStatic = new QWidget();
{
auto vBox = new QVBoxLayout(wgtAttrStatic);
vBox->setContentsMargins(2, 0, 2, 0);
vBox->setSpacing(3);
hBox = new QHBoxLayout();
auto label = new QLabel(tr("Play Duration"));
label->setMinimumWidth(100);
hBox->addWidget(label);
auto timeEdit = new QTimeEdit(QTime::fromMSecsSinceStartOfDay(m_attr.duration*1000));
timeEdit->setDisplayFormat("H:mm:ss");
timeEdit->setCurrentSectionIndex(2);
connect(timeEdit, &QTimeEdit::timeChanged, this, [this](const QTime &time) {
m_attr.duration = time.msecsSinceStartOfDay() / 1000;
});
hBox->addWidget(timeEdit);
hBox->addStretch();
vBox->addLayout(hBox);
vBox->addStretch();
}
auto stackBox = new QStackedLayout;
vBox->addLayout(stackBox);
stackBox->addWidget(wgtAttrFlip);
stackBox->addWidget(wgtAttrScroll);
stackBox->addWidget(wgtAttrStatic);
stackBox->setCurrentIndex(m_attr.playMode);
connect(fdPlayStyle, &QButtonGroup::idToggled, this, [this, stackBox, pageInfoWgt](int value, bool checked) {
if(! checked) return;
m_attr.playMode = value;
updImg();
stackBox->setCurrentIndex(value);
pageInfoWgt->setVisible(value==Flip);
});
connect(this, &EText::updPageCnt, wgtAttr, [this, fdPageCnt, fdPageIdx, fdPageDur, fdDur] {
fdPageCnt->setText(QString::number(mImgs.size()));
fdPageIdx->setRange(1, mImgs.size());
fdPageIdx->setValue(1);
fdDur->setTime(QTime::fromMSecsSinceStartOfDay(fdPageDur->time().msecsSinceStartOfDay() * mImgs.size()));
});
return wgtAttr;
}
bool EText::save(const QString &pageDir) {
QString idDir = pageDir + QString("/%1-%2-%3-%4-%5").arg(zValue()).arg((int)x()).arg((int)y()).arg((int)mWidth).arg((int)mHeight);
QDir().mkpath(idDir);
for(int i=0; i<mImgs.count(); i++) mImgs[i].save(idDir + QString("/text%1.png").arg(i));
return true;
}
QJsonObject EText::attrJson() const {
QJsonArray files;
for(int i=0; i<mImgs.count(); i++) files.append(QString("text%1.png").arg(i)); //上下滚动,生成一张纵向长图
QJsonObject obj;
addBaseAttr(obj);
obj["elementType"] = "Text";
obj["widget"] = QJsonObject{
{"text", m_attr.text},
{"align", (int) m_attr.align},
{"backColor", m_attr.backColor.name(QColor::HexArgb)},
{"files", files},
{"idDir", QString("%1-%2-%3-%4-%5").arg(zValue()).arg((int)x()).arg((int)y()).arg((int)mWidth).arg((int)mHeight)}
};
obj["play"] = QJsonObject{
{"style", m_attr.playMode},
{"turning", QJsonObject{
{"strEffect", m_attr.flip.effect},
{"iEffectTime", m_attr.flip.pageDuration},
{"iEffectSpeed", m_attr.flip.effectDuration}
}},
{"rolling", QJsonObject{
{"rollingStyle", m_attr.scroll.effect},
{"rollingSpeed", m_attr.scroll.effectSpeed},
{"headTailSpacing", m_attr.scroll.headTailSpacing},
{"playDuration", m_attr.scroll.duration}
}},
{"static", QJsonObject{{"playDuration", m_attr.duration}}}
};
return obj;
}
void EText::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
painter->save();
auto rect = innerRect();
if(m_attr.playMode!=EText::Flip) curIdx = 0;
else if(curIdx>=mImgs.size()) curIdx = mImgs.size() - 1;
else if(curIdx < 0) curIdx = 0;
if(m_attr.playMode==EText::Scroll) painter->drawImage(rect.x(), rect.y(), mImgs[0], 0, 0, rect.width(), rect.height());
else painter->drawImage(rect.x(), rect.y(), mImgs[curIdx]);
painter->restore();
EBase::paint(painter, option, widget);
}
void EText::updImg() {
auto innerRect = this->innerRect();
int width = innerRect.width();
int height = innerRect.height();
if(width<1 || height<1) return;
QTextDocument doc;
doc.setDocumentMargin(0);
QFont font;
font.setFamilies({"Arial","黑体"});
font.setPixelSize(16);
if(! gTextAntialiasing) font.setStyleStrategy(QFont::NoAntialias);
doc.setDefaultFont(font);
doc.setDefaultStyleSheet("body {color: #fff;}");
doc.setHtml(m_attr.text);
if(m_attr.playMode==EText::Flip) {
doc.setPageSize(innerRect.size());
auto pageHeight = height;
auto pageCnt = doc.pageCount();
QImage img(width, pageHeight*pageCnt, QImage::Format_ARGB32);
img.fill(m_attr.backColor);
{
QPainter painter(&img);
doc.drawContents(&painter);
}
if(pageCnt > 1) {
check:
for(int y=pageHeight-1; y<img.height(); y+=pageHeight) for(int x=0; x<width; x++) if(img.pixelColor(x, y)!=m_attr.backColor) {
pageHeight *= 2;
doc.setPageSize(QSizeF(width, pageHeight));
pageCnt = doc.pageCount();
img = QImage(width, pageHeight*pageCnt, QImage::Format_ARGB32);
img.fill(m_attr.backColor);
{
QPainter painter(&img);
doc.drawContents(&painter);
}
if(pageHeight/height <= 16) goto check;
else goto forend;
}
if(pageCnt > 1) {
for(int y=img.height()-pageHeight; y<img.height(); y++) for(int x=0; x<width; x++) if(img.pixelColor(x, y)!=m_attr.backColor) goto forend;
pageCnt--;
}
}
forend:
QRect rect(0, 0, width, pageHeight);
mImgs.clear();
for(int i=0; i<pageCnt; i++) {
auto pageImg = img.copy(rect);
alignV(pageImg, height);
mImgs.append(pageImg);
rect.translate(0, pageHeight);
}
emit updPageCnt();
} else if(m_attr.playMode==EText::Scroll) {//生成一张大图
if(m_attr.scroll.effect==0||m_attr.scroll.effect==2) width = qMax(width, ((int)doc.idealWidth()) + m_attr.scroll.headTailSpacing);
else {
doc.setTextWidth(width);
height = doc.size().height() + m_attr.scroll.headTailSpacing;
}
QImage img(width, height, QImage::Format_ARGB32);
img.fill(m_attr.backColor);
{
QPainter painter(&img);
doc.drawContents(&painter);
}
if(m_attr.scroll.effect==0||m_attr.scroll.effect==2) alignV(img);
mImgs.clear();
mImgs.append(img);
// if(img.width()<=8192) mImgs.append(img);
// else {
// for(int i=0; i<img.width(); i+=8192) {
// QImage imgpart(8192, height, QImage::Format_ARGB32);
// imgpart.fill(m_attr.backColor);
// {
// QPainter painter(&imgpart);
// painter.drawImage(-i, 0, img);
// }
// mImgs.append(imgpart);
// }
// }
} else if(m_attr.playMode==EText::Static) {//生成一张图
doc.setTextWidth(width);
QImage img(width, height, QImage::Format_ARGB32);
img.fill(m_attr.backColor);
{
QPainter painter(&img);
doc.drawContents(&painter);
}
alignV(img);
mImgs.clear();
mImgs.append(img);
}
update();
}
void EText::alignV(QImage &img, int cutHeight) {
int width = img.width(), height = img.height();
if(cutHeight==0) cutHeight = height;
if(m_attr.align & Qt::AlignTop) {
int ss = 0;
for(; ss<height; ss++) for(int i=0; i<width; i++) if(img.pixelColor(i, ss)!=m_attr.backColor) goto l12;
if(cutHeight==height) return;
ss = 0;
l12:
img = copy(img, 0, ss, width, cutHeight);
} else if(m_attr.align & Qt::AlignVCenter) {
int ss = 0, ee = height - 1;
for(; ss<height; ss++) for(int i=0; i<width; i++) if(img.pixelColor(i, ss)!=m_attr.backColor) goto l2;
if(cutHeight==height) return;
ss = 0;
goto l3;
l2:
for(; ee>ss; ee--) for(int i=0; i<width; i++) if(img.pixelColor(i, ee)!=m_attr.backColor) goto l3;
l3:
img = copy(img, 0, (ss+ee-cutHeight+2)/2, width, cutHeight);
} else if(m_attr.align & Qt::AlignBottom) {
int ee = height - 1;
for(; ee>=0; ee--) for(int i=0; i<width; i++) if(img.pixelColor(i, ee)!=m_attr.backColor) goto l32;
if(cutHeight==height) return;
ee = height - 1;
l32:
img = copy(img, 0, ee+1-cutHeight, width, cutHeight);
} else if(cutHeight != height) img = copy(img, 0, 0, width, cutHeight);
}
QImage EText::copy(QImage &img, int x, int y, int w, int h) {
QImage imgpart(w, h, QImage::Format_ARGB32);
imgpart.fill(m_attr.backColor);
{
QPainter painter(&imgpart);
painter.drawImage(-x, -y, img);
}
return imgpart;
}