图元预览改为懒加载;添加帧缓存;修改图元预览渲染机制;固定渲染倍率*

dev-wuyize
karlis 2023-03-22 19:58:17 +08:00
parent 7e0e07292f
commit beee94ebe0
11 changed files with 121 additions and 44 deletions

View File

@ -84,7 +84,7 @@ void EditorWidget::initFileMenu()
auto* item = dynamic_cast<EditorWidgetItem*>(this->tabWidget->currentWidget()); auto* item = dynamic_cast<EditorWidgetItem*>(this->tabWidget->currentWidget());
if (item != nullptr) if (item != nullptr)
{ {
//item->save(); item->save();
} }
}); });
connect(actionSaveAs, &QAction::triggered, this, [this] { connect(actionSaveAs, &QAction::triggered, this, [this] {

View File

@ -25,9 +25,9 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
qDebug() << elementInfoDisplayWidget; qDebug() << elementInfoDisplayWidget;
auto centralRefresh = [this]() { auto centralRefresh = [this]() {
layerInfoDisplayWidget->refresh(); layerInfoDisplayWidget->refresh();
elementInfoDisplayWidget->refresh();
treeWidget->refresh(); treeWidget->refresh();
previewWindow->refresh(); previewWindow->refresh();
elementInfoDisplayWidget->lazyRefresh();
}; };
connect(previewWindow, &PreviewWindow::triggerCentralRefresh, centralRefresh); connect(previewWindow, &PreviewWindow::triggerCentralRefresh, centralRefresh);
connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh); connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh);

View File

@ -4,6 +4,7 @@
#include <QFileDialog> #include <QFileDialog>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QMessagebox> #include <QMessagebox>
#include <QTimer>
ElementPoolWidget::ElementPoolWidget(QWidget* parent) ElementPoolWidget::ElementPoolWidget(QWidget* parent)
: QWidget(parent) : QWidget(parent)
@ -38,10 +39,15 @@ void ElementPoolWidget::setElementList(std::vector<GraphicElement*> elements) {
pictureList->clear(); pictureList->clear();
this->elements = elements; this->elements = elements;
for (int index = 0; index < elements.size(); index++) { for (int index = 0; index < elements.size(); index++) {
QListWidgetItem* pItem = new QListWidgetItem( QListWidgetItem* pItem = new QListWidgetItem(elements[index]->name);
elements[index]->getPreview(QSize(iconWidth - 25, iconHeight - 25)), QPainter* painter = new QPainter();
elements[index]->name); QImage* image = new QImage(QSize(iconWidth - 12, iconHeight - 12), QImage::Format_ARGB32);
image->fill(Qt::transparent);
pItem->setIcon(QIcon(QPixmap::fromImage(*image)));
pItem->setSizeHint(QSize(iconWidth, iconHeight)); pItem->setSizeHint(QSize(iconWidth, iconHeight));
painter->begin(image);
elements[index]->paintPreview(painter);
painter->end();
pictureList->insertItem(index, pItem); pictureList->insertItem(index, pItem);
} }
if(elements.size() > 0) if(elements.size() > 0)
@ -66,15 +72,47 @@ void ElementPoolWidget::setElementManager(ElementManager* element)
this->setElementList(this->elementManager->elements); this->setElementList(this->elementManager->elements);
} }
void ElementPoolWidget::lazyRefresh()
{
if (!refreshWait) {
refreshWait = true;
QTimer::singleShot(1000, this, SLOT(refresh()));
}
}
void ElementPoolWidget::refresh() { void ElementPoolWidget::refresh() {
this->setElementList(this->elementManager->elements); refreshWait = false;
// update(); if (elementManager != nullptr)
{
for (int i = 0; i < elements.size(); i++)
{
QListWidgetItem* pItem = pictureList->item(i);
if (pItem == nullptr)
{
pItem = new QListWidgetItem(elements[i]->name);
pictureList->insertItem(i, pItem);
}
QPainter* painter = new QPainter();
QImage* image = new QImage(QSize(iconWidth - 12, iconHeight - 12), QImage::Format_ARGB32);
image->fill(Qt::transparent);
painter->begin(image);
elements[i]->paintPreview(painter);
painter->end();
pItem->setIcon(QIcon(QPixmap::fromImage(*image)));
pItem->setData(Qt::UserRole, QVariant::fromValue(image));
pItem->setSizeHint(QSize(iconWidth, iconHeight));
pictureList->insertItem(i, pItem);
}
}
} }
void ElementPoolWidget::refreshPicture(GraphicElement* element) { void ElementPoolWidget::refreshPicture(GraphicElement* element) {
for (int i = 0; i < elements.size(); i++) { for (int i = 0; i < elements.size(); i++) {
if (element == elements[i]) { if (element == elements[i]) {
pictureList->item(i)->setIcon(elements[i]->getPreview(QSize(iconWidth - 25, iconHeight - 25))); QPainter* painter = new QPainter();
painter->begin(pictureList->item(i)->data(Qt::UserRole).value<QImage*>());
elements[i]->paintPreview(painter);
painter->end();
// update(); // update();
return; return;
} }
@ -84,7 +122,10 @@ void ElementPoolWidget::refreshPicture(GraphicElement* element) {
void ElementPoolWidget::refreshPictureByIndex(int index) { void ElementPoolWidget::refreshPictureByIndex(int index) {
if (index >= 0 && index < elements.size()) if (index >= 0 && index < elements.size())
{ {
pictureList->item(index)->setIcon(elements[index]->getPreview(QSize(iconWidth - 25, iconHeight - 25))); QPainter* painter = new QPainter();
painter->begin(pictureList->item(index)->data(Qt::UserRole).value<QImage*>());
elements[index]->paintPreview(painter);
painter->end();
// update(); // update();
} }
} }
@ -118,7 +159,6 @@ void ElementPoolWidget::popMenu(const QPoint& pos)
}); });
menu->addAction(QString::fromLocal8Bit("ɾ³ý"), this, [this, currentElement]() { menu->addAction(QString::fromLocal8Bit("ɾ³ý"), this, [this, currentElement]() {
this->elementManager->removeElement(currentElement); this->elementManager->removeElement(currentElement);
emit triggerCentralRefresh();
}); });
menu->actions().last()->setDisabled(currentElement->referencedCount > 0); menu->actions().last()->setDisabled(currentElement->referencedCount > 0);
} }

