1825 lines
56 KiB
C++
1825 lines
56 KiB
C++
//=============================================================================
|
|
// MuseScore
|
|
// Music Composition & Notation
|
|
// $Id: text.cpp 5627 2012-05-14 20:18:41Z wschweer $
|
|
//
|
|
// 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 "text.h"
|
|
#include "xml.h"
|
|
#include "style.h"
|
|
#include "score.h"
|
|
#include "utils.h"
|
|
#include "page.h"
|
|
#include "sym.h"
|
|
#include "symbol.h"
|
|
#include "textline.h"
|
|
#include "system.h"
|
|
#include "measure.h"
|
|
#include "box.h"
|
|
#include "segment.h"
|
|
#include "mscore.h"
|
|
#include "textframe.h"
|
|
|
|
enum SymbolType {
|
|
SYMBOL_UNKNOWN,
|
|
SYMBOL_COPYRIGHT,
|
|
SYMBOL_FRACTION
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// SymCode
|
|
//---------------------------------------------------------
|
|
|
|
struct SymCode {
|
|
int code;
|
|
const char* text;
|
|
SymbolType type;
|
|
};
|
|
|
|
SymCode charReplaceMap[] = {
|
|
{ 0xa9, "(C)", SYMBOL_COPYRIGHT },
|
|
{ 0x00BC, "1/4", SYMBOL_FRACTION },
|
|
{ 0x00BD, "1/2", SYMBOL_FRACTION },
|
|
{ 0x00BE, "3/4", SYMBOL_FRACTION },
|
|
{ 0x2153, "1/3", SYMBOL_FRACTION },
|
|
{ 0x2154, "2/3", SYMBOL_FRACTION },
|
|
{ 0x2155, "1/5", SYMBOL_FRACTION },
|
|
{ 0x2156, "2/5", SYMBOL_FRACTION },
|
|
{ 0x2157, "3/5", SYMBOL_FRACTION },
|
|
{ 0x2158, "4/5", SYMBOL_FRACTION },
|
|
{ 0x2159, "1/6", SYMBOL_FRACTION },
|
|
{ 0x215A, "5/6", SYMBOL_FRACTION },
|
|
{ 0x215B, "1/8", SYMBOL_FRACTION },
|
|
{ 0x215C, "3/8", SYMBOL_FRACTION },
|
|
{ 0x215D, "5/8", SYMBOL_FRACTION },
|
|
{ 0x215E, "7/8", SYMBOL_FRACTION }
|
|
};
|
|
|
|
QTextCursor* Text::_cursor;
|
|
|
|
//---------------------------------------------------------
|
|
// createDoc
|
|
//---------------------------------------------------------
|
|
|
|
void Text::createDoc()
|
|
{
|
|
_doc = new QTextDocument(0);
|
|
_doc->setDocumentMargin(0);
|
|
_doc->setUseDesignMetrics(true);
|
|
_doc->setUndoRedoEnabled(true);
|
|
_doc->documentLayout()->setProperty("cursorWidth", QVariant(2));
|
|
QTextOption to = _doc->defaultTextOption();
|
|
to.setUseDesignMetrics(true);
|
|
to.setWrapMode(QTextOption::NoWrap);
|
|
_doc->setDefaultTextOption(to);
|
|
_doc->setDefaultFont(textStyle().font(spatium()));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Text
|
|
//---------------------------------------------------------
|
|
|
|
Text::Text(Score* s)
|
|
: SimpleText(s)
|
|
{
|
|
setFlag(ELEMENT_MOVABLE, true);
|
|
_doc = 0;
|
|
_styleIndex = TEXT_STYLE_DEFAULT;
|
|
}
|
|
|
|
Text::Text(const Text& e)
|
|
: SimpleText(e)
|
|
{
|
|
if (e._doc)
|
|
_doc = e._doc->clone();
|
|
else
|
|
_doc = 0;
|
|
_styleIndex = e._styleIndex;
|
|
}
|
|
|
|
Text::~Text()
|
|
{
|
|
delete _doc;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setText
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setText(const QString& s)
|
|
{
|
|
if (styled())
|
|
SimpleText::setText(s);
|
|
else
|
|
setUnstyledText(s);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setUnstyledText
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setUnstyledText(const QString& s)
|
|
{
|
|
Align align = textStyle().align();
|
|
_doc->clear();
|
|
|
|
QTextCursor c(_doc);
|
|
c.setVisualNavigation(true);
|
|
c.movePosition(QTextCursor::Start);
|
|
Qt::Alignment a;
|
|
if (align & ALIGN_HCENTER)
|
|
a = Qt::AlignHCenter;
|
|
else if (align & ALIGN_RIGHT)
|
|
a = Qt::AlignRight;
|
|
else
|
|
a = Qt::AlignLeft;
|
|
QTextBlockFormat bf = c.blockFormat();
|
|
bf.setAlignment(a);
|
|
c.setBlockFormat(bf);
|
|
|
|
QTextCharFormat tf = c.charFormat();
|
|
tf.setFont(textStyle().font(spatium()));
|
|
c.setBlockCharFormat(tf);
|
|
c.insertText(s);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setText
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setText(const QTextDocumentFragment& f)
|
|
{
|
|
setHtml(f.toHtml());
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setHtml
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setHtml(const QString& s)
|
|
{
|
|
setUnstyled();
|
|
_doc->clear();
|
|
_doc->setHtml(s);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// text
|
|
//---------------------------------------------------------
|
|
|
|
QString Text::text() const
|
|
{
|
|
return styled() ? SimpleText::text() : _doc->toPlainText();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getHtml
|
|
//---------------------------------------------------------
|
|
|
|
QString Text::getHtml() const
|
|
{
|
|
return styled() ? "" : _doc->toHtml("utf-8");
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// systemFlag
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::systemFlag() const
|
|
{
|
|
return textStyle().systemFlag();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setAbove
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setAbove(bool val)
|
|
{
|
|
setYoff(val ? -2.0 : 7.0);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// layout
|
|
//---------------------------------------------------------
|
|
|
|
void Text::layout()
|
|
{
|
|
layout1();
|
|
adjustReadPos();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// layout1
|
|
//---------------------------------------------------------
|
|
|
|
void Text::layout1()
|
|
{
|
|
if (styled())
|
|
SimpleText::layout();
|
|
else {
|
|
QPointF o(textStyle().offset(spatium()));
|
|
|
|
_doc->setDefaultFont(textStyle().font(spatium()));
|
|
qreal w = -1.0;
|
|
|
|
if (parent() && layoutToParentWidth()) {
|
|
Element* e = parent();
|
|
w = e->width();
|
|
if (e->type() == HBOX || e->type() == VBOX || e->type() == TBOX) {
|
|
Box* b = static_cast<Box*>(e);
|
|
w -= ((b->leftMargin() + b->rightMargin()) * MScore::DPMM);
|
|
}
|
|
}
|
|
|
|
QTextOption to = _doc->defaultTextOption();
|
|
to.setUseDesignMetrics(true);
|
|
to.setWrapMode(w <= 0.0 ? QTextOption::NoWrap : QTextOption::WrapAtWordBoundaryOrAnywhere);
|
|
_doc->setDefaultTextOption(to);
|
|
|
|
if (w <= 0.0)
|
|
w = _doc->idealWidth();
|
|
_doc->setTextWidth(w);
|
|
|
|
QSizeF size(_doc->size());
|
|
|
|
if (align() & ALIGN_BOTTOM) {
|
|
o.ry() += 3;
|
|
o.ry() -= size.height();
|
|
}
|
|
else if (align() & ALIGN_VCENTER)
|
|
o.ry() -= (size.height() * .5);
|
|
else if (align() & ALIGN_BASELINE)
|
|
o.ry() -= baseLine();
|
|
|
|
if (align() & ALIGN_RIGHT)
|
|
o.rx() -= size.width();
|
|
else if (align() & ALIGN_HCENTER)
|
|
o.rx() -= (size.width() * .5);
|
|
|
|
bbox().setRect(0.0, 0.0, size.width(), size.height());
|
|
_doc->setModified(false);
|
|
setPos(o);
|
|
}
|
|
if (parent()) {
|
|
Element* e = parent();
|
|
qreal w, h, xo, yo;
|
|
if (layoutToParentWidth()) {
|
|
if (e->type() == HBOX || e->type() == VBOX || e->type() == TBOX) {
|
|
// consider inner margins of frame
|
|
Box* b = static_cast<Box*>(e);
|
|
xo = b->leftMargin() * MScore::DPMM;
|
|
yo = b->topMargin() * MScore::DPMM;
|
|
w = b->width() - xo - b->rightMargin() * MScore::DPMM;
|
|
h = b->height() - yo - b->bottomMargin() * MScore::DPMM;
|
|
}
|
|
else {
|
|
w = e->width();
|
|
h = e->height();
|
|
xo = 0.0;
|
|
yo = 0.0;
|
|
}
|
|
QPointF ro(_textStyle.reloff() * .01);
|
|
rxpos() += xo + ro.x() * w;
|
|
rypos() += yo + ro.y() * h;
|
|
}
|
|
if (e->type() == SEGMENT) {
|
|
Segment* s = static_cast<Segment*>(e);
|
|
rypos() += s->measure()->system()->staff(staffIdx())->y();
|
|
}
|
|
}
|
|
|
|
if (hasFrame())
|
|
layoutFrame();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// pageRectangle
|
|
//---------------------------------------------------------
|
|
|
|
QRectF Text::pageRectangle() const
|
|
{
|
|
if (parent() && (parent()->type() == HBOX || parent()->type() == VBOX || parent()->type() == TBOX)) {
|
|
QRectF r = parent()->abbox();
|
|
Box* box = static_cast<Box*>(parent());
|
|
qreal x = r.x() + box->leftMargin() * MScore::DPMM;
|
|
qreal y = r.y() + box->topMargin() * MScore::DPMM;
|
|
qreal h = r.height() - (box->topMargin() + box->bottomMargin()) * MScore::DPMM;
|
|
qreal w = r.width() - (box->leftMargin() + box->rightMargin()) * MScore::DPMM;
|
|
|
|
// QSizeF ps = _doc->pageSize();
|
|
// return QRectF(x, y, ps.width(), ps.height());
|
|
|
|
return QRectF(x, y, w, h);
|
|
}
|
|
else
|
|
return abbox();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// draw
|
|
//---------------------------------------------------------
|
|
|
|
void Text::draw(QPainter* painter) const
|
|
{
|
|
drawFrame(painter);
|
|
if (styled()) {
|
|
SimpleText::draw(painter);
|
|
return;
|
|
}
|
|
QAbstractTextDocumentLayout::PaintContext c;
|
|
bool printing = score() && score()->printing();
|
|
if (_cursor
|
|
&& _doc
|
|
&& _cursor->document() == _doc
|
|
&& !printing) {
|
|
if (_cursor->hasSelection()) {
|
|
QAbstractTextDocumentLayout::Selection selection;
|
|
selection.cursor = *_cursor;
|
|
selection.format.setBackground(c.palette.brush(QPalette::Active, QPalette::Highlight));
|
|
selection.format.setForeground(c.palette.brush(QPalette::Active, QPalette::HighlightedText));
|
|
c.selections.append(selection);
|
|
}
|
|
c.cursorPosition = _cursor->position();
|
|
}
|
|
else
|
|
c.cursorPosition = -1;
|
|
|
|
if ((printing || !score()->showInvisible()) && !visible())
|
|
return;
|
|
c.palette.setColor(QPalette::Text, textColor());
|
|
|
|
_doc->documentLayout()->draw(painter, c);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// write
|
|
//---------------------------------------------------------
|
|
|
|
void Text::write(Xml& xml) const
|
|
{
|
|
xml.stag(name());
|
|
writeProperties(xml, true);
|
|
xml.etag();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// read
|
|
//---------------------------------------------------------
|
|
|
|
void Text::read(XmlReader& e)
|
|
{
|
|
while (e.readNextStartElement()) {
|
|
if (!readProperties(e))
|
|
e.unknown();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// writeProperties
|
|
//---------------------------------------------------------
|
|
|
|
void Text::writeProperties(Xml& xml, bool writeText) const
|
|
{
|
|
Element::writeProperties(xml);
|
|
if (xml.clipboardmode || styled())
|
|
xml.tag("style", textStyle().name());
|
|
if (xml.clipboardmode || !styled())
|
|
_textStyle.writeProperties(xml);
|
|
if (writeText) {
|
|
if (styled())
|
|
xml.tag("text", text());
|
|
else {
|
|
xml.stag("html-data");
|
|
xml.writeHtml(_doc->toHtml("utf-8"));
|
|
xml.etag();
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// isSimpleText
|
|
// check if _doc can be converted to simple text
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::isSimpleText() const
|
|
{
|
|
if (_doc->blockCount() > 1)
|
|
return false;
|
|
int n = 0;
|
|
QTextBlock b(_doc->firstBlock());
|
|
QTextBlock::iterator i(_doc->firstBlock().begin());
|
|
for (; !i.atEnd(); ++i)
|
|
++n;
|
|
return n <= 1;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// readProperties
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::readProperties(XmlReader& e)
|
|
{
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "style") {
|
|
QString val(e.readElementText());
|
|
int st;
|
|
bool ok;
|
|
int i = val.toInt(&ok);
|
|
if (ok) {
|
|
// obsolete old text styles
|
|
switch (i) {
|
|
case 1: i = TEXT_STYLE_UNSTYLED; break;
|
|
case 2: i = TEXT_STYLE_TITLE; break;
|
|
case 3: i = TEXT_STYLE_SUBTITLE; break;
|
|
case 4: i = TEXT_STYLE_COMPOSER; break;
|
|
case 5: i = TEXT_STYLE_POET; break;
|
|
case 6: i = TEXT_STYLE_LYRIC1; break;
|
|
case 7: i = TEXT_STYLE_LYRIC2; break;
|
|
case 8: i = TEXT_STYLE_FINGERING; break;
|
|
case 9: i = TEXT_STYLE_INSTRUMENT_LONG; break;
|
|
case 10: i = TEXT_STYLE_INSTRUMENT_SHORT; break;
|
|
case 11: i = TEXT_STYLE_INSTRUMENT_EXCERPT; break;
|
|
|
|
case 12: i = TEXT_STYLE_DYNAMICS; break;
|
|
case 13: i = TEXT_STYLE_TECHNIK; break;
|
|
case 14: i = TEXT_STYLE_TEMPO; break;
|
|
case 15: i = TEXT_STYLE_METRONOME; break;
|
|
case 16: i = TEXT_STYLE_FOOTER; break; // TEXT_STYLE_COPYRIGHT
|
|
case 17: i = TEXT_STYLE_MEASURE_NUMBER; break;
|
|
case 18: i = TEXT_STYLE_FOOTER; break; // TEXT_STYLE_PAGE_NUMBER_ODD
|
|
case 19: i = TEXT_STYLE_FOOTER; break; // TEXT_STYLE_PAGE_NUMBER_EVEN
|
|
case 20: i = TEXT_STYLE_TRANSLATOR; break;
|
|
case 21: i = TEXT_STYLE_TUPLET; break;
|
|
|
|
case 22: i = TEXT_STYLE_SYSTEM; break;
|
|
case 23: i = TEXT_STYLE_STAFF; break;
|
|
case 24: i = TEXT_STYLE_HARMONY; break;
|
|
case 25: i = TEXT_STYLE_REHEARSAL_MARK; break;
|
|
case 26: i = TEXT_STYLE_REPEAT; break;
|
|
case 27: i = TEXT_STYLE_VOLTA; break;
|
|
case 28: i = TEXT_STYLE_FRAME; break;
|
|
case 29: i = TEXT_STYLE_TEXTLINE; break;
|
|
case 30: i = TEXT_STYLE_GLISSANDO; break;
|
|
case 31: i = TEXT_STYLE_STRING_NUMBER; break;
|
|
|
|
case 32: i = TEXT_STYLE_OTTAVA; break;
|
|
case 33: i = TEXT_STYLE_BENCH; break;
|
|
case 34: i = TEXT_STYLE_HEADER; break;
|
|
case 35: i = TEXT_STYLE_FOOTER; break;
|
|
case 0:
|
|
default:
|
|
qDebug("Text:readProperties: style %d<%s> invalid", i, qPrintable(val));
|
|
i = TEXT_STYLE_UNSTYLED;
|
|
break;
|
|
}
|
|
st = i;
|
|
}
|
|
else
|
|
st = score()->style()->textStyleType(val);
|
|
|
|
if (st == TEXT_STYLE_UNSTYLED)
|
|
setUnstyled();
|
|
else if (st == TEXT_STYLE_UNKNOWN)
|
|
_styleIndex = st;
|
|
else
|
|
setTextStyleType(st);
|
|
}
|
|
else if (tag == "styleName") // obsolete, unstyled text
|
|
e.skipCurrentElement(); // _styleName = val;
|
|
else if (tag == "data") // obsolete
|
|
_doc->setHtml(e.readElementText());
|
|
else if (tag == "html") {
|
|
QString s = Xml::htmlToString(e);
|
|
setHtml(s);
|
|
}
|
|
else if (tag == "text")
|
|
setText(e.readElementText());
|
|
else if (tag == "html-data") {
|
|
QString s = Xml::htmlToString(e);
|
|
if (score()->mscVersion() <= 114) {
|
|
s.replace("MScore1", "FreeSerifMscore");
|
|
s.replace(QChar(0xe10e), QChar(0x266e)); //natural
|
|
s.replace(QChar(0xe10c), QChar(0x266f)); // sharp
|
|
s.replace(QChar(0xe10d), QChar(0x266d)); // flat
|
|
s.replace(QChar(0xe104), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd5e))), // note2_Sym
|
|
s.replace(QChar(0xe105), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd5f))); // note4_Sym
|
|
s.replace(QChar(0xe106), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd60))); // note8_Sym
|
|
s.replace(QChar(0xe107), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd61))); // note16_Sym
|
|
s.replace(QChar(0xe108), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd62))); // note32_Sym
|
|
s.replace(QChar(0xe109), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd63))); // note64_Sym
|
|
s.replace(QChar(0xe10a), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd6d))); // dot
|
|
s.replace(QChar(0xe10b), QString("%1%2%3%4").arg(QChar(0xd834)).arg(QChar(0xdd6d)).arg(QChar(0xd834)).arg(QChar(0xdd6d))); // dotdot
|
|
s.replace(QChar(0xe167), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd0b))); // coda
|
|
s.replace(QChar(0xe168), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd0c))); // varcoda
|
|
s.replace(QChar(0xe169), QString("%1%2").arg(QChar(0xd834)).arg(QChar(0xdd0c))); // segno
|
|
if (_doc == 0)
|
|
createDoc();
|
|
// import instrument names as unstyled html
|
|
if (_styleIndex != TEXT_STYLE_INSTRUMENT_SHORT
|
|
&& _styleIndex != TEXT_STYLE_INSTRUMENT_LONG
|
|
&& isSimpleText()) {
|
|
_doc->setHtml(s);
|
|
QString s = _doc->toPlainText();
|
|
delete _doc;
|
|
_doc = 0;
|
|
setText(s);
|
|
}
|
|
else {
|
|
setUnstyled();
|
|
setHtml(s);
|
|
}
|
|
}
|
|
else {
|
|
setHtml(s);
|
|
}
|
|
}
|
|
else if (tag == "subtype") // obsolete
|
|
e.skipCurrentElement();
|
|
else if (tag == "frameWidth") { // obsolete
|
|
qreal spMM = spatium() / MScore::DPMM;
|
|
setFrameWidth(Spatium(e.readDouble() / spMM));
|
|
}
|
|
else if (tag == "paddingWidth") { // obsolete
|
|
qreal spMM = spatium() / MScore::DPMM;
|
|
setPaddingWidth(Spatium(e.readDouble() / spMM));
|
|
}
|
|
else if (_textStyle.readProperties(e))
|
|
;
|
|
else if (!Element::readProperties(e))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// spatiumChanged
|
|
//---------------------------------------------------------
|
|
|
|
void Text::spatiumChanged(qreal oldVal, qreal newVal)
|
|
{
|
|
Element::spatiumChanged(oldVal, newVal);
|
|
|
|
if (!sizeIsSpatiumDependent() || styled())
|
|
return;
|
|
qreal v = newVal / oldVal;
|
|
|
|
QTextCursor c(_doc);
|
|
QTextBlock cb = _doc->begin();
|
|
while (cb.isValid()) {
|
|
QTextBlock::iterator i(cb.begin());
|
|
for (; !i.atEnd(); ++i) {
|
|
QTextFragment f = i.fragment();
|
|
if (f.isValid()) {
|
|
int pos = f.position();
|
|
int len = f.length();
|
|
c.setPosition(pos, QTextCursor::MoveAnchor);
|
|
c.setPosition(pos + len, QTextCursor::KeepAnchor);
|
|
QTextCharFormat cf = c.charFormat();
|
|
QFont font = cf.font();
|
|
font.setPointSizeF(font.pointSizeF() * v);
|
|
cf.setFont(font);
|
|
c.setCharFormat(cf);
|
|
}
|
|
}
|
|
cb = cb.next();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// startEdit
|
|
//---------------------------------------------------------
|
|
|
|
void Text::startEdit(MuseScoreView* view, const QPointF& p)
|
|
{
|
|
setEditMode(true);
|
|
if (styled()) {
|
|
SimpleText::startEdit(view, p);
|
|
return;
|
|
}
|
|
undoPushProperty(P_HTML_TEXT);
|
|
_cursor = new QTextCursor(_doc);
|
|
_cursor->setVisualNavigation(true);
|
|
setCursor(p);
|
|
qreal w = 2.0; // 8.0 / view->matrix().m11();
|
|
score()->rebuildBspTree();
|
|
score()->addRefresh(canvasBoundingRect().adjusted(-w, -w, w, w));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// edit
|
|
// return true if event is accepted
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::edit(MuseScoreView* view, int grip, int key, Qt::KeyboardModifiers modifiers, const QString& s)
|
|
{
|
|
if (styled())
|
|
return SimpleText::edit(view, grip, key, modifiers, s);
|
|
if (MScore::debugMode)
|
|
qDebug("Text::edit(%p) key 0x%x mod 0x%x\n", this, key, int(modifiers));
|
|
if (!editMode() || !_cursor) {
|
|
qDebug("Text::edit(%p): not in edit mode: %d %p", this, editMode(), _cursor);
|
|
return false;
|
|
}
|
|
score()->setLayoutAll(type() == INSTRUMENT_NAME);
|
|
static const qreal w = 2.0; // 8.0 / view->matrix().m11();
|
|
score()->addRefresh(canvasBoundingRect().adjusted(-w, -w, w, w));
|
|
|
|
if (modifiers == Qt::ControlModifier) {
|
|
switch (key) {
|
|
case Qt::Key_A: // select all
|
|
_cursor->select(QTextCursor::Document);
|
|
break;
|
|
case Qt::Key_B: // toggle bold face
|
|
{
|
|
QTextCharFormat f = _cursor->charFormat();
|
|
f.setFontWeight(f.fontWeight() == QFont::Bold ? QFont::Normal : QFont::Bold);
|
|
_cursor->setCharFormat(f);
|
|
}
|
|
break;
|
|
case Qt::Key_I: // toggle italic
|
|
{
|
|
QTextCharFormat f = _cursor->charFormat();
|
|
f.setFontItalic(!f.fontItalic());
|
|
_cursor->setCharFormat(f);
|
|
}
|
|
break;
|
|
case Qt::Key_U: // toggle underline
|
|
{
|
|
QTextCharFormat f = _cursor->charFormat();
|
|
f.setFontUnderline(!f.fontUnderline());
|
|
_cursor->setCharFormat(f);
|
|
}
|
|
break;
|
|
case Qt::Key_Up:
|
|
{
|
|
QTextCharFormat f = _cursor->charFormat();
|
|
if (f.verticalAlignment() == QTextCharFormat::AlignNormal)
|
|
f.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
|
|
else if (f.verticalAlignment() == QTextCharFormat::AlignSubScript)
|
|
f.setVerticalAlignment(QTextCharFormat::AlignNormal);
|
|
_cursor->setCharFormat(f);
|
|
}
|
|
break;
|
|
|
|
case Qt::Key_Down:
|
|
{
|
|
QTextCharFormat f = _cursor->charFormat();
|
|
if (f.verticalAlignment() == QTextCharFormat::AlignNormal)
|
|
f.setVerticalAlignment(QTextCharFormat::AlignSubScript);
|
|
else if (f.verticalAlignment() == QTextCharFormat::AlignSuperScript)
|
|
f.setVerticalAlignment(QTextCharFormat::AlignNormal);
|
|
_cursor->setCharFormat(f);
|
|
}
|
|
break;
|
|
}
|
|
#ifndef Q_WS_MAC
|
|
if (key != Qt::Key_Space && key != Qt::Key_Minus)
|
|
return true;
|
|
#endif
|
|
}
|
|
#ifdef Q_WS_MAC
|
|
else if (modifiers == Qt::AltModifier) {
|
|
if (key != Qt::Key_Space && key != Qt::Key_Minus)
|
|
return true;
|
|
}
|
|
#endif
|
|
QTextCursor::MoveMode mm = (modifiers & Qt::ShiftModifier)
|
|
? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor;
|
|
switch (key) {
|
|
case Qt::Key_Return:
|
|
_cursor->insertText(QString("\r"));
|
|
break;
|
|
|
|
case Qt::Key_Backspace:
|
|
_cursor->deletePreviousChar();
|
|
break;
|
|
|
|
case Qt::Key_Delete:
|
|
_cursor->deleteChar();
|
|
break;
|
|
|
|
case Qt::Key_Left:
|
|
if (!_cursor->movePosition(QTextCursor::Left, mm) && (type() == LYRICS || type() == FIGURED_BASS))
|
|
return false;
|
|
break;
|
|
|
|
case Qt::Key_Right:
|
|
if (!_cursor->movePosition(QTextCursor::Right, mm) && (type() == LYRICS || type() == FIGURED_BASS))
|
|
return false;
|
|
break;
|
|
|
|
case Qt::Key_Up:
|
|
_cursor->movePosition(QTextCursor::Up, mm);
|
|
break;
|
|
|
|
case Qt::Key_Down:
|
|
_cursor->movePosition(QTextCursor::Down, mm);
|
|
break;
|
|
|
|
case Qt::Key_Home:
|
|
_cursor->movePosition(QTextCursor::Start, mm);
|
|
break;
|
|
|
|
case Qt::Key_End:
|
|
_cursor->movePosition(QTextCursor::End, mm);
|
|
break;
|
|
|
|
case Qt::Key_Space:
|
|
_cursor->insertText(" ");
|
|
break;
|
|
|
|
case Qt::Key_Minus:
|
|
_cursor->insertText("-");
|
|
break;
|
|
|
|
default:
|
|
insertText(s);
|
|
break;
|
|
}
|
|
if (key == Qt::Key_Return || key == Qt::Key_Space || key == Qt::Key_Tab) {
|
|
replaceSpecialChars();
|
|
}
|
|
layoutEdit();
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// insertText
|
|
//---------------------------------------------------------
|
|
|
|
void Text::insertText(const QString& s)
|
|
{
|
|
if (styled()) {
|
|
SimpleText::insertText(s);
|
|
}
|
|
else {
|
|
if (!s.isEmpty())
|
|
_cursor->insertText(s);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// layoutEdit
|
|
//---------------------------------------------------------
|
|
|
|
void Text::layoutEdit()
|
|
{
|
|
layout();
|
|
if (parent() && parent()->type() == TBOX) {
|
|
TBox* tbox = static_cast<TBox*>(parent());
|
|
tbox->layout();
|
|
System* system = tbox->system();
|
|
system->setHeight(tbox->height());
|
|
score()->doLayoutPages();
|
|
score()->setUpdateAll(true);
|
|
}
|
|
else {
|
|
static const qreal w = 2.0; // 8.0 / view->matrix().m11();
|
|
score()->addRefresh(canvasBoundingRect().adjusted(-w, -w, w, w));
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// replaceSpecialChars
|
|
//---------------------------------------------------------
|
|
|
|
void Text::replaceSpecialChars()
|
|
{
|
|
for (const SymCode& sym : charReplaceMap) {
|
|
if (sym.type == SYMBOL_FRACTION && !MScore::replaceFractions)
|
|
continue;
|
|
const char* s = sym.text;
|
|
QTextCursor cur = _doc->find(s, _cursor->position() - 1 - strlen(s), QTextDocument::FindWholeWords);
|
|
if (cur.isNull())
|
|
continue;
|
|
|
|
// do not go beyond the cursor
|
|
if (cur.selectionEnd() > _cursor->selectionEnd())
|
|
continue;
|
|
int code = sym.code;
|
|
QString ss;
|
|
if (code & 0xffff0000) {
|
|
ss = QChar(QChar::highSurrogate(code));
|
|
ss += QChar(QChar::lowSurrogate(code));
|
|
}
|
|
else
|
|
ss = QChar(code);
|
|
cur.insertText(ss);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// moveCursorToStart
|
|
//---------------------------------------------------------
|
|
|
|
void Text::moveCursorToStart()
|
|
{
|
|
if (styled()) {
|
|
SimpleText::moveCursorToStart();
|
|
return;
|
|
}
|
|
|
|
if (_cursor)
|
|
_cursor->movePosition(QTextCursor::Start);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// moveCursorToEnd
|
|
//---------------------------------------------------------
|
|
|
|
void Text::moveCursorToEnd()
|
|
{
|
|
if (styled()) {
|
|
SimpleText::moveCursorToEnd();
|
|
return;
|
|
}
|
|
|
|
if (_cursor)
|
|
_cursor->movePosition(QTextCursor::End);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// shape
|
|
//---------------------------------------------------------
|
|
|
|
QPainterPath Text::shape() const
|
|
{
|
|
if (styled())
|
|
return SimpleText::shape();
|
|
QPainterPath pp;
|
|
|
|
for (QTextBlock tb = _doc->begin(); tb.isValid(); tb = tb.next()) {
|
|
QTextLayout* tl = tb.layout();
|
|
int n = tl->lineCount();
|
|
for (int i = 0; i < n; ++i) {
|
|
QTextLine l = tl->lineAt(i);
|
|
QRectF r(l.naturalTextRect().translated(tl->position()));
|
|
r.adjust(-l.position().x(), 0.0, 0.0, 0.0);
|
|
pp.addRect(r);
|
|
}
|
|
}
|
|
return pp;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// baseLine
|
|
// returns ascent of first text line in first block
|
|
//---------------------------------------------------------
|
|
|
|
qreal Text::baseLine() const
|
|
{
|
|
if (styled())
|
|
return SimpleText::baseLine();
|
|
for (QTextBlock tb = _doc->begin(); tb.isValid(); tb = tb.next()) {
|
|
const QTextLayout* tl = tb.layout();
|
|
if (tl->lineCount()) {
|
|
return (tl->lineAt(0).ascent() + tl->lineAt(0).leading()
|
|
+ tl->position().y());
|
|
}
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// lineSpacing
|
|
//---------------------------------------------------------
|
|
|
|
qreal Text::lineSpacing() const
|
|
{
|
|
return QFontMetricsF(textStyle().font(spatium())).lineSpacing();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// lineHeight
|
|
// HACK
|
|
//---------------------------------------------------------
|
|
|
|
qreal Text::lineHeight() const
|
|
{
|
|
return QFontMetricsF(textStyle().font(spatium())).height();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// addChar
|
|
//---------------------------------------------------------
|
|
|
|
void Text::addChar(int code)
|
|
{
|
|
QString ss;
|
|
if (code & 0xffff0000) {
|
|
ss = QChar(QChar::highSurrogate(code));
|
|
ss += QChar(QChar::lowSurrogate(code));
|
|
}
|
|
else
|
|
ss = QChar(code);
|
|
if (styled()) {
|
|
SimpleText::insertText(ss);
|
|
return;
|
|
}
|
|
_cursor->insertText(ss);
|
|
score()->setLayoutAll(true);
|
|
score()->end();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setBlockFormat
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setBlockFormat(const QTextBlockFormat& bf)
|
|
{
|
|
if (!_cursor)
|
|
return;
|
|
_cursor->setBlockFormat(bf);
|
|
score()->setLayoutAll(true);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCursor
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::setCursor(const QPointF& p, QTextCursor::MoveMode mode)
|
|
{
|
|
if (styled())
|
|
return SimpleText::setCursor(p, mode);
|
|
QPointF pt = p - canvasPos();
|
|
if (!bbox().contains(pt))
|
|
return false;
|
|
|
|
int idx = _doc->documentLayout()->hitTest(pt, Qt::FuzzyHit);
|
|
if (idx == -1)
|
|
return true;
|
|
if (_cursor) {
|
|
_cursor->setPosition(idx, mode);
|
|
if (_cursor->hasSelection())
|
|
QApplication::clipboard()->setText(_cursor->selectedText(), QClipboard::Selection);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mousePress
|
|
// set text cursor
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::mousePress(const QPointF& p, QMouseEvent* ev)
|
|
{
|
|
bool shift = ev->modifiers() & Qt::ShiftModifier;
|
|
if (!setCursor(p, shift ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor))
|
|
return false;
|
|
if (ev->button() == Qt::MidButton)
|
|
paste();
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// paste
|
|
//---------------------------------------------------------
|
|
|
|
void Text::paste()
|
|
{
|
|
QString txt = QApplication::clipboard()->text(QClipboard::Clipboard);
|
|
if (MScore::debugMode)
|
|
qDebug("Text::paste() <%s>\n", qPrintable(txt));
|
|
if (styled())
|
|
SimpleText::insertText(txt);
|
|
else
|
|
_cursor->insertText(txt);
|
|
layoutEdit();
|
|
bool lo = type() == INSTRUMENT_NAME;
|
|
score()->setLayoutAll(lo);
|
|
score()->setUpdateAll();
|
|
score()->end();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// dragAnchor
|
|
//---------------------------------------------------------
|
|
|
|
QLineF Text::dragAnchor() const
|
|
{
|
|
QPointF p1;
|
|
|
|
if (parent()->type() == MEASURE) {
|
|
Measure* m = static_cast<Measure*>(parent());
|
|
System* system = m->system();
|
|
qreal yp = system->staff(staffIdx())->y() + system->y() + system->page()->pos().x();
|
|
qreal xp = m->canvasPos().x();
|
|
p1 = QPointF(xp, yp);
|
|
}
|
|
else {
|
|
p1 = parent()->canvasPos(); // QPointF(parent()->canvasBoundingRect().topLeft());
|
|
if (parent()->type() == SEGMENT) {
|
|
Segment* s = static_cast<Segment*>(parent());
|
|
p1.ry() += s ? s->measure()->system()->staff(staffIdx())->y() : 0.0;
|
|
}
|
|
}
|
|
|
|
QPointF p2;
|
|
QRectF r(canvasBoundingRect());
|
|
|
|
if (align() & ALIGN_BOTTOM)
|
|
p2.ry() = r.bottom();
|
|
else if (align() & ALIGN_VCENTER)
|
|
p2.ry() = r.center().y();
|
|
else if (align() & ALIGN_BASELINE)
|
|
p2.ry() = canvasPos().y();
|
|
else // ALIGN_TOP
|
|
p2.ry() = r.top();
|
|
|
|
if (align() & ALIGN_RIGHT)
|
|
p2.rx() = r.right();
|
|
else if (align() & ALIGN_HCENTER)
|
|
p2.rx() = r.center().x();
|
|
else // ALIGN_LEFT
|
|
p2.rx() = r.left();
|
|
|
|
return QLineF(p1, p2);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// dragTo
|
|
//---------------------------------------------------------
|
|
|
|
void Text::dragTo(const QPointF& p)
|
|
{
|
|
setCursor(p, QTextCursor::KeepAnchor);
|
|
score()->setUpdateAll();
|
|
score()->end();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// sizeIsSpatiumDependent
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::sizeIsSpatiumDependent() const
|
|
{
|
|
return textStyle().sizeIsSpatiumDependent();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setSizeIsSpatiumDependent
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setSizeIsSpatiumDependent(int v)
|
|
{
|
|
_textStyle.setSizeIsSpatiumDependent(v);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// xoff
|
|
//---------------------------------------------------------
|
|
|
|
qreal Text::xoff() const
|
|
{
|
|
return textStyle().offset().x();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// offsetType
|
|
//---------------------------------------------------------
|
|
|
|
OffsetType Text::offsetType() const
|
|
{
|
|
return textStyle().offsetType();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// reloff
|
|
//---------------------------------------------------------
|
|
|
|
QPointF Text::reloff() const
|
|
{
|
|
return textStyle().reloff();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setAlign
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setAlign(Align val)
|
|
{
|
|
_textStyle.setAlign(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setXoff
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setXoff(qreal val)
|
|
{
|
|
_textStyle.setXoff(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setYoff
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setYoff(qreal val)
|
|
{
|
|
_textStyle.setYoff(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setOffsetType
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setOffsetType(OffsetType val)
|
|
{
|
|
_textStyle.setOffsetType(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setRxoff
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setRxoff(qreal v)
|
|
{
|
|
_textStyle.setRxoff(v);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setRyoff
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setRyoff(qreal v)
|
|
{
|
|
_textStyle.setRyoff(v);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setReloff
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setReloff(const QPointF& p)
|
|
{
|
|
_textStyle.setReloff(p);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// yoff
|
|
//---------------------------------------------------------
|
|
|
|
qreal Text::yoff() const
|
|
{
|
|
return textStyle().offset().y();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setFrameWidth
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setFrameWidth(Spatium val)
|
|
{
|
|
_textStyle.setFrameWidth(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setPaddingWidth
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setPaddingWidth(Spatium val)
|
|
{
|
|
_textStyle.setPaddingWidth(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setFrameColor
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setFrameColor(const QColor& val)
|
|
{
|
|
_textStyle.setFrameColor(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setFrameRound
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setFrameRound(int val)
|
|
{
|
|
_textStyle.setFrameRound(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCircle
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setCircle(bool val)
|
|
{
|
|
_textStyle.setCircle(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setItalic
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setItalic(bool val)
|
|
{
|
|
_textStyle.setItalic(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setBold
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setBold(bool val)
|
|
{
|
|
_textStyle.setBold(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setSize
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setSize(qreal v)
|
|
{
|
|
_textStyle.setSize(v);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setHasFrame
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setHasFrame(bool val)
|
|
{
|
|
_textStyle.setHasFrame(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// font
|
|
//---------------------------------------------------------
|
|
|
|
QFont Text::font() const
|
|
{
|
|
return _textStyle.font(spatium());
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// styleChanged
|
|
//---------------------------------------------------------
|
|
|
|
void Text::styleChanged()
|
|
{
|
|
if (styled()) {
|
|
if (_styleIndex != TEXT_STYLE_UNKNOWN)
|
|
setTextStyle(score()->textStyle(_styleIndex));
|
|
setText(text()); // destroy formatting
|
|
score()->setLayoutAll(true);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setScore
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setScore(Score* s)
|
|
{
|
|
if (s == score())
|
|
return;
|
|
Element::setScore(s);
|
|
// TODO: handle custom text styles
|
|
styleChanged();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setFont
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setFont(const QFont& f)
|
|
{
|
|
_textStyle.setFont(f);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// clear
|
|
//---------------------------------------------------------
|
|
|
|
void Text::clear()
|
|
{
|
|
if (styled())
|
|
SimpleText::clear();
|
|
else
|
|
_doc->clear();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setTextStyleType
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setTextStyleType(int st)
|
|
{
|
|
// if (st == _styleIndex)
|
|
// return;
|
|
_styleIndex = st;
|
|
if (st != TEXT_STYLE_UNKNOWN)
|
|
setTextStyle(score()->textStyle(st));
|
|
if (_doc && !_doc->isEmpty() && !editMode()) {
|
|
SimpleText::setText(_doc->toPlainText());
|
|
delete _doc;
|
|
_doc = 0;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setUnstyled
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setUnstyled()
|
|
{
|
|
if (!styled())
|
|
return;
|
|
_styleIndex = TEXT_STYLE_UNSTYLED;
|
|
createDoc();
|
|
if (!SimpleText::isEmpty())
|
|
setUnstyledText(SimpleText::text());
|
|
if (editMode())
|
|
_cursor = new QTextCursor(_doc);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// startCursorEdit
|
|
//---------------------------------------------------------
|
|
|
|
QTextCursor* Text::startCursorEdit()
|
|
{
|
|
if (styled()) {
|
|
qDebug("Text::startCursorEdit(): edit styled text\n");
|
|
return 0;
|
|
}
|
|
if (_cursor) {
|
|
qDebug("Text::startCursorEdit(): cursor already active\n");
|
|
return 0;
|
|
}
|
|
_cursor = new QTextCursor(_doc);
|
|
return _cursor;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// endEdit
|
|
//---------------------------------------------------------
|
|
|
|
void Text::endEdit()
|
|
{
|
|
setEditMode(false);
|
|
if (styled())
|
|
SimpleText::endEdit();
|
|
else {
|
|
endCursorEdit();
|
|
layoutEdit();
|
|
|
|
if (links()) {
|
|
foreach(Element* e, *links()) {
|
|
if (e == this)
|
|
continue;
|
|
e->undoChangeProperty(P_HTML_TEXT, getHtml());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// endCursorEdit
|
|
//---------------------------------------------------------
|
|
|
|
void Text::endCursorEdit()
|
|
{
|
|
delete _cursor;
|
|
_cursor = 0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// isEmpty
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::isEmpty() const
|
|
{
|
|
return styled() ? SimpleText::text().isEmpty() : _doc->isEmpty();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setModified
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setModified(bool v)
|
|
{
|
|
if (!styled())
|
|
_doc->setModified(v);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getFragment
|
|
//---------------------------------------------------------
|
|
|
|
QTextDocumentFragment Text::getFragment() const
|
|
{
|
|
if (styled())
|
|
return QTextDocumentFragment::fromPlainText(text());
|
|
else
|
|
return QTextDocumentFragment(_doc);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// undoSetText
|
|
//---------------------------------------------------------
|
|
|
|
void Text::undoSetText(const QString& s)
|
|
{
|
|
score()->undoChangeProperty(this, P_TEXT, s);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getProperty
|
|
//---------------------------------------------------------
|
|
|
|
QVariant Text::getProperty(P_ID propertyId) const
|
|
{
|
|
switch(propertyId) {
|
|
case P_TEXT_STYLE:
|
|
return QVariant(_styleIndex);
|
|
case P_HTML_TEXT:
|
|
return getHtml();
|
|
case P_TEXT:
|
|
return text();
|
|
|
|
default:
|
|
return Element::getProperty(propertyId);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setProperty
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::setProperty(P_ID propertyId, const QVariant& v)
|
|
{
|
|
score()->addRefresh(canvasBoundingRect());
|
|
bool rv = true;
|
|
switch(propertyId) {
|
|
case P_TEXT_STYLE:
|
|
_styleIndex = v.toInt();
|
|
setGenerated(false);
|
|
break;
|
|
case P_TEXT:
|
|
setText(v.toString());
|
|
break;
|
|
case P_HTML_TEXT:
|
|
setHtml(v.toString());
|
|
break;
|
|
default:
|
|
rv = Element::setProperty(propertyId, v);
|
|
break;
|
|
}
|
|
score()->setLayoutAll(true);
|
|
return rv;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// spellCheckUnderline
|
|
//---------------------------------------------------------
|
|
|
|
void Text::spellCheckUnderline(bool on)
|
|
{
|
|
printf("spellCheckUnderline %d\n", on);
|
|
if (styled()) {
|
|
}
|
|
else {
|
|
QTextCharFormat tf;
|
|
if (on) {
|
|
// underline with red squiggle
|
|
tf.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
|
|
tf.setUnderlineColor(Qt::red);
|
|
}
|
|
QTextCursor c(_doc);
|
|
c.select(QTextCursor::Document);
|
|
c.setCharFormat(tf);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// undo
|
|
//---------------------------------------------------------
|
|
|
|
void Text::undo()
|
|
{
|
|
if (styled())
|
|
;
|
|
else
|
|
_doc->undo();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// redo
|
|
//---------------------------------------------------------
|
|
|
|
void Text::redo()
|
|
{
|
|
if (styled())
|
|
;
|
|
else
|
|
_doc->undo();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// selection
|
|
//---------------------------------------------------------
|
|
|
|
QString Text::selection() const
|
|
{
|
|
QString s;
|
|
if (!styled()) {
|
|
if (_cursor && _cursor->hasSelection())
|
|
s = _cursor->selectedText();
|
|
}
|
|
else
|
|
return SimpleText::selectedText();
|
|
return s;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// curFont
|
|
//---------------------------------------------------------
|
|
|
|
QFont Text::curFont() const
|
|
{
|
|
if (styled())
|
|
return font();
|
|
else
|
|
return _cursor->charFormat().font();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// curItalic
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::curItalic() const
|
|
{
|
|
if (styled())
|
|
return false;
|
|
else
|
|
return _cursor->charFormat().fontItalic();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// curBold
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::curBold() const
|
|
{
|
|
if (styled())
|
|
return false;
|
|
else
|
|
return _cursor->charFormat().fontWeight() == QFont::Bold;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// curUnderline
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::curUnderline() const
|
|
{
|
|
if (styled())
|
|
return false;
|
|
else
|
|
return _cursor->charFormat().fontUnderline();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// curSubscript
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::curSubscript() const
|
|
{
|
|
if (styled())
|
|
return false;
|
|
else
|
|
return _cursor->charFormat().verticalAlignment() == QTextCharFormat::AlignSubScript;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// curSuperScript
|
|
//---------------------------------------------------------
|
|
|
|
bool Text::curSuperscript() const
|
|
{
|
|
if (styled())
|
|
return false;
|
|
else
|
|
return _cursor->charFormat().verticalAlignment() == QTextCharFormat::AlignSuperScript;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCurFontPointSize
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setCurFontPointSize(double value)
|
|
{
|
|
if (!styled()) {
|
|
QTextCharFormat format;
|
|
format.setFontPointSize(value);
|
|
_cursor->mergeCharFormat(format);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCurFontFamily
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setCurFontFamily(const QString& s)
|
|
{
|
|
if (!styled()) {
|
|
QTextCharFormat format;
|
|
format.setFontFamily(s);
|
|
_cursor->mergeCharFormat(format);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCurBold
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setCurBold(bool val)
|
|
{
|
|
if (!styled()) {
|
|
QTextCharFormat format;
|
|
format.setFontWeight(val ? QFont::Bold : QFont::Normal);
|
|
_cursor->mergeCharFormat(format);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCurUnderline
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setCurUnderline(bool val)
|
|
{
|
|
if (!styled()) {
|
|
QTextCharFormat format;
|
|
format.setFontUnderline(val);
|
|
_cursor->mergeCharFormat(format);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCurItalic
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setCurItalic(bool val)
|
|
{
|
|
if (!styled()) {
|
|
QTextCharFormat format;
|
|
format.setFontItalic(val);
|
|
_cursor->mergeCharFormat(format);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCurSuperscript
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setCurSuperscript(bool val)
|
|
{
|
|
if (!styled()) {
|
|
QTextCharFormat format;
|
|
format.setVerticalAlignment(val ? QTextCharFormat::AlignSuperScript : QTextCharFormat::AlignNormal);
|
|
_cursor->mergeCharFormat(format);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCurSubscript
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setCurSubscript(bool val)
|
|
{
|
|
if (!styled()) {
|
|
QTextCharFormat format;
|
|
format.setVerticalAlignment(val ? QTextCharFormat::AlignSubScript : QTextCharFormat::AlignNormal);
|
|
_cursor->mergeCharFormat(format);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setCurHalign
|
|
//---------------------------------------------------------
|
|
|
|
void Text::setCurHalign(int val)
|
|
{
|
|
if (styled())
|
|
return;
|
|
|
|
QTextBlockFormat bformat;
|
|
|
|
Qt::Alignment qa = bformat.alignment() & ~Qt::AlignHorizontal_Mask;
|
|
switch(val) {
|
|
case ALIGN_HCENTER:
|
|
qa |= Qt::AlignHCenter;
|
|
break;
|
|
case ALIGN_RIGHT:
|
|
qa |= Qt::AlignRight;
|
|
break;
|
|
case ALIGN_LEFT:
|
|
qa |= Qt::AlignLeft;
|
|
break;
|
|
}
|
|
|
|
bformat.setAlignment(qa);
|
|
_cursor->mergeBlockFormat(bformat);
|
|
setAlign((align() & ~ ALIGN_HMASK) | Align(val));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// indentLess
|
|
//---------------------------------------------------------
|
|
|
|
void Text::indentLess()
|
|
{
|
|
if (styled())
|
|
return;
|
|
|
|
QTextList* list = _cursor->currentList();
|
|
if (list == 0) {
|
|
QTextBlockFormat format = _cursor->blockFormat();
|
|
int indent = format.indent();
|
|
if (indent) {
|
|
indent--;
|
|
format.setIndent(indent);
|
|
_cursor->insertBlock(format);
|
|
}
|
|
return;
|
|
}
|
|
QTextCharFormat format = _cursor->blockCharFormat();
|
|
QTextListFormat listFormat = list->format();
|
|
QTextBlock block = _cursor->block();
|
|
if (block.next().isValid())
|
|
block = block.next();
|
|
else {
|
|
block = QTextBlock();
|
|
}
|
|
_cursor->insertBlock(block.blockFormat());
|
|
_cursor->setCharFormat(block.charFormat());
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// indentMore
|
|
//---------------------------------------------------------
|
|
|
|
void Text::indentMore()
|
|
{
|
|
QTextList* list = _cursor->currentList();
|
|
if (list == 0) {
|
|
QTextBlockFormat format = _cursor->blockFormat();
|
|
format.setIndent(format.indent() + 1);
|
|
_cursor->insertBlock(format);
|
|
return;
|
|
}
|
|
unorderedList();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// unorderedList
|
|
//---------------------------------------------------------
|
|
|
|
void Text::unorderedList()
|
|
{
|
|
if (styled())
|
|
return;
|
|
QTextCharFormat format = _cursor->charFormat();
|
|
QTextListFormat listFormat;
|
|
QTextList* list = _cursor->currentList();
|
|
if (list) {
|
|
listFormat = list->format();
|
|
int indent = listFormat.indent();
|
|
listFormat.setIndent(indent + 1);
|
|
}
|
|
listFormat.setStyle(QTextListFormat::ListDisc);
|
|
_cursor->insertList(listFormat);
|
|
_cursor->setCharFormat(format);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// orderedList
|
|
//---------------------------------------------------------
|
|
|
|
void Text::orderedList()
|
|
{
|
|
QTextCharFormat format = _cursor->charFormat();
|
|
QTextListFormat listFormat;
|
|
QTextList* list = _cursor->currentList();
|
|
if (list) {
|
|
listFormat = list->format();
|
|
int indent = listFormat.indent();
|
|
listFormat.setIndent(indent + 1);
|
|
}
|
|
listFormat.setStyle(QTextListFormat::ListDecimal);
|
|
_cursor->insertList(listFormat);
|
|
_cursor->setCharFormat(format);
|
|
}
|
|
|