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 "mscoreview.h"
24 :
25 : #include "../dom/page.h"
26 : #include "../dom/score.h"
27 : #include "../dom/text.h"
28 :
29 : using namespace mu;
30 :
31 : namespace mu::engraving {
32 0 : static bool elementLower(const EngravingItem* e1, const EngravingItem* e2)
33 : {
34 0 : if (!e1->selectable()) {
35 0 : return false;
36 : }
37 0 : if (!e2->selectable()) {
38 0 : return true;
39 : }
40 0 : return e1->z() < e2->z();
41 : }
42 :
43 0 : EngravingItem* MuseScoreView::elementAt(const PointF& p) const
44 : {
45 0 : std::vector<EngravingItem*> el = elementsAt(p);
46 0 : EngravingItem* e = el.front();
47 0 : if (e && e->isPage()) {
48 0 : e = *std::next(el.begin());
49 : }
50 0 : return e;
51 0 : }
52 :
53 0 : Page* MuseScoreView::point2page(const PointF& p) const
54 : {
55 0 : if (score()->linearMode()) {
56 0 : return score()->pages().empty() ? 0 : score()->pages().front();
57 : }
58 0 : for (Page* page : score()->pages()) {
59 0 : if (page->ldata()->bbox().translated(page->pos()).contains(p)) {
60 0 : return page;
61 : }
62 : }
63 0 : return 0;
64 : }
65 :
66 : //---------------------------------------------------------
67 : // elementsAt
68 : // p is in canvas coordinates
69 : //---------------------------------------------------------
70 :
71 0 : const std::vector<EngravingItem*> MuseScoreView::elementsAt(const PointF& p) const
72 : {
73 0 : std::vector<EngravingItem*> el;
74 :
75 0 : Page* page = point2page(p);
76 0 : if (page) {
77 0 : el = page->items(p - page->pos());
78 0 : std::sort(el.begin(), el.end(), elementLower);
79 : }
80 :
81 0 : return el;
82 0 : }
83 :
84 0 : EngravingItem* MuseScoreView::elementNear(const PointF& pos) const
85 : {
86 0 : std::vector<EngravingItem*> near = elementsNear(pos);
87 0 : if (near.empty()) {
88 0 : return nullptr;
89 : }
90 0 : return near.front();
91 0 : }
92 :
93 0 : const std::vector<EngravingItem*> MuseScoreView::elementsNear(const PointF& pos) const
94 : {
95 0 : std::vector<EngravingItem*> ll;
96 0 : Page* page = point2page(pos);
97 0 : if (!page) {
98 0 : return ll;
99 : }
100 :
101 0 : PointF p = pos - page->pos();
102 0 : double w = selectionProximity();
103 0 : RectF r(p.x() - w, p.y() - w, 3.0 * w, 3.0 * w);
104 :
105 0 : std::vector<EngravingItem*> el = page->items(r);
106 0 : for (EngravingItem* e : el) {
107 0 : e->itemDiscovered = 0;
108 0 : if (!e->selectable() || e->isPage()) {
109 0 : continue;
110 : }
111 0 : if (e->contains(p)) {
112 0 : ll.push_back(e);
113 : }
114 : }
115 0 : size_t n = ll.size();
116 0 : if ((n == 0) || ((n == 1) && (ll[0]->isMeasure()))) {
117 : //
118 : // if no relevant element hit, look nearby
119 : //
120 0 : for (EngravingItem* e : el) {
121 0 : if (e->isPage() || !e->selectable()) {
122 0 : continue;
123 : }
124 0 : if (e->intersects(r)) {
125 0 : ll.push_back(e);
126 : }
127 : }
128 : }
129 0 : if (!ll.empty()) {
130 0 : std::sort(ll.begin(), ll.end(), elementLower);
131 : }
132 0 : return ll;
133 0 : }
134 : }
|