View File

@ -14,6 +14,7 @@ private:
QListWidget* pictureList; QListWidget* pictureList;
int iconWidth, iconHeight; int iconWidth, iconHeight;
ElementManager* elementManager; ElementManager* elementManager;
bool refreshWait = false;
public: public:
int currentIndex = -1; int currentIndex = -1;
@ -22,6 +23,7 @@ public:
void setElementManager(ElementManager* element); void setElementManager(ElementManager* element);
~ElementPoolWidget(); ~ElementPoolWidget();
void enableEdit(); void enableEdit();
void lazyRefresh();
signals: signals:
void elementSelected(GraphicElement* element); void elementSelected(GraphicElement* element);

View File

@ -45,7 +45,6 @@ void GroupElement::setSourceLayer(FolderLayerWrapper* sourceLayer)
PixelPath GroupElement::getPaintObject() const PixelPath GroupElement::getPaintObject() const
{ {
if (sourceLayer != nullptr) { if (sourceLayer != nullptr) {
sourceLayer->refresh();
return sourceLayer->getCache(); return sourceLayer->getCache();
} }
else else
@ -113,8 +112,9 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const LayerSt
maxScale = std::max(fabs(transform.m11() / cos(angle)), fabs(transform.m22() / cos(angle))); maxScale = std::max(fabs(transform.m11() / cos(angle)), fabs(transform.m22() / cos(angle)));
else else
maxScale = std::max(fabs(transform.m12() / sin(angle)), fabs(transform.m21() / sin(angle))); maxScale = std::max(fabs(transform.m12() / sin(angle)), fabs(transform.m21() / sin(angle)));
double pixelRatio = maxScale * QGuiApplication::primaryScreen()->devicePixelRatio(); //double pixelRatio = maxScale * QGuiApplication::primaryScreen()->devicePixelRatio();
if (painterPath == painterPathPrev && styles.getHash() == stylesHashValue && pixelRatio == pixelRatioPrev) double pixelRatio = 5;
if (painterPath == painterPathPrev && styles.getHash() == stylesHashValue && fabs(pixelRatio - pixelRatioPrev) < 1e-3)
{ {
transform.translate(movPrev.x(), movPrev.y()); transform.translate(movPrev.x(), movPrev.y());
painter->setTransform(transform.scale(1 / pixelRatio, 1 / pixelRatio)); painter->setTransform(transform.scale(1 / pixelRatio, 1 / pixelRatio));
@ -153,31 +153,26 @@ bool GroupElement::isClosed() const
} }
QPixmap SimpleElement::getPreview(QSize size) void SimpleElement::paintPreview(QPainter* painter)
{ {
QPixmap result(size + QSize(5, 5)); painter->save();
QPainter painter(&result); painter->setWindow(painterPath.boundingRect().x() - 5, painterPath.boundingRect().y() - 5, (painterPath.boundingRect().width() + 10) * QGuiApplication::primaryScreen()->devicePixelRatio(), (painterPath.boundingRect().height() + 10) * QGuiApplication::primaryScreen()->devicePixelRatio());
painter.setRenderHint(QPainter::Antialiasing); painter->drawPath(painterPath);
painter.setRenderHint(QPainter::SmoothPixmapTransform); painter->restore();
painter.scale(size.width() / painterPath.boundingRect().width(), size.height() / painterPath.boundingRect().height());
painter.drawPath(painterPath);
return result;
} }
QPixmap GroupElement::getPreview(QSize size) void GroupElement::paintPreview(QPainter* painter)
{ {
painter->save();
auto cache = sourceLayer->getCache(); auto cache = sourceLayer->getCache();
QPixmap result(QSize(1024, 1024)); painter->setRenderHint(QPainter::Antialiasing, true);
QPainter painter(&result); painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.setRenderHint(QPainter::Antialiasing); painter->setWindow(cache.getBoundingRect().toRect().x() - 5, cache.getBoundingRect().toRect().y() - 5, (cache.getBoundingRect().toRect().width() + 10) * QGuiApplication::primaryScreen()->devicePixelRatio(), (cache.getBoundingRect().toRect().height() + 10) * QGuiApplication::primaryScreen()->devicePixelRatio());
painter.setRenderHint(QPainter::SmoothPixmapTransform); //painter->translate(-cache.getBoundingRect().toRect().x() - 5, -cache.getBoundingRect().toRect().y() - 5);
sourceLayer->paint(&painter, QTransform(), true); //double maxScale = std::max(cache.getBoundingRect().toRect().width() + 10, cache.getBoundingRect().toRect().height() + 10) * QGuiApplication::primaryScreen()->devicePixelRatio();
painter.end(); //painter->scale(1 / maxScale, 1/ maxScale);
QRect rect(cache.getBoundingRect().toRect()); sourceLayer->paint(painter, QTransform(), true);
rect.setTopLeft(rect.topLeft() - QPoint(5, 5)); painter->restore();
rect.setBottomRight(rect.bottomRight() + QPoint(5, 5));
result = result.copy(rect);
return result.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
} }
void GroupElement::collectReachable(std::set<LayerWrapper*>& set) const void GroupElement::collectReachable(std::set<LayerWrapper*>& set) const

View File

@ -20,6 +20,7 @@ class ComposedPainterPath;
class GraphicElement class GraphicElement
{ {
public: public:
bool needRefresh = true;
size_t referencedCount = 0; size_t referencedCount = 0;
Renderer::ElementRenderer *renderer; Renderer::ElementRenderer *renderer;
QString name = ""; QString name = "";
@ -35,7 +36,7 @@ public:
virtual PixelPath getPaintObject(const LayerStyleContainer& styles) const = 0; virtual PixelPath getPaintObject(const LayerStyleContainer& styles) const = 0;
virtual void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) = 0; virtual void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) = 0;
virtual bool isClosed() const = 0; virtual bool isClosed() const = 0;
virtual QPixmap getPreview(QSize size) = 0; virtual void paintPreview(QPainter* painter) = 0;
}; };
@ -59,7 +60,7 @@ public:
PixelPath getPaintObject(const LayerStyleContainer& styles) const override; PixelPath getPaintObject(const LayerStyleContainer& styles) const override;
void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override;
bool isClosed() const override; bool isClosed() const override;
QPixmap getPreview(QSize size) override; void paintPreview(QPainter* painter) override;
}; };
class GroupElement : public GraphicElement class GroupElement : public GraphicElement
@ -77,10 +78,12 @@ public:
void setSourceLayer(FolderLayerWrapper* sourceLayer); void setSourceLayer(FolderLayerWrapper* sourceLayer);
void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override;
bool isClosed() const override; bool isClosed() const override;
QPixmap getPreview(QSize size) override; void paintPreview(QPainter* painter) override;
void collectReachable(std::set<LayerWrapper*>& set) const; void collectReachable(std::set<LayerWrapper*>& set) const;
}; };
Q_DECLARE_METATYPE(GraphicElement*)
//******************************** BitmapPath ********************************// //******************************** BitmapPath ********************************//
//using std::vector; //using std::vector;

