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 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | BMGroup::BMGroup(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) |
17 | { |
18 | setParent(parent); |
19 | construct(definition, version); |
20 | } |
21 | |
22 | BMBase *BMGroup::clone() const |
23 | { |
24 | return new BMGroup(*this); |
25 | } |
26 | |
27 | void 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 | |
52 | void 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 | |
72 | void 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 | |
99 | bool BMGroup::acceptsTrim() const |
100 | { |
101 | return true; |
102 | } |
103 | |
104 | void 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 | |
119 | QT_END_NAMESPACE |
120 |