LCOV - code coverage report
Current view: top level - src/notationscene/qml/MuseScore/NotationScene - notationruler.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 99 0
Test Date: 2026-11-05 04:07:02

            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 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 "notationruler.h"
      24              : 
      25              : #include "draw/types/color.h"
      26              : #include "draw/types/drawtypes.h"
      27              : 
      28              : #include "engraving/dom/measure.h"
      29              : #include "engraving/dom/score.h"
      30              : #include "engraving/dom/segment.h"
      31              : #include "engraving/dom/staff.h"
      32              : #include "engraving/dom/sig.h"
      33              : #include "engraving/dom/system.h"
      34              : #include "engraving/dom/timesig.h"
      35              : 
      36              : #include "ui/view/iconcodes.h"
      37              : #include "draw/painter.h"
      38              : 
      39              : using namespace mu::notation;
      40              : using namespace mu::engraving;
      41              : using namespace muse::draw;
      42              : 
      43            0 : void NotationRuler::paint(Painter* painter, const NoteInputState& state)
      44              : {
      45            0 :     TRACEFUNC;
      46              : 
      47            0 :     if (!state.isValid()) {
      48            0 :         return;
      49              :     }
      50              : 
      51            0 :     const Staff* staff = state.staff();
      52            0 :     const Segment* currSegment = state.segment();
      53            0 :     const System* system = currSegment->system();
      54            0 :     const Measure* measure = currSegment->measure();
      55            0 :     const SysStaff* sysStaff = system ? system->staff(state.staffIdx()) : nullptr;
      56            0 :     const TimeSig* timeSig = staff ? staff->timeSig(state.tick()) : nullptr;
      57              : 
      58            0 :     if (!measure || !sysStaff || !timeSig) {
      59            0 :         return;
      60              :     }
      61              : 
      62            0 :     const muse::PointF measurePos = measure->canvasPos();
      63            0 :     const size_t lineCount = timeSig->numerator() * 2;
      64            0 :     const double spatium = staff->score()->style().spatium();
      65            0 :     const double aboveStaffSpacing = spatium * 2;
      66            0 :     const double lineY = measurePos.y() + sysStaff->y() - aboveStaffSpacing;
      67              : 
      68            0 :     if (state.beyondScore()) {
      69            0 :         const Measure* lastMeasure = state.staff()->score()->lastMeasure();
      70            0 :         const double lineX = lastMeasure->pageBoundingRect().right() + spatium;
      71            0 :         paintLine(painter, LineType::CurrentPosition, PointF(lineX, lineY), spatium, state.voice());
      72            0 :         return;
      73              :     }
      74              : 
      75            0 :     const int inputTicks = state.tick().ticks();
      76            0 :     const int measureTicks = measure->tick().ticks();
      77            0 :     const int ticksBeat = mu::engraving::ticks_beat(timeSig->denominator());
      78            0 :     const int subdivisionTicks = ticksBeat / 2;
      79              : 
      80            0 :     std::map<size_t, const Segment*> lineToSegment;
      81              : 
      82            0 :     for (const Segment& segment : measure->segments()) {
      83            0 :         if (!segment.isChordRestType()) {
      84            0 :             continue;
      85              :         }
      86              : 
      87            0 :         const int segmentTicks = segment.tick().ticks();
      88            0 :         if (segmentTicks % subdivisionTicks != 0) {
      89            0 :             continue; // this segment does not correspond to any line
      90              :         }
      91              : 
      92            0 :         const size_t line = (segmentTicks - measureTicks) / subdivisionTicks;
      93            0 :         lineToSegment[line] = &segment;
      94              :     }
      95              : 
      96            0 :     size_t prevAccurateLine = muse::nidx;
      97            0 :     bool currentPositionPainted = false;
      98              : 
      99            0 :     for (size_t i = 0; i < lineCount; ++i) {
     100            0 :         const int lineTicks = measureTicks + subdivisionTicks * static_cast<int>(i);
     101            0 :         double lineX = 0.0;
     102              : 
     103            0 :         auto it = lineToSegment.find(i);
     104            0 :         if (it != lineToSegment.end()) {
     105            0 :             lineX = measurePos.x() + it->second->x();
     106            0 :             prevAccurateLine = i;
     107            0 :         } else if (prevAccurateLine != muse::nidx) {
     108            0 :             auto prevIt = lineToSegment.find(prevAccurateLine);
     109            0 :             auto nextIt = std::next(prevIt);
     110              : 
     111            0 :             if (nextIt != lineToSegment.end()) {
     112            0 :                 const size_t dist = nextIt->first - prevIt->first;
     113            0 :                 const double segmentWidth = (nextIt->second->x() - prevIt->second->x()) / static_cast<double>(dist);
     114            0 :                 lineX = measurePos.x() + prevIt->second->x() + segmentWidth * (i % dist);
     115              :             } else {
     116            0 :                 const size_t dist = lineCount - prevIt->first;
     117            0 :                 const double segmentWidth = (measure->width() - prevIt->second->x()) / static_cast<double>(dist);
     118            0 :                 lineX = measurePos.x() + prevIt->second->x() + segmentWidth * (i % dist);
     119              :             }
     120              :         } else {
     121            0 :             UNREACHABLE;
     122              :             continue;
     123              :         }
     124              : 
     125            0 :         const LineType type = lineType(lineTicks, inputTicks, i);
     126            0 :         paintLine(painter, type, PointF(lineX, lineY), spatium, state.voice());
     127            0 :         currentPositionPainted |= type == LineType::CurrentPosition;
     128              :     }
     129              : 
     130            0 :     if (!currentPositionPainted) {
     131            0 :         const double lineX = measurePos.x() + currSegment->x();
     132            0 :         paintLine(painter, LineType::CurrentPosition, PointF(lineX, lineY), spatium, state.voice());
     133              :     }
     134            0 : }
     135              : 
     136            0 : NotationRuler::LineType NotationRuler::lineType(int lineTicks, int inputTicks, size_t lineIdx)
     137              : {
     138            0 :     if (lineTicks == inputTicks) {
     139            0 :         return LineType::CurrentPosition;
     140              :     }
     141              : 
     142            0 :     return lineIdx % 2 == 0 ? LineType::MainBeat : LineType::Subdivision;
     143              : }
     144              : 
     145            0 : void NotationRuler::paintLine(Painter* painter, LineType type, const PointF& point, double spatium, voice_idx_t voiceIdx)
     146              : {
     147            0 :     muse::RectF rect;
     148            0 :     muse::Color color = configuration()->selectionColor(voiceIdx);
     149              : 
     150            0 :     switch (type) {
     151            0 :     case LineType::CurrentPosition:
     152            0 :         rect.setHeight(spatium * 4.);
     153            0 :         rect.setWidth(spatium * 2.);
     154            0 :         rect.setX(point.x() - rect.width() / 2);
     155            0 :         color.setAlpha(192);
     156            0 :         break;
     157            0 :     case LineType::MainBeat:
     158            0 :         rect.setHeight(spatium * 2.);
     159            0 :         rect.setWidth(spatium / 6.);
     160            0 :         rect.setX(point.x());
     161            0 :         color.setAlpha(192);
     162            0 :         break;
     163            0 :     case LineType::Subdivision:
     164            0 :         rect.setHeight(spatium);
     165            0 :         rect.setWidth(spatium / 6.);
     166            0 :         rect.setX(point.x());
     167            0 :         color.setAlpha(128);
     168            0 :         break;
     169              :     }
     170              : 
     171            0 :     rect.setY(point.y() - rect.height());
     172              : 
     173            0 :     if (type == LineType::CurrentPosition) {
     174            0 :         Font font(uiConfiguration()->iconsFontFamily(), Font::Type::Icon);
     175            0 :         font.setPointSizeF(spatium / 6.);
     176              : 
     177            0 :         painter->setPen(color);
     178            0 :         painter->setFont(font);
     179            0 :         painter->drawText(rect, AlignHCenter | AlignBottom, TextDontClip,
     180            0 :                           Char(static_cast<char16_t>(muse::ui::IconCode::Code::DURATION_CURSOR)));
     181            0 :     } else {
     182            0 :         painter->fillRect(rect, color);
     183              :     }
     184            0 : }
        

Generated by: LCOV version 2.0-1