View File

@ -14,6 +14,7 @@ LayerWrapper *LayerManager::getRoot() const
void LayerManager::paint(QPainter *painter, QSize size,LayerWrapper* selecetedLayer) const void LayerManager::paint(QPainter *painter, QSize size,LayerWrapper* selecetedLayer) const
{ {
painter->save(); painter->save();
root->markNeedRefresh();
root->getCache(); root->getCache();
root->paint(painter); root->paint(painter);
painter->restore(); painter->restore();

View File

@ -25,10 +25,10 @@ FolderLayerWrapper*LayerWrapper::getParent() const
PixelPath LayerWrapper::getCache(LayerWrapper* selectedLayer) PixelPath LayerWrapper::getCache(LayerWrapper* selectedLayer)
{ {
this->refresh(selectedLayer); if (needRefresh)
if (selectedLayer == this)
{ {
this->cache.highLight(); this->refresh(selectedLayer);
needRefresh = false;
} }
return cache; return cache;
} }
@ -461,3 +461,15 @@ void LayerWrapper::paintVisualBounding(QPainter* painter) const
painter->drawRect(cache.getBoundingRect()); painter->drawRect(cache.getBoundingRect());
painter->restore(); painter->restore();
} }
void LayerWrapper::markNeedRefresh()
{
this->needRefresh = true;
}
void FolderLayerWrapper::markNeedRefresh()
{
LayerWrapper::markNeedRefresh();
for (auto& child : children)
child->markNeedRefresh();
}

