383 lines
12 KiB
C++
383 lines
12 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 "textline.h"
|
|
|
|
#include "io/xml.h"
|
|
|
|
#include "score.h"
|
|
#include "staff.h"
|
|
#include "system.h"
|
|
#include "undo.h"
|
|
#include "musescoreCore.h"
|
|
|
|
using namespace mu;
|
|
|
|
namespace Ms {
|
|
//---------------------------------------------------------
|
|
// textLineSegmentStyle
|
|
//---------------------------------------------------------
|
|
|
|
static const ElementStyle textLineSegmentStyle {
|
|
{ Sid::textLinePosAbove, Pid::OFFSET },
|
|
{ Sid::textLineMinDistance, Pid::MIN_DISTANCE },
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// systemTextLineSegmentStyle
|
|
//---------------------------------------------------------
|
|
|
|
static const ElementStyle systemTextLineSegmentStyle {
|
|
{ Sid::systemTextLinePosAbove, Pid::OFFSET },
|
|
{ Sid::systemTextLineMinDistance, Pid::MIN_DISTANCE },
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// textLineStyle
|
|
//---------------------------------------------------------
|
|
|
|
static const ElementStyle textLineStyle {
|
|
// { Sid::textLineSystemFlag, Pid::SYSTEM_FLAG },
|
|
{ Sid::textLineFontFace, Pid::BEGIN_FONT_FACE },
|
|
{ Sid::textLineFontFace, Pid::CONTINUE_FONT_FACE },
|
|
{ Sid::textLineFontFace, Pid::END_FONT_FACE },
|
|
{ Sid::textLineFontSize, Pid::BEGIN_FONT_SIZE },
|
|
{ Sid::textLineFontSize, Pid::CONTINUE_FONT_SIZE },
|
|
{ Sid::textLineFontSize, Pid::END_FONT_SIZE },
|
|
{ Sid::textLineFontStyle, Pid::BEGIN_FONT_STYLE },
|
|
{ Sid::textLineFontStyle, Pid::CONTINUE_FONT_STYLE },
|
|
{ Sid::textLineFontStyle, Pid::END_FONT_STYLE },
|
|
{ Sid::textLineTextAlign, Pid::BEGIN_TEXT_ALIGN },
|
|
{ Sid::textLineTextAlign, Pid::CONTINUE_TEXT_ALIGN },
|
|
{ Sid::textLineTextAlign, Pid::END_TEXT_ALIGN },
|
|
{ Sid::textLinePlacement, Pid::PLACEMENT },
|
|
{ Sid::textLinePosAbove, Pid::OFFSET },
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// systemTextLineStyle
|
|
//---------------------------------------------------------
|
|
|
|
static const ElementStyle systemTextLineStyle {
|
|
// { Sid::systemTextLineSystemFlag, Pid::SYSTEM_FLAG },
|
|
{ Sid::systemTextLineFontFace, Pid::BEGIN_FONT_FACE },
|
|
{ Sid::systemTextLineFontFace, Pid::CONTINUE_FONT_FACE },
|
|
{ Sid::systemTextLineFontFace, Pid::END_FONT_FACE },
|
|
{ Sid::systemTextLineFontSize, Pid::BEGIN_FONT_SIZE },
|
|
{ Sid::systemTextLineFontSize, Pid::CONTINUE_FONT_SIZE },
|
|
{ Sid::systemTextLineFontSize, Pid::END_FONT_SIZE },
|
|
{ Sid::systemTextLineFontStyle, Pid::BEGIN_FONT_STYLE },
|
|
{ Sid::systemTextLineFontStyle, Pid::CONTINUE_FONT_STYLE },
|
|
{ Sid::systemTextLineFontStyle, Pid::END_FONT_STYLE },
|
|
{ Sid::systemTextLineTextAlign, Pid::BEGIN_TEXT_ALIGN },
|
|
{ Sid::systemTextLineTextAlign, Pid::CONTINUE_TEXT_ALIGN },
|
|
{ Sid::systemTextLineTextAlign, Pid::END_TEXT_ALIGN },
|
|
{ Sid::systemTextLinePlacement, Pid::PLACEMENT },
|
|
{ Sid::systemTextLinePosAbove, Pid::OFFSET },
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// TextLineSegment
|
|
//---------------------------------------------------------
|
|
|
|
TextLineSegment::TextLineSegment(Spanner* sp, System* parent, bool system)
|
|
: TextLineBaseSegment(ElementType::TEXTLINE_SEGMENT, sp, parent, ElementFlag::MOVABLE | ElementFlag::ON_STAFF)
|
|
{
|
|
setSystemFlag(system);
|
|
if (systemFlag()) {
|
|
initElementStyle(&systemTextLineSegmentStyle);
|
|
} else {
|
|
initElementStyle(&textLineSegmentStyle);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// propertyDelegate
|
|
//---------------------------------------------------------
|
|
|
|
EngravingItem* TextLineSegment::propertyDelegate(Pid pid)
|
|
{
|
|
if (pid == Pid::SYSTEM_FLAG) {
|
|
return static_cast<TextLine*>(spanner());
|
|
}
|
|
return TextLineBaseSegment::propertyDelegate(pid);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// layout
|
|
//---------------------------------------------------------
|
|
|
|
void TextLineSegment::layout()
|
|
{
|
|
TextLineBaseSegment::layout();
|
|
if (isStyled(Pid::OFFSET)) {
|
|
roffset() = textLine()->propertyDefault(Pid::OFFSET).value<PointF>();
|
|
}
|
|
autoplaceSpannerSegment();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// TextLine
|
|
//---------------------------------------------------------
|
|
|
|
TextLine::TextLine(EngravingItem* parent, bool system)
|
|
: TextLineBase(ElementType::TEXTLINE, parent)
|
|
{
|
|
setSystemFlag(system);
|
|
|
|
initStyle();
|
|
|
|
setBeginText("");
|
|
setContinueText("");
|
|
setEndText("");
|
|
setBeginTextOffset(PointF(0, 0));
|
|
setContinueTextOffset(PointF(0, 0));
|
|
setEndTextOffset(PointF(0, 0));
|
|
setLineVisible(true);
|
|
|
|
setBeginHookType(HookType::NONE);
|
|
setEndHookType(HookType::NONE);
|
|
setBeginHookHeight(Spatium(1.5));
|
|
setEndHookHeight(Spatium(1.5));
|
|
|
|
initElementStyle(&textLineStyle);
|
|
|
|
resetProperty(Pid::BEGIN_TEXT_PLACE);
|
|
resetProperty(Pid::CONTINUE_TEXT_PLACE);
|
|
resetProperty(Pid::END_TEXT_PLACE);
|
|
}
|
|
|
|
TextLine::TextLine(const TextLine& tl)
|
|
: TextLineBase(tl)
|
|
{
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// initStyle
|
|
//---------------------------------------------------------
|
|
|
|
void TextLine::initStyle()
|
|
{
|
|
if (systemFlag()) {
|
|
initElementStyle(&systemTextLineStyle);
|
|
} else {
|
|
initElementStyle(&textLineStyle);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// write
|
|
//---------------------------------------------------------
|
|
|
|
void TextLine::write(XmlWriter& xml) const
|
|
{
|
|
if (!xml.canWrite(this)) {
|
|
return;
|
|
}
|
|
if (systemFlag()) {
|
|
xml.startObject(QString("TextLine"), this, QString("system=\"1\""));
|
|
} else {
|
|
xml.startObject(this);
|
|
}
|
|
// other styled properties are included in TextLineBase pids list
|
|
writeProperty(xml, Pid::PLACEMENT);
|
|
writeProperty(xml, Pid::OFFSET);
|
|
TextLineBase::writeProperties(xml);
|
|
xml.endObject();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// read
|
|
//---------------------------------------------------------
|
|
|
|
void TextLine::read(XmlReader& e)
|
|
{
|
|
bool system = e.intAttribute("system", 0) == 1;
|
|
setSystemFlag(system);
|
|
initStyle();
|
|
TextLineBase::read(e);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// createLineSegment
|
|
//---------------------------------------------------------
|
|
|
|
LineSegment* TextLine::createLineSegment(System* parent)
|
|
{
|
|
TextLineSegment* seg = new TextLineSegment(this, parent, systemFlag());
|
|
seg->setTrack(track());
|
|
// note-anchored line segments are relative to system not to staff
|
|
if (anchor() == Spanner::Anchor::NOTE) {
|
|
seg->setFlag(ElementFlag::ON_STAFF, false);
|
|
}
|
|
|
|
if (systemFlag()) {
|
|
seg->initElementStyle(&systemTextLineSegmentStyle);
|
|
} else {
|
|
seg->initElementStyle(&textLineSegmentStyle);
|
|
}
|
|
|
|
return seg;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getTextLinePos
|
|
//---------------------------------------------------------
|
|
|
|
Sid TextLineSegment::getTextLinePos(bool above) const
|
|
{
|
|
if (systemFlag()) {
|
|
return above ? Sid::systemTextLinePosAbove : Sid::systemTextLinePosBelow;
|
|
} else {
|
|
return above ? Sid::textLinePosAbove : Sid::textLinePosBelow;
|
|
}
|
|
}
|
|
|
|
Sid TextLine::getTextLinePos(bool above) const
|
|
{
|
|
if (systemFlag()) {
|
|
return above ? Sid::systemTextLinePosAbove : Sid::systemTextLinePosBelow;
|
|
} else {
|
|
return above ? Sid::textLinePosAbove : Sid::textLinePosBelow;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getPropertyStyle
|
|
//---------------------------------------------------------
|
|
|
|
Sid TextLineSegment::getPropertyStyle(Pid pid) const
|
|
{
|
|
if (pid == Pid::OFFSET) {
|
|
if (spanner()->anchor() == Spanner::Anchor::NOTE) {
|
|
return Sid::NOSTYLE;
|
|
} else {
|
|
return getTextLinePos(spanner()->placeAbove());
|
|
}
|
|
}
|
|
return TextLineBaseSegment::getPropertyStyle(pid);
|
|
}
|
|
|
|
Sid TextLine::getPropertyStyle(Pid pid) const
|
|
{
|
|
if (pid == Pid::OFFSET) {
|
|
if (anchor() == Spanner::Anchor::NOTE) {
|
|
return Sid::NOSTYLE;
|
|
} else {
|
|
return getTextLinePos(placeAbove());
|
|
}
|
|
}
|
|
return TextLineBase::getPropertyStyle(pid);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// propertyDefault
|
|
//---------------------------------------------------------
|
|
|
|
QVariant TextLine::propertyDefault(Pid propertyId) const
|
|
{
|
|
switch (propertyId) {
|
|
case Pid::PLACEMENT:
|
|
if (systemFlag()) {
|
|
return score()->styleV(Sid::textLinePlacement);
|
|
} else {
|
|
return score()->styleV(Sid::systemTextLinePlacement);
|
|
}
|
|
case Pid::BEGIN_TEXT:
|
|
case Pid::CONTINUE_TEXT:
|
|
case Pid::END_TEXT:
|
|
return "";
|
|
case Pid::LINE_VISIBLE:
|
|
return true;
|
|
case Pid::BEGIN_TEXT_OFFSET:
|
|
case Pid::CONTINUE_TEXT_OFFSET:
|
|
case Pid::END_TEXT_OFFSET:
|
|
return PointF(0, 0);
|
|
case Pid::BEGIN_HOOK_TYPE:
|
|
case Pid::END_HOOK_TYPE:
|
|
return int(HookType::NONE);
|
|
case Pid::BEGIN_TEXT_PLACE:
|
|
case Pid::CONTINUE_TEXT_PLACE:
|
|
case Pid::END_TEXT_PLACE:
|
|
return int(PlaceText::LEFT);
|
|
case Pid::BEGIN_HOOK_HEIGHT:
|
|
case Pid::END_HOOK_HEIGHT:
|
|
return Spatium(1.5);
|
|
default:
|
|
return TextLineBase::propertyDefault(propertyId);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setProperty
|
|
//---------------------------------------------------------
|
|
|
|
bool TextLine::setProperty(Pid id, const QVariant& v)
|
|
{
|
|
switch (id) {
|
|
case Pid::PLACEMENT:
|
|
setPlacement(Placement(v.toInt()));
|
|
break;
|
|
default:
|
|
return TextLineBase::setProperty(id, v);
|
|
}
|
|
triggerLayout();
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// undoChangeProperty
|
|
//---------------------------------------------------------
|
|
|
|
void TextLine::undoChangeProperty(Pid id, const QVariant& v, PropertyFlags ps)
|
|
{
|
|
if (id == Pid::SYSTEM_FLAG) {
|
|
score()->undo(new ChangeTextLineProperty(this, v));
|
|
for (SpannerSegment* s : spannerSegments()) {
|
|
score()->undo(new ChangeTextLineProperty(s, v));
|
|
triggerLayout();
|
|
}
|
|
return;
|
|
}
|
|
TextLineBase::undoChangeProperty(id, v, ps);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// layoutSystem
|
|
// layout spannersegment for system
|
|
//---------------------------------------------------------
|
|
|
|
SpannerSegment* TextLine::layoutSystem(System* system)
|
|
{
|
|
TextLineSegment* tls = toTextLineSegment(TextLineBase::layoutSystem(system));
|
|
|
|
if (tls->spanner()) {
|
|
for (SpannerSegment* ss : tls->spanner()->spannerSegments()) {
|
|
ss->setFlag(ElementFlag::SYSTEM, systemFlag());
|
|
ss->setTrack(systemFlag() ? 0 : track());
|
|
}
|
|
tls->spanner()->setFlag(ElementFlag::SYSTEM, systemFlag());
|
|
tls->spanner()->setTrack(systemFlag() ? 0 : track());
|
|
}
|
|
|
|
return tls;
|
|
}
|
|
} // namespace Ms
|