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) 2025 MuseScore Limited
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 "previewmeasure.h"
24 :
25 : #include <QPainter>
26 : #include <QLinearGradient>
27 :
28 : #include "draw/painter.h"
29 : #include "draw/internal/qpainterprovider.h"
30 :
31 : #include "engraving/dom/measure.h"
32 : #include "engraving/dom/score.h"
33 : #include "engraving/dom/shadownote.h"
34 : #include "engraving/dom/staff.h"
35 : #include "engraving/dom/system.h"
36 :
37 : using namespace mu::notation;
38 : using namespace mu::engraving;
39 : using namespace muse;
40 : using namespace muse::draw;
41 :
42 0 : void PreviewMeasure::setScore(const Score* score)
43 : {
44 0 : m_score = score;
45 0 : }
46 :
47 0 : bool PreviewMeasure::isValid() const
48 : {
49 0 : if (!m_score || !m_score->inputState().noteEntryMode()) {
50 0 : return false;
51 : }
52 :
53 0 : const ShadowNote* note = m_score->shadowNote();
54 0 : return (note && note->visible() && note->isBeyondScore()) || m_score->inputState().beyondScore();
55 : }
56 :
57 0 : muse::RectF PreviewMeasure::rect() const
58 : {
59 0 : if (!isValid()) {
60 0 : return muse::RectF();
61 : }
62 :
63 0 : const Measure* lastMeasure = m_score->lastMeasure();
64 0 : const PointF lastMeasurePos = lastMeasure->canvasPos();
65 :
66 0 : const Fraction tick = lastMeasure->endTick();
67 0 : const double spatium = m_score->style().spatium();
68 0 : const double previewWidth = 6 * spatium;
69 :
70 0 : RectF rect = RectF(lastMeasurePos.x() + lastMeasure->width(), lastMeasurePos.y(),
71 0 : previewWidth, lastMeasure->height());
72 :
73 0 : const Staff* firstStaff = m_score->staves().front();
74 0 : const double firstStaffLineWidth = m_score->style().styleAbsolute(Sid::staffLineWidth) * firstStaff->staffMag(tick);
75 :
76 0 : const Staff* lastStaff = m_score->staves().back();
77 0 : const double lastStaffLineWidth = m_score->style().styleAbsolute(Sid::staffLineWidth) * lastStaff->staffMag(tick);
78 :
79 0 : rect.adjust(0.0, -0.5 * firstStaffLineWidth, 0.0, 0.5 * lastStaffLineWidth);
80 :
81 0 : return rect;
82 : }
83 :
84 0 : void PreviewMeasure::paint(Painter* painter)
85 : {
86 0 : if (!isValid()) {
87 0 : return;
88 : }
89 :
90 0 : const Measure* lastMeasure = m_score->lastMeasure();
91 0 : const System* lastSystem = lastMeasure->system();
92 :
93 0 : if (!lastMeasure) {
94 0 : return;
95 : }
96 :
97 0 : const Fraction tick = lastMeasure->endTick();
98 0 : const double spatium = m_score->style().spatium();
99 0 : const double previewWidth = 6 * spatium;
100 :
101 0 : const PointF measurePos = lastMeasure->canvasPos();
102 0 : const double startX = measurePos.x() + lastMeasure->width();
103 :
104 0 : QColor lineColor = [&] {
105 0 : const Color color = configuration()->noteInputPreviewColor();
106 0 : if (color.isValid() && color != configuration()->selectionColor()) {
107 0 : return color.toQColor();
108 : } else {
109 0 : return configuration()->selectionColor(m_score->inputState().voice());
110 : }
111 0 : }();
112 :
113 0 : for (staff_idx_t staffIdx = 0; staffIdx < m_score->nstaves(); ++staffIdx) {
114 0 : Staff* staff = m_score->staff(staffIdx);
115 0 : SysStaff* sysStaff = lastSystem->staff(staffIdx);
116 :
117 0 : if (!sysStaff->show()) {
118 0 : continue;
119 : }
120 :
121 0 : const int staffLines = staff->lines(tick);
122 0 : const double lineDist = staff->staffType(tick)->lineDistance().toAbsolute(staff->staffMag(tick) * spatium);
123 0 : const double lineWidth = m_score->style().styleAbsolute(Sid::staffLineWidth) * staff->staffMag(tick);
124 :
125 0 : const double staffY = measurePos.y() + sysStaff->y();
126 :
127 0 : paintStaffLines(painter, PointF(startX, staffY), previewWidth, staffLines, lineDist, lineWidth, lineColor);
128 : }
129 : }
130 :
131 0 : void PreviewMeasure::paintStaffLines(Painter* painter, const PointF& pos, double width, int lines, double lineDist, double lineWidth,
132 : QColor lineColor)
133 : {
134 0 : if (lines <= 0 || width <= 0) {
135 0 : return;
136 : }
137 :
138 0 : QPainterProvider* qpainterProvider = dynamic_cast<QPainterProvider*>(painter->provider().get());
139 0 : QPainter* qpainter = qpainterProvider->qpainter();
140 :
141 0 : QLinearGradient gradient(pos.x(), pos.y(), pos.x() + width, pos.y());
142 0 : gradient.setColorAt(0, lineColor);
143 0 : lineColor.setAlpha(0);
144 0 : gradient.setColorAt(1, lineColor);
145 :
146 0 : qpainter->setBrush(Qt::NoBrush);
147 0 : qpainter->setPen(QPen(gradient, lineWidth, Qt::SolidLine, Qt::FlatCap));
148 :
149 0 : for (int i = 0; i < lines; ++i) {
150 0 : double y = pos.y() + i * lineDist;
151 0 : qpainter->drawLine(QLineF(pos.x(), y, pos.x() + width, y));
152 : }
153 0 : }
|