blob: 70b568800d18c615cf03a5b1263d1aba69bb6762 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qquickdesignersupport_p.h"
#include <private/qquickitem_p.h>
#if QT_CONFIG(quick_shadereffect)
#include <QtQuick/private/qquickshadereffectsource_p.h>
#endif
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQml/private/qabstractanimationjob_p.h>
#include <private/qqmlengine_p.h>
#include <private/qquickview_p.h>
#include <private/qsgrenderloop_p.h>
#include <QtQuick/private/qquickstategroup_p.h>
#include <QtGui/QImage>
#include <private/qqmlvme_p.h>
#include <private/qqmlcomponentattached_p.h>
#include <private/qqmldata_p.h>
#include <private/qsgadaptationlayer_p.h>
#include "qquickdesignerwindowmanager_p.h"
QT_BEGIN_NAMESPACE
QQuickDesignerSupport::QQuickDesignerSupport()
{
}
QQuickDesignerSupport::~QQuickDesignerSupport()
{
typedef QHash<QQuickItem*, QSGLayer*>::iterator ItemTextureHashIt;
for (ItemTextureHashIt iterator = m_itemTextureHash.begin(), end = m_itemTextureHash.end(); iterator != end; ++iterator) {
QSGLayer *texture = iterator.value();
QQuickItem *item = iterator.key();
QQuickItemPrivate::get(item)->derefFromEffectItem(true);
delete texture;
}
}
void QQuickDesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool hide)
{
if (referencedItem == nullptr)
return;
QQuickItemPrivate::get(referencedItem)->refFromEffectItem(hide);
QQuickWindowPrivate::get(referencedItem->window())->updateDirtyNode(referencedItem);
Q_ASSERT(QQuickItemPrivate::get(referencedItem)->rootNode());
if (!m_itemTextureHash.contains(referencedItem)) {
QSGRenderContext *rc = QQuickWindowPrivate::get(referencedItem->window())->context;
QSGLayer *texture = rc->sceneGraphContext()->createLayer(rc);
QSizeF itemSize = referencedItem->size();
texture->setLive(true);
texture->setItem(QQuickItemPrivate::get(referencedItem)->rootNode());
texture->setRect(QRectF(QPointF(0, 0), itemSize));
texture->setSize(itemSize.toSize());
texture->setRecursive(true);
#if QT_CONFIG(opengl)
#ifndef QT_OPENGL_ES
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
texture->setFormat(GL_RGBA8);
else
texture->setFormat(GL_RGBA);
#else
texture->setFormat(GL_RGBA);
#endif
#endif
texture->setHasMipmaps(false);
m_itemTextureHash.insert(referencedItem, texture);
}
}
void QQuickDesignerSupport::derefFromEffectItem(QQuickItem *referencedItem, bool unhide)
{
if (referencedItem == nullptr)
return;
delete m_itemTextureHash.take(referencedItem);
QQuickItemPrivate::get(referencedItem)->derefFromEffectItem(unhide);
}
QImage QQuickDesignerSupport::renderImageForItem(QQuickItem *referencedItem, const QRectF &boundingRect, const QSize &imageSize)
{
if (referencedItem == nullptr || referencedItem->parentItem() == nullptr) {
qDebug() << __FILE__ << __LINE__ << "Warning: Item can be rendered.";
return QImage();
}
QSGLayer *renderTexture = m_itemTextureHash.value(referencedItem);
Q_ASSERT(renderTexture);
if (renderTexture == nullptr)
return QImage();
renderTexture->setRect(boundingRect);
renderTexture->setSize(imageSize);
renderTexture->setItem(QQuickItemPrivate::get(referencedItem)->rootNode());
renderTexture->markDirtyTexture();
renderTexture->updateTexture();
QImage renderImage = renderTexture->toImage();
renderImage = renderImage.mirrored(false, true);
if (renderImage.size().isEmpty())
qDebug() << __FILE__ << __LINE__ << "Warning: Image is empty.";
return renderImage;
}
bool QQuickDesignerSupport::isDirty(QQuickItem *referencedItem, DirtyType dirtyType)
{
if (referencedItem == nullptr)
return false;
return QQuickItemPrivate::get(referencedItem)->dirtyAttributes & dirtyType;
}
void QQuickDesignerSupport::addDirty(QQuickItem *referencedItem, QQuickDesignerSupport::DirtyType dirtyType)
{
if (referencedItem == nullptr)
return;
QQuickItemPrivate::get(referencedItem)->dirtyAttributes |= dirtyType;
}
void QQuickDesignerSupport::resetDirty(QQuickItem *referencedItem)
{
if (referencedItem == nullptr)
return;
QQuickItemPrivate::get(referencedItem)->dirtyAttributes = 0x0;
QQuickItemPrivate::get(referencedItem)->removeFromDirtyList();
}
QTransform QQuickDesignerSupport::windowTransform(QQuickItem *referencedItem)
{
if (referencedItem == nullptr)
return QTransform();
return QQuickItemPrivate::get(referencedItem)->itemToWindowTransform();
}
QTransform QQuickDesignerSupport::parentTransform(QQuickItem *referencedItem)
{
if (referencedItem == nullptr)
return QTransform();
QTransform parentTransform;
QQuickItemPrivate::get(referencedItem)->itemToParentTransform(parentTransform);
return parentTransform;
}
QString propertyNameForAnchorLine(const QQuickAnchors::Anchor &anchorLine)
{
switch (anchorLine) {
case QQuickAnchors::LeftAnchor: return QLatin1String("left");
case QQuickAnchors::RightAnchor: return QLatin1String("right");
case QQuickAnchors::TopAnchor: return QLatin1String("top");
case QQuickAnchors::BottomAnchor: return QLatin1String("bottom");
case QQuickAnchors::HCenterAnchor: return QLatin1String("horizontalCenter");
case QQuickAnchors::VCenterAnchor: return QLatin1String("verticalCenter");
case QQuickAnchors::BaselineAnchor: return QLatin1String("baseline");
case QQuickAnchors::InvalidAnchor: // fallthrough:
default: return QString();
}
}
bool isValidAnchorName(const QString &name)
{
static QStringList anchorNameList(QStringList() << QLatin1String("anchors.top")
<< QLatin1String("anchors.left")
<< QLatin1String("anchors.right")
<< QLatin1String("anchors.bottom")
<< QLatin1String("anchors.verticalCenter")
<< QLatin1String("anchors.horizontalCenter")
<< QLatin1String("anchors.fill")
<< QLatin1String("anchors.centerIn")
<< QLatin1String("anchors.baseline"));
return anchorNameList.contains(name);
}
bool QQuickDesignerSupport::isAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem)
{
QQuickItemPrivate *fromItemPrivate = QQuickItemPrivate::get(fromItem);
QQuickAnchors *anchors = fromItemPrivate->anchors();
return anchors->fill() == toItem
|| anchors->centerIn() == toItem
|| anchors->bottom().item == toItem
|| anchors->top().item == toItem
|| anchors->left().item == toItem
|| anchors->right().item == toItem
|| anchors->verticalCenter().item == toItem
|| anchors->horizontalCenter().item == toItem
|| anchors->baseline().item == toItem;
}
bool QQuickDesignerSupport::areChildrenAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem)
{
const auto childItems = fromItem->childItems();
for (QQuickItem *childItem : childItems) {
if (childItem) {
if (isAnchoredTo(childItem, toItem))
return true;
if (areChildrenAnchoredTo(childItem, toItem))
return true;
}
}
return false;
}
QQuickAnchors *anchors(QQuickItem *item)
{
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
return itemPrivate->anchors();
}
QQuickAnchors::Anchor anchorLineFlagForName(const QString &name)
{
if (name == QLatin1String("anchors.top"))
return QQuickAnchors::TopAnchor;
if (name == QLatin1String("anchors.left"))
return QQuickAnchors::LeftAnchor;
if (name == QLatin1String("anchors.bottom"))
return QQuickAnchors::BottomAnchor;
if (name == QLatin1String("anchors.right"))
return QQuickAnchors::RightAnchor;
if (name == QLatin1String("anchors.horizontalCenter"))
return QQuickAnchors::HCenterAnchor;
if (name == QLatin1String("anchors.verticalCenter"))
return QQuickAnchors::VCenterAnchor;
if (name == QLatin1String("anchors.baseline"))
return QQuickAnchors::BaselineAnchor;
Q_ASSERT_X(false, Q_FUNC_INFO, "wrong anchor name - this should never happen");
return QQuickAnchors::LeftAnchor;
}
bool QQuickDesignerSupport::hasAnchor(QQuickItem *item, const QString &name)
{
if (!isValidAnchorName(name))
return false;
if (name == QLatin1String("anchors.fill"))
return anchors(item)->fill() != nullptr;
if (name == QLatin1String("anchors.centerIn"))
return anchors(item)->centerIn() != nullptr;
if (name == QLatin1String("anchors.right"))
return anchors(item)->right().item != nullptr;
if (name == QLatin1String("anchors.top"))
return anchors(item)->top().item != nullptr;
if (name == QLatin1String("anchors.left"))
return anchors(item)->left().item != nullptr;
if (name == QLatin1String("anchors.bottom"))
return anchors(item)->bottom().item != nullptr;
if (name == QLatin1String("anchors.horizontalCenter"))
return anchors(item)->horizontalCenter().item != nullptr;
if (name == QLatin1String("anchors.verticalCenter"))
return anchors(item)->verticalCenter().item != nullptr;
if (name == QLatin1String("anchors.baseline"))
return anchors(item)->baseline().item != nullptr;
return anchors(item)->usedAnchors().testFlag(anchorLineFlagForName(name));
}
QQuickItem *QQuickDesignerSupport::anchorFillTargetItem(QQuickItem *item)
{
return anchors(item)->fill();
}
QQuickItem *QQuickDesignerSupport::anchorCenterInTargetItem(QQuickItem *item)
{
return anchors(item)->centerIn();
}
QPair<QString, QObject*> QQuickDesignerSupport::anchorLineTarget(QQuickItem *item, const QString &name, QQmlContext *context)
{
QObject *targetObject = nullptr;
QString targetName;
if (name == QLatin1String("anchors.fill")) {
targetObject = anchors(item)->fill();
} else if (name == QLatin1String("anchors.centerIn")) {
targetObject = anchors(item)->centerIn();
} else {
QQmlProperty metaProperty(item, name, context);
if (!metaProperty.isValid())
return QPair<QString, QObject*>();
QQuickAnchorLine anchorLine = metaProperty.read().value<QQuickAnchorLine>();
if (anchorLine.anchorLine != QQuickAnchors::InvalidAnchor) {
targetObject = anchorLine.item;
targetName = propertyNameForAnchorLine(anchorLine.anchorLine);
}
}
return QPair<QString, QObject*>(targetName, targetObject);
}
void QQuickDesignerSupport::resetAnchor(QQuickItem *item, const QString &name)
{
if (name == QLatin1String("anchors.fill")) {
anchors(item)->resetFill();
} else if (name == QLatin1String("anchors.centerIn")) {
anchors(item)->resetCenterIn();
} else if (name == QLatin1String("anchors.top")) {
anchors(item)->resetTop();
} else if (name == QLatin1String("anchors.left")) {
anchors(item)->resetLeft();
} else if (name == QLatin1String("anchors.right")) {
anchors(item)->resetRight();
} else if (name == QLatin1String("anchors.bottom")) {
anchors(item)->resetBottom();
} else if (name == QLatin1String("anchors.horizontalCenter")) {
anchors(item)->resetHorizontalCenter();
} else if (name == QLatin1String("anchors.verticalCenter")) {
anchors(item)->resetVerticalCenter();
} else if (name == QLatin1String("anchors.baseline")) {
anchors(item)->resetBaseline();
}
}
void QQuickDesignerSupport::emitComponentCompleteSignalForAttachedProperty(QObject *object)
{
if (!object)
return;
QQmlData *data = QQmlData::get(object);
if (data && data->context) {
QQmlComponentAttached *componentAttached = data->context->componentAttached;
while (componentAttached) {
if (componentAttached->parent())
if (componentAttached->parent() == object)
emit componentAttached->completed();
componentAttached = componentAttached->next;
}
}
}
QList<QObject*> QQuickDesignerSupport::statesForItem(QQuickItem *item)
{
QList<QObject*> objectList;
const QList<QQuickState *> stateList = QQuickItemPrivate::get(item)->_states()->states();
objectList.reserve(stateList.size());
for (QQuickState* state : stateList)
objectList.append(state);
return objectList;
}
bool QQuickDesignerSupport::isComponentComplete(QQuickItem *item)
{
return QQuickItemPrivate::get(item)->componentComplete;
}
int QQuickDesignerSupport::borderWidth(QQuickItem *item)
{
QQuickRectangle *rectangle = qobject_cast<QQuickRectangle*>(item);
if (rectangle)
return rectangle->border()->width();
return 0;
}
void QQuickDesignerSupport::refreshExpressions(QQmlContext *context)
{
QQmlContextPrivate::get(context)->data->refreshExpressions();
}
void QQuickDesignerSupport::setRootItem(QQuickView *view, QQuickItem *item)
{
QQuickViewPrivate::get(view)->setRootObject(item);
}
bool QQuickDesignerSupport::isValidWidth(QQuickItem *item)
{
return QQuickItemPrivate::get(item)->heightValid;
}
bool QQuickDesignerSupport::isValidHeight(QQuickItem *item)
{
return QQuickItemPrivate::get(item)->widthValid;
}
void QQuickDesignerSupport::updateDirtyNode(QQuickItem *item)
{
if (item->window())
QQuickWindowPrivate::get(item->window())->updateDirtyNode(item);
}
void QQuickDesignerSupport::activateDesignerWindowManager()
{
QSGRenderLoop::setInstance(new QQuickDesignerWindowManager);
}
void QQuickDesignerSupport::activateDesignerMode()
{
QQmlEnginePrivate::activateDesignerMode();
}
void QQuickDesignerSupport::disableComponentComplete()
{
QQmlVME::disableComponentComplete();
}
void QQuickDesignerSupport::enableComponentComplete()
{
QQmlVME::enableComponentComplete();
}
void QQuickDesignerSupport::createOpenGLContext(QQuickWindow *window)
{
QQuickDesignerWindowManager::createOpenGLContext(window);
}
void QQuickDesignerSupport::polishItems(QQuickWindow *window)
{
QQuickWindowPrivate::get(window)->polishItems();
}
ComponentCompleteDisabler::ComponentCompleteDisabler()
{
QQuickDesignerSupport::disableComponentComplete();
}
ComponentCompleteDisabler::~ComponentCompleteDisabler()
{
QQuickDesignerSupport::enableComponentComplete();
}
QT_END_NAMESPACE