1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "bmgroup_p.h"
5
6#include <QJsonObject>
7#include <QJsonArray>
8
9#include "bmbase_p.h"
10#include "bmshape_p.h"
11#include "bmtrimpath_p.h"
12#include "bmbasictransform_p.h"
13
14QT_BEGIN_NAMESPACE
15
16BMGroup::BMGroup(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent)
17{
18 setParent(parent);
19 construct(definition, version);
20}
21
22BMBase *BMGroup::clone() const
23{
24 return new BMGroup(*this);
25}
26
27void BMGroup::construct(const QJsonObject &definition, const QVersionNumber &version)
28{
29 BMBase::parse(definition);
30 if (m_hidden)
31 return;
32
33 qCDebug(lcLottieQtBodymovinParser) << "BMGroup::construct()"
34 << m_name;
35
36 QJsonArray groupItems = definition.value(key: QLatin1String("it")).toArray();
37 QJsonArray::const_iterator itemIt = groupItems.constEnd();
38 while (itemIt != groupItems.constBegin()) {
39 itemIt--;
40 BMShape *shape = BMShape::construct(definition: (*itemIt).toObject(), version, parent: this);
41 if (shape) {
42 // Transform affects how group contents are drawn.
43 // It must be traversed first when drawing
44 if (shape->type() == BM_SHAPE_TRANS_IX)
45 prependChild(child: shape);
46 else
47 appendChild(child: shape);
48 }
49 }
50}
51
52void BMGroup::updateProperties(int frame)
53{
54 BMShape::updateProperties(frame);
55
56 for (BMBase *child : children()) {
57 if (child->hidden())
58 continue;
59
60 BMShape *shape = static_cast<BMShape*>(child);
61 if (shape->type() == BM_SHAPE_TRIM_IX) {
62 BMTrimPath *trim = static_cast<BMTrimPath*>(shape);
63 if (m_appliedTrim)
64 m_appliedTrim->applyTrim(trimmer: *trim);
65 else
66 m_appliedTrim = trim;
67 } else if (m_appliedTrim && shape->acceptsTrim())
68 shape->applyTrim(trimmer: *m_appliedTrim);
69 }
70}
71
72void BMGroup::render(LottieRenderer &renderer) const
73{
74 qCDebug(lcLottieQtBodymovinRender) << "Group:" << name();
75
76 renderer.saveState();
77
78 if (m_appliedTrim && !m_appliedTrim->hidden()) {
79 if (m_appliedTrim->simultaneous())
80 renderer.setTrimmingState(LottieRenderer::Simultaneous);
81 else
82 renderer.setTrimmingState(LottieRenderer::Individual);
83 } else
84 renderer.setTrimmingState(LottieRenderer::Off);
85
86 for (BMBase *child : children()) {
87 if (child->hidden())
88 continue;
89 child->render(renderer);
90 }
91
92 if (m_appliedTrim && !m_appliedTrim->hidden()
93 && !m_appliedTrim->simultaneous())
94 m_appliedTrim->render(renderer);
95
96 renderer.restoreState();
97}
98
99bool BMGroup::acceptsTrim() const
100{
101 return true;
102}
103
104void BMGroup::applyTrim(const BMTrimPath &trimmer)
105{
106 Q_ASSERT_X(!m_appliedTrim, "BMGroup", "A trim already assigned");
107
108 m_appliedTrim = static_cast<BMTrimPath*>(trimmer.clone());
109 // Setting a friendly name helps in testing
110 m_appliedTrim->setName(QStringLiteral("Inherited from") + trimmer.name());
111
112 for (BMBase *child : children()) {
113 BMShape *shape = static_cast<BMShape*>(child);
114 if (shape->acceptsTrim())
115 shape->applyTrim(trimmer: *m_appliedTrim);
116 }
117}
118
119QT_END_NAMESPACE
120

source code of qtlottie/src/bodymovin/bmgroup.cpp