1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickdesignersupport_p.h"
5#include <private/qquickitem_p.h>
6
7#if QT_CONFIG(quick_shadereffect)
8#include <QtQuick/private/qquickshadereffectsource_p.h>
9#endif
10#include <QtQuick/private/qquickrectangle_p.h>
11#include <QtQml/private/qabstractanimationjob_p.h>
12#include <private/qqmlengine_p.h>
13#include <private/qquickview_p.h>
14#include <QtQuick/private/qquickstategroup_p.h>
15#include <QtGui/QImage>
16#include <private/qqmlvme_p.h>
17#include <private/qqmlcomponentattached_p.h>
18#include <private/qqmldata_p.h>
19#include <private/qsgadaptationlayer_p.h>
20
21QT_BEGIN_NAMESPACE
22
23QQuickDesignerSupport::QQuickDesignerSupport()
24{
25}
26
27QQuickDesignerSupport::~QQuickDesignerSupport()
28{
29 typedef QHash<QQuickItem*, QSGLayer*>::iterator ItemTextureHashIt;
30
31 for (ItemTextureHashIt iterator = m_itemTextureHash.begin(), end = m_itemTextureHash.end(); iterator != end; ++iterator) {
32 QSGLayer *texture = iterator.value();
33 QQuickItem *item = iterator.key();
34 QQuickItemPrivate::get(item)->derefFromEffectItem(unhide: true);
35 delete texture;
36 }
37}
38
39void QQuickDesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool hide)
40{
41 if (referencedItem == nullptr)
42 return;
43
44 QQuickItemPrivate::get(item: referencedItem)->refFromEffectItem(hide);
45 QQuickWindowPrivate::get(c: referencedItem->window())->updateDirtyNode(referencedItem);
46
47 Q_ASSERT(QQuickItemPrivate::get(referencedItem)->rootNode());
48
49 if (!m_itemTextureHash.contains(key: referencedItem)) {
50 QSGRenderContext *rc = QQuickWindowPrivate::get(c: referencedItem->window())->context;
51 QSGLayer *texture = rc->sceneGraphContext()->createLayer(renderContext: rc);
52
53 QSizeF itemSize = referencedItem->size();
54 texture->setLive(true);
55 texture->setItem(QQuickItemPrivate::get(item: referencedItem)->rootNode());
56 texture->setRect(QRectF(QPointF(0, 0), itemSize));
57 texture->setSize(itemSize.toSize());
58 texture->setRecursive(true);
59 texture->setFormat(QSGLayer::RGBA8);
60 texture->setHasMipmaps(false);
61
62 m_itemTextureHash.insert(key: referencedItem, value: texture);
63 }
64}
65
66void QQuickDesignerSupport::derefFromEffectItem(QQuickItem *referencedItem, bool unhide)
67{
68 if (referencedItem == nullptr)
69 return;
70
71 delete m_itemTextureHash.take(key: referencedItem);
72 QQuickItemPrivate::get(item: referencedItem)->derefFromEffectItem(unhide);
73}
74
75QImage QQuickDesignerSupport::renderImageForItem(QQuickItem *referencedItem, const QRectF &boundingRect, const QSize &imageSize)
76{
77 if (referencedItem == nullptr || referencedItem->parentItem() == nullptr) {
78 qDebug() << __FILE__ << __LINE__ << "Warning: Item can be rendered.";
79 return QImage();
80 }
81
82 QSGLayer *renderTexture = m_itemTextureHash.value(key: referencedItem);
83
84 Q_ASSERT(renderTexture);
85 if (renderTexture == nullptr)
86 return QImage();
87 renderTexture->setRect(boundingRect);
88 renderTexture->setSize(imageSize);
89 renderTexture->setItem(QQuickItemPrivate::get(item: referencedItem)->rootNode());
90 renderTexture->markDirtyTexture();
91 renderTexture->updateTexture();
92
93 QImage renderImage = renderTexture->toImage();
94 renderImage = renderImage.mirrored(horizontally: false, vertically: true);
95
96 if (renderImage.size().isEmpty())
97 qDebug() << __FILE__ << __LINE__ << "Warning: Image is empty.";
98
99 return renderImage;
100}
101
102bool QQuickDesignerSupport::isDirty(QQuickItem *referencedItem, DirtyType dirtyType)
103{
104 if (referencedItem == nullptr)
105 return false;
106
107 return QQuickItemPrivate::get(item: referencedItem)->dirtyAttributes & dirtyType;
108}
109
110void QQuickDesignerSupport::addDirty(QQuickItem *referencedItem, QQuickDesignerSupport::DirtyType dirtyType)
111{
112 if (referencedItem == nullptr)
113 return;
114
115 QQuickItemPrivate::get(item: referencedItem)->dirtyAttributes |= dirtyType;
116}
117
118void QQuickDesignerSupport::resetDirty(QQuickItem *referencedItem)
119{
120 if (referencedItem == nullptr)
121 return;
122
123 QQuickItemPrivate::get(item: referencedItem)->dirtyAttributes = 0x0;
124 QQuickItemPrivate::get(item: referencedItem)->removeFromDirtyList();
125}
126
127QTransform QQuickDesignerSupport::windowTransform(QQuickItem *referencedItem)
128{
129 if (referencedItem == nullptr)
130 return QTransform();
131
132 return QQuickItemPrivate::get(item: referencedItem)->itemToWindowTransform();
133}
134
135QTransform QQuickDesignerSupport::parentTransform(QQuickItem *referencedItem)
136{
137 if (referencedItem == nullptr)
138 return QTransform();
139
140 QTransform parentTransform;
141
142 QQuickItemPrivate::get(item: referencedItem)->itemToParentTransform(&parentTransform);
143
144 return parentTransform;
145}
146
147QString propertyNameForAnchorLine(const QQuickAnchors::Anchor &anchorLine)
148{
149 switch (anchorLine) {
150 case QQuickAnchors::LeftAnchor: return QLatin1String("left");
151 case QQuickAnchors::RightAnchor: return QLatin1String("right");
152 case QQuickAnchors::TopAnchor: return QLatin1String("top");
153 case QQuickAnchors::BottomAnchor: return QLatin1String("bottom");
154 case QQuickAnchors::HCenterAnchor: return QLatin1String("horizontalCenter");
155 case QQuickAnchors::VCenterAnchor: return QLatin1String("verticalCenter");
156 case QQuickAnchors::BaselineAnchor: return QLatin1String("baseline");
157 case QQuickAnchors::InvalidAnchor: // fallthrough:
158 default: return QString();
159 }
160}
161
162bool isValidAnchorName(const QString &name)
163{
164 static QStringList anchorNameList(QStringList() << QLatin1String("anchors.top")
165 << QLatin1String("anchors.left")
166 << QLatin1String("anchors.right")
167 << QLatin1String("anchors.bottom")
168 << QLatin1String("anchors.verticalCenter")
169 << QLatin1String("anchors.horizontalCenter")
170 << QLatin1String("anchors.fill")
171 << QLatin1String("anchors.centerIn")
172 << QLatin1String("anchors.baseline"));
173
174 return anchorNameList.contains(str: name);
175}
176
177bool QQuickDesignerSupport::isAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem)
178{
179 QQuickItemPrivate *fromItemPrivate = QQuickItemPrivate::get(item: fromItem);
180 QQuickAnchors *anchors = fromItemPrivate->anchors();
181 return anchors->fill() == toItem
182 || anchors->centerIn() == toItem
183 || anchors->bottom().item == toItem
184 || anchors->top().item == toItem
185 || anchors->left().item == toItem
186 || anchors->right().item == toItem
187 || anchors->verticalCenter().item == toItem
188 || anchors->horizontalCenter().item == toItem
189 || anchors->baseline().item == toItem;
190}
191
192bool QQuickDesignerSupport::areChildrenAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem)
193{
194 const auto childItems = fromItem->childItems();
195 for (QQuickItem *childItem : childItems) {
196 if (childItem) {
197 if (isAnchoredTo(fromItem: childItem, toItem))
198 return true;
199
200 if (areChildrenAnchoredTo(fromItem: childItem, toItem))
201 return true;
202 }
203 }
204
205 return false;
206}
207
208QQuickAnchors *anchors(QQuickItem *item)
209{
210 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
211 return itemPrivate->anchors();
212}
213
214QQuickAnchors::Anchor anchorLineFlagForName(const QString &name)
215{
216 if (name == QLatin1String("anchors.top"))
217 return QQuickAnchors::TopAnchor;
218
219 if (name == QLatin1String("anchors.left"))
220 return QQuickAnchors::LeftAnchor;
221
222 if (name == QLatin1String("anchors.bottom"))
223 return QQuickAnchors::BottomAnchor;
224
225 if (name == QLatin1String("anchors.right"))
226 return QQuickAnchors::RightAnchor;
227
228 if (name == QLatin1String("anchors.horizontalCenter"))
229 return QQuickAnchors::HCenterAnchor;
230
231 if (name == QLatin1String("anchors.verticalCenter"))
232 return QQuickAnchors::VCenterAnchor;
233
234 if (name == QLatin1String("anchors.baseline"))
235 return QQuickAnchors::BaselineAnchor;
236
237
238 Q_ASSERT_X(false, Q_FUNC_INFO, "wrong anchor name - this should never happen");
239 return QQuickAnchors::LeftAnchor;
240}
241
242bool QQuickDesignerSupport::hasAnchor(QQuickItem *item, const QString &name)
243{
244 if (!isValidAnchorName(name))
245 return false;
246
247 if (name == QLatin1String("anchors.fill"))
248 return anchors(item)->fill() != nullptr;
249
250 if (name == QLatin1String("anchors.centerIn"))
251 return anchors(item)->centerIn() != nullptr;
252
253 if (name == QLatin1String("anchors.right"))
254 return anchors(item)->right().item != nullptr;
255
256 if (name == QLatin1String("anchors.top"))
257 return anchors(item)->top().item != nullptr;
258
259 if (name == QLatin1String("anchors.left"))
260 return anchors(item)->left().item != nullptr;
261
262 if (name == QLatin1String("anchors.bottom"))
263 return anchors(item)->bottom().item != nullptr;
264
265 if (name == QLatin1String("anchors.horizontalCenter"))
266 return anchors(item)->horizontalCenter().item != nullptr;
267
268 if (name == QLatin1String("anchors.verticalCenter"))
269 return anchors(item)->verticalCenter().item != nullptr;
270
271 if (name == QLatin1String("anchors.baseline"))
272 return anchors(item)->baseline().item != nullptr;
273
274 return anchors(item)->usedAnchors().testFlag(flag: anchorLineFlagForName(name));
275}
276
277QQuickItem *QQuickDesignerSupport::anchorFillTargetItem(QQuickItem *item)
278{
279 return anchors(item)->fill();
280}
281
282QQuickItem *QQuickDesignerSupport::anchorCenterInTargetItem(QQuickItem *item)
283{
284 return anchors(item)->centerIn();
285}
286
287
288
289QPair<QString, QObject*> QQuickDesignerSupport::anchorLineTarget(QQuickItem *item, const QString &name, QQmlContext *context)
290{
291 QObject *targetObject = nullptr;
292 QString targetName;
293
294 if (name == QLatin1String("anchors.fill")) {
295 targetObject = anchors(item)->fill();
296 } else if (name == QLatin1String("anchors.centerIn")) {
297 targetObject = anchors(item)->centerIn();
298 } else {
299 QQmlProperty metaProperty(item, name, context);
300 if (!metaProperty.isValid())
301 return QPair<QString, QObject*>();
302
303 QQuickAnchorLine anchorLine = metaProperty.read().value<QQuickAnchorLine>();
304 if (anchorLine.anchorLine != QQuickAnchors::InvalidAnchor) {
305 targetObject = anchorLine.item;
306 targetName = propertyNameForAnchorLine(anchorLine: anchorLine.anchorLine);
307 }
308
309 }
310
311 return QPair<QString, QObject*>(targetName, targetObject);
312}
313
314void QQuickDesignerSupport::resetAnchor(QQuickItem *item, const QString &name)
315{
316 if (name == QLatin1String("anchors.fill")) {
317 anchors(item)->resetFill();
318 } else if (name == QLatin1String("anchors.centerIn")) {
319 anchors(item)->resetCenterIn();
320 } else if (name == QLatin1String("anchors.top")) {
321 anchors(item)->resetTop();
322 } else if (name == QLatin1String("anchors.left")) {
323 anchors(item)->resetLeft();
324 } else if (name == QLatin1String("anchors.right")) {
325 anchors(item)->resetRight();
326 } else if (name == QLatin1String("anchors.bottom")) {
327 anchors(item)->resetBottom();
328 } else if (name == QLatin1String("anchors.horizontalCenter")) {
329 anchors(item)->resetHorizontalCenter();
330 } else if (name == QLatin1String("anchors.verticalCenter")) {
331 anchors(item)->resetVerticalCenter();
332 } else if (name == QLatin1String("anchors.baseline")) {
333 anchors(item)->resetBaseline();
334 }
335}
336
337void QQuickDesignerSupport::emitComponentCompleteSignalForAttachedProperty(QObject *object)
338{
339 if (!object)
340 return;
341
342 QQmlData *data = QQmlData::get(object);
343 if (data && data->context) {
344 QQmlComponentAttached *componentAttached = data->context->componentAttacheds();
345 while (componentAttached) {
346 if (componentAttached->parent())
347 if (componentAttached->parent() == object)
348 emit componentAttached->completed();
349
350 componentAttached = componentAttached->next();
351 }
352 }
353}
354
355QList<QObject*> QQuickDesignerSupport::statesForItem(QQuickItem *item)
356{
357 QList<QObject*> objectList;
358 const QList<QQuickState *> stateList = QQuickItemPrivate::get(item)->_states()->states();
359
360 objectList.reserve(asize: stateList.size());
361 for (QQuickState* state : stateList)
362 objectList.append(t: state);
363
364 return objectList;
365}
366
367bool QQuickDesignerSupport::isComponentComplete(QQuickItem *item)
368{
369 return QQuickItemPrivate::get(item)->componentComplete;
370}
371
372int QQuickDesignerSupport::borderWidth(QQuickItem *item)
373{
374 QQuickRectangle *rectangle = qobject_cast<QQuickRectangle*>(object: item);
375 if (rectangle)
376 return rectangle->border()->width();
377
378 return 0;
379}
380
381void QQuickDesignerSupport::refreshExpressions(QQmlContext *context)
382{
383 QQmlContextData::get(context)->refreshExpressions();
384}
385
386void QQuickDesignerSupport::setRootItem(QQuickView *view, QQuickItem *item)
387{
388 QQuickViewPrivate::get(view)->setRootObject(item);
389}
390
391bool QQuickDesignerSupport::isValidWidth(QQuickItem *item)
392{
393 return QQuickItemPrivate::get(item)->heightValid();
394}
395
396bool QQuickDesignerSupport::isValidHeight(QQuickItem *item)
397{
398 return QQuickItemPrivate::get(item)->widthValid();
399}
400
401void QQuickDesignerSupport::updateDirtyNode(QQuickItem *item)
402{
403 if (item->window())
404 QQuickWindowPrivate::get(c: item->window())->updateDirtyNode(item);
405}
406
407void QQuickDesignerSupport::activateDesignerMode()
408{
409 QQmlEnginePrivate::activateDesignerMode();
410}
411
412void QQuickDesignerSupport::disableComponentComplete()
413{
414 QQmlVME::disableComponentComplete();
415}
416
417void QQuickDesignerSupport::enableComponentComplete()
418{
419 QQmlVME::enableComponentComplete();
420}
421
422void QQuickDesignerSupport::polishItems(QQuickWindow *window)
423{
424 QQuickWindowPrivate::get(c: window)->polishItems();
425}
426
427ComponentCompleteDisabler::ComponentCompleteDisabler()
428{
429 QQuickDesignerSupport::disableComponentComplete();
430}
431
432ComponentCompleteDisabler::~ComponentCompleteDisabler()
433{
434 QQuickDesignerSupport::enableComponentComplete();
435}
436
437
438QT_END_NAMESPACE
439

source code of qtdeclarative/src/quick/designer/qquickdesignersupport.cpp