240 lines
8.5 KiB
C++
240 lines
8.5 KiB
C++
//=============================================================================
|
|
// MuseScore
|
|
// Music Composition & Notation
|
|
//
|
|
// Copyright (C) 2008-2011 Werner Schweer
|
|
//
|
|
// 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 LICENCE.GPL
|
|
//=============================================================================
|
|
|
|
#include "score.h"
|
|
#include "stafftext.h"
|
|
#include "system.h"
|
|
#include "staff.h"
|
|
#include "xml.h"
|
|
|
|
namespace Ms {
|
|
|
|
//---------------------------------------------------------
|
|
// StaffText
|
|
//---------------------------------------------------------
|
|
|
|
StaffText::StaffText(Score* s)
|
|
: Text(s)
|
|
{
|
|
setFlags(ElementFlag::MOVABLE | ElementFlag::SELECTABLE | ElementFlag::ON_STAFF);
|
|
setTextStyleType(TextStyleType::STAFF);
|
|
setPlacement(Placement::ABOVE); // default
|
|
_setAeolusStops = false;
|
|
_swing = false;
|
|
clearAeolusStops();
|
|
setSwingParameters(MScore::division / 2, 60);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// write
|
|
//---------------------------------------------------------
|
|
|
|
void StaffText::write(XmlWriter& xml) const
|
|
{
|
|
if (!xml.canWrite(this))
|
|
return;
|
|
xml.stag("StaffText");
|
|
for (ChannelActions s : _channelActions) {
|
|
int channel = s.channel;
|
|
for (QString name : s.midiActionNames)
|
|
xml.tagE(QString("MidiAction channel=\"%1\" name=\"%2\"").arg(channel).arg(name));
|
|
}
|
|
for (int voice = 0; voice < VOICES; ++voice) {
|
|
if (!_channelNames[voice].isEmpty())
|
|
xml.tagE(QString("channelSwitch voice=\"%1\" name=\"%2\"").arg(voice).arg(_channelNames[voice]));
|
|
}
|
|
if (_setAeolusStops) {
|
|
for (int i = 0; i < 4; ++i)
|
|
xml.tag(QString("aeolus group=\"%1\"").arg(i), aeolusStops[i]);
|
|
}
|
|
if (swing()) {
|
|
QString swingUnit;
|
|
if (swingParameters()->swingUnit == MScore::division / 2)
|
|
swingUnit = TDuration(TDuration::DurationType::V_EIGHTH).name();
|
|
else if (swingParameters()->swingUnit == MScore::division / 4)
|
|
swingUnit = TDuration(TDuration::DurationType::V_16TH).name();
|
|
else
|
|
swingUnit = TDuration(TDuration::DurationType::V_ZERO).name();
|
|
int swingRatio = swingParameters()->swingRatio;
|
|
xml.tagE(QString("swing unit=\"%1\" ratio= \"%2\"").arg(swingUnit).arg(swingRatio));
|
|
}
|
|
Text::writeProperties(xml);
|
|
xml.etag();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// read
|
|
//---------------------------------------------------------
|
|
|
|
void StaffText::read(XmlReader& e)
|
|
{
|
|
for (int voice = 0; voice < VOICES; ++voice)
|
|
_channelNames[voice].clear();
|
|
clearAeolusStops();
|
|
while (e.readNextStartElement()) {
|
|
const QStringRef& tag(e.name());
|
|
if (tag == "MidiAction") {
|
|
int channel = e.intAttribute("channel", 0);
|
|
QString name = e.attribute("name");
|
|
bool found = false;
|
|
int n = _channelActions.size();
|
|
for (int i = 0; i < n; ++i) {
|
|
ChannelActions* a = &_channelActions[i];
|
|
if (a->channel == channel) {
|
|
a->midiActionNames.append(name);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
ChannelActions a;
|
|
a.channel = channel;
|
|
a.midiActionNames.append(name);
|
|
_channelActions.append(a);
|
|
}
|
|
e.readNext();
|
|
}
|
|
else if (tag == "channelSwitch" || tag == "articulationChange") {
|
|
int voice = e.intAttribute("voice", -1);
|
|
if (voice >= 0 && voice < VOICES)
|
|
_channelNames[voice] = e.attribute("name");
|
|
else if (voice == -1) {
|
|
// no voice applies channel to all voices for
|
|
// compatibility
|
|
for (int i = 0; i < VOICES; ++i)
|
|
_channelNames[i] = e.attribute("name");
|
|
}
|
|
e.readNext();
|
|
}
|
|
else if (tag == "aeolus") {
|
|
int group = e.intAttribute("group", -1);
|
|
if (group >= 0 && group < 4)
|
|
aeolusStops[group] = e.readInt();
|
|
else
|
|
e.readNext();
|
|
_setAeolusStops = true;
|
|
}
|
|
else if (tag == "swing") {
|
|
QString swingUnit = e.attribute("unit","");
|
|
int unit = 0;
|
|
if (swingUnit == TDuration(TDuration::DurationType::V_EIGHTH).name())
|
|
unit = MScore::division / 2;
|
|
else if (swingUnit == TDuration(TDuration::DurationType::V_16TH).name())
|
|
unit = MScore:: division / 4;
|
|
else if (swingUnit == TDuration(TDuration::DurationType::V_ZERO).name())
|
|
unit = 0;
|
|
int ratio = e.intAttribute("ratio", 60);
|
|
setSwing(true);
|
|
setSwingParameters(unit, ratio);
|
|
e.readNext();
|
|
}
|
|
else if (!Text::readProperties(e))
|
|
e.unknown();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// clearAeolusStops
|
|
//---------------------------------------------------------
|
|
|
|
void StaffText::clearAeolusStops()
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
aeolusStops[i] = 0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setAeolusStop
|
|
//---------------------------------------------------------
|
|
|
|
void StaffText::setAeolusStop(int group, int idx, bool val)
|
|
{
|
|
if (val)
|
|
aeolusStops[group] |= (1 << idx);
|
|
else
|
|
aeolusStops[group] &= ~(1 << idx);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getAeolusStop
|
|
//---------------------------------------------------------
|
|
|
|
bool StaffText::getAeolusStop(int group, int idx) const
|
|
{
|
|
return aeolusStops[group] & (1 << idx);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// layout
|
|
//---------------------------------------------------------
|
|
|
|
void StaffText::layout()
|
|
{
|
|
if (autoplace())
|
|
setUserOff(QPointF());
|
|
QPointF p(textStyle().offset(spatium()));
|
|
if (placement() == Element::Placement::BELOW)
|
|
p.ry() = - p.ry() + lineHeight();
|
|
setPos(p);
|
|
Text::layout1();
|
|
if (!parent()) // palette & clone trick
|
|
return;
|
|
|
|
if (autoplace() && segment()) {
|
|
qreal minDistance = score()->styleP(StyleIdx::dynamicsMinDistance); // TODO
|
|
Shape s1 = segment()->staffShape(staffIdx()).translated(segment()->pos());
|
|
Shape s2 = shape().translated(segment()->pos());
|
|
|
|
if (placement() == Element::Placement::ABOVE) {
|
|
qreal d = s2.minVerticalDistance(s1);
|
|
if (d > -minDistance)
|
|
rUserYoffset() = -d - minDistance;
|
|
}
|
|
else {
|
|
qreal d = s1.minVerticalDistance(s2);
|
|
if (d > -minDistance)
|
|
rUserYoffset() = d + minDistance;
|
|
}
|
|
}
|
|
adjustReadPos();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// segment
|
|
//---------------------------------------------------------
|
|
|
|
Segment* StaffText::segment() const
|
|
{
|
|
if (!parent()->isSegment()) {
|
|
qDebug("StaffText parent %s\n", parent()->name());
|
|
return 0;
|
|
}
|
|
Segment* s = toSegment(parent());
|
|
return s;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// propertyDefault
|
|
//---------------------------------------------------------
|
|
|
|
QVariant StaffText::propertyDefault(P_ID id) const
|
|
{
|
|
switch(id) {
|
|
case P_ID::PLACEMENT:
|
|
return int(Placement::ABOVE);
|
|
default:
|
|
return Text::propertyDefault(id);
|
|
}
|
|
}
|
|
|
|
}
|
|
|