Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "page.h"
24 :
25 : #ifndef ENGRAVING_NO_ACCESSIBILITY
26 : #include "accessibility/accessibleitem.h"
27 : #endif
28 :
29 : #include "factory.h"
30 : #include "measurebase.h"
31 : #include "mscore.h"
32 : #include "rootitem.h"
33 : #include "score.h"
34 : #include "system.h"
35 :
36 : using namespace mu::engraving;
37 :
38 : //---------------------------------------------------------
39 : // Page
40 : //---------------------------------------------------------
41 :
42 3554 : Page::Page(Score* parent)
43 3554 : : EngravingItem(ElementType::PAGE, parent, ElementFlag::NOT_SELECTABLE)
44 : {
45 3554 : m_bspTreeValid = false;
46 3554 : }
47 :
48 0 : void Page::setOwnershipParent(Score* score)
49 : {
50 0 : EngravingItem::setOwnershipParent(score);
51 0 : }
52 :
53 126770 : EngravingItem* Page::layoutParent() const
54 : {
55 : // A page is the top of the visual hierarchy: it is not laid out inside anything.
56 126770 : return nullptr;
57 : }
58 :
59 3 : EngravingItem* Page::accessibleParentItem() const
60 : {
61 : // Above the visual hierarchy sits the root item, which exists only to head the
62 : // accessibility tree. A page that is not in the score belongs to the dummy's tree,
63 : // which the base implementation finds.
64 3 : return ownershipParent() ? score()->rootItem() : EngravingItem::accessibleParentItem();
65 : }
66 :
67 6624 : Page::~Page()
68 : {
69 3315 : for (System* s : m_systems) {
70 3 : if (s->page() == this) {
71 0 : s->setPage(nullptr);
72 : }
73 : }
74 6624 : }
75 :
76 10228 : MeasureBase* Page::firstMeasureBase() const
77 : {
78 10228 : if (m_systems.empty()) {
79 0 : return nullptr;
80 : }
81 10228 : System* firstSys = m_systems.front();
82 10228 : return firstSys ? firstSys->first() : nullptr;
83 : }
84 :
85 7 : MeasureBase* Page::lastMeasureBase() const
86 : {
87 7 : if (m_systems.empty()) {
88 0 : return nullptr;
89 : }
90 7 : System* lastSys = m_systems.back();
91 7 : return lastSys ? lastSys->last() : nullptr;
92 : }
93 :
94 : //---------------------------------------------------------
95 : // items
96 : //---------------------------------------------------------
97 :
98 5 : std::vector<EngravingItem*> Page::items(const RectF& rect)
99 : {
100 5 : if (!m_bspTreeValid) {
101 5 : doRebuildBspTree();
102 : }
103 5 : return bspTree.items(rect);
104 : }
105 :
106 0 : std::vector<EngravingItem*> Page::items(const PointF& point)
107 : {
108 0 : if (!m_bspTreeValid) {
109 0 : doRebuildBspTree();
110 : }
111 0 : return bspTree.items(point);
112 : }
113 :
114 : //---------------------------------------------------------
115 : // appendSystem
116 : //---------------------------------------------------------
117 :
118 10053 : void Page::appendSystem(System* s)
119 : {
120 10053 : s->setPage(this);
121 10053 : m_systems.push_back(s);
122 10053 : }
123 :
124 4 : EngravingItemList Page::accessibleChildren() const
125 : {
126 : // The systems are owned by the score, but it is the page that places them, so the
127 : // page is where the accessibility tree finds them.
128 4 : EngravingItemList children = EngravingItem::accessibleChildren();
129 4 : children.insert(children.end(), m_systems.begin(), m_systems.end());
130 :
131 4 : return children;
132 0 : }
133 :
134 : #ifndef ENGRAVING_NO_ACCESSIBILITY
135 0 : AccessibleItemPtr Page::createAccessible()
136 : {
137 0 : return std::make_shared<AccessibleItem>(this, AccessibleItem::Group);
138 : }
139 :
140 : #endif
141 :
142 : //---------------------------------------------------------
143 : // scanElements
144 : //---------------------------------------------------------
145 :
146 14 : void Page::scanElements(std::function<void(EngravingItem*)> func)
147 : {
148 40 : for (System* s :m_systems) {
149 166 : for (MeasureBase* m : s->measures()) {
150 140 : m->scanElements(func);
151 : }
152 26 : s->scanElements(func);
153 : }
154 :
155 14 : func(this);
156 :
157 56 : for (int i = 0; i < MAX_HEADERS; i++) {
158 42 : if (Text* t = headerText(i)) {
159 0 : func(t);
160 : }
161 : }
162 56 : for (int i = 0; i < MAX_FOOTERS; i++) {
163 42 : if (Text* t = footerText(i)) {
164 0 : func(t);
165 : }
166 : }
167 14 : }
168 :
169 : //---------------------------------------------------------
170 : // doRebuildBspTree
171 : //---------------------------------------------------------
172 :
173 5 : void Page::doRebuildBspTree()
174 : {
175 5 : int n = 0;
176 390 : auto countElements = [&](EngravingItem* item) {
177 390 : if (item->collectForDrawing()) {
178 390 : ++n;
179 : }
180 395 : };
181 :
182 5 : scanElements(countElements);
183 :
184 5 : RectF r;
185 5 : if (score()->linearMode()) {
186 0 : double w = 0.0;
187 0 : double h = 0.0;
188 0 : if (!m_systems.empty()) {
189 0 : h = m_systems.front()->height();
190 0 : if (!m_systems.front()->measures().empty()) {
191 0 : MeasureBase* mb = m_systems.front()->measures().back();
192 0 : w = mb->x() + mb->width();
193 : }
194 : }
195 0 : r = RectF(0.0, 0.0, w, h);
196 : } else {
197 5 : r = pageBoundingRect();
198 : }
199 :
200 5 : bspTree.initialize(r, n);
201 :
202 390 : auto bspInsert = [&] (EngravingItem* item) {
203 390 : if (item->collectForDrawing()) {
204 390 : bspTree.insert(item);
205 : }
206 395 : };
207 5 : scanElements(bspInsert);
208 :
209 5 : m_bspTreeValid = true;
210 5 : }
211 :
212 : //---------------------------------------------------------
213 : // getDisplayPageNumber
214 : //---------------------------------------------------------
215 :
216 33490 : int Page::getDisplayPageNumber() const
217 : {
218 33490 : return static_cast<int>(m_pageNumber) + 1 + score()->pageNumberOffset();
219 : }
220 :
221 : //---------------------------------------------------------
222 : // isOdd
223 : //---------------------------------------------------------
224 :
225 28428 : bool Page::isOdd() const
226 : {
227 28428 : return getDisplayPageNumber() & 1;
228 : }
229 :
230 : //---------------------------------------------------------
231 : // elements
232 : //---------------------------------------------------------
233 :
234 4 : std::vector<EngravingItem*> Page::elements() const
235 : {
236 4 : return getChildren(false);
237 : }
238 :
239 : //---------------------------------------------------------
240 : // tm
241 : //---------------------------------------------------------
242 :
243 7600 : double Page::tm() const
244 : {
245 15049 : return ((!style().styleB(Sid::pageTwosided) || isOdd())
246 15049 : ? style().styleD(Sid::pageOddTopMargin) : style().styleD(Sid::pageEvenTopMargin)) * DPI;
247 : }
248 :
249 : //---------------------------------------------------------
250 : // bm
251 : //---------------------------------------------------------
252 :
253 10585 : double Page::bm() const
254 : {
255 20987 : return ((!style().styleB(Sid::pageTwosided) || isOdd())
256 20987 : ? style().styleD(Sid::pageOddBottomMargin) : style().styleD(Sid::pageEvenBottomMargin)) * DPI;
257 : }
258 :
259 : //---------------------------------------------------------
260 : // lm
261 : //---------------------------------------------------------
262 :
263 10800 : double Page::lm() const
264 : {
265 21377 : return ((!style().styleB(Sid::pageTwosided) || isOdd())
266 21377 : ? style().styleD(Sid::pageOddLeftMargin) : style().styleD(Sid::pageEvenLeftMargin)) * DPI;
267 : }
268 :
269 : //---------------------------------------------------------
270 : // rm
271 : //---------------------------------------------------------
272 :
273 240 : double Page::rm() const
274 : {
275 240 : return (style().styleD(Sid::pageWidth) - style().styleD(Sid::pagePrintableWidth)) * DPI - lm();
276 : }
277 :
278 : //---------------------------------------------------------
279 : // tbbox
280 : // calculates and returns smallest rectangle containing all (visible) page elements
281 : //---------------------------------------------------------
282 :
283 0 : RectF Page::tbbox() const
284 : {
285 0 : double x1 = width();
286 0 : double x2 = 0.0;
287 0 : double y1 = height();
288 0 : double y2 = 0.0;
289 0 : const std::vector<EngravingItem*> el = elements();
290 0 : for (EngravingItem* e : el) {
291 0 : if (e == this || !e->isPrintable()) {
292 0 : continue;
293 : }
294 0 : RectF ebbox = e->pageBoundingRect();
295 0 : if (ebbox.left() < x1) {
296 0 : x1 = ebbox.left();
297 : }
298 0 : if (ebbox.right() > x2) {
299 0 : x2 = ebbox.right();
300 : }
301 0 : if (ebbox.top() < y1) {
302 0 : y1 = ebbox.top();
303 : }
304 0 : if (ebbox.bottom() > y2) {
305 0 : y2 = ebbox.bottom();
306 : }
307 : }
308 0 : if (x1 < x2 && y1 < y2) {
309 0 : return RectF(x1, y1, x2 - x1, y2 - y1);
310 : } else {
311 0 : return pageBoundingRect();
312 : }
313 0 : }
314 :
315 : //---------------------------------------------------------
316 : // endTick
317 : //---------------------------------------------------------
318 :
319 643 : Fraction Page::endTick() const
320 : {
321 643 : return m_systems.empty() ? Fraction(-1, 1) : m_systems.back()->measures().back()->endTick();
322 : }
323 :
324 0 : Measure* Page::firstMeasure() const
325 : {
326 0 : for (System* s : m_systems) {
327 0 : if (Measure* m = s->firstMeasure()) {
328 0 : return m;
329 : }
330 : }
331 :
332 0 : return nullptr;
333 : }
334 :
335 18 : bool Page::isLocked() const
336 : {
337 18 : MeasureBase* firstMeasure = firstMeasureBase();
338 18 : return firstMeasure ? firstMeasure->isStartOfPageLock() : false;
339 : }
340 :
341 10195 : const RangeLock* Page::pageLock() const
342 : {
343 10195 : MeasureBase* firstMeasure = firstMeasureBase();
344 10195 : return firstMeasure ? firstMeasure->pageLock() : nullptr;
345 : }
|