305 lines
8.5 KiB
C++
305 lines
8.5 KiB
C++
/*
|
|
* SPDX-License-Identifier: GPL-3.0-only
|
|
* MuseScore-CLA-applies
|
|
*
|
|
* MuseScore
|
|
* Music Composition & Notation
|
|
*
|
|
* Copyright (C) 2022 MuseScore BVBA 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 3 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "stringtunings.h"
|
|
|
|
#include "types/typesconv.h"
|
|
#include "utils.h"
|
|
|
|
#include "part.h"
|
|
#include "score.h"
|
|
#include "segment.h"
|
|
#include "undo.h"
|
|
|
|
#include "containers.h"
|
|
#include "translation.h"
|
|
|
|
using namespace mu;
|
|
using namespace mu::engraving;
|
|
|
|
// STYLE
|
|
static const ElementStyle STRING_TUNINGS_STYLE {
|
|
{ Sid::staffTextPlacement, Pid::PLACEMENT },
|
|
{ Sid::staffTextMinDistance, Pid::MIN_DISTANCE },
|
|
};
|
|
|
|
StringTunings::StringTunings(Segment* parent, TextStyleType textStyleType)
|
|
: StaffTextBase(ElementType::STRING_TUNINGS, parent, textStyleType, ElementFlag::MOVABLE | ElementFlag::ON_STAFF)
|
|
{
|
|
initElementStyle(&STRING_TUNINGS_STYLE);
|
|
}
|
|
|
|
StringTunings::StringTunings(const StringTunings& s)
|
|
: StaffTextBase(s)
|
|
{
|
|
}
|
|
|
|
StringTunings* StringTunings::clone() const
|
|
{
|
|
return new StringTunings(*this);
|
|
}
|
|
|
|
bool StringTunings::isEditable() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PropertyValue StringTunings::getProperty(Pid id) const
|
|
{
|
|
if (id == Pid::STRINGTUNINGS_STRINGS_COUNT) {
|
|
Fraction tick = this->tick();
|
|
if (staff()->isTabStaff(tick)) {
|
|
return staff()->lines(tick);
|
|
} else {
|
|
for (const Staff* _staff : staff()->staffList()) {
|
|
if (_staff == staff()) {
|
|
continue;
|
|
}
|
|
|
|
if (_staff->score() == staff()->score() && _staff->isTabStaff(tick)) {
|
|
return _staff->lines(tick);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_stringsNumber.has_value()) {
|
|
return m_stringsNumber.value();
|
|
}
|
|
|
|
return stringData()->strings();
|
|
} else if (id == Pid::STRINGTUNINGS_PRESET) {
|
|
return m_preset;
|
|
} else if (id == Pid::STRINGTUNINGS_VISIBLE_STRINGS) {
|
|
std::vector<int> visibleStrings;
|
|
for (string_idx_t string : m_visibleStrings) {
|
|
visibleStrings.emplace_back(static_cast<int>(string));
|
|
}
|
|
|
|
return visibleStrings;
|
|
}
|
|
|
|
return StaffTextBase::getProperty(id);
|
|
}
|
|
|
|
PropertyValue StringTunings::propertyDefault(Pid id) const
|
|
{
|
|
if (id == Pid::STRINGTUNINGS_STRINGS_COUNT) {
|
|
return stringData()->strings();
|
|
} else if (id == Pid::STRINGTUNINGS_PRESET) {
|
|
return String();
|
|
} else if (id == Pid::STRINGTUNINGS_VISIBLE_STRINGS) {
|
|
return {};
|
|
}
|
|
|
|
return StaffTextBase::propertyDefault(id);
|
|
}
|
|
|
|
bool StringTunings::setProperty(Pid id, const PropertyValue& val)
|
|
{
|
|
if (id == Pid::STRINGTUNINGS_STRINGS_COUNT) {
|
|
Fraction tick = this->tick();
|
|
if (staff()->isTabStaff(tick)) {
|
|
staff()->staffType(tick)->setLines(val.toInt());
|
|
} else {
|
|
for (Staff* _staff : staff()->staffList()) {
|
|
if (_staff == staff()) {
|
|
continue;
|
|
}
|
|
|
|
if (_staff->score() == staff()->score() && _staff->isTabStaff(tick)) {
|
|
_staff->staffType(tick)->setLines(val.toInt());
|
|
}
|
|
}
|
|
}
|
|
|
|
m_stringsNumber = val.toInt();
|
|
} else if (id == Pid::STRINGTUNINGS_PRESET) {
|
|
m_preset = val.value<String>();
|
|
} else if (id == Pid::STRINGTUNINGS_VISIBLE_STRINGS) {
|
|
m_visibleStrings.clear();
|
|
std::vector<int> ignoredStrings = val.value<std::vector<int> >();
|
|
for (int string : ignoredStrings) {
|
|
m_visibleStrings.emplace_back(static_cast<string_idx_t>(string));
|
|
}
|
|
} else {
|
|
return StaffTextBase::setProperty(id, val);
|
|
}
|
|
|
|
triggerLayout();
|
|
return true;
|
|
}
|
|
|
|
String StringTunings::accessibleInfo() const
|
|
{
|
|
const StringData* stringData = this->stringData();
|
|
if (stringData->isNull()) {
|
|
return String();
|
|
}
|
|
|
|
String elementName = score() ? score()->getTextStyleUserName(TextStyleType::STRING_TUNINGS).translated()
|
|
: TConv::translatedUserName(TextStyleType::STRING_TUNINGS);
|
|
String info;
|
|
|
|
const std::vector<instrString>& stringList = stringData->stringList();
|
|
int numOfStrings = static_cast<int>(stringList.size());
|
|
for (int i = 0; i < numOfStrings; ++i) {
|
|
string_idx_t index = numOfStrings - i - 1;
|
|
if (mu::contains(m_visibleStrings, index)) {
|
|
const instrString str = stringList[index];
|
|
String pitchStr = pitch2string(str.pitch, str.useFlat);
|
|
if (pitchStr.empty()) {
|
|
LOGE() << "Invalid get pitch name for " << str.pitch;
|
|
continue;
|
|
}
|
|
|
|
info += mtrc("engraving", "String %1").arg(String::number(i + 1)) + u", "
|
|
+ mtrc("engraving", "Value %1").arg(pitchStr) + u"; ";
|
|
}
|
|
}
|
|
|
|
return String(u"%1: %2").arg(elementName, info);
|
|
}
|
|
|
|
String StringTunings::screenReaderInfo() const
|
|
{
|
|
return accessibleInfo();
|
|
}
|
|
|
|
const StringData* StringTunings::stringData() const
|
|
{
|
|
return &m_stringData;
|
|
}
|
|
|
|
void StringTunings::setStringData(const StringData& stringData)
|
|
{
|
|
m_stringData.set(stringData);
|
|
triggerLayout();
|
|
}
|
|
|
|
void StringTunings::undoStringData(const StringData& stringData)
|
|
{
|
|
score()->undo(new ChangeStringData(this, stringData));
|
|
triggerLayout();
|
|
}
|
|
|
|
const String& StringTunings::preset() const
|
|
{
|
|
return m_preset;
|
|
}
|
|
|
|
void StringTunings::setPreset(const String& preset)
|
|
{
|
|
m_preset = preset;
|
|
}
|
|
|
|
const std::vector<string_idx_t>& StringTunings::visibleStrings() const
|
|
{
|
|
return m_visibleStrings;
|
|
}
|
|
|
|
void StringTunings::setVisibleStrings(const std::vector<string_idx_t>& visibleStrings)
|
|
{
|
|
m_visibleStrings = visibleStrings;
|
|
}
|
|
|
|
void StringTunings::updateText()
|
|
{
|
|
String updatedText = generateText();
|
|
undoChangeProperty(Pid::TEXT, updatedText, PropertyFlags::STYLED);
|
|
|
|
if (updatedText.empty()) {
|
|
m_noStringVisible = true;
|
|
} else {
|
|
m_noStringVisible = false;
|
|
}
|
|
}
|
|
|
|
bool StringTunings::noStringVisible() const
|
|
{
|
|
return m_noStringVisible;
|
|
}
|
|
|
|
String StringTunings::generateText() const
|
|
{
|
|
const StringData* stringData = this->stringData();
|
|
if (!stringData || stringData->isNull()) {
|
|
return u"";
|
|
}
|
|
|
|
auto guitarStringSymbol = [](int i) { return String(u"<sym>guitarString") + String::number(i) + u"</sym>"; };
|
|
|
|
const std::vector<instrString>& stringList = stringData->stringList();
|
|
std::vector<String> visibleStringList;
|
|
int numOfStrings = static_cast<int>(stringList.size());
|
|
for (int i = 0; i < numOfStrings; ++i) {
|
|
string_idx_t index = numOfStrings - i - 1;
|
|
if (mu::contains(m_visibleStrings, index)) {
|
|
const instrString str = stringList[index];
|
|
String pitchStr = pitch2string(str.pitch, str.useFlat);
|
|
if (pitchStr.empty()) {
|
|
LOGE() << "Invalid get pitch name for " << str.pitch;
|
|
continue;
|
|
}
|
|
|
|
Char accidental;
|
|
if (pitchStr.size() > 1) {
|
|
Char sym(pitchStr[1]);
|
|
if (!sym.isDigit()) {
|
|
accidental = sym;
|
|
}
|
|
}
|
|
|
|
visibleStringList.emplace_back(String(guitarStringSymbol(i + 1) + u" \u2012 "
|
|
+ String(pitchStr[0]).toUpper() + accidental) + u" ");
|
|
}
|
|
}
|
|
|
|
if (visibleStringList.empty()) {
|
|
return u"";
|
|
}
|
|
|
|
size_t columnCount = 0;
|
|
size_t rowCount = 0;
|
|
|
|
if (visibleStringList.size() < 4) {
|
|
rowCount = visibleStringList.size();
|
|
columnCount = 1;
|
|
} else {
|
|
rowCount = std::ceil(static_cast<double>(visibleStringList.size()) / 2);
|
|
columnCount = 2;
|
|
}
|
|
|
|
String result;
|
|
for (size_t i = 0; i < rowCount; ++i) {
|
|
for (size_t j = 0; j < columnCount; ++j) {
|
|
size_t index = i + j * rowCount;
|
|
if (index < visibleStringList.size()) {
|
|
result += visibleStringList[index];
|
|
}
|
|
result += u"\t";
|
|
}
|
|
result += u"\n";
|
|
}
|
|
|
|
return result;
|
|
}
|