MuseScore/src/libmscore/bsymbol.cpp
2021-04-19 17:08:37 +02:00

263 lines
6.6 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 <cmath>
#include "score.h"
#include "image.h"
#include "xml.h"
#include "staff.h"
#include "segment.h"
#include "page.h"
#include "system.h"
#include "measure.h"
namespace Ms {
//---------------------------------------------------------
// BSymbol
//---------------------------------------------------------
BSymbol::BSymbol(Score* s, ElementFlags f)
: Element(s, f)
{
_align = Align::LEFT | Align::BASELINE;
}
BSymbol::BSymbol(const BSymbol& s)
: Element(s)
{
_align = s._align;
for (Element* e : s._leafs) {
Element* ee = e->clone();
ee->setParent(this);
_leafs.append(ee);
}
}
//---------------------------------------------------------
// writeProperties
//---------------------------------------------------------
void BSymbol::writeProperties(XmlWriter& xml) const
{
for (const Element* e : leafs()) {
e->write(xml);
}
Element::writeProperties(xml);
}
//---------------------------------------------------------
// readProperties
//---------------------------------------------------------
bool BSymbol::readProperties(XmlReader& e)
{
const QStringRef& tag = e.name();
if (Element::readProperties(e)) {
return true;
} else if (tag == "systemFlag") {
setSystemFlag(e.readInt());
} else if (tag == "Symbol" || tag == "FSymbol") {
Element* element = name2Element(tag, score());
element->read(e);
add(element);
} else if (tag == "Image") {
if (MScore::noImages) {
e.skipCurrentElement();
} else {
Element* element = name2Element(tag, score());
element->read(e);
add(element);
}
} else {
return false;
}
return true;
}
//---------------------------------------------------------
// add
//---------------------------------------------------------
void BSymbol::add(Element* e)
{
if (e->isSymbol() || e->isImage()) {
e->setParent(this);
e->setTrack(track());
_leafs.append(e);
toBSymbol(e)->setZ(z() - 1); // draw on top of parent
} else {
qDebug("BSymbol::add: unsupported type %s", e->name());
}
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void BSymbol::remove(Element* e)
{
if (e->isSymbol() || e->isImage()) {
if (!_leafs.removeOne(e)) {
qDebug("BSymbol::remove: element <%s> not found", e->name());
}
} else {
qDebug("BSymbol::remove: unsupported type %s", e->name());
}
}
//---------------------------------------------------------
// acceptDrop
//---------------------------------------------------------
bool BSymbol::acceptDrop(EditData& data) const
{
return data.dropElement->isSymbol() || data.dropElement->isImage();
}
//---------------------------------------------------------
// drop
//---------------------------------------------------------
Element* BSymbol::drop(EditData& data)
{
Element* el = data.dropElement;
if (el->isSymbol() || el->isImage()) {
el->setParent(this);
QPointF p = data.pos - pagePos() - data.dragOffset;
el->setOffset(p);
score()->undoAddElement(el);
return el;
} else {
delete el;
}
return 0;
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void BSymbol::layout()
{
if (staff()) {
setMag(staff()->staffMag(tick()));
}
if (!parent()) {
setOffset(.0, .0);
setPos(.0, .0);
}
for (Element* e : qAsConst(_leafs)) {
e->layout();
}
}
//---------------------------------------------------------
// drag
//---------------------------------------------------------
QRectF BSymbol::drag(EditData& ed)
{
QRectF r(canvasBoundingRect());
foreach (const Element* e, _leafs) {
r |= e->canvasBoundingRect();
}
qreal x = ed.delta.x();
qreal y = ed.delta.y();
qreal _spatium = spatium();
if (ed.hRaster) {
qreal hRaster = _spatium / MScore::hRaster();
int n = lrint(x / hRaster);
x = hRaster * n;
}
if (ed.vRaster) {
qreal vRaster = _spatium / MScore::vRaster();
int n = lrint(y / vRaster);
y = vRaster * n;
}
setOffset(QPointF(x, y));
r |= canvasBoundingRect();
foreach (const Element* e, _leafs) {
r |= e->canvasBoundingRect();
}
return r;
}
//---------------------------------------------------------
// dragAnchorLines
//---------------------------------------------------------
QVector<QLineF> BSymbol::dragAnchorLines() const
{
return genericDragAnchorLines();
}
//---------------------------------------------------------
// pagePos
//---------------------------------------------------------
QPointF BSymbol::pagePos() const
{
if (parent() && (parent()->type() == ElementType::SEGMENT)) {
QPointF p(pos());
System* system = segment()->measure()->system();
if (system) {
p.ry() += system->staff(staffIdx())->y() + system->y();
}
p.rx() = pageX();
return p;
} else {
return Element::pagePos();
}
}
//---------------------------------------------------------
// canvasPos
//---------------------------------------------------------
QPointF BSymbol::canvasPos() const
{
if (parent() && (parent()->type() == ElementType::SEGMENT)) {
QPointF p(pos());
Segment* s = toSegment(parent());
System* system = s->measure()->system();
if (system) {
int si = staffIdx();
p.ry() += system->staff(si)->y() + system->y();
Page* page = system->page();
if (page) {
p.ry() += page->y();
}
}
p.rx() = canvasX();
return p;
} else {
return Element::canvasPos();
}
}
}