View File

@ -35,6 +35,7 @@ class LayerWrapper
PixelPath cache; PixelPath cache;
public: public:
bool needRefresh = true;
QTreeWidgetItem* qTreeWidgetItem; QTreeWidgetItem* qTreeWidgetItem;
bool selected; bool selected;
bool hidden; bool hidden;
@ -77,6 +78,7 @@ class LayerWrapper
virtual bool referencingGroupElement() const; virtual bool referencingGroupElement() const;
virtual void paintVisualBounding(QPainter* painter) const; virtual void paintVisualBounding(QPainter* painter) const;
bool canApplyStyles() const; bool canApplyStyles() const;
virtual void markNeedRefresh();
}; };
class FolderLayerWrapper : public LayerWrapper class FolderLayerWrapper : public LayerWrapper
@ -104,6 +106,7 @@ class FolderLayerWrapper : public LayerWrapper
void refreshTreeItem() override; void refreshTreeItem() override;
size_t referencedCount(bool excludeSelf = false) const override; size_t referencedCount(bool excludeSelf = false) const override;
bool deleteable(bool excludeSubTree = false) const override; bool deleteable(bool excludeSubTree = false) const override;
void markNeedRefresh() override;
}; };
class LeafLayerWrapper : public LayerWrapper class LeafLayerWrapper : public LayerWrapper

View File

