抽离场景打开逻辑、添加编辑界面的左右拖动功能

This commit is contained in:
2026-07-16 11:04:12 +08:00
parent 570f359339
commit 808a38628e
10 changed files with 330 additions and 27 deletions
+188
View File
@@ -0,0 +1,188 @@
#include "PicSceneLoader.h"
#include "picscene.h"
#include "pictextitem.h"
#include "PicImageItem.h"
#include "PicDateItem.h"
#include "PicScheduleShiftItem.h"
#include "piccodeitem.h"
#include "PicCounterItem.h"
#include <QFile>
#include <QXmlStreamReader>
#include <QXmlStreamAttributes>
#include <QDebug>
#include <QImage>
#include <QPainter>
#include <QScopedPointer>
#include <cmath>
namespace {
PicTextItem* createSceneItem(SourceType sourceType)
{
switch (sourceType) {
case IMAGE:
return new PicImageItem();
case DATETIME:
return new PicDateItem();
case SCHEDULE_SHIFT:
return new PicScheduleShiftItem();
case CODE:
return new PicCodeItem();
case COUNTER:
return new PicCounterItem();
case TEXT:
case UNKNOWN:
default:
return new PicTextItem(nullptr, nullptr, sourceType);
}
}
SourceType sourceTypeFromAttrs(const QXmlStreamAttributes& attrs)
{
if (!attrs.hasAttribute("sourceType")) {
return SourceType::UNKNOWN;
}
bool ok = false;
int value = attrs.value("sourceType").toInt(&ok);
if (!ok) {
return SourceType::UNKNOWN;
}
if (value < SourceType::UNKNOWN || value > SourceType::COUNTER) {
return SourceType::UNKNOWN;
}
return static_cast<SourceType>(value);
}
bool parseVbFileElement(QXmlStreamReader& reader, PicScene* scene)
{
float posX = 0.0f;
float posY = 0.0f;
bool condition = false;
int catchStartValue = -1;
int catchValue = -1;
QXmlStreamAttributes itemAttrs;
QString htmlCData;
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
const QString elementName = reader.name().toString();
if (elementName == "pointer_x") {
posX = reader.readElementText().toDouble();
} else if (elementName == "pointer_y") {
posY = reader.readElementText().toDouble();
} else if (elementName == "Condition") {
condition = reader.readElementText().toInt() != 0;
} else if (elementName == "CatchStartValue") {
catchStartValue = reader.readElementText().toInt();
} else if (elementName == "CatchValue") {
catchValue = reader.readElementText().toInt();
} else if (elementName == "itemAttrs") {
itemAttrs = reader.attributes();
reader.skipCurrentElement();
} else if (elementName == "html_src") {
reader.skipCurrentElement();
} else {
reader.skipCurrentElement();
}
} else if (reader.isCDATA()) {
htmlCData += reader.text().toString();
} else if (token == QXmlStreamReader::EndElement && reader.name() == "VBfile") {
break;
}
}
SourceType sourceType = sourceTypeFromAttrs(itemAttrs);
PicTextItem* item = createSceneItem(sourceType);
if (!item) {
qWarning() << "PicSceneLoader: skip invalid VBfile item";
return true;
}
item->setAttrs(itemAttrs);
item->setPos(posX, posY);
item->SpecialConditions = condition;
item->CatchCnt1StartValue = catchStartValue;
item->CatchCnt1CurrValue = catchValue;
if (!htmlCData.isEmpty()) {
item->setHtml(htmlCData);
}
scene->addItem(item);
return true;
}
} // namespace
namespace PicSceneLoader {
PicScene* createSceneFromFile(const QString& xmlFilename)
{
QFile file(xmlFilename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "PicSceneLoader: failed to open" << xmlFilename << file.errorString();
return nullptr;
}
QXmlStreamReader reader(&file);
PicScene* scene = new PicScene();
while (!reader.atEnd()) {
reader.readNext();
if (reader.isStartElement() && reader.name() == "VBfiles") {
while (reader.readNextStartElement()) {
if (reader.name() == "VBfile") {
if (!parseVbFileElement(reader, scene)) {
delete scene;
return nullptr;
}
} else {
reader.skipCurrentElement();
}
}
}
}
if (reader.hasError()) {
qWarning() << "PicSceneLoader: XML parse error" << reader.errorString()
<< "at" << reader.lineNumber() << ":" << reader.columnNumber();
delete scene;
return nullptr;
}
return scene;
}
QImage previewSceneFromFile(const QString &xmlFilename)
{
QScopedPointer<PicScene> scene(createSceneFromFile(xmlFilename));
if (!scene) {
return QImage();
}
QRectF contentRect = scene->itemsBoundingRect();
if (!contentRect.isValid() || contentRect.isEmpty()) {
return QImage(1, 1, QImage::Format_ARGB32_Premultiplied);
}
QSize imageSize(qMax<int>(1, int(std::ceil(contentRect.width()))),
qMax<int>(1, int(std::ceil(contentRect.height()))));
QImage image(imageSize, QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
scene->render(&painter, QRectF(QPointF(0, 0), imageSize), contentRect);
painter.end();
return image;
}
} // namespace PicSceneLoader