MuseScore/libmscore/input.cpp
2020-05-28 09:50:45 +02:00

278 lines
7.4 KiB
C++

//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2011 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENSE.GPL
//=============================================================================
#include "input.h"
#include "segment.h"
#include "part.h"
#include "staff.h"
#include "stem.h"
#include "hook.h"
#include "score.h"
#include "chord.h"
#include "rest.h"
#include "measure.h"
#include "accidental.h"
#include "durationtype.h"
#include "select.h"
namespace Ms {
class DrumSet;
//---------------------------------------------------------
// drumset
//---------------------------------------------------------
const Drumset* InputState::drumset() const
{
if (_segment == 0 || _track == -1) {
return 0;
}
return _segment->score()->staff(_track / VOICES)->part()->instrument(_segment->tick())->drumset();
}
//---------------------------------------------------------
// staffGroup
//---------------------------------------------------------
StaffGroup InputState::staffGroup() const
{
if (_segment == 0 || _track == -1) {
return StaffGroup::STANDARD;
}
return _segment->score()->staff(_track / VOICES)->staffType(_segment->tick())->group();
}
//---------------------------------------------------------
// tick
//---------------------------------------------------------
Fraction InputState::tick() const
{
return _segment ? _segment->tick() : Fraction(0,1);
}
//---------------------------------------------------------
// cr
//---------------------------------------------------------
ChordRest* InputState::cr() const
{
// _track could potentially be -1, for instance after navigation through a frame
return _segment && _track >= 0 ? toChordRest(_segment->element(_track)) : 0;
}
//---------------------------------------------------------
// setDots
//---------------------------------------------------------
void InputState::setDots(int n)
{
if (n && (!_duration.isValid() || _duration.isZero() || _duration.isMeasure())) {
_duration = TDuration::DurationType::V_QUARTER;
}
_duration.setDots(n);
}
//---------------------------------------------------------
// note
//---------------------------------------------------------
Note* InputState::note(Element* e)
{
return e && e->isNote() ? toNote(e) : nullptr;
}
//---------------------------------------------------------
// chordRest
//---------------------------------------------------------
ChordRest* InputState::chordRest(Element* e)
{
if (!e) {
return nullptr;
}
if (e->isChordRest()) {
return toChordRest(e);
}
if (e->isNote()) {
return toNote(e)->chord();
}
if (e->isStem()) {
return toStem(e)->chord();
}
if (e->isHook()) {
return toHook(e)->chord();
}
return nullptr;
}
//---------------------------------------------------------
// update
//---------------------------------------------------------
void InputState::update(Selection& selection)
{
setDuration(TDuration::DurationType::V_INVALID);
setRest(false);
setAccidentalType(AccidentalType::NONE);
Note* n1 = nullptr;
ChordRest* cr1 = nullptr;
bool differentAccidentals = false;
bool differentDurations = false;
bool chordsAndRests = false;
for (Element* e : selection.elements()) {
if (Note* n = note(e)) {
if (n1) {
if (n->accidentalType() != n1->accidentalType()) {
setAccidentalType(AccidentalType::NONE);
differentAccidentals = true;
}
} else {
setAccidentalType(n->accidentalType());
n1 = n;
}
}
if (ChordRest* cr = chordRest(e)) {
if (cr1) {
if (cr->durationType() != cr1->durationType()) {
setDuration(TDuration::DurationType::V_INVALID);
differentDurations = true;
}
if ((cr->isRest() && !cr1->isRest()) || (!cr->isRest() && cr1->isRest())) {
setRest(false);
chordsAndRests = true;
}
} else {
setDuration(cr->durationType());
setRest(cr->isRest());
cr1 = cr;
}
}
if (differentAccidentals && differentDurations && chordsAndRests) {
break;
}
}
Element* e = selection.element();
if (e == 0) {
return;
}
ChordRest* cr = chordRest(e);
Note* n = note(e);
if (!n && cr && cr->isChord()) {
n = toChord(cr)->upNote();
}
if (cr) {
setTrack(cr->track());
setNoteType(n ? n->noteType() : NoteType::NORMAL);
setBeamMode(cr->beamMode());
}
setDrumNote(-1);
if (n) {
const Instrument* instr = n->part()->instrument();
if (instr->useDrumset()) {
setDrumNote(n->pitch());
}
}
}
//---------------------------------------------------------
// moveInputPos
//---------------------------------------------------------
void InputState::moveInputPos(Element* e)
{
if (e == 0) {
return;
}
Segment* s;
if (e->isChordRest()) {
s = toChordRest(e)->segment();
} else {
s = toSegment(e);
}
if (s->isSegment()) {
if (s->measure()->isMMRest()) {
Measure* m = s->measure()->mmRestFirst();
s = m->findSegment(SegmentType::ChordRest, m->tick());
}
_lastSegment = _segment;
_segment = s;
}
}
//---------------------------------------------------------
// setSegment
//---------------------------------------------------------
void InputState::setSegment(Segment* s)
{
if (s && s->measure()->isMMRest()) {
Measure* m = s->measure()->mmRestFirst();
s = m->findSegment(SegmentType::ChordRest, m->tick());
}
_segment = s;
_lastSegment = s;
}
//---------------------------------------------------------
// nextInputPos
//---------------------------------------------------------
Segment* InputState::nextInputPos() const
{
Measure* m = _segment->measure();
Segment* s = _segment->next1(SegmentType::ChordRest);
for (; s; s = s->next1(SegmentType::ChordRest)) {
if (s->element(_track)) {
if (s->element(_track)->isRest() && toRest(s->element(_track))->isGap()) {
m = s->measure();
} else {
return s;
}
} else if (s->measure() != m) {
return s;
}
}
return 0;
}
//---------------------------------------------------------
// moveToNextInputPos
// TODO: special case: note is first note of tie: goto to last note of tie
//---------------------------------------------------------
void InputState::moveToNextInputPos()
{
Segment* s = nextInputPos();
_lastSegment = _segment;
if (s) {
_segment = s;
}
}
//---------------------------------------------------------
// endOfScore
//---------------------------------------------------------
bool InputState::endOfScore() const
{
return (_lastSegment == _segment) && !nextInputPos();
}
}