@ -21,37 +21,51 @@ InfoDisplayWidget::InfoDisplayWidget(QWidget* parent) :QWidget(parent)
ui.rotation->setLabel(("旋转角度")); ui.rotation->setLabel(("旋转角度"));
ui.scaleX->setLabel(("水平缩放")); ui.scaleX->setLabel(("水平缩放"));
ui.scaleY->setLabel(("垂直缩放")); ui.scaleY->setLabel(("垂直缩放"));
ui.rotation->setValidator(new QIntValidator(-10000, 10000, this)); ui.rotation->setValidator(new QDoubleValidator(-10000, 10000, 6, this));
ui.styleList->setDisabled(true); ui.styleList->setDisabled(true);
connect(ui.rotation, &QLineEdit::textChanged, [=](QString content) { connect(ui.rotation, &QLineEdit::textChanged, [=](QString content) {
if (fabs(content.toDouble() - this->displayLayer->property.rotation) < 1e-6)
return;
this->displayLayer->property.rotation = content.toDouble(); this->displayLayer->property.rotation = content.toDouble();
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
ui.offsetX->setValidator(new QIntValidator(-10000, 10000, this)); ui.offsetX->setValidator(new QDoubleValidator(-10000, 10000, 2, this));
connect(ui.offsetX, &QLineEdit::textChanged, [=](QString content) { connect(ui.offsetX, &QLineEdit::textChanged, [=](QString content) {
if (fabs(content.toDouble() - this->displayLayer->property.offset.x()) < 1e-6)
return;
this->displayLayer->property.offset = { content.toDouble(), this->displayLayer->property.offset.y() }; this->displayLayer->property.offset = { content.toDouble(), this->displayLayer->property.offset.y() };
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
ui.offsetY->setValidator(new QIntValidator(-10000, 10000, this)); ui.offsetY->setValidator(new QDoubleValidator(-10000, 10000, 2, this));
connect(ui.offsetY, &QLineEdit::textChanged, [=](QString content) { connect(ui.offsetY, &QLineEdit::textChanged, [=](QString content) {
if (fabs(content.toDouble() - this->displayLayer->property.offset.y()) < 1e-6)
return;
this->displayLayer->property.offset = { this->displayLayer->property.offset.x(), content.toDouble() }; this->displayLayer->property.offset = { this->displayLayer->property.offset.x(), content.toDouble() };
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
ui.scaleX->setValidator(new QDoubleValidator(0, 1000, 4, this)); ui.scaleX->setValidator(new QDoubleValidator(0, 10000, 6, this));
connect(ui.scaleX, &QLineEdit::textChanged, [=](QString content) { connect(ui.scaleX, &QLineEdit::textChanged, [=](QString content) {
if (fabs(content.toDouble() - this->displayLayer->property.scale.x()) < 1e-6)
return;
this->displayLayer->property.scale = { content.toDouble(), this->displayLayer->property.scale.y() }; this->displayLayer->property.scale = { content.toDouble(), this->displayLayer->property.scale.y() };
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
ui.scaleY->setValidator(new QDoubleValidator(0, 1000, 4, this)); ui.scaleY->setValidator(new QDoubleValidator(0, 10000, 6, this));
connect(ui.scaleY, &QLineEdit::textChanged, [=](QString content) { connect(ui.scaleY, &QLineEdit::textChanged, [=](QString content) {
if (fabs(content.toDouble() - this->displayLayer->property.scale.y()) < 1e-6)
return;
this->displayLayer->property.scale = { this->displayLayer->property.scale.x(), content.toDouble() }; this->displayLayer->property.scale = { this->displayLayer->property.scale.x(), content.toDouble() };
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
connect(ui.flipX, &QtMaterialCheckBox::toggled, [=](bool state) { connect(ui.flipX, &QtMaterialCheckBox::toggled, [=](bool state) {
if (state == this->displayLayer->property.flipX)
return;
this->displayLayer->property.flipX = state; this->displayLayer->property.flipX = state;
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
connect(ui.flipY, &QtMaterialCheckBox::toggled, [=](bool state) { connect(ui.flipY, &QtMaterialCheckBox::toggled, [=](bool state) {
if (state == this->displayLayer->property.flipY)
return;
this->displayLayer->property.flipY = state; this->displayLayer->property.flipY = state;
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });

View File

@ -239,6 +239,7 @@ QAction* LayerTreeWidget::getPromoteUpAction()
auto layer = pair.first; auto layer = pair.first;
auto parent = pair.second; auto parent = pair.second;
this->moveLayer(layer, parent); this->moveLayer(layer, parent);
this->setCurrentItem(layer->qTreeWidgetItem);
}); });
optionList.append(option); optionList.append(option);
} }
@ -255,6 +256,11 @@ QAction* LayerTreeWidget::getPromoteDownAction()
std::vector<FolderLayerWrapper*> layers; std::vector<FolderLayerWrapper*> layers;
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>(); auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
auto parent = layer->getParent(); auto parent = layer->getParent();
if (parent == nullptr)
{
action->setEnabled(false);
return action;
}
for (auto child : parent->children) for (auto child : parent->children)
{ {
if (child.get() == layer || typeid(*child) != typeid(FolderLayerWrapper)) if (child.get() == layer || typeid(*child) != typeid(FolderLayerWrapper))
@ -278,6 +284,7 @@ QAction* LayerTreeWidget::getPromoteDownAction()
auto layer = pair.first; auto layer = pair.first;
auto parent = pair.second; auto parent = pair.second;
this->moveLayer(layer, parent); this->moveLayer(layer, parent);
this->setCurrentItem(layer->qTreeWidgetItem);
}); });
optionList.append(option); optionList.append(option);
} }