523 lines
18 KiB
C++
523 lines
18 KiB
C++
#include "pagelistitem.h"
|
||
#include "cfg.h"
|
||
#include "tools.h"
|
||
#include "base/ffutil.h"
|
||
#include "program/wplanlist.h"
|
||
#include "base/lodateselector.h"
|
||
#include "program/ebase.h"
|
||
#include "program/etext.h"
|
||
#include "program/ephoto.h"
|
||
#include "program/evideo.h"
|
||
#include "program/eaudio.h"
|
||
#include "program/egif.h"
|
||
#include "program/edclock.h"
|
||
#include "program/eaclock.h"
|
||
#include "program/eenviron.h"
|
||
#include "program/eweb.h"
|
||
#include "program/etimer.h"
|
||
#include "program/emultiwin.h"
|
||
#include <QMessageBox>
|
||
#include <QJsonArray>
|
||
#include <QDir>
|
||
#include <QBoxLayout>
|
||
#include <QSpinBox>
|
||
#include <QLineEdit>
|
||
#include <QDateEdit>
|
||
|
||
class PageScene : public QGraphicsScene {
|
||
public:
|
||
PageScene(qreal x, qreal y, qreal width, qreal height, QObject *parent = nullptr) : QGraphicsScene(x, y, width, height, parent) {};
|
||
void drawBackground(QPainter *painter, const QRectF &rect) {
|
||
QGraphicsScene::drawBackground(painter, rect);
|
||
painter->fillRect(sceneRect(), Qt::black);
|
||
}
|
||
};
|
||
|
||
PageListItem::PageListItem(const QJsonObject &attr, const QString &pageDir) : mAttr(attr), mPageDir(pageDir) {
|
||
setSizeHint(QSize(0,80));
|
||
mScene = new PageScene(0, 0, gProgItem->mWidth, gProgItem->mHeight, this);
|
||
auto elements = mAttr["elements"].toArray();
|
||
foreach(auto ele, elements) {
|
||
QString type = ele["elementType"].toString();
|
||
EBase *element = 0;
|
||
if(type=="Text") element = new EText(ele.toObject());
|
||
else if(type=="Photo") element = EPhoto::create(ele.toObject(), this);
|
||
else if(type=="Gif") element = EGif::create(ele.toObject(), this);
|
||
else if(type=="Movie") element = EVideo::create(ele.toObject(), this);
|
||
else if(type=="Audio") element = EAudio::create(ele.toObject(), this);
|
||
else if(type=="DClock") element = new EDClock(ele.toObject());
|
||
else if(type=="AClock") element = new EAClock(ele.toObject());
|
||
else if(type=="Temp") element = new EEnviron(ele.toObject());
|
||
else if(type=="Web") element = new EWeb(ele.toObject());
|
||
else if(type=="Timer") element = new ETimer(ele.toObject());
|
||
else if(type=="Window") element = new EMultiWin(ele.toObject(), this);
|
||
if(element) mScene->addItem(element);
|
||
}
|
||
}
|
||
|
||
//更新页属性参数到page.json
|
||
void PageListItem::updateJson() {
|
||
if(mAttrWgt==0) return; //没有点开该页面进行编辑
|
||
QJsonArray elements;
|
||
auto items = mScene->items();
|
||
foreach(auto item, items) {
|
||
auto element = static_cast<EBase*>(item);
|
||
if(element->mMultiWin == nullptr) elements.append(element->attrJson());
|
||
}
|
||
mAttr.insert("elements", elements);
|
||
|
||
QJsonArray audios;
|
||
auto cnt = mAudiosList->count();
|
||
for(int i=0; i<cnt; i++) {
|
||
auto info = mAudiosList->item(i)->data(Qt::UserRole).value<AudioInfo>();
|
||
audios.append(QJsonObject{
|
||
{"dir", info.dir},
|
||
{"name", info.name},
|
||
{"dur", info.dur},
|
||
{"vol", info.vol}
|
||
});
|
||
}
|
||
mAttr.insert("audios", audios);
|
||
}
|
||
bool PageListItem::saveFiles() {
|
||
mPageDir = gProgItem->mProgDir + "/" + mAttr["name"].toString();
|
||
QDir pageQDir(mPageDir);
|
||
if(! pageQDir.exists() && ! pageQDir.mkpath(".")) return false;
|
||
|
||
QJsonArray elements;
|
||
auto items = mScene->items();
|
||
foreach(auto item, items) {
|
||
auto element = static_cast<EBase*>(item);
|
||
if(element->mMultiWin == nullptr && element->save(mPageDir)) elements.append(element->attrJson());
|
||
}
|
||
mAttr.insert("elements", elements);
|
||
if(mAttrWgt!=0) {
|
||
QJsonArray audios;
|
||
auto cnt = mAudiosList->count();
|
||
for(int i=0; i<cnt; i++) {
|
||
auto info = mAudiosList->item(i)->data(Qt::UserRole).value<AudioInfo>();
|
||
QString oldFile = info.dir + PAGEDEL_SUFFIX + "/" + info.name;
|
||
if(QFileInfo::exists(oldFile)) ;
|
||
else if(QFileInfo::exists(oldFile = info.dir + "/" + info.name)) ;
|
||
else continue;
|
||
QFile::copy(oldFile, mPageDir + "/" + info.name);
|
||
info.dir = mPageDir;
|
||
audios.append(QJsonObject{
|
||
{"dir", info.dir},
|
||
{"name", info.name},
|
||
{"dur", info.dur},
|
||
{"vol", info.vol}
|
||
});
|
||
}
|
||
mAttr.insert("audios", audios);
|
||
}
|
||
|
||
QFile file(mPageDir + "/page.json");
|
||
if(! file.open(QIODevice::WriteOnly)) {
|
||
QMessageBox::critical(gMainWin, "Write Error", mPageDir + "/page.json "+file.errorString());
|
||
return false;
|
||
}
|
||
file.write(QJsonDocument(mAttr).toJson());
|
||
file.close();
|
||
return true;
|
||
}
|
||
|
||
QWidget *PageListItem::itemWgt() {
|
||
auto wgtPage = new QWidget();
|
||
auto hBox = new QHBoxLayout(wgtPage);
|
||
mGraView = new QGraphicsView();
|
||
mGraView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||
mGraView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||
mGraView->setEnabled(false);
|
||
mGraView->setFrameShape(QFrame::NoFrame);
|
||
mGraView->setFixedSize(120, 60);
|
||
mGraView->setStyleSheet("QGraphicsView{background-color:transparent;}");
|
||
mGraView->setScene(mScene);
|
||
qreal scale = qMin(mGraView->width() / mScene->width(), mGraView->height() / mScene->height());
|
||
mGraView->scale(scale, scale);
|
||
hBox->addWidget(mGraView);
|
||
|
||
fdPlayTimes = new QLabel(QString::number(mAttr["repeat"].toInt()));
|
||
hBox->addWidget(fdPlayTimes);
|
||
|
||
hBox->addWidget(new QLabel(tr("times")));
|
||
hBox->addStretch();
|
||
return wgtPage;
|
||
}
|
||
|
||
QWidget *PageListItem::attrWgt() {
|
||
if(mAttrWgt!=0) return mAttrWgt;
|
||
mAttrWgt = new QWidget();
|
||
mAttrWgt->setStyleSheet(R"rrr(
|
||
QPushButton {
|
||
padding-left: 4px;
|
||
padding-right: 4px;
|
||
padding-top: 2px;
|
||
padding-bottom: 2px;
|
||
border-radius: 4px;
|
||
}
|
||
QPushButton:hover {
|
||
background-color: #dddddd;
|
||
}
|
||
|
||
QPushButton#bnAddPlan {
|
||
image: url(:/res/program/AddPlan.png);
|
||
width: 24;
|
||
height: 24;
|
||
}
|
||
QPushButton#bnClearPlan {
|
||
image: url(:/res/program/Clean.png);
|
||
width: 24;
|
||
height: 24;
|
||
}
|
||
QPushButton#bnDel {
|
||
image: url(:/res/program/Delete.png);
|
||
width: 18;
|
||
height: 18;
|
||
}
|
||
QPushButton#bnAddPlan:pressed,
|
||
QPushButton#bnClearPlan:pressed,
|
||
QPushButton#bnDel:pressed {
|
||
margin-top: 1px;
|
||
margin-left: 1px;
|
||
margin-bottom: -1px;
|
||
margin-right: -1px;
|
||
}
|
||
|
||
QPushButton[ssName="weeklySelector"] {
|
||
border: 1px solid #6A838F;
|
||
width: 24;
|
||
height: 24;
|
||
}
|
||
QPushButton[ssName="weeklySelector"]:checked {
|
||
background-color: #0099cc;
|
||
}
|
||
)rrr");
|
||
auto vBox = new QVBoxLayout(mAttrWgt);
|
||
vBox->setContentsMargins(6, 0, 6, 0);
|
||
vBox->setSpacing(4);
|
||
|
||
auto hBox = new QHBoxLayout();
|
||
auto lb1 = new QLabel(tr("Page name"));
|
||
lb1->setMinimumWidth(80);
|
||
hBox->addWidget(lb1);
|
||
|
||
auto fdPageName = new QLineEdit(mAttr["name"].toString());
|
||
connect(fdPageName, &QLineEdit::textEdited, this, [this, fdPageName](const QString &text) {
|
||
bool isDupli = false;
|
||
auto listWgt = listWidget();
|
||
if(nullptr != listWgt) {
|
||
int n = listWgt->count();
|
||
for(int i=0; i<n; i++) {
|
||
auto item = static_cast<PageListItem*>(listWgt->item(i));
|
||
if(text == item->mAttr["name"].toString()) {
|
||
isDupli = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if(isDupli) {
|
||
QString newName = tr("New") + QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz");
|
||
mAttr["name"] = newName;
|
||
fdPageName->setText(newName);
|
||
} else mAttr["name"] = text;
|
||
});
|
||
hBox->addWidget(fdPageName);
|
||
|
||
vBox->addLayout(hBox);
|
||
|
||
hBox = new QHBoxLayout();
|
||
lb1 = new QLabel(tr("Play times"));
|
||
lb1->setMinimumWidth(80);
|
||
hBox->addWidget(lb1);
|
||
|
||
auto fdPlayTimes = new QSpinBox();
|
||
fdPlayTimes->setRange(1, 9999);
|
||
fdPlayTimes->setValue(mAttr["repeat"].toInt());
|
||
connect(fdPlayTimes, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
|
||
mAttr["repeat"] = value;
|
||
this->fdPlayTimes->setText(QString::number(value));
|
||
});
|
||
hBox->addWidget(fdPlayTimes);
|
||
hBox->addSpacing(20);
|
||
|
||
auto fdLoop = new QCheckBox(tr("Sources Repeat"));
|
||
fdLoop->setChecked(mAttr["loop"].toBool());
|
||
connect(fdLoop, &QCheckBox::toggled, this, [this](bool checked) {
|
||
mAttr["loop"] = checked;
|
||
});
|
||
hBox->addWidget(fdLoop);
|
||
|
||
hBox->addStretch();
|
||
|
||
vBox->addLayout(hBox);
|
||
|
||
auto line = new QFrame();
|
||
line->setFrameShape(QFrame::HLine);
|
||
line->setFrameShadow(QFrame::Sunken);
|
||
vBox->addWidget(line);
|
||
|
||
hBox = new QHBoxLayout();
|
||
auto lb = new QLabel();
|
||
lb->setPixmap(QPixmap(":/res/program/Audio.png").scaledToHeight(24, Qt::SmoothTransformation));
|
||
hBox->addWidget(lb);
|
||
hBox->addWidget(new QLabel(tr("Audios")));
|
||
hBox->addStretch();
|
||
|
||
hBox->addWidget(new QLabel(tr("Total Dur")));
|
||
auto fdTtlDur = new QLabel("0");
|
||
hBox->addWidget(fdTtlDur);
|
||
hBox->addWidget(new QLabel(tr("s")));
|
||
hBox->addStretch();
|
||
|
||
auto btnAdd = new QPushButton();
|
||
btnAdd->setIcon(QIcon(":/res/program/Add.png"));
|
||
btnAdd->setProperty("style","multiTool");
|
||
|
||
mAudiosList = new QListWidget();
|
||
connect(btnAdd, &QPushButton::clicked, this, [this, fdTtlDur] {
|
||
auto files = QFileDialog::getOpenFileNames(gMainWin, tr("Select File"), gFileHome, EAudio::filters());
|
||
int durs = fdTtlDur->text().toInt();
|
||
for(int i=0; i<files.count(); i++) {
|
||
int64_t dur;
|
||
QString err = audioInfo(files[i].toUtf8(), &dur);
|
||
if(! err.isEmpty()) {
|
||
QMessageBox::critical(gMainWin, "Audio Error", err+"\n"+files[i]);
|
||
continue;
|
||
}
|
||
QFileInfo fInfo(files[i]);
|
||
AudioInfo info{fInfo.absolutePath(), fInfo.fileName(), (int)(dur/1000000)};
|
||
auto item = new QListWidgetItem(QIcon(":/res/program/Audio.png"), info.name);
|
||
item->setData(Qt::UserRole, QVariant::fromValue(info));
|
||
mAudiosList->addItem(item);
|
||
if(i == files.count()-1) {
|
||
mAudiosList->setCurrentItem(item);
|
||
gFileHome = fInfo.absolutePath();
|
||
}
|
||
durs += info.dur;
|
||
mAudiosList->addItem(item);
|
||
}
|
||
fdTtlDur->setText(QString::number(durs));
|
||
});
|
||
hBox->addWidget(btnAdd);
|
||
|
||
auto btnDel = new QPushButton();
|
||
btnDel->setIcon(QIcon(":/res/program/Delete.png"));
|
||
btnDel->setProperty("style","multiTool");
|
||
connect(btnDel, &QPushButton::clicked, this, [this, fdTtlDur] {
|
||
auto row = mAudiosList->currentRow();
|
||
if(row < 0) return;
|
||
int durs = fdTtlDur->text().toInt();
|
||
auto item = mAudiosList->takeItem(row);
|
||
auto info = static_cast<AudioInfo>(item->data(Qt::UserRole).value<AudioInfo>());
|
||
durs -= info.dur;
|
||
delete item;
|
||
fdTtlDur->setText(QString::number(durs));
|
||
});
|
||
hBox->addWidget(btnDel);
|
||
|
||
auto btnGoUp = new QPushButton();
|
||
btnGoUp->setIcon(QIcon(":/res/program/GoUp.png"));
|
||
btnGoUp->setProperty("style","multiTool");
|
||
connect(btnGoUp, &QPushButton::clicked, this, [this] {
|
||
int row = mAudiosList->currentRow();
|
||
if(row < 1) return;
|
||
mAudiosList->insertItem(row-1, mAudiosList->takeItem(row));
|
||
mAudiosList->setCurrentRow(row-1);
|
||
});
|
||
hBox->addWidget(btnGoUp);
|
||
|
||
auto btnGoDown = new QPushButton();
|
||
btnGoDown->setIcon(QIcon(":/res/program/GoDown.png"));
|
||
btnGoDown->setProperty("style","multiTool");
|
||
connect(btnGoDown, &QPushButton::clicked, this, [this] {
|
||
int row = mAudiosList->currentRow();
|
||
if(row < 0 || row > mAudiosList->count() - 2) return;
|
||
mAudiosList->insertItem(row+1, mAudiosList->takeItem(row));
|
||
mAudiosList->setCurrentRow(row+1);
|
||
});
|
||
hBox->addWidget(btnGoDown);
|
||
|
||
vBox->addLayout(hBox);
|
||
|
||
mAudiosList->setMinimumHeight(120);
|
||
mAudiosList->setIconSize(QSize(20, 20));
|
||
vBox->addWidget(mAudiosList, 1);
|
||
|
||
auto audios = mAttr["audios"].toArray();
|
||
int durs = 0;
|
||
foreach(auto audio, audios) {
|
||
AudioInfo info{audio["dir"].toString(), audio["name"].toString(), audio["dur"].toInt(), audio["vol"].toInt()};
|
||
if(info.dir.isEmpty() || info.name.isEmpty() || info.dur==0) continue;
|
||
auto item = new QListWidgetItem(QIcon(":/res/program/Audio.png"), info.name);
|
||
item->setData(Qt::UserRole, QVariant::fromValue(info));
|
||
durs += info.dur;
|
||
mAudiosList->addItem(item);
|
||
}
|
||
fdTtlDur->setText(QString::number(durs));
|
||
|
||
auto wgtAudioInfo = new QWidget();
|
||
wgtAudioInfo->hide();
|
||
hBox = new QHBoxLayout(wgtAudioInfo);
|
||
hBox->setContentsMargins(0,0,0,0);
|
||
hBox->setSpacing(2);
|
||
|
||
hBox->addWidget(new QLabel(tr("Duration")));
|
||
hBox->addSpacing(4);
|
||
|
||
auto fdAudioDur = new QLabel("0");
|
||
hBox->addWidget(fdAudioDur);
|
||
hBox->addWidget(new QLabel(tr("s")));
|
||
|
||
hBox->addStretch();
|
||
hBox->addWidget(new QLabel(tr("Vol")));
|
||
|
||
auto fdVol = new QSlider(Qt::Horizontal);
|
||
fdVol->setMaximum(100);
|
||
fdVol->setMinimumWidth(120);
|
||
hBox->addWidget(fdVol);
|
||
|
||
auto fdAudioVol = new QLabel("0");
|
||
fdAudioVol->setAlignment(Qt::AlignRight);
|
||
fdAudioVol->setFixedWidth(38);
|
||
hBox->addWidget(fdAudioVol);
|
||
|
||
vBox->addWidget(wgtAudioInfo);
|
||
|
||
connect(fdVol, &QSlider::valueChanged, this, [this, fdAudioVol](int value) {
|
||
fdAudioVol->setText(QString::number(value)+"%");
|
||
auto item = mAudiosList->currentItem();
|
||
if(item==nullptr) return;
|
||
auto info = static_cast<AudioInfo>(item->data(Qt::UserRole).value<AudioInfo>());
|
||
info.vol = value;
|
||
item->setData(Qt::UserRole, QVariant::fromValue(info));
|
||
});
|
||
connect(mAudiosList, &QListWidget::currentItemChanged, this, [fdAudioDur, wgtAudioInfo, fdVol, fdAudioVol](QListWidgetItem *current, QListWidgetItem *) {
|
||
if(current==nullptr) {
|
||
wgtAudioInfo->hide();
|
||
return;
|
||
}
|
||
wgtAudioInfo->show();
|
||
auto info = static_cast<AudioInfo>(current->data(Qt::UserRole).value<AudioInfo>());
|
||
fdAudioDur->setText(QString::number(info.dur));
|
||
fdVol->setValue(info.vol);
|
||
fdAudioVol->setText(QString::number(info.vol)+"%");
|
||
});
|
||
|
||
line = new QFrame();
|
||
line->setFrameShape(QFrame::HLine);
|
||
line->setFrameShadow(QFrame::Sunken);
|
||
vBox->addWidget(line);
|
||
|
||
QJsonValue validDate = mAttr["validDate"];
|
||
|
||
auto wValidDate = new QCheckBox(tr("Valid Date"));
|
||
bool isDateValid = validDate["isValid"].toBool();
|
||
wValidDate->setChecked(isDateValid);
|
||
vBox->addWidget(wValidDate);
|
||
|
||
hBox = new QHBoxLayout();
|
||
|
||
auto fdStart = new QDateEdit();
|
||
fdStart->setDisplayFormat("yyyy-MM-dd");
|
||
fdStart->setEnabled(isDateValid);
|
||
fdStart->setDate(QDate::fromString(validDate["start"].toString(), "yyyy-MM-dd"));
|
||
hBox->addWidget(fdStart);
|
||
|
||
auto bnDateStart = new LoDateSelector();
|
||
bnDateStart->setEnabled(isDateValid);
|
||
connect(bnDateStart, &LoDateSelector::sDateSelected, fdStart, &QDateEdit::setDate);
|
||
hBox->addWidget(bnDateStart);
|
||
|
||
hBox->addWidget(new QLabel("~"));
|
||
|
||
auto fdEnd = new QDateEdit();
|
||
fdEnd->setDisplayFormat("yyyy-MM-dd");
|
||
fdEnd->setEnabled(isDateValid);
|
||
fdEnd->setDate(QDate::fromString(validDate["end"].toString(), "yyyy-MM-dd"));
|
||
connect(fdStart, &QDateEdit::dateChanged, this, [this, wValidDate, fdStart, fdEnd](const QDate &date) {
|
||
auto end = fdEnd->date();
|
||
if(! date.isValid() || date > end) {
|
||
QMessageBox::warning(gMainWin, tr("Warning"), tr("Start Time can't be later than End Time"));
|
||
fdStart->setDate(end);
|
||
}
|
||
mAttr["validDate"] = QJsonObject{
|
||
{"isValid", wValidDate->isChecked()},
|
||
{"start", fdStart->date().toString("yyyy-MM-dd")},
|
||
{"end", end.toString("yyyy-MM-dd")}
|
||
};
|
||
});
|
||
connect(fdEnd, &QDateEdit::dateChanged, this, [this, wValidDate, fdStart, fdEnd](const QDate &date) {
|
||
QDate start = fdStart->date();
|
||
if(! date.isValid() || start > date) {
|
||
QMessageBox::warning(gMainWin, tr("Warning"), tr("End Time can't be earlier than Start Time"));
|
||
fdEnd->setDate(start);
|
||
}
|
||
mAttr["validDate"] = QJsonObject{
|
||
{"isValid", wValidDate->isChecked()},
|
||
{"start", start.toString("yyyy-MM-dd")},
|
||
{"end", fdEnd->date().toString("yyyy-MM-dd")}
|
||
};
|
||
});
|
||
hBox->addWidget(fdEnd);
|
||
|
||
auto bnDateEnd = new LoDateSelector();
|
||
bnDateEnd->setEnabled(isDateValid);
|
||
connect(bnDateEnd, &LoDateSelector::sDateSelected, fdEnd, &QDateEdit::setDate);
|
||
hBox->addWidget(bnDateEnd);
|
||
|
||
hBox->addStretch();
|
||
|
||
connect(wValidDate, &QCheckBox::toggled, this, [this, fdStart, fdEnd, bnDateStart, bnDateEnd](bool checked) {
|
||
fdStart->setEnabled(checked);
|
||
fdEnd->setEnabled(checked);
|
||
bnDateStart->setEnabled(checked);
|
||
bnDateEnd->setEnabled(checked);
|
||
mAttr["validDate"] = QJsonObject{
|
||
{"isValid", checked},
|
||
{"start", fdStart->date().toString("yyyy-MM-dd")},
|
||
{"end", fdEnd->date().toString("yyyy-MM-dd")}
|
||
};
|
||
});
|
||
|
||
vBox->addLayout(hBox);
|
||
|
||
line = new QFrame();
|
||
line->setFrameShape(QFrame::HLine);
|
||
line->setFrameShadow(QFrame::Sunken);
|
||
vBox->addWidget(line);
|
||
|
||
hBox = new QHBoxLayout();
|
||
hBox->setSpacing(12);
|
||
hBox->addWidget(new QLabel(tr("Plan")));
|
||
|
||
hBox->addStretch();
|
||
|
||
auto bnAddPlan = new QPushButton();
|
||
bnAddPlan->setObjectName("bnAddPlan");
|
||
hBox->addWidget(bnAddPlan);
|
||
|
||
auto bnClearPlan = new QPushButton();
|
||
bnClearPlan->setObjectName("bnClearPlan");
|
||
hBox->addWidget(bnClearPlan);
|
||
|
||
vBox->addLayout(hBox);
|
||
|
||
auto wPlans = new wPlanList();
|
||
wPlans->setStyleSheet(R"rrr(
|
||
QListWidget::item {
|
||
height: 100;
|
||
border-top: 1px solid #6A838F;
|
||
margin-right: 9px;
|
||
})rrr");
|
||
|
||
wPlans->onRestorePlan(mAttr["plans"].toArray());
|
||
connect(bnAddPlan, &QPushButton::clicked, wPlans, &wPlanList::onAddPlan);
|
||
connect(bnClearPlan, &QPushButton::clicked, wPlans, &wPlanList::clear);
|
||
connect(wPlans, &QListWidget::itemChanged, this, [this, wPlans] {
|
||
mAttr["plans"] = wPlans->plansJson();
|
||
});
|
||
vBox->addWidget(wPlans, 2);
|
||
return mAttrWgt;
|
||
}
|