MuseScore/src/engraving/libmscore/layoutbreak.cpp

375 lines
10 KiB
C++

/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 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 "log.h"
#include "layoutbreak.h"
#include "rw/xml.h"
#include "score.h"
#include "measurebase.h"
using namespace mu;
using namespace mu::draw;
using namespace mu::engraving;
namespace Ms {
//---------------------------------------------------------
// sectionBreakStyle
//---------------------------------------------------------
static const ElementStyle sectionBreakStyle {
{ Sid::SectionPause, Pid::PAUSE }
};
//---------------------------------------------------------
// LayoutBreak
//---------------------------------------------------------
LayoutBreak::LayoutBreak(MeasureBase* parent)
: EngravingItem(ElementType::LAYOUT_BREAK, parent, ElementFlag::SYSTEM | ElementFlag::HAS_TAG)
{
_pause = 0.;
_startWithLongNames = false;
_startWithMeasureOne = false;
_firstSystemIndentation = false;
_layoutBreakType = LayoutBreakType(propertyDefault(Pid::LAYOUT_BREAK).toInt());
initElementStyle(&sectionBreakStyle);
resetProperty(Pid::PAUSE);
resetProperty(Pid::START_WITH_LONG_NAMES);
resetProperty(Pid::START_WITH_MEASURE_ONE);
resetProperty(Pid::FIRST_SYSTEM_INDENTATION);
lw = spatium() * 0.3;
}
LayoutBreak::LayoutBreak(const LayoutBreak& lb)
: EngravingItem(lb)
{
_layoutBreakType = lb._layoutBreakType;
lw = lb.lw;
_pause = lb._pause;
_startWithLongNames = lb._startWithLongNames;
_startWithMeasureOne = lb._startWithMeasureOne;
_firstSystemIndentation = lb._firstSystemIndentation;
layout0();
}
void LayoutBreak::setParent(MeasureBase* parent)
{
EngravingItem::setParent(parent);
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void LayoutBreak::write(XmlWriter& xml) const
{
xml.startObject(this);
EngravingItem::writeProperties(xml);
for (auto id :
{ Pid::LAYOUT_BREAK, Pid::PAUSE, Pid::START_WITH_LONG_NAMES, Pid::START_WITH_MEASURE_ONE, Pid::FIRST_SYSTEM_INDENTATION }) {
writeProperty(xml, id);
}
xml.endObject();
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void LayoutBreak::read(XmlReader& e)
{
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
if (tag == "subtype") {
readProperty(e, Pid::LAYOUT_BREAK);
} else if (tag == "pause") {
readProperty(e, Pid::PAUSE);
} else if (tag == "startWithLongNames") {
readProperty(e, Pid::START_WITH_LONG_NAMES);
} else if (tag == "startWithMeasureOne") {
readProperty(e, Pid::START_WITH_MEASURE_ONE);
} else if (tag == "firstSystemIndentation"
|| tag == "firstSystemIdentation" /* pre-4.0 typo */) {
readProperty(e, Pid::FIRST_SYSTEM_INDENTATION);
} else if (!EngravingItem::readProperties(e)) {
e.unknown();
}
}
layout0();
}
//---------------------------------------------------------
// draw
//---------------------------------------------------------
void LayoutBreak::draw(mu::draw::Painter* painter) const
{
TRACE_OBJ_DRAW;
using namespace mu::draw;
if (score()->printing() || !score()->showUnprintable()) {
return;
}
Pen pen;
pen.setColor(selected() ? engravingConfiguration()->selectionColor() : engravingConfiguration()->formattingMarksColor());
pen.setWidthF(lw / 2);
pen.setJoinStyle(PenJoinStyle::MiterJoin);
pen.setCapStyle(PenCapStyle::SquareCap);
pen.setDashPattern({ 1, 3 });
painter->setPen(pen);
painter->setBrush(BrushStyle::NoBrush);
painter->drawRect(m_iconBorderRect);
pen.setWidthF(lw);
pen.setStyle(PenStyle::SolidLine);
painter->setPen(pen);
painter->drawPath(m_iconPath);
}
//---------------------------------------------------------
// layout0
//---------------------------------------------------------
void LayoutBreak::layout0()
{
qreal _spatium = spatium();
qreal w = _spatium * 2.5;
qreal h = w;
m_iconBorderRect = RectF(0.0, 0.0, w, h);
m_iconPath = PainterPath();
switch (layoutBreakType()) {
case LayoutBreakType::LINE:
m_iconPath.moveTo(w * .8, h * .3);
m_iconPath.lineTo(w * .8, h * .6);
m_iconPath.lineTo(w * .3, h * .6);
m_iconPath.moveTo(w * .4, h * .5);
m_iconPath.lineTo(w * .25, h * .6);
m_iconPath.lineTo(w * .4, h * .7);
m_iconPath.lineTo(w * .4, h * .5);
break;
case LayoutBreakType::PAGE:
m_iconPath.moveTo(w * .25, h * .2);
m_iconPath.lineTo(w * .60, h * .2);
m_iconPath.lineTo(w * .75, h * .35);
m_iconPath.lineTo(w * .75, h * .8);
m_iconPath.lineTo(w * .25, h * .8);
m_iconPath.lineTo(w * .25, h * .2);
m_iconPath.moveTo(w * .55, h * .21); // 0.01 to avoid overlap
m_iconPath.lineTo(w * .55, h * .40);
m_iconPath.lineTo(w * .74, h * .40);
break;
case LayoutBreakType::SECTION:
m_iconPath.moveTo(w * .25, h * .2);
m_iconPath.lineTo(w * .75, h * .2);
m_iconPath.lineTo(w * .75, h * .8);
m_iconPath.lineTo(w * .25, h * .8);
m_iconPath.moveTo(w * .55, h * .21); // 0.01 to avoid overlap
m_iconPath.lineTo(w * .55, h * .79);
break;
case LayoutBreakType::NOBREAK:
m_iconPath.moveTo(w * .1, h * .5);
m_iconPath.lineTo(w * .9, h * .5);
m_iconPath.moveTo(w * .7, h * .3);
m_iconPath.lineTo(w * .5, h * .5);
m_iconPath.lineTo(w * .7, h * .7);
m_iconPath.lineTo(w * .7, h * .3);
m_iconPath.moveTo(w * .3, h * .3);
m_iconPath.lineTo(w * .5, h * .5);
m_iconPath.lineTo(w * .3, h * .7);
m_iconPath.lineTo(w * .3, h * .3);
break;
default:
LOGD("unknown layout break symbol");
break;
}
setbbox(m_iconBorderRect.adjusted(-lw, -lw, lw, lw));
}
//---------------------------------------------------------
// setLayoutBreakType
//---------------------------------------------------------
void LayoutBreak::setLayoutBreakType(LayoutBreakType val)
{
_layoutBreakType = val;
layout0();
}
//---------------------------------------------------------
// spatiumChanged
//---------------------------------------------------------
void LayoutBreak::spatiumChanged(qreal, qreal)
{
lw = spatium() * 0.3;
layout0();
}
//---------------------------------------------------------
// acceptDrop
//---------------------------------------------------------
bool LayoutBreak::acceptDrop(EditData& data) const
{
return data.dropElement->type() == ElementType::LAYOUT_BREAK
&& toLayoutBreak(data.dropElement)->layoutBreakType() != layoutBreakType();
}
//---------------------------------------------------------
// drop
//---------------------------------------------------------
EngravingItem* LayoutBreak::drop(EditData& data)
{
EngravingItem* e = data.dropElement;
score()->undoChangeElement(this, e);
return e;
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
PropertyValue LayoutBreak::getProperty(Pid propertyId) const
{
switch (propertyId) {
case Pid::LAYOUT_BREAK:
return _layoutBreakType;
case Pid::PAUSE:
return _pause;
case Pid::START_WITH_LONG_NAMES:
return _startWithLongNames;
case Pid::START_WITH_MEASURE_ONE:
return _startWithMeasureOne;
case Pid::FIRST_SYSTEM_INDENTATION:
return _firstSystemIndentation;
default:
return EngravingItem::getProperty(propertyId);
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool LayoutBreak::setProperty(Pid propertyId, const PropertyValue& v)
{
switch (propertyId) {
case Pid::LAYOUT_BREAK:
setLayoutBreakType(v.value<LayoutBreakType>());
break;
case Pid::PAUSE:
setPause(v.toDouble());
score()->setUpTempoMap();
break;
case Pid::START_WITH_LONG_NAMES:
setStartWithLongNames(v.toBool());
break;
case Pid::START_WITH_MEASURE_ONE:
setStartWithMeasureOne(v.toBool());
break;
case Pid::FIRST_SYSTEM_INDENTATION:
setFirstSystemIndentation(v.toBool());
break;
default:
if (!EngravingItem::setProperty(propertyId, v)) {
return false;
}
break;
}
triggerLayoutAll();
setGenerated(false);
return true;
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
PropertyValue LayoutBreak::propertyDefault(Pid id) const
{
switch (id) {
case Pid::LAYOUT_BREAK:
return PropertyValue(); // LAYOUT_BREAK_LINE;
case Pid::PAUSE:
return score()->styleD(Sid::SectionPause);
case Pid::START_WITH_LONG_NAMES:
return true;
case Pid::START_WITH_MEASURE_ONE:
return true;
case Pid::FIRST_SYSTEM_INDENTATION:
return true;
default:
return EngravingItem::propertyDefault(id);
}
}
//---------------------------------------------------------
// propertyId
//---------------------------------------------------------
Pid LayoutBreak::propertyId(const QStringRef& name) const
{
if (name == propertyName(Pid::LAYOUT_BREAK)) {
return Pid::LAYOUT_BREAK;
}
return EngravingItem::propertyId(name);
}
void LayoutBreak::added()
{
IF_ASSERT_FAILED(score()) {
return;
}
score()->setUpTempoMap();
}
void LayoutBreak::removed()
{
IF_ASSERT_FAILED(score()) {
return;
}
score()->setUpTempoMap();
}
}