LCOV - code coverage report
Current view: top level - src/braille/internal - notationbraille.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 607 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) 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 "notationbraille.h"
      24              : 
      25              : #include "translation.h"
      26              : 
      27              : #include "engraving/dom/factory.h"
      28              : #include "engraving/dom/measure.h"
      29              : #include "engraving/dom/score.h"
      30              : #include "engraving/dom/segment.h"
      31              : #include "engraving/dom/select.h"
      32              : #include "engraving/dom/slur.h"
      33              : #include "engraving/dom/staff.h"
      34              : #include "engraving/dom/tie.h"
      35              : 
      36              : #include "engraving/editing/noteinput.h"
      37              : 
      38              : #include "notation/inotation.h"
      39              : #include "notation/inotationelements.h" // IWYU pragma: keep
      40              : #include "notation/inotationinteraction.h"
      41              : #include "notation/inotationnoteinput.h" // IWYU pragma: keep
      42              : #include "notationscene/notationcommands.h"
      43              : 
      44              : #include "braille.h"
      45              : #include "braillecode.h"
      46              : #include "brailleinput.h"
      47              : #include "brailleinputparser.h"
      48              : #include "louis.h"
      49              : 
      50              : using namespace muse;
      51              : using namespace muse::io;
      52              : using namespace mu::braille;
      53              : using namespace mu::notation;
      54              : 
      55              : namespace mu::engraving {
      56            0 : void NotationBraille::init()
      57              : {
      58            0 :     setEnabled(brailleConfiguration()->braillePanelEnabled());
      59            0 :     setCurrentItemPosition(-1, -1);
      60              : 
      61            0 :     setMode(BrailleMode::Navigation);
      62              : 
      63            0 :     path_t tablesdir = tablesDefaultDirPath();
      64            0 :     setTablesDir(tablesdir.toStdString().c_str());
      65            0 :     initTables(tablesdir.toStdString());
      66              : 
      67            0 :     std::string welcome = braille_translate(table_for_literature.c_str(), "Welcome to MuseScore Studio!");
      68            0 :     setBrailleInfo(QString(welcome.c_str()));
      69              : 
      70            0 :     brailleConfiguration()->braillePanelEnabledChanged().onNotify(this, [this]() {
      71            0 :         bool enabled = brailleConfiguration()->braillePanelEnabled();
      72            0 :         setEnabled(enabled);
      73            0 :     });
      74              : 
      75            0 :     updateTableForLyricsFromPreferences();
      76            0 :     brailleConfiguration()->brailleTableChanged().onNotify(this, [this]() {
      77            0 :         updateTableForLyricsFromPreferences();
      78            0 :     });
      79              : 
      80            0 :     setIntervalDirection(brailleConfiguration()->intervalDirection());
      81            0 :     brailleConfiguration()->intervalDirectionChanged().onNotify(this, [this]() {
      82            0 :         BrailleIntervalDirection direction = brailleConfiguration()->intervalDirection();
      83            0 :         setIntervalDirection(direction);
      84            0 :     });
      85              : 
      86            0 :     projectSession()->currentNotationChanged().onNotify(this, [this]() {
      87            0 :         if (notation()) {
      88            0 :             notation()->interaction()->selectionChanged().onNotify(this, [this]() {
      89            0 :                 doBraille();
      90            0 :             }, Mode::SetReplace);
      91              : 
      92            0 :             notation()->notationChanged().onReceive(this, [this](const muse::RectF&) {
      93            0 :                 setCurrentItemPosition(0, 0);
      94            0 :                 doBraille(true);
      95            0 :             }, Mode::SetReplace);
      96              : 
      97            0 :             notation()->interaction()->noteInput()->stateChanged().onNotify(this, [this]() {
      98            0 :                 if (interaction()->noteInput()->isNoteInputMode()) {
      99            0 :                     if (isNavigationMode()) {
     100            0 :                         setMode(BrailleMode::BrailleInput);
     101              :                     }
     102              :                 } else {
     103            0 :                     if (isBrailleInputMode()) {
     104            0 :                         setMode(BrailleMode::Navigation);
     105              :                     }
     106              :                 }
     107            0 :             }, Mode::SetReplace);
     108              : 
     109            0 :             notation()->interaction()->noteInput()->noteAdded().onNotify(this, [this]() {
     110            0 :                 if (currentEngravingItem() && currentEngravingItem()->isNote()) {
     111            0 :                     LOGD() << "Note added: " << currentEngravingItem()->accessibleInfo();
     112            0 :                     Note* note = toNote(currentEngravingItem());
     113            0 :                     brailleInput()->setOctave(note->octave());
     114              :                 }
     115            0 :             }, Mode::SetReplace);
     116              :         }
     117            0 :     }, Mode::SetReplace);
     118            0 : }
     119              : 
     120            0 : void NotationBraille::updateTableForLyricsFromPreferences()
     121              : {
     122            0 :     QString table = brailleConfiguration()->brailleTable();
     123            0 :     int startPos = table.indexOf('[');
     124            0 :     int endPos = table.indexOf(']');
     125            0 :     if (startPos != -1 && endPos != -1) {
     126            0 :         table = table.mid(startPos + 1, endPos - startPos - 1);
     127            0 :         QString table_full_path = QString::fromStdString(tables_dir) + "/" + table;
     128            0 :         if (check_tables(table_full_path.toStdString().c_str()) == 0) {
     129            0 :             updateTableForLyrics(table.toStdString());
     130              :         } else {
     131            0 :             LOGD() << "Table check error!";
     132              :         }
     133            0 :     }
     134            0 : }
     135              : 
     136            0 : void NotationBraille::doBraille(bool force)
     137              : {
     138            0 :     if (brailleConfiguration()->braillePanelEnabled()) {
     139            0 :         EngravingItem* e = nullptr;
     140            0 :         Measure* m = nullptr;
     141              : 
     142            0 :         if (selection()->isSingle()) {
     143            0 :             e = selection()->element();
     144            0 :             LOGD() << " selected " << e->accessibleInfo();
     145            0 :             m = e->findMeasure();
     146            0 :         } else if (selection()->isRange()) {
     147            0 :             for (auto el: selection()->elements()) {
     148            0 :                 if (el->isMeasure()) {
     149            0 :                     m = toMeasure(el);
     150            0 :                     break;
     151              :                 } else {
     152            0 :                     m = el->findMeasure();
     153            0 :                     if (m) {
     154            0 :                         break;
     155              :                     }
     156              :                 }
     157              :             }
     158            0 :             e = m ? m : selection()->elements().front();
     159            0 :         } else if (selection()->isList()) {
     160            0 :             e = selection()->elements().front();
     161            0 :             m = e->findMeasure();
     162              :         }
     163            0 :         if (e) {
     164            0 :             setCurrentEngravingItem(e, false);
     165              : 
     166            0 :             if (!m) {
     167            0 :                 brailleEngravingItemList()->clear();
     168            0 :                 Braille lb(score());
     169            0 :                 bool res = lb.convertItem(e, brailleEngravingItemList());
     170            0 :                 if (!res) {
     171            0 :                     QString txt = e->accessibleInfo();
     172            0 :                     std::string braille = braille_long_translate(table_for_literature.c_str(), txt.toStdString());
     173            0 :                     brailleEngravingItemList()->setBrailleStr(QString::fromStdString(braille));
     174            0 :                     setBrailleInfo(QString::fromStdString(braille));
     175            0 :                 } else {
     176            0 :                     setBrailleInfo(brailleEngravingItemList()->brailleStr());
     177              :                 }
     178            0 :                 current_measure = nullptr;
     179            0 :             } else {
     180            0 :                 if (m != current_measure || force) {
     181            0 :                     brailleEngravingItemList()->clear();
     182            0 :                     Braille lb(score());
     183            0 :                     lb.convertMeasure(m, brailleEngravingItemList());
     184            0 :                     setBrailleInfo(brailleEngravingItemList()->brailleStr());
     185            0 :                     current_measure = m;
     186            0 :                 }
     187            0 :                 current_bei = brailleEngravingItemList()->getItem(e);
     188            0 :                 if (current_bei != nullptr) {
     189            0 :                     setCurrentItemPosition(current_bei->start(), current_bei->end());
     190              :                 }
     191              :             }
     192              :         }
     193              :     }
     194            0 : }
     195              : 
     196            0 : mu::engraving::Score* NotationBraille::score()
     197              : {
     198            0 :     return notation()->elements()->msScore()->score();
     199              : }
     200              : 
     201            0 : mu::engraving::Selection* NotationBraille::selection()
     202              : {
     203            0 :     return &score()->selection();
     204              : }
     205              : 
     206            0 : ValCh<std::string> NotationBraille::brailleInfo() const
     207              : {
     208            0 :     return m_brailleInfo;
     209              : }
     210              : 
     211            0 : ValCh<int> NotationBraille::cursorPosition() const
     212              : {
     213            0 :     return m_cursorPosition;
     214              : }
     215              : 
     216            0 : ValCh<int> NotationBraille::currentItemPositionStart() const
     217              : {
     218            0 :     return m_currentItemPositionStart;
     219              : }
     220              : 
     221            0 : ValCh<int> NotationBraille::currentItemPositionEnd() const
     222              : {
     223            0 :     return m_currentItemPositionEnd;
     224              : }
     225              : 
     226            0 : ValCh<std::string> NotationBraille::keys() const
     227              : {
     228            0 :     return m_keys;
     229              : }
     230              : 
     231            0 : ValCh<bool> NotationBraille::enabled() const
     232              : {
     233            0 :     return m_enabled;
     234              : }
     235              : 
     236            0 : ValCh<BrailleIntervalDirection> NotationBraille::intervalDirection() const
     237              : {
     238            0 :     return m_intervalDirection;
     239              : }
     240              : 
     241            0 : ValCh<int> NotationBraille::mode() const
     242              : {
     243            0 :     return m_mode;
     244              : }
     245              : 
     246            0 : ValCh<std::string> NotationBraille::cursorColor() const
     247              : {
     248            0 :     return m_cursorColor;
     249              : }
     250              : 
     251            0 : void NotationBraille::setEnabled(bool enabled)
     252              : {
     253            0 :     if (enabled == m_enabled.val) {
     254            0 :         return;
     255              :     }
     256            0 :     m_enabled.set(enabled);
     257              : }
     258              : 
     259            0 : void NotationBraille::setIntervalDirection(const BrailleIntervalDirection direction)
     260              : {
     261            0 :     if (direction == m_intervalDirection.val) {
     262            0 :         return;
     263              :     }
     264            0 :     m_intervalDirection.set(direction);
     265              : }
     266              : 
     267            0 : BrailleEngravingItemList* NotationBraille::brailleEngravingItemList()
     268              : {
     269            0 :     return &m_beil;
     270              : }
     271              : 
     272            0 : QString NotationBraille::getBrailleStr()
     273              : {
     274            0 :     return m_beil.brailleStr();
     275              : }
     276              : 
     277            0 : BrailleInputState* NotationBraille::brailleInput()
     278              : {
     279            0 :     return &m_braille_input;
     280              : }
     281              : 
     282            0 : void NotationBraille::setBrailleInfo(const QString& info)
     283              : {
     284            0 :     std::string infoStd = info.toStdString();
     285              : 
     286            0 :     if (m_brailleInfo.val == infoStd) {
     287            0 :         return;
     288              :     }
     289              : 
     290            0 :     m_brailleInfo.set(infoStd);
     291            0 : }
     292              : 
     293            0 : void NotationBraille::setCursorPosition(const int pos)
     294              : {
     295            0 :     if (!isNavigationMode()) {
     296            0 :         return;
     297              :     }
     298              : 
     299            0 :     if (m_cursorPosition.val == pos || pos == 0) {
     300            0 :         return;
     301              :     }
     302              : 
     303            0 :     m_cursorPosition.set(pos);
     304              : 
     305            0 :     current_bei = brailleEngravingItemList()->getItem(pos);
     306            0 :     if (current_bei != NULL && current_bei->el() != NULL
     307            0 :         && (current_bei->type() == BEIType::EngravingItem
     308            0 :             || current_bei->type() == BEIType::LyricItem)) {
     309            0 :         setCurrentEngravingItem(current_bei->el(), true);
     310              :     }
     311              : }
     312              : 
     313            0 : void NotationBraille::setCurrentItemPosition(const int start, const int end)
     314              : {
     315            0 :     if (m_currentItemPositionStart.val == start
     316            0 :         && m_currentItemPositionEnd.val == end) {
     317            0 :         return;
     318              :     }
     319              : 
     320            0 :     m_currentItemPositionStart.set(start);
     321            0 :     m_currentItemPositionEnd.set(end);
     322              : }
     323              : 
     324            0 : INotationPtr NotationBraille::notation()
     325              : {
     326            0 :     return projectSession()->currentNotation();
     327              : }
     328              : 
     329            0 : INotationInteractionPtr NotationBraille::interaction()
     330              : {
     331            0 :     return notation() ? notation()->interaction() : nullptr;
     332              : }
     333              : 
     334            0 : DurationType getDuration(const QString key)
     335              : {
     336              :     static const DurationType types[] = {
     337              :         DurationType::V_64TH, DurationType::V_32ND, DurationType::V_16TH,
     338              :         DurationType::V_EIGHTH, DurationType::V_QUARTER, DurationType::V_HALF,
     339              :         DurationType::V_WHOLE, DurationType::V_BREVE, DurationType::V_LONG
     340              :     };
     341            0 :     bool is_ok = false;
     342            0 :     int val = key.toInt(&is_ok);
     343              : 
     344            0 :     if (!is_ok || val < 1 || val > 9) {
     345            0 :         return DurationType::V_INVALID;
     346              :     } else {
     347            0 :         return types[val - 1];
     348              :     }
     349              : }
     350              : 
     351            0 : void NotationBraille::setInputNoteDuration(Duration d)
     352              : {
     353            0 :     InputState& inputState = score()->inputState();
     354            0 :     inputState.setDuration(d);
     355            0 :     score()->setInputState(inputState);
     356            0 :     brailleInput()->setCurrentDuration(d.type());
     357            0 : }
     358              : 
     359            0 : void NotationBraille::setTupletDuration(int tuplet, Duration d)
     360              : {
     361            0 :     LOGD() << tuplet << " " << (int)d.type();
     362            0 :     brailleInput()->setCurrentDuration(d.type());
     363              : 
     364            0 :     switch (tuplet) {
     365            0 :     case 2:
     366            0 :         d = d.shiftRetainDots(-1, false);
     367            0 :         d = d.shiftRetainDots(-1, true);
     368            0 :         break;
     369            0 :     case 3:
     370            0 :         d = d.shiftRetainDots(-1, false);
     371            0 :         break;
     372            0 :     case 5: case 6: case 7:
     373            0 :         d = d.shiftRetainDots(-2, false);
     374            0 :         break;
     375            0 :     case 8:
     376            0 :         d = d.shiftRetainDots(-2, false);
     377            0 :         d = d.shiftRetainDots(-1, true);
     378            0 :         break;
     379            0 :     case 9:
     380            0 :         d = d.shiftRetainDots(-3, false);
     381            0 :         break;
     382              :     }
     383            0 :     InputState& inputState = score()->inputState();
     384            0 :     inputState.setDuration(d);
     385            0 :     score()->setInputState(inputState);
     386            0 : }
     387              : 
     388            0 : static TupletOptions makeTupletOption(int num)
     389              : {
     390            0 :     TupletOptions option;
     391            0 :     switch (num) {
     392            0 :     case 2:
     393            0 :         option.ratio = { 2, 3 };
     394            0 :         break;
     395            0 :     case 3:
     396            0 :         option.ratio = { 3, 2 };
     397            0 :         break;
     398            0 :     case 5:
     399            0 :         option.ratio = { 5, 4 };
     400            0 :         break;
     401            0 :     case 6:
     402            0 :         option.ratio = { 6, 4 };
     403            0 :         break;
     404            0 :     case 7:
     405            0 :         option.ratio = { 7, 4 };
     406            0 :         break;
     407            0 :     case 8:
     408            0 :         option.ratio = { 8, 6 };
     409            0 :         break;
     410            0 :     case 9:
     411            0 :         option.ratio = { 9, 8 };
     412            0 :         break;
     413            0 :     default:
     414            0 :         break;
     415              :     }
     416            0 :     return option;
     417              : }
     418              : 
     419            0 : bool matchPattern(const std::string sequence, const std::string pattern)
     420              : {
     421            0 :     QStringList seqs = QString::fromStdString(sequence).split("+");
     422            0 :     QStringList pats = QString::fromStdString(pattern).split("+");
     423              : 
     424            0 :     if (seqs.length() != pats.length()) {
     425            0 :         return false;
     426              :     }
     427            0 :     seqs.sort();
     428            0 :     pats.sort();
     429              : 
     430            0 :     for (int i = 0; i < seqs.length(); i++) {
     431            0 :         if (seqs.at(i) != pats.at(i)) {
     432            0 :             return false;
     433              :         }
     434              :     }
     435            0 :     return true;
     436            0 : }
     437              : 
     438            0 : void NotationBraille::setKeys(const QString& sequence)
     439              : {
     440            0 :     LOGD() << sequence;
     441            0 :     std::string seq = sequence.toStdString();
     442            0 :     m_keys.set(seq);
     443              : 
     444            0 :     if (seq == "Left") {
     445            0 :         interaction()->select(SelectionTarget::PrevChord);
     446            0 :     } else if (seq == "Right") {
     447            0 :         interaction()->select(SelectionTarget::NextChord);
     448            0 :     } else if (matchPattern(seq, "Ctrl+Left")) {
     449            0 :         interaction()->select(SelectionTarget::PrevMeasure);
     450            0 :     } else if (matchPattern(seq, "Ctrl+Right")) {
     451            0 :         interaction()->select(SelectionTarget::NextMeasure);
     452            0 :     } else if (matchPattern(seq, "Alt+Left")) {
     453            0 :         interaction()->select(SelectionTarget::PrevItem);
     454            0 :     } else if (matchPattern(seq, "Alt+Right")) {
     455            0 :         interaction()->select(SelectionTarget::NextItem);
     456            0 :     } else if (matchPattern(seq, "Ctrl+End")) {
     457            0 :         interaction()->select(SelectionTarget::LastItem);
     458            0 :     } else if (matchPattern(seq, "Ctrl+Home")) {
     459            0 :         interaction()->select(SelectionTarget::FirstItem);
     460            0 :     } else if (seq == "Delete") {
     461            0 :         if (currentEngravingItem()) {
     462            0 :             interaction()->deleteSelection();
     463            0 :             if (!brailleInput()->intervals().empty()) {
     464            0 :                 brailleInput()->removeLastInterval();
     465              :             }
     466              :         }
     467            0 :     } else if (seq == "N") {
     468            0 :         toggleMode();
     469            0 :         brailleInput()->initialize();
     470            0 :     } else if (seq == "Plus") {
     471            0 :         if (isBrailleInputMode()) {
     472            0 :             interaction()->noteInput()->doubleNoteInputDuration();
     473              :         }
     474            0 :     } else if (seq == "Minus") {
     475            0 :         if (isBrailleInputMode()) {
     476            0 :             interaction()->noteInput()->halveNoteInputDuration();
     477              :         }
     478            0 :     } else if (matchPattern(seq, "Space+F") && isBrailleInputMode()) {
     479            0 :         brailleInput()->setNoteGroup(NoteGroup::Group1);
     480            0 :         brailleInput()->resetBuffer();
     481            0 :     } else if (matchPattern(seq, "Space+D") && isBrailleInputMode()) {
     482            0 :         brailleInput()->setNoteGroup(NoteGroup::Group2);
     483            0 :         brailleInput()->resetBuffer();
     484            0 :     } else if (matchPattern(seq, "Space+S") && isBrailleInputMode()) {
     485            0 :         brailleInput()->setNoteGroup(NoteGroup::Group3);
     486            0 :         brailleInput()->resetBuffer();
     487            0 :     } else if (matchPattern(seq, "Space+S+D+J+K") && isBrailleInputMode()) {
     488            0 :         LOGD() << "tuplet input";
     489            0 :         brailleInput()->setTupletIndicator(true);
     490            0 :         brailleInput()->resetBuffer();
     491            0 :     } else if (seq == "Space") {
     492            0 :         brailleInput()->reset();
     493            0 :     } else if (isBrailleInputMode() && !sequence.isEmpty()) {
     494            0 :         QString pattern = parseBrailleKeyInput(sequence);
     495            0 :         if (!pattern.isEmpty()) {
     496            0 :             brailleInput()->insertToBuffer(pattern);
     497              :         } else {
     498            0 :             brailleInput()->insertToBuffer(sequence);
     499              :         }
     500            0 :         LOGD() << brailleInput()->buffer();
     501            0 :         std::string braille = translate2Braille(brailleInput()->buffer().toStdString());
     502            0 :         BieRecognize(braille, brailleInput()->tupletIndicator());
     503              : 
     504            0 :         NoteName prevNoteName = NoteName::C;
     505            0 :         int prevNoteOctave = -1; // unknown octave
     506              : 
     507            0 :         if (const Segment* seg = interaction()->noteInput()->state().segment()) {
     508            0 :             const track_idx_t track = interaction()->noteInput()->state().track();
     509            0 :             Chord* prevChord = nullptr;
     510              : 
     511            0 :             for (Segment* s = seg->prev1(SegmentType::ChordRest); s; s = s->prev1(SegmentType::ChordRest)) {
     512            0 :                 EngravingItem* e = s->element(track);
     513            0 :                 if (e && e->isChord()) {
     514            0 :                     prevChord = toChord(e);
     515            0 :                     break;
     516              :                 }
     517              :             }
     518              : 
     519            0 :             if (prevChord) {
     520            0 :                 Note* rootNote = (currentIntervalDirection() == IntervalDirection::Up) ? prevChord->downNote() : prevChord->upNote();
     521            0 :                 String pitchName;
     522            0 :                 String accidental; // needed for tpc2name
     523            0 :                 tpc2name(rootNote->tpc(), NoteSpellingType::STANDARD, NoteCaseType::UPPER, pitchName, accidental);
     524            0 :                 size_t inote = String("CDEFGAB").indexOf(pitchName.at(0));
     525            0 :                 IF_ASSERT_FAILED(inote <= 6) {
     526              :                 } else {
     527            0 :                     prevNoteName = static_cast<NoteName>(inote);
     528            0 :                     prevNoteOctave = rootNote->octave();
     529              :                 }
     530            0 :             }
     531              :         }
     532              : 
     533            0 :         brailleInput()->setNoteName(prevNoteName, true);
     534            0 :         brailleInput()->setOctave(prevNoteOctave, true);
     535              : 
     536            0 :         BieSequencePatternType type = brailleInput()->parseBraille(currentIntervalDirection());
     537            0 :         switch (type) {
     538            0 :         case BieSequencePatternType::Note: {
     539            0 :             LOGD() << "note";
     540            0 :             if (brailleInput()->accidental() != mu::notation::AccidentalType::NONE) {
     541            0 :                 interaction()->noteInput()->setAccidental(brailleInput()->accidental());
     542              :             }
     543              : 
     544            0 :             setVoice(brailleInput()->accord());
     545              : 
     546            0 :             if (brailleInput()->tupletNumber() != -1
     547            0 :                 && brailleInput()->tupletDuration().type() != DurationType::V_INVALID) {
     548            0 :                 Duration duration = brailleInput()->tupletDuration();
     549            0 :                 int tuplet = brailleInput()->tupletNumber();
     550            0 :                 setTupletDuration(tuplet, duration);
     551            0 :                 TupletOptions option = makeTupletOption(brailleInput()->tupletNumber());
     552            0 :                 interaction()->noteInput()->addTuplet(option);
     553            0 :                 brailleInput()->clearTuplet();
     554              :             }
     555              : 
     556            0 :             DurationType d = brailleInput()->getCloseDuration();
     557            0 :             Duration duration = Duration(d);
     558            0 :             setInputNoteDuration(duration);
     559              : 
     560            0 :             NoteInputParams params;
     561            0 :             const int note = static_cast<int>(brailleInput()->noteName());
     562            0 :             bool ok = mu::engraving::NoteInput::resolveNoteInputParams(score(), note, /*addFlag*/ false, params);
     563            0 :             if (!ok) {
     564            0 :                 return;
     565              :             }
     566              : 
     567            0 :             interaction()->noteInput()->addNote(params, NoteAddingMode::NextChord);
     568              : 
     569            0 :             if (brailleInput()->addedOctave() != -1) {
     570            0 :                 if (brailleInput()->addedOctave() < brailleInput()->octave()) {
     571            0 :                     for (int i = brailleInput()->addedOctave(); i < brailleInput()->octave(); i++) {
     572            0 :                         interaction()->movePitch(MoveDirection::Down, PitchMode::OCTAVE);
     573              :                     }
     574            0 :                 } else if (brailleInput()->addedOctave() > brailleInput()->octave()) {
     575            0 :                     for (int i = brailleInput()->octave(); i < brailleInput()->addedOctave(); i++) {
     576            0 :                         interaction()->movePitch(MoveDirection::Up, PitchMode::OCTAVE);
     577              :                     }
     578              :                 }
     579            0 :                 brailleInput()->setOctave(brailleInput()->addedOctave(), true);
     580              :             }
     581              : 
     582            0 :             if (brailleInput()->longSlurStart()) {
     583            0 :                 if (brailleInput()->longSlurStartNote() == NULL) {
     584            0 :                     if (currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
     585            0 :                         Note* currentNote = toNote(currentEngravingItem());
     586            0 :                         brailleInput()->setLongSlurStartNote(currentNote);
     587              :                     }
     588              :                 }
     589              :             }
     590              : 
     591            0 :             if (brailleInput()->tieStartNote() != NULL) {
     592            0 :                 addTie();
     593            0 :                 brailleInput()->clearTie();
     594              :             }
     595              : 
     596            0 :             if (brailleInput()->slurStartNote() != NULL) {
     597            0 :                 addSlur();
     598            0 :                 brailleInput()->clearSlur();
     599              :             }
     600              : 
     601            0 :             playbackController()->playElements({ currentEngravingItem() });
     602            0 :             brailleInput()->reset();
     603            0 :             break;
     604              :         }
     605            0 :         case BieSequencePatternType::Rest: {
     606            0 :             LOGD() << "rest";
     607            0 :             DurationType d = brailleInput()->getCloseDuration();
     608            0 :             Duration duration = Duration(d);
     609            0 :             if (brailleInput()->dots() > 0) {
     610            0 :                 duration.setDots(brailleInput()->dots());
     611              :             }
     612            0 :             setInputNoteDuration(Duration(duration));
     613            0 :             interaction()->putRest(duration);
     614            0 :             brailleInput()->reset();
     615            0 :             break;
     616              :         }
     617            0 :         case BieSequencePatternType::Interval: {
     618            0 :             LOGD() << "interval";
     619            0 :             if (brailleInput()->accidental() != mu::notation::AccidentalType::NONE) {
     620            0 :                 interaction()->noteInput()->setAccidental(brailleInput()->accidental());
     621              :             }
     622              : 
     623            0 :             NoteInputParams params;
     624            0 :             const int note = static_cast<int>(brailleInput()->noteName());
     625            0 :             bool ok = mu::engraving::NoteInput::resolveNoteInputParams(score(), note, /*addFlag*/ true, params);
     626            0 :             if (!ok) {
     627            0 :                 return;
     628              :             }
     629              : 
     630            0 :             interaction()->noteInput()->addNote(params, NoteAddingMode::CurrentChord);
     631              : 
     632            0 :             if (brailleInput()->addedOctave() != -1) {
     633            0 :                 if (brailleInput()->addedOctave() < brailleInput()->octave()) {
     634            0 :                     for (int i = brailleInput()->addedOctave(); i < brailleInput()->octave(); i++) {
     635            0 :                         interaction()->movePitch(MoveDirection::Down, PitchMode::OCTAVE);
     636              :                     }
     637            0 :                 } else if (brailleInput()->addedOctave() > brailleInput()->octave()) {
     638            0 :                     for (int i = brailleInput()->octave(); i < brailleInput()->addedOctave(); i++) {
     639            0 :                         interaction()->movePitch(MoveDirection::Up, PitchMode::OCTAVE);
     640              :                     }
     641              :                 }
     642            0 :                 brailleInput()->setOctave(brailleInput()->addedOctave());
     643              :             }
     644            0 :             playbackController()->playElements({ currentEngravingItem() });
     645            0 :             brailleInput()->reset();
     646            0 :             break;
     647              :         }
     648            0 :         case BieSequencePatternType::Tuplet: case BieSequencePatternType::Tuplet3: {
     649            0 :             LOGD() << "tuplet";
     650            0 :             const QString stateTuplet = muse::qtrc("braille/notation", "Tuplet %1").arg(brailleInput()->tupletNumber());
     651            0 :             accessibilityController()->announce(stateTuplet);
     652            0 :             break;
     653            0 :         }
     654            0 :         case BieSequencePatternType::Tie: {
     655            0 :             LOGD() << "tie";
     656            0 :             if (brailleInput()->tie()) {
     657            0 :                 if (currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
     658            0 :                     Note* note = toNote(currentEngravingItem());
     659            0 :                     brailleInput()->setTieStartNote(note);
     660              :                 }
     661              :             }
     662            0 :             brailleInput()->reset();
     663            0 :             break;
     664              :         }
     665            0 :         case BieSequencePatternType::NoteSlur: {
     666            0 :             LOGD() << "note slur";
     667            0 :             if (brailleInput()->noteSlur()) {
     668            0 :                 if (brailleInput()->slurStartNote() == NULL) {
     669            0 :                     if (currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
     670            0 :                         Note* note = toNote(currentEngravingItem());
     671            0 :                         brailleInput()->setSlurStartNote(note);
     672              :                     }
     673              :                 }
     674              :             }
     675            0 :             brailleInput()->reset();
     676            0 :             break;
     677              :         }
     678            0 :         case BieSequencePatternType::LongSlurStop: {
     679            0 :             LOGD() << "long slur stop";
     680            0 :             if (brailleInput()->longSlurStop()) {
     681            0 :                 if (brailleInput()->longSlurStartNote() != NULL) {
     682            0 :                     addLongSlur();
     683            0 :                     brailleInput()->clearLongSlur();
     684              :                 }
     685              :             }
     686            0 :             brailleInput()->reset();
     687            0 :             break;
     688              :         }
     689            0 :         case BieSequencePatternType::Dot: {
     690            0 :             LOGD() << "dot " << brailleInput()->dots();
     691            0 :             if (brailleInput()->dots() > 0) {
     692            0 :                 interaction()->increaseDecreaseDuration(-brailleInput()->dots(), true);
     693              :             }
     694            0 :             brailleInput()->reset();
     695            0 :             break;
     696              :         }
     697            0 :         default: {
     698              :             // TODO
     699              :         }
     700              :         }
     701            0 :     } else if (isBrailleInputMode() && !sequence.isEmpty()) {
     702            0 :         QString pattern = parseBrailleKeyInput(sequence);
     703            0 :         if (!pattern.isEmpty()) {
     704            0 :             brailleInput()->insertToBuffer(pattern);
     705              :         } else {
     706            0 :             brailleInput()->insertToBuffer(sequence);
     707              :         }
     708            0 :     }
     709            0 : }
     710              : 
     711            0 : bool NotationBraille::addTie()
     712              : {
     713            0 :     if (!brailleInput()->tieStartNote()) {
     714            0 :         return false;
     715              :     }
     716              : 
     717            0 :     if (!currentEngravingItem() || !currentEngravingItem()->isNote()) {
     718            0 :         return false;
     719              :     }
     720              : 
     721            0 :     score()->startCmd(TranslatableString("undoableAction", "Add tie"));
     722              : 
     723            0 :     Note* startNote = brailleInput()->tieStartNote();
     724            0 :     Note* endNote = toNote(currentEngravingItem());
     725              : 
     726            0 :     Tie* tie = Factory::createTie(startNote);
     727            0 :     tie->setStartNote(startNote);
     728            0 :     tie->setEndNote(endNote);
     729            0 :     tie->setTrack(startNote->track());
     730            0 :     tie->setTick(startNote->chord()->segment()->tick());
     731            0 :     tie->setTicks(endNote->chord()->segment()->tick() - startNote->chord()->segment()->tick());
     732            0 :     score()->undoAddElement(tie);
     733            0 :     score()->endCmd();
     734            0 :     return true;
     735              : }
     736              : 
     737            0 : bool NotationBraille::addSlur()
     738              : {
     739            0 :     if (brailleInput()->slurStartNote() != NULL
     740            0 :         && currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
     741            0 :         Note* note1 = brailleInput()->slurStartNote();
     742            0 :         Note* note2 = toNote(currentEngravingItem());
     743              : 
     744            0 :         if (note1->parent()->isChordRest() && note2->parent()->isChordRest()) {
     745            0 :             LOGD() << "add slur";
     746            0 :             ChordRest* firstChordRest = toChordRest(note1->parent());
     747            0 :             ChordRest* secondChordRest = toChordRest(note2->parent());
     748              : 
     749            0 :             score()->startCmd(TranslatableString("undoableAction", "Add slur"));
     750              : 
     751            0 :             Slur* slur = Factory::createSlur(firstChordRest->score()->dummy());
     752            0 :             slur->setScore(firstChordRest->score());
     753            0 :             slur->setTick(firstChordRest->tick());
     754            0 :             slur->setTick2(secondChordRest->tick());
     755            0 :             slur->setTrack(firstChordRest->track());
     756            0 :             if (secondChordRest->staff()->part() == firstChordRest->staff()->part()
     757            0 :                 && !secondChordRest->staff()->isLinked(firstChordRest->staff())) {
     758            0 :                 slur->setTrack2(secondChordRest->track());
     759              :             } else {
     760            0 :                 slur->setTrack2(firstChordRest->track());
     761              :             }
     762            0 :             slur->setStartElement(firstChordRest);
     763            0 :             slur->setEndElement(secondChordRest);
     764              : 
     765            0 :             firstChordRest->score()->undoAddElement(slur);
     766            0 :             SlurSegment* ss = new SlurSegment(slur);
     767            0 :             ss->setSpannerSegmentType(SpannerSegmentType::SINGLE);
     768            0 :             if (firstChordRest == secondChordRest) {
     769            0 :                 ss->setSlurOffset(Grip::END, PointF(3.0 * firstChordRest->spatium(), 0.0));
     770              :             }
     771            0 :             slur->add(ss);
     772              : 
     773            0 :             score()->endCmd();
     774            0 :             doBraille(true);
     775            0 :             return true;
     776              :         }
     777            0 :         return false;
     778              :     } else {
     779            0 :         return false;
     780              :     }
     781              : }
     782              : 
     783            0 : bool NotationBraille::addLongSlur()
     784              : {
     785            0 :     if (brailleInput()->longSlurStartNote() != NULL
     786            0 :         && currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
     787            0 :         Note* note1 = brailleInput()->longSlurStartNote();
     788            0 :         Note* note2 = toNote(currentEngravingItem());
     789              : 
     790            0 :         if (note1->parent()->isChordRest() && note2->parent()->isChordRest()) {
     791            0 :             ChordRest* firstChordRest = toChordRest(note1->parent());
     792            0 :             ChordRest* secondChordRest = toChordRest(note2->parent());
     793              : 
     794            0 :             score()->startCmd(TranslatableString("undoableAction", "Add long slur"));
     795              : 
     796            0 :             Slur* slur = Factory::createSlur(firstChordRest->score()->dummy());
     797            0 :             slur->setScore(firstChordRest->score());
     798            0 :             slur->setTick(firstChordRest->tick());
     799            0 :             slur->setTick2(secondChordRest->tick());
     800            0 :             slur->setTrack(firstChordRest->track());
     801            0 :             if (secondChordRest->staff()->part() == firstChordRest->staff()->part()
     802            0 :                 && !secondChordRest->staff()->isLinked(firstChordRest->staff())) {
     803            0 :                 slur->setTrack2(secondChordRest->track());
     804              :             } else {
     805            0 :                 slur->setTrack2(firstChordRest->track());
     806              :             }
     807            0 :             slur->setStartElement(firstChordRest);
     808            0 :             slur->setEndElement(secondChordRest);
     809              : 
     810            0 :             firstChordRest->score()->undoAddElement(slur);
     811            0 :             SlurSegment* ss = new SlurSegment(slur);
     812            0 :             ss->setSpannerSegmentType(SpannerSegmentType::SINGLE);
     813            0 :             if (firstChordRest == secondChordRest) {
     814            0 :                 ss->setSlurOffset(Grip::END, PointF(3.0 * firstChordRest->spatium(), 0.0));
     815              :             }
     816            0 :             slur->add(ss);
     817              : 
     818            0 :             score()->endCmd();
     819            0 :             doBraille(true);
     820            0 :             return true;
     821              :         }
     822            0 :         return false;
     823              :     } else {
     824            0 :         return false;
     825              :     }
     826              : }
     827              : 
     828            0 : bool NotationBraille::setVoice(bool new_voice)
     829              : {
     830            0 :     if (currentEngravingItem() == NULL || currentMeasure() == NULL) {
     831            0 :         return false;
     832              :     }
     833              : 
     834            0 :     staff_idx_t staff = currentEngravingItem()->staffIdx();
     835              : 
     836            0 :     if (new_voice) {
     837            0 :         int voices = 0;
     838            0 :         for (size_t i = 1; i < VOICES; ++i) {
     839            0 :             if (current_measure->hasVoice(staff * VOICES + i)) {
     840            0 :                 voices++;
     841              :             }
     842              :         }
     843            0 :         if (voices >= 3) {
     844            0 :             return false;
     845              :         }
     846              : 
     847            0 :         score()->inputState().moveInputPos(currentMeasure()->segments().firstCRSegment());
     848            0 :         interaction()->noteInput()->setCurrentVoice(voices + 1);
     849            0 :         return true;
     850              :     } else {
     851            0 :         Segment* segment = score()->inputState().segment();
     852            0 :         Measure* measure = segment->measure();
     853            0 :         if (!measure->hasVoice(staff + 1) && segment->tick() == measure->tick()) {
     854            0 :             interaction()->noteInput()->setCurrentVoice(0);
     855              :         }
     856            0 :         return false;
     857              :     }
     858              : }
     859              : 
     860            0 : void NotationBraille::setMode(const BrailleMode mode)
     861              : {
     862            0 :     switch (mode) {
     863            0 :     case BrailleMode::Undefined:
     864              :     case BrailleMode::Navigation:
     865            0 :         setCursorColor("black");
     866            0 :         break;
     867            0 :     case BrailleMode::BrailleInput:
     868            0 :         setCursorColor("green");
     869            0 :         break;
     870              :     }
     871              : 
     872            0 :     m_mode.set((int)mode);
     873            0 : }
     874              : 
     875            0 : void NotationBraille::toggleMode()
     876              : {
     877            0 :     switch ((BrailleMode)mode().val) {
     878            0 :     case BrailleMode::Undefined:
     879              :     case BrailleMode::Navigation:
     880            0 :         setMode(BrailleMode::BrailleInput);
     881            0 :         break;
     882            0 :     case BrailleMode::BrailleInput:
     883            0 :         setMode(BrailleMode::Navigation);
     884            0 :         break;
     885              :     }
     886              : 
     887            0 :     commandDispatcher()->dispatch(notation::TOGGLE_NOTE_INPUT_COMMAND);
     888              : 
     889            0 :     const QString stateTitle = interaction()->noteInput()->isNoteInputMode()
     890              :                                //: Braille input with 6 keyboard keys (F,D,S & J,K,L) to represent the 6 dots in a braille cell.
     891            0 :                                ? muse::qtrc("braille/notation", "Six-key input mode")
     892              :                                //: Braille navigation.
     893            0 :                                : muse::qtrc("braille/notation", "Navigation mode");
     894              : 
     895            0 :     accessibilityController()->announce(stateTitle);
     896            0 : }
     897              : 
     898            0 : bool NotationBraille::isNavigationMode()
     899              : {
     900            0 :     return mode().val == (int)BrailleMode::Navigation;
     901              : }
     902              : 
     903            0 : bool NotationBraille::isBrailleInputMode()
     904              : {
     905            0 :     return mode().val == (int)BrailleMode::BrailleInput;
     906              : }
     907              : 
     908            0 : void NotationBraille::setCursorColor(const QString color)
     909              : {
     910            0 :     m_cursorColor.set(color.toStdString());
     911            0 : }
     912              : 
     913            0 : path_t NotationBraille::tablesDefaultDirPath() const
     914              : {
     915            0 :     return globalConfiguration()->appDataPath() + "tables";
     916              : }
     917              : 
     918            0 : void NotationBraille::setCurrentEngravingItem(EngravingItem* e, bool select)
     919              : {
     920            0 :     if (!e) {
     921            0 :         return;
     922              :     }
     923              : 
     924            0 :     bool play = current_engraving_item != e;
     925            0 :     current_engraving_item = e;
     926            0 :     if (isNavigationMode()) {
     927            0 :         if (select) {
     928            0 :             if (play) {
     929            0 :                 playbackController()->playElements({ e });
     930              :             }
     931            0 :             if (e->isChord()) {
     932            0 :                 e = toChord(e)->upNote(); // select a note rather than the chord
     933              :             }
     934            0 :             interaction()->select({ e });
     935              :         }
     936              :     }
     937              : }
     938              : 
     939            0 : IntervalDirection NotationBraille::currentIntervalDirection()
     940              : {
     941            0 :     switch (m_intervalDirection.val) {
     942            0 :     case BrailleIntervalDirection::Up:
     943            0 :         return IntervalDirection::Up;
     944            0 :     case BrailleIntervalDirection::Down:
     945            0 :         return IntervalDirection::Down;
     946            0 :     case BrailleIntervalDirection::Auto:
     947            0 :         break;
     948              :     }
     949            0 :     if (EngravingItem* element = currentEngravingItem()) {
     950            0 :         if (Staff* staff = element->staff()) {
     951            0 :             ClefType clef = staff->clef(element->tick());
     952            0 :             if (clef >= ClefType::G && clef <= ClefType::C3) {
     953            0 :                 return IntervalDirection::Down;
     954              :             }
     955            0 :             return IntervalDirection::Up;
     956              :         }
     957              :     }
     958            0 :     return IntervalDirection::Down;
     959              : }
     960              : 
     961            0 : EngravingItem* NotationBraille::currentEngravingItem()
     962              : {
     963            0 :     return current_engraving_item;
     964              : }
     965              : 
     966            0 : Measure* NotationBraille::currentMeasure()
     967              : {
     968            0 :     return current_measure;
     969              : }
     970              : }
        

Generated by: LCOV version 2.0-1