MuseScore/libmscore/box.cpp

651 lines
21 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2002-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 "box.h"
#include "textframe.h"
2012-05-26 14:26:10 +02:00
#include "text.h"
#include "score.h"
#include "barline.h"
#include "repeat.h"
#include "symbol.h"
#include "system.h"
#include "image.h"
#include "layoutbreak.h"
#include "fret.h"
#include "mscore.h"
#include "stafftext.h"
#include "icon.h"
2014-04-09 16:09:21 +02:00
#include "xml.h"
2012-05-26 14:26:10 +02:00
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:26:10 +02:00
static const qreal BOX_MARGIN = 0.0;
//---------------------------------------------------------
// Box
//---------------------------------------------------------
Box::Box(Score* score)
: MeasureBase(score)
{
editMode = false;
_boxWidth = Spatium(0);
_boxHeight = Spatium(0);
_leftMargin = BOX_MARGIN;
_rightMargin = BOX_MARGIN;
_topMargin = BOX_MARGIN;
_bottomMargin = BOX_MARGIN;
_topGap = 0.0;
_bottomGap = 0.0;
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void Box::layout()
{
MeasureBase::layout();
foreach (Element* el, _el) {
if (el->type() != ElementType::LAYOUT_BREAK)
2012-05-26 14:26:10 +02:00
el->layout();
}
}
//---------------------------------------------------------
// draw
//---------------------------------------------------------
void Box::draw(QPainter* painter) const
{
if (score() && score()->printing())
return;
if (selected() || editMode || dropTarget() || score()->showFrames()) {
qreal w = spatium() * .15;
2013-07-04 21:07:53 +02:00
QPainterPathStroker stroker;
stroker.setWidth(w);
stroker.setJoinStyle(Qt::MiterJoin);
stroker.setCapStyle(Qt::SquareCap);
QVector<qreal> dashes ;
dashes.append(1);
dashes.append(3);
stroker.setDashPattern(dashes);
QPainterPath path;
2012-05-26 14:26:10 +02:00
w *= .5;
2013-07-04 21:07:53 +02:00
path.addRect(bbox().adjusted(w, w, -w, -w));
QPainterPath stroke = stroker.createStroke(path);
painter->setBrush(Qt::NoBrush);
painter->fillPath(stroke, (selected() || editMode || dropTarget()) ? MScore::selectColor[0] : MScore::frameMarginColor);
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// startEdit
//---------------------------------------------------------
void Box::startEdit(MuseScoreView*, const QPointF&)
{
editMode = true;
if (type() == ElementType::HBOX)
2014-05-26 18:18:01 +02:00
undoPushProperty(P_ID::BOX_WIDTH);
else
2014-05-26 18:18:01 +02:00
undoPushProperty(P_ID::BOX_HEIGHT);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// edit
//---------------------------------------------------------
bool Box::edit(MuseScoreView*, int /*grip*/, int /*key*/, Qt::KeyboardModifiers, const QString&)
{
return false;
}
//---------------------------------------------------------
// editDrag
//---------------------------------------------------------
void Box::editDrag(const EditData& ed)
{
if (type() == ElementType::VBOX) {
2012-05-26 14:26:10 +02:00
_boxHeight = Spatium((ed.pos.y() - abbox().y()) / spatium());
if (ed.vRaster) {
qreal vRaster = 1.0 / MScore::vRaster();
int n = lrint(_boxHeight.val() / vRaster);
_boxHeight = Spatium(vRaster * n);
}
2013-01-02 09:29:17 +01:00
bbox().setRect(0.0, 0.0, system()->width(), point(boxHeight()));
2012-05-26 14:26:10 +02:00
system()->setHeight(height());
score()->doLayoutPages();
}
else {
_boxWidth += Spatium(ed.delta.x() / spatium());
if (ed.hRaster) {
qreal hRaster = 1.0 / MScore::hRaster();
int n = lrint(_boxWidth.val() / hRaster);
_boxWidth = Spatium(hRaster * n);
}
score()->setLayoutAll(true);
}
layout();
}
//---------------------------------------------------------
// endEdit
//---------------------------------------------------------
void Box::endEdit()
{
editMode = false;
layout();
}
//---------------------------------------------------------
// updateGrips
//---------------------------------------------------------
2014-03-16 14:57:32 +01:00
void Box::updateGrips(int* grips, int* defaultGrip, QRectF* grip) const
2012-05-26 14:26:10 +02:00
{
*grips = 1;
2014-03-16 14:57:32 +01:00
*defaultGrip = 1;
2012-05-26 14:26:10 +02:00
QRectF r(abbox());
if (type() == ElementType::HBOX)
2012-05-26 14:26:10 +02:00
grip[0].translate(QPointF(r.right(), r.top() + r.height() * .5));
else if (type() == ElementType::VBOX)
2012-05-26 14:26:10 +02:00
grip[0].translate(QPointF(r.x() + r.width() * .5, r.bottom()));
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void Box::write(Xml& xml) const
{
xml.stag(name());
2014-05-26 18:18:01 +02:00
writeProperty(xml, P_ID::BOX_HEIGHT);
writeProperty(xml, P_ID::BOX_WIDTH);
writeProperty(xml, P_ID::TOP_GAP);
writeProperty(xml, P_ID::BOTTOM_GAP);
writeProperty(xml, P_ID::LEFT_MARGIN);
writeProperty(xml, P_ID::RIGHT_MARGIN);
writeProperty(xml, P_ID::TOP_MARGIN);
writeProperty(xml, P_ID::BOTTOM_MARGIN);
2012-05-26 14:26:10 +02:00
Element::writeProperties(xml);
foreach (const Element* el, _el)
el->write(xml);
xml.etag();
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void Box::read(XmlReader& e)
2012-05-26 14:26:10 +02:00
{
_leftMargin = _rightMargin = _topMargin = _bottomMargin = 0.0;
bool keepMargins = false; // whether original margins have to be kept when reading old file
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2012-08-10 17:01:35 +02:00
if (tag == "height")
2013-01-11 18:10:18 +01:00
_boxHeight = Spatium(e.readDouble());
2012-08-10 17:01:35 +02:00
else if (tag == "width")
2013-01-11 18:10:18 +01:00
_boxWidth = Spatium(e.readDouble());
2012-08-10 17:01:35 +02:00
else if (tag == "topGap")
2013-01-11 18:10:18 +01:00
_topGap = e.readDouble();
2012-08-10 17:01:35 +02:00
else if (tag == "bottomGap")
2013-01-11 18:10:18 +01:00
_bottomGap = e.readDouble();
2012-08-10 17:01:35 +02:00
else if (tag == "leftMargin")
2013-01-11 18:10:18 +01:00
_leftMargin = e.readDouble();
2012-08-10 17:01:35 +02:00
else if (tag == "rightMargin")
2013-01-11 18:10:18 +01:00
_rightMargin = e.readDouble();
2012-08-10 17:01:35 +02:00
else if (tag == "topMargin")
2013-01-11 18:10:18 +01:00
_topMargin = e.readDouble();
2012-08-10 17:01:35 +02:00
else if (tag == "bottomMargin")
2013-01-11 18:10:18 +01:00
_bottomMargin = e.readDouble();
2012-05-26 14:26:10 +02:00
else if (tag == "Text") {
Text* t;
if (type() == ElementType::TBOX) {
2012-05-26 14:26:10 +02:00
t = static_cast<TBox*>(this)->getText();
t->read(e);
}
else {
t = new Text(score());
t->read(e);
add(t);
if (score()->mscVersion() <= 114)
t->setLayoutToParentWidth(true);
2012-05-26 14:26:10 +02:00
}
}
else if (tag == "Symbol") {
Symbol* s = new Symbol(score());
s->read(e);
add(s);
}
else if (tag == "Image") {
if (MScore::noImages)
e.skipCurrentElement();
else {
Image* image = new Image(score());
image->setTrack(e.track());
image->read(e);
add(image);
}
2012-05-26 14:26:10 +02:00
}
2012-09-24 14:48:43 +02:00
else if (tag == "FretDiagram") {
FretDiagram* f = new FretDiagram(score());
f->read(e);
add(f);
}
2012-05-26 14:26:10 +02:00
else if (tag == "LayoutBreak") {
LayoutBreak* lb = new LayoutBreak(score());
lb->read(e);
add(lb);
}
else if (tag == "HBox") {
HBox* hb = new HBox(score());
hb->read(e);
add(hb);
keepMargins = true; // in old file, box nesting used outer box margins
}
else if (tag == "VBox") {
VBox* vb = new VBox(score());
vb->read(e);
add(vb);
keepMargins = true; // in old file, box nesting used outer box margins
}
2013-01-11 18:10:18 +01:00
else if (Element::readProperties(e))
;
2012-05-26 14:26:10 +02:00
else
2013-01-11 18:10:18 +01:00
e.unknown();
2012-05-26 14:26:10 +02:00
}
// with .msc versions prior to 1.17, box margins were only used when nesting another box inside this box:
// for backward compatibility set them to 0 in all other cases
if (score()->mscVersion() < 117 && (type() == ElementType::HBOX || type() == ElementType::VBOX) && !keepMargins) {
2012-05-26 14:26:10 +02:00
_leftMargin = _rightMargin = _topMargin = _bottomMargin = 0.0;
}
}
//---------------------------------------------------------
// add
/// Add new Element \a el to Box
//---------------------------------------------------------
void Box::add(Element* e)
{
if (e->type() == ElementType::TEXT)
2012-05-26 14:26:10 +02:00
static_cast<Text*>(e)->setLayoutToParentWidth(true);
MeasureBase::add(e);
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant Box::getProperty(P_ID propertyId) const
{
2012-08-10 17:01:35 +02:00
switch(propertyId) {
2014-05-26 18:18:01 +02:00
case P_ID::BOX_HEIGHT:
2012-08-10 17:01:35 +02:00
return _boxHeight.val();
2014-05-26 18:18:01 +02:00
case P_ID::BOX_WIDTH:
2012-08-10 17:01:35 +02:00
return _boxWidth.val();
2014-05-26 18:18:01 +02:00
case P_ID::TOP_GAP:
2012-08-10 17:01:35 +02:00
return _topGap;
2014-05-26 18:18:01 +02:00
case P_ID::BOTTOM_GAP:
2012-08-10 17:01:35 +02:00
return _bottomGap;
2014-05-26 18:18:01 +02:00
case P_ID::LEFT_MARGIN:
2012-08-10 17:01:35 +02:00
return _leftMargin;
2014-05-26 18:18:01 +02:00
case P_ID::RIGHT_MARGIN:
2012-08-10 17:01:35 +02:00
return _rightMargin;
2014-05-26 18:18:01 +02:00
case P_ID::TOP_MARGIN:
2012-08-10 17:01:35 +02:00
return _topMargin;
2014-05-26 18:18:01 +02:00
case P_ID::BOTTOM_MARGIN:
2012-08-10 17:01:35 +02:00
return _bottomMargin;
default:
return MeasureBase::getProperty(propertyId);
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool Box::setProperty(P_ID propertyId, const QVariant& v)
{
score()->addRefresh(canvasBoundingRect());
2012-08-10 17:01:35 +02:00
switch(propertyId) {
2014-05-26 18:18:01 +02:00
case P_ID::BOX_HEIGHT:
2012-08-10 17:01:35 +02:00
_boxHeight = Spatium(v.toDouble());
2012-05-26 14:26:10 +02:00
break;
2014-05-26 18:18:01 +02:00
case P_ID::BOX_WIDTH:
2012-08-10 17:01:35 +02:00
_boxWidth = Spatium(v.toDouble());
break;
2014-05-26 18:18:01 +02:00
case P_ID::TOP_GAP:
2012-08-10 17:01:35 +02:00
_topGap = v.toDouble();
break;
2014-05-26 18:18:01 +02:00
case P_ID::BOTTOM_GAP:
2012-08-10 17:01:35 +02:00
_bottomGap = v.toDouble();
break;
2014-05-26 18:18:01 +02:00
case P_ID::LEFT_MARGIN:
2012-08-10 17:01:35 +02:00
_leftMargin = v.toDouble();
break;
2014-05-26 18:18:01 +02:00
case P_ID::RIGHT_MARGIN:
2012-08-10 17:01:35 +02:00
_rightMargin = v.toDouble();
break;
2014-05-26 18:18:01 +02:00
case P_ID::TOP_MARGIN:
2012-08-10 17:01:35 +02:00
_topMargin = v.toDouble();
break;
2014-05-26 18:18:01 +02:00
case P_ID::BOTTOM_MARGIN:
2012-08-10 17:01:35 +02:00
_bottomMargin = v.toDouble();
break;
default:
return MeasureBase::setProperty(propertyId, v);
2012-05-26 14:26:10 +02:00
}
2012-08-10 17:01:35 +02:00
score()->setLayoutAll(true);
return true;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
QVariant Box::propertyDefault(P_ID id) const
{
2012-08-10 17:01:35 +02:00
switch(id) {
2014-05-26 18:18:01 +02:00
case P_ID::BOX_HEIGHT:
case P_ID::BOX_WIDTH:
case P_ID::TOP_GAP:
case P_ID::BOTTOM_GAP:
2012-08-10 17:01:35 +02:00
return 0.0;
2014-05-26 18:18:01 +02:00
case P_ID::LEFT_MARGIN:
case P_ID::RIGHT_MARGIN:
case P_ID::TOP_MARGIN:
case P_ID::BOTTOM_MARGIN:
2012-08-10 17:01:35 +02:00
return BOX_MARGIN;
default:
return MeasureBase::propertyDefault(id);
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// HBox
//---------------------------------------------------------
HBox::HBox(Score* score)
: Box(score)
{
setBoxWidth(Spatium(5.0));
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void HBox::layout()
{
if (parent() && parent()->type() == ElementType::VBOX) {
2012-05-26 14:26:10 +02:00
VBox* vb = static_cast<VBox*>(parent());
qreal x = vb->leftMargin() * MScore::DPMM;
qreal y = vb->topMargin() * MScore::DPMM;
qreal w = point(boxWidth());
qreal h = vb->height() - (vb->topMargin() + vb->bottomMargin()) * MScore::DPMM;
setPos(x, y);
2013-01-02 09:29:17 +01:00
bbox().setRect(0.0, 0.0, w, h);
2012-05-26 14:26:10 +02:00
}
else {
2013-01-02 09:29:17 +01:00
bbox().setRect(0.0, 0.0, point(boxWidth()), system()->height());
2012-05-26 14:26:10 +02:00
}
Box::layout();
adjustReadPos();
}
//---------------------------------------------------------
// layout2
// height (bbox) is defined now
//---------------------------------------------------------
void HBox::layout2()
{
Box::layout();
}
//---------------------------------------------------------
// acceptDrop
//---------------------------------------------------------
bool Box::acceptDrop(MuseScoreView*, const QPointF&, Element* e) const
{
ElementType type = e->type();
if(e->flag(ElementFlag::ON_STAFF))
return false;
2012-05-26 14:26:10 +02:00
switch(type) {
case ElementType::LAYOUT_BREAK:
case ElementType::TEXT:
case ElementType::STAFF_TEXT:
case ElementType::IMAGE:
case ElementType::SYMBOL:
2012-05-26 14:26:10 +02:00
return true;
case ElementType::ICON:
switch(static_cast<Icon*>(e)->iconType()) {
case IconType::VFRAME:
case IconType::TFRAME:
case IconType::FFRAME:
case IconType::MEASURE:
2012-05-26 14:26:10 +02:00
return true;
default:
break;
2012-05-26 14:26:10 +02:00
}
break;
default:
break;
2012-05-26 14:26:10 +02:00
}
return false;
}
//---------------------------------------------------------
// drop
//---------------------------------------------------------
Element* Box::drop(const DropData& data)
{
Element* e = data.element;
if(e->flag(ElementFlag::ON_STAFF))
return 0;
2012-05-26 14:26:10 +02:00
switch(e->type()) {
case ElementType::LAYOUT_BREAK:
2012-05-26 14:26:10 +02:00
{
LayoutBreak* lb = static_cast<LayoutBreak*>(e);
if (_pageBreak || _lineBreak) {
if (
(lb->layoutBreakType() == LayoutBreak::LayoutBreakType::PAGE && _pageBreak)
|| (lb->layoutBreakType() == LayoutBreak::LayoutBreakType::LINE && _lineBreak)
|| (lb->layoutBreakType() == LayoutBreak::LayoutBreakType::SECTION && _sectionBreak)
2012-05-26 14:26:10 +02:00
) {
//
// if break already set
//
delete lb;
break;
}
foreach(Element* elem, _el) {
if (elem->type() == ElementType::LAYOUT_BREAK) {
2012-05-26 14:26:10 +02:00
score()->undoChangeElement(elem, e);
break;
}
}
break;
}
lb->setTrack(-1); // this are system elements
lb->setParent(this);
score()->undoAddElement(lb);
return lb;
}
case ElementType::STAFF_TEXT:
2012-05-26 14:26:10 +02:00
{
Text* text = new Text(score());
text->setTextStyleType(TextStyleType::FRAME);
2012-05-26 14:26:10 +02:00
text->setParent(this);
text->setText(static_cast<StaffText*>(e)->text());
2012-05-26 14:26:10 +02:00
score()->undoAddElement(text);
delete e;
return text;
}
case ElementType::ICON:
switch(static_cast<Icon*>(e)->iconType()) {
case IconType::VFRAME:
score()->insertMeasure(ElementType::VBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::TFRAME:
score()->insertMeasure(ElementType::TBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::FFRAME:
score()->insertMeasure(ElementType::FBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::MEASURE:
score()->insertMeasure(ElementType::MEASURE, this);
2012-05-26 14:26:10 +02:00
break;
default:
break;
2012-05-26 14:26:10 +02:00
}
break;
default:
e->setParent(this);
score()->undoAddElement(e);
return e;
}
return 0;
}
//---------------------------------------------------------
// drag
//---------------------------------------------------------
2013-10-22 12:05:31 +02:00
QRectF HBox::drag(EditData* data)
2012-05-26 14:26:10 +02:00
{
QRectF r(canvasBoundingRect());
2013-10-22 12:05:31 +02:00
qreal diff = data->delta.x();
2012-05-26 14:26:10 +02:00
qreal x1 = userOff().x() + diff;
if (parent()->type() == ElementType::VBOX) {
2012-05-26 14:26:10 +02:00
VBox* vb = static_cast<VBox*>(parent());
qreal x2 = parent()->width() - width() - (vb->leftMargin() + vb->rightMargin()) * MScore::DPMM;
if (x1 < 0.0)
x1 = 0.0;
else if (x1 > x2)
x1 = x2;
}
setUserOff(QPointF(x1, 0.0));
2013-10-24 12:09:00 +02:00
setStartDragPosition(data->delta);
2012-05-26 14:26:10 +02:00
return canvasBoundingRect() | r;
}
//---------------------------------------------------------
// endEditDrag
//---------------------------------------------------------
void HBox::endEditDrag()
{
score()->setLayoutAll(true);
2013-06-05 15:47:34 +02:00
score()->update();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// isMovable
//---------------------------------------------------------
bool HBox::isMovable() const
{
return parent() && (parent()->type() == ElementType::HBOX || parent()->type() == ElementType::VBOX);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// VBox
//---------------------------------------------------------
VBox::VBox(Score* score)
: Box(score)
{
setBoxHeight(Spatium(10.0));
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void VBox::layout()
{
setPos(QPointF()); // !?
if (system())
2013-01-02 09:29:17 +01:00
bbox().setRect(0.0, 0.0, system()->width(), point(boxHeight()));
2012-05-26 14:26:10 +02:00
else
2013-01-02 09:29:17 +01:00
bbox().setRect(0.0, 0.0, 50, 50);
2012-05-26 14:26:10 +02:00
Box::layout();
}
//---------------------------------------------------------
// getGrip
//---------------------------------------------------------
QPointF VBox::getGrip(int) const
{
return QPointF(0.0, boxHeight().val());
}
//---------------------------------------------------------
// setGrip
//---------------------------------------------------------
void VBox::setGrip(int, const QPointF& pt)
{
setBoxHeight(Spatium(pt.y()));
layout();
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void FBox::layout()
{
2012-09-24 14:48:43 +02:00
// setPos(QPointF()); // !?
2013-01-02 09:29:17 +01:00
bbox().setRect(0.0, 0.0, system()->width(), point(boxHeight()));
2012-05-26 14:26:10 +02:00
Box::layout();
}
//---------------------------------------------------------
// add
/// Add new Element \a e to fret diagram box
//---------------------------------------------------------
void FBox::add(Element* e)
{
e->setParent(this);
if (e->type() == ElementType::FRET_DIAGRAM) {
2012-09-24 14:48:43 +02:00
// FretDiagram* fd = static_cast<FretDiagram*>(e);
// fd->setFlag(ElementFlag::MOVABLE, false);
2012-05-26 14:26:10 +02:00
}
else {
qDebug("FBox::add: element not allowed");
2012-05-26 14:26:10 +02:00
return;
}
2013-03-25 16:27:20 +01:00
_el.push_back(e);
2012-05-26 14:26:10 +02:00
}
2013-05-13 18:49:17 +02:00
}