QmlDesigner: Keep context as background

When drilling into components we keep the context as an image
in the background.

Change-Id: I12c291ab1cff02d30f53f92ccd9a551a9dd63704
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
Reviewed-by: Henning Gründl <henning.gruendl@qt.io>
This commit is contained in:
Thomas Hartmann
2023-06-29 17:22:42 +02:00
parent ccdf0730df
commit b85eb8aa04
15 changed files with 153 additions and 11 deletions

View File

@@ -480,6 +480,11 @@ void ViewManager::exportAsImage()
d->formEditorView.exportAsImage();
}
QImage ViewManager::takeFormEditorScreenshot()
{
return d->formEditorView.takeFormEditorScreenshot();
}
void ViewManager::reformatFileUsingTextEditorView()
{
d->textEditorView.reformatFile();

View File

@@ -74,6 +74,7 @@ public:
const AbstractView *view() const;
void exportAsImage();
QImage takeFormEditorScreenshot();
void reformatFileUsingTextEditorView();
QWidgetAction *componentViewAction() const;

View File

@@ -3,6 +3,8 @@
#include "backgroundaction.h"
#include <theme.h>
#include <utils/stylehelper.h>
#include <QComboBox>
@@ -28,6 +30,14 @@ QIcon iconForColor(const QColor &color) {
image.fill(0);
QPainter p(&image);
if (color == BackgroundAction::ContextImage) {
const QString unicode = Theme::getIconUnicode(Theme::Icon::textures_medium);
const QString fontName = "qtds_propertyIconFont.ttf";
QIcon icon = Utils::StyleHelper::getIconFromIconFont(fontName, unicode, 10, 10, Qt::white);
return icon;
}
p.fillRect(2, 2, size - 4, size - 4, Qt::black);
if (color.alpha() == 0) {
@@ -70,13 +80,13 @@ QList<QColor> BackgroundAction::colors()
{
static QColor alphaZero(Qt::transparent);
static QList<QColor> colorList = {alphaZero,
QColor(BackgroundAction::ContextImage),
QColor(Qt::black),
QColor(0x4c4e50),
QColor(Qt::darkGray),
QColor(Qt::lightGray),
QColor(Qt::white)};
return colorList;
}

View File

@@ -11,14 +11,12 @@ namespace QmlDesigner {
class BackgroundAction : public QWidgetAction
{
enum BackgroundType {
CheckboardBackground,
WhiteBackground,
BlackBackground
};
enum BackgroundType { CheckboardBackground, WhiteBackground, BlackBackground };
Q_OBJECT
public:
enum SpecialColor { ContextImage = Qt::yellow };
explicit BackgroundAction(QObject *parent);
void setColor(const QColor &color);

View File

@@ -2,9 +2,13 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "formeditorgraphicsview.h"
#include "backgroundaction.h"
#include "formeditoritem.h"
#include "formeditorwidget.h"
#include "navigation2d.h"
#include <theme.h>
#include <utils/hostosinfo.h>
#include <QAction>
@@ -198,10 +202,28 @@ void FormEditorGraphicsView::drawBackground(QPainter *painter, const QRectF &rec
painter->save();
painter->setBrushOrigin(0, 0);
painter->fillRect(rectangle.intersected(rootItemRect()), backgroundBrush());
// paint rect around editable area
painter->setPen(Qt::black);
painter->drawRect(rootItemRect());
if (backgroundBrush().color() == BackgroundAction::ContextImage) {
painter->fillRect(rectangle.intersected(rootItemRect()), Qt::gray);
painter->setOpacity(0.5);
if (!m_backgroundImage.isNull())
painter->drawImage(rootItemRect().topLeft() + m_backgroundImage.offset(),
m_backgroundImage);
painter->setOpacity(1.0);
} else {
painter->fillRect(rectangle.intersected(rootItemRect()), backgroundBrush());
}
QPen pen(Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_FormEditorSelectionColor));
pen.setStyle(Qt::DotLine);
pen.setWidth(1);
painter->setPen(pen);
painter->drawRect(rootItemRect().adjusted(-1, -1, 0, 0));
painter->restore();
}
@@ -210,6 +232,17 @@ void FormEditorGraphicsView::frame(const QRectF &boundingRect)
fitInView(boundingRect, Qt::KeepAspectRatio);
}
void FormEditorGraphicsView::setBackgoundImage(const QImage &image)
{
m_backgroundImage = image;
update();
}
QImage FormEditorGraphicsView::backgroundImage() const
{
return m_backgroundImage;
}
void FormEditorGraphicsView::setZoomFactor(double zoom)
{
resetTransform();

View File

@@ -28,6 +28,9 @@ public:
void setZoomFactor(double zoom);
void frame(const QRectF &bbox);
void setBackgoundImage(const QImage &image);
QImage backgroundImage() const;
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
@@ -45,6 +48,7 @@ private:
Panning m_isPanning = Panning::NotStarted;
QPoint m_panningStartPosition;
QRectF m_rootItemRect;
QImage m_backgroundImage;
};
} // namespace QmlDesigner

View File

@@ -63,6 +63,8 @@ void FormEditorView::modelAttached(Model *model)
if (!isEnabled())
return;
m_formEditorWidget->setBackgoundImage({});
temporaryBlockView();
setupFormEditorWidget();
@@ -649,6 +651,10 @@ void FormEditorView::auxiliaryDataChanged(const ModelNode &node,
if (FormEditorItem *editorItem = scene()->itemForQmlItemNode(item))
editorItem->setFrameColor(data.value<QColor>());
}
if (key == contextImageProperty) {
m_formEditorWidget->setBackgoundImage(data.value<QImage>());
}
}
static void updateTransitions(FormEditorScene *scene, const QmlItemNode &qmlItemNode)
@@ -784,6 +790,11 @@ void FormEditorView::exportAsImage()
m_formEditorWidget->exportAsImage(m_scene->rootFormEditorItem()->boundingRect());
}
QImage FormEditorView::takeFormEditorScreenshot()
{
return m_formEditorWidget->takeFormEditorScreenshot();
}
QPicture FormEditorView::renderToPicture() const
{
return m_formEditorWidget->renderToPicture();
@@ -954,6 +965,11 @@ void FormEditorView::setupRootItemSize()
formEditorWidget()->setRootItemRect(rootQmlNode.instanceBoundingRect());
formEditorWidget()->centerScene();
auto contextImage = rootModelNode().auxiliaryData(contextImageProperty);
if (contextImage)
m_formEditorWidget->setBackgoundImage(contextImage.value().value<QImage>());
}
}

View File

@@ -117,6 +117,7 @@ public:
void setGotoErrorCallback(std::function<void(int, int)> gotoErrorCallback);
void exportAsImage();
QImage takeFormEditorScreenshot();
QPicture renderToPicture() const;
void setupFormEditorWidget();

View File

@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "formeditorwidget.h"
#include "backgroundaction.h"
#include "designeractionmanager.h"
#include "designericons.h"
#include "designersettings.h"
@@ -332,11 +333,13 @@ void FormEditorWidget::changeBackgound(const QColor &color)
if (color.alpha() == 0) {
m_graphicsView->activateCheckboardBackground();
if (m_formEditorView->rootModelNode().hasAuxiliaryData(formeditorColorProperty)) {
m_formEditorView->rootModelNode().setAuxiliaryData(formeditorColorProperty, {});
m_formEditorView->rootModelNode().setAuxiliaryDataWithoutLock(formeditorColorProperty,
{});
}
} else {
m_graphicsView->activateColoredBackground(color);
m_formEditorView->rootModelNode().setAuxiliaryData(formeditorColorProperty, color);
m_formEditorView->rootModelNode().setAuxiliaryDataWithoutLock(formeditorColorProperty,
color);
}
}
@@ -397,6 +400,10 @@ void FormEditorWidget::updateActions()
} else {
m_backgroundAction->setColor(Qt::transparent);
}
if (m_formEditorView->rootModelNode().hasAuxiliaryData(contextImageProperty))
m_backgroundAction->setColor(BackgroundAction::ContextImage);
} else {
m_rootWidthAction->clearLineEditText();
m_rootHeightAction->clearLineEditText();
@@ -540,6 +547,40 @@ void FormEditorWidget::exportAsImage(const QRectF &boundingRect)
}
}
QImage FormEditorWidget::takeFormEditorScreenshot()
{
const QRectF boundingRect = m_formEditorView->scene()->rootFormEditorItem()->boundingRect();
m_formEditorView->scene()->manipulatorLayerItem()->setVisible(false);
QImage image(boundingRect.size().toSize(), QImage::Format_ARGB32);
if (!m_graphicsView->backgroundImage().isNull()) {
image = m_graphicsView->backgroundImage();
const QPoint offset = m_graphicsView->backgroundImage().offset();
QPainter painter(&image);
QTransform viewportTransform = m_graphicsView->viewportTransform();
m_graphicsView->render(&painter,
QRectF(-offset, boundingRect.size()),
viewportTransform.mapRect(boundingRect).toRect());
image.setOffset(offset);
} else {
QPainter painter(&image);
QTransform viewportTransform = m_graphicsView->viewportTransform();
m_graphicsView->render(&painter,
QRectF(0, 0, image.width(), image.height()),
viewportTransform.mapRect(boundingRect).toRect());
}
m_formEditorView->scene()->manipulatorLayerItem()->setVisible(true);
return image;
}
QPicture FormEditorWidget::renderToPicture() const
{
QPicture picture;
@@ -568,6 +609,17 @@ bool FormEditorWidget::errorMessageBoxIsVisible() const
return m_documentErrorWidget && m_documentErrorWidget->isVisible();
}
void FormEditorWidget::setBackgoundImage(const QImage &image)
{
m_graphicsView->setBackgoundImage(image);
updateActions();
}
QImage FormEditorWidget::backgroundImage() const
{
return m_graphicsView->backgroundImage();
}
DocumentWarningWidget *FormEditorWidget::errorWidget()
{
if (m_documentErrorWidget.isNull()) {

View File

@@ -63,12 +63,17 @@ public:
void showWarningMessageBox(const QList<DocumentMessage> &warnings);
void exportAsImage(const QRectF &boundingRect);
QImage takeFormEditorScreenshot();
QPicture renderToPicture() const;
FormEditorGraphicsView *graphicsView() const;
bool errorMessageBoxIsVisible() const;
void setBackgoundImage(const QImage &image);
QImage backgroundImage() const;
protected:
QActionGroup *toolActionGroup() const;
DocumentWarningWidget *errorWidget();

View File

@@ -108,6 +108,8 @@ inline constexpr AuxiliaryDataKeyView rotBlockProperty{AuxiliaryDataType::NodeIn
inline constexpr AuxiliaryDataKeyView languageProperty{AuxiliaryDataType::Temporary, "language"};
inline constexpr AuxiliaryDataKeyView bakeLightsManualProperty{AuxiliaryDataType::Document,
"bakeLightsManual"};
inline constexpr AuxiliaryDataKeyView contextImageProperty{AuxiliaryDataType::Temporary,
"contextImage"};
// Most material preview aux properties are duplicated as document and instance types, as they
// are both required to be persistent and used at runtime to control material preview rendering

View File

@@ -182,6 +182,7 @@ public:
QVariant auxiliaryDataWithDefault(AuxiliaryDataKeyView key) const;
QVariant auxiliaryDataWithDefault(AuxiliaryDataKeyDefaultValue key) const;
void setAuxiliaryData(AuxiliaryDataKeyView key, const QVariant &data) const;
void setAuxiliaryDataWithoutLock(AuxiliaryDataKeyView key, const QVariant &data) const;
void setAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name, const QVariant &data) const;
void setAuxiliaryDataWithoutLock(AuxiliaryDataType type,
Utils::SmallStringView name,

View File

@@ -1473,6 +1473,7 @@ WriteLocker::WriteLocker(ModelPrivate *model)
if (m_model->m_writeLock)
qWarning() << "QmlDesigner: Misbehaving view calls back to model!!!";
// FIXME: Enable it again
QTC_CHECK(!m_model->m_writeLock);
Q_ASSERT(!m_model->m_writeLock);
model->m_writeLock = true;
}
@@ -1484,6 +1485,7 @@ WriteLocker::WriteLocker(Model *model)
if (m_model->m_writeLock)
qWarning() << "QmlDesigner: Misbehaving view calls back to model!!!";
// FIXME: Enable it again
QTC_CHECK(!m_model->m_writeLock);
Q_ASSERT(!m_model->m_writeLock);
m_model->m_writeLock = true;
}
@@ -1493,6 +1495,7 @@ WriteLocker::~WriteLocker()
if (!m_model->m_writeLock)
qWarning() << "QmlDesigner: WriterLocker out of sync!!!";
// FIXME: Enable it again
QTC_CHECK(m_model->m_writeLock);
Q_ASSERT(m_model->m_writeLock);
m_model->m_writeLock = false;
}

View File

@@ -1002,6 +1002,12 @@ void ModelNode::setAuxiliaryData(AuxiliaryDataKeyView key, const QVariant &data)
}
}
void ModelNode::setAuxiliaryDataWithoutLock(AuxiliaryDataKeyView key, const QVariant &data) const
{
if (isValid())
m_model->d->setAuxiliaryData(internalNode(), key, data);
}
void ModelNode::setAuxiliaryDataWithoutLock(AuxiliaryDataType type,
Utils::SmallStringView name,
const QVariant &data) const

View File

@@ -265,6 +265,9 @@ void DocumentManager::resetPossibleImports()
bool DocumentManager::goIntoComponent(const ModelNode &modelNode)
{
QImage image = QmlDesignerPlugin::instance()->viewManager().takeFormEditorScreenshot();
const QPoint offset = image.offset();
image.setOffset(offset - QmlItemNode(modelNode).instancePosition().toPoint());
if (modelNode.isValid() && modelNode.isComponent() && designDocument()) {
QmlDesignerPlugin::instance()->viewManager().setComponentNode(modelNode);
QHash<PropertyName, QVariant> oldProperties = getProperties(modelNode);
@@ -282,6 +285,8 @@ bool DocumentManager::goIntoComponent(const ModelNode &modelNode)
ModelNode rootModelNode = designDocument()->rewriterView()->rootModelNode();
applyProperties(rootModelNode, oldProperties);
rootModelNode.setAuxiliaryData(AuxiliaryDataType::Temporary, "contextImage", image);
return true;
}