qt/LedOK/player/playwin.cpp
2024-02-21 18:08:50 +08:00

271 lines
11 KiB
C++

#include "playwin.h"
#include "eledigiclock.h"
#include "eleanaclock.h"
#include "eleborder.h"
#include "elegif.h"
#include "elescroll.h"
#include "eletimer.h"
#include "elevideo.h"
#include "srccopy.h"
#include "posdlg.h"
#include <QFileInfo>
#include <QLabel>
#include <QMouseEvent>
#include <QMovie>
#include <QWebEngineView>
#include <QGuiApplication>
#include <QOpenGLWidget>
PlayWin* PlayWin::self = 0;
QPoint gPlayPos{0, 0};
PlayWin *PlayWin::newIns(int width, int height, QString dir, const JValue &aprog, QWidget *parent) {
if(! gPlayPos.isNull() && QGuiApplication::screenAt(QPoint(gPlayPos.x()+width/2, gPlayPos.y()+height/2))==0) gPlayPos = QPoint();
return new PlayWin(gPlayPos.x(), gPlayPos.y(), width, height, dir, aprog, parent);
}
PlayWin::PlayWin(int x, int y, int width, int height, QString dir, const JValue &aprog, QWidget *parent) : QWidget(parent) {
self = this;
setAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_QuitOnClose, false);
setWindowFlag(Qt::FramelessWindowHint);
setWindowFlag(Qt::WindowStaysOnTopHint);
setGeometry(x, y, width, height+1);
auto plt = palette();
plt.setColor(QPalette::Window, Qt::black);
setPalette(plt);
gl = new QOpenGLWidget(this);
gl->setGeometry(0, height, width, 1);
connect(gl, &QOpenGLWidget::frameSwapped, gl, (void(QOpenGLWidget::*)())&QOpenGLWidget::update);
auto task = aprog["task"];
auto jpages = task["items"];
auto partLengths = task["partLengths"];
auto isVertical = task["isVertical"].toBool();
QWidget *box = this;
if(partLengths.size() > 1) {
box = new QWidget(this);
auto width = task["width"].toInt();
auto height = task["height"].toInt();
box->setGeometry(0, 0, width, height);
auto mask = new QWidget(this);
mask->setAutoFillBackground(true);
auto pal = mask->palette();
pal.setColor(QPalette::Window, Qt::black);
mask->setPalette(pal);
auto len0 = partLengths[0].toInt();
isVertical ? mask->setGeometry(0, len0, width, height - len0) : mask->setGeometry(len0, 0, width - len0, height);
int x = 0, y = 0;
for(int i=1; i<(int)partLengths.size(); i++) {
auto part = new SrcCopy(this, box);
if(isVertical) {
y -= partLengths[i-1].toInt();
x += width;
part->setGeometry(x, y, width, partLengths[i].toInt() - y);
} else {
x -= partLengths[i-1].toInt();
y += height;
part->setGeometry(x, y, partLengths[i].toInt() - x, height);
}
}
}
for(auto &pageMap : jpages) {
auto _program = pageMap["_program"];
auto layers = _program["layers"];
if(layers.empty()) continue;
Page page;
page.repeatTimes = pageMap["repeatTimes"].toInt();
for(int ll=(int)layers.size()-1; ll>=0; ll--) {
Layer layer;
layer.isLoop = layers[ll]["repeat"].toBool();
auto sources = layers[ll]["sources"];
auto border = layers[ll]["border"];
EleBorder *bdEle = 0;
int bdWidth = 0, bdStart = 0xffff, bdEnd = 0;
if(! border.isNull()) {
bdEle = new EleBorder(dir+"/"+border["img"].toString(), border["eff"].toString(), border["speed"].toInt(), box);
bdWidth = bdEle->img.height();
}
Source src;
for(auto &source : sources) {
src.type = source["_type"].toString();
if(src.type.isEmpty()) continue;
auto timeSpan = source["timeSpan"].toInt()*1000;
if(timeSpan==0) continue;
auto x = source["left"].toInt()+bdWidth;
auto y = source["top"].toInt()+bdWidth;
auto w = source["width"].toInt()-bdWidth-bdWidth;
auto h = source["height"].toInt()-bdWidth-bdWidth;
bool notAudio = src.type!="Audio";
if((w<=0 || h<=0) && notAudio) continue;
src.startTime = source["playTime"].toInt()*1000;
if(bdStart > src.startTime) bdStart = src.startTime;
src.endTime = src.startTime + timeSpan;
if(bdEnd < src.endTime) bdEnd = src.endTime;
if(layer.dur < src.endTime) layer.dur = src.endTime;
if(notAudio) {
if(page.sDur < src.endTime) page.sDur = src.endTime;
} else if(page.audioDur < src.endTime) page.audioDur = src.endTime;
if(src.exitDur!=0) src.exitStart = timeSpan*60/1000 - src.exitDur;
auto id = source["id"].toString();
src.view = 0;
if(src.type=="Image") {
if(source["fileExt"].toString()=="gif") src.view = new EleGif(dir+"/"+id, box);
else {
auto lb = new QLabel(box);
lb->setPixmap(QPixmap(dir+"/"+id));
lb->setScaledContents(true);
src.view = lb;
}
} else if(src.type.startsWith("Environ")) {
auto arrayPics = source["arrayPics"];
for(int i=(int)arrayPics.size()-1; i>=0; i--) if(arrayPics[i]["name"].toString() == "previewTmp") {
if(source["bSingleScroll"].toBool()) src.view = new EleScroll(box, dir+"/" + arrayPics[i]["id"].toString(), 'l', source["iScrollSpeed"].toDouble());
else src.view = new EleScroll(box, dir+"/"+arrayPics[i]["id"].toString());
break;
}
} else if(src.type=="MultiPng" || src.type=="SplitText") {
auto imgs = source["arrayPics"];
if(! imgs.empty()) src.view = new EleScroll(box, dir+"/", imgs[0], w, h);
} else if(src.type=="DigitalClockNew") src.view = new EleDigiClock(dir+"/", source, box);
else if(src.type=="AnalogClock") src.view = new EleAnaClock(w, h, dir+"/"+id, source, box);
else if(src.type=="Video" || src.type=="Audio") {
auto video = new EleVideo(dir+"/"+id, box);
auto vol = source["vol"].toInt(100);
if(vol<100) video->player->setVol(vol/100.0);
src.view = video;
} else if(src.type=="WebURL") {
auto web = new QWebEngineView(box);
web->load(QUrl(source["url"].toString()));
src.view = web;
}
else if(src.type=="Timer") src.view = new EleTimer(source, box);
else continue;
if(src.view==0) continue;
src.view->setVisible(false);
if(w) src.view->setGeometry(x, y, w, h);
layer.srcs.push_back(src);
}
if(bdEle && ! sources.empty()) {
auto geometry = border["geometry"];
src.startTime = bdStart;
src.endTime = bdEnd;
src.view = bdEle;
src.view->setVisible(false);
src.view->setGeometry(geometry[0].toInt(), geometry[1].toInt(), geometry[2].toInt(), geometry[3].toInt());
layer.srcs.push_back(src);
}
if(! layer.srcs.empty()) page.layers.emplace_back(std::move(layer));
}
if(page.sDur==0) {
if(page.audioDur > 0) page.sDur = page.audioDur;
else continue;
}
page.tDur = page.sDur * page.repeatTimes;
for(auto layer=page.layers.begin(); layer<page.layers.end(); ++layer) {
for(auto src=layer->srcs.begin(); src<layer->srcs.end(); ++src) {
if(src->startTime >= page.sDur) {
if(layer->srcs.size() > 1) layer->srcs.erase(src--);
else {
page.layers.erase(layer--);
goto conti_layer;
}
} else if(src->endTime > page.sDur) src->endTime = page.sDur;
}
if(layer->dur > page.sDur) layer->dur = page.sDur;
if(layer->dur == page.sDur) layer->isLoop = false;
conti_layer:;
}
pages.emplace_back(std::move(page));
}
menu = new QMenu(this);
auto act = menu->addAction(tr("Move to Top Left"));
connect(act, &QAction::triggered, this, [this] {
move(0,0);
});
act = menu->addAction(tr("Set Position"));
connect(act, &QAction::triggered, this, [this] {
PosDlg dlg(this);
dlg.exec();
});
act = menu->addAction(tr("Close"));
connect(act, &QAction::triggered, this, [this] {
if(self==this) self = nullptr;
close();
});
setVisible(true);
if(pages.empty()) return;
pages[0].setMillis((std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() + 999)/1000*1000);
connect(gl, &QOpenGLWidget::frameSwapped, this, &PlayWin::doFrame, Qt::UniqueConnection);
}
void PlayWin::doFrame() {
if(! isVisible()) return;
auto milli = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
auto& lastPage = pages[curAva];
if(milli >= lastPage.endMilli) {
lastPage.hide();
if(curTimes < lastPage.repeatTimes) curTimes++;
else {
curTimes = 1;
curAva++;
if(curAva >= (int)pages.size()) {
curAva = 0;
auto isDiff = milli-lastPage.endMilli>=1000;
pages[curAva].setMillis(isDiff ? milli : lastPage.endMilli);
return;
}
}
pages[curAva].setMillis(lastPage.endMilli);
} else {
for(auto &layer : lastPage.layers) {
for(auto &src : layer.srcs) {
if(src.view->isVisible()) {
if(milli >= src.endMilli) src.hide();
else src.doEff();
} else if(milli < src.endMilli && milli >= src.startMilli) src.show();
}
if(milli >= layer.endMilli) {
layer.endMilli += layer.dur;
for(auto &src : layer.srcs) {
src.endMilli += layer.dur;
src.startMilli += layer.dur;
if(src.startTime > 0) src.hide();
else src.show();
}
}
}
}
}
void PlayWin::mousePressEvent(QMouseEvent *e) {
if(e->button() == Qt::LeftButton) {
mPressRel = pos() - e->globalPos();
}
}
void PlayWin::mouseReleaseEvent(QMouseEvent *e) {
if(e->button() == Qt::LeftButton) mPressRel.setX(INT_MAX);
}
void PlayWin::mouseMoveEvent(QMouseEvent *e) {
if(e->buttons() & Qt::LeftButton) {
if(mPressRel.x()==INT_MAX) return;
move(mPressRel + e->globalPos());
}
}
void PlayWin::leaveEvent(QEvent *) {
mPressRel.setX(INT_MAX);
}
void PlayWin::contextMenuEvent(QContextMenuEvent *event){
menu->exec(event->globalPos());
}
void PlayWin::closeEvent(QCloseEvent *) {
if(self==this) self = 0;
gPlayPos = pos();
}