fixes for text editing
This commit is contained in:
parent
b5b21b2d9e
commit
72e1501be5
5 changed files with 121 additions and 53 deletions
|
@ -68,7 +68,7 @@ bool CharFormat::operator==(const CharFormat& cf) const
|
|||
|
||||
void TextCursor::clearSelection()
|
||||
{
|
||||
_selectLine = _line;
|
||||
_selectLine = _row;
|
||||
_selectColumn = _column;
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ void TextCursor::init()
|
|||
|
||||
int TextCursor::columns() const
|
||||
{
|
||||
return _text->textBlock(_line).columns();
|
||||
return _text->textBlock(_row).columns();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -102,7 +102,7 @@ int TextCursor::columns() const
|
|||
|
||||
QChar TextCursor::currentCharacter() const
|
||||
{
|
||||
const TextBlock& t = _text->_layout[line()];
|
||||
const TextBlock& t = _text->_layout[_row];
|
||||
QString s = t.text(column(), column());
|
||||
if (s.isEmpty())
|
||||
return QChar();
|
||||
|
@ -115,7 +115,7 @@ QChar TextCursor::currentCharacter() const
|
|||
|
||||
void TextCursor::updateCursorFormat()
|
||||
{
|
||||
TextBlock* block = &_text->_layout[line()];
|
||||
TextBlock* block = &_text->_layout[_row];
|
||||
int col = hasSelection() ? selectColumn() : column();
|
||||
const CharFormat* format = block->formatAt(col);
|
||||
if (format)
|
||||
|
@ -921,7 +921,7 @@ QColor Text::textColor() const
|
|||
|
||||
void Text::insert(TextCursor* cursor, uint code)
|
||||
{
|
||||
if (cursor->line() >= _layout.size())
|
||||
if (cursor->row() >= rows())
|
||||
_layout.append(TextBlock());
|
||||
if (code == '\t')
|
||||
code = ' ';
|
||||
|
@ -931,7 +931,7 @@ void Text::insert(TextCursor* cursor, uint code)
|
|||
s = QString(QChar(QChar::highSurrogate(code))).append(QChar(QChar::lowSurrogate(code)));
|
||||
else
|
||||
s = QString(code);
|
||||
_layout[cursor->line()].insert(cursor, s);
|
||||
_layout[cursor->row()].insert(cursor, s);
|
||||
|
||||
cursor->setColumn(cursor->column() + 1);
|
||||
cursor->clearSelection();
|
||||
|
@ -988,10 +988,10 @@ void Text::createLayout()
|
|||
token.clear();
|
||||
}
|
||||
else if (c == '\n') {
|
||||
_layout[cursor.line()].setEol(true);
|
||||
cursor.setLine(cursor.line() + 1);
|
||||
_layout[cursor.row()].setEol(true);
|
||||
cursor.setRow(cursor.row() + 1);
|
||||
cursor.setColumn(0);
|
||||
if (_layout.size() <= cursor.line())
|
||||
if (rows() <= cursor.row())
|
||||
_layout.append(TextBlock());
|
||||
}
|
||||
else {
|
||||
|
@ -1147,7 +1147,7 @@ void Text::layout1()
|
|||
|
||||
QRectF bb;
|
||||
qreal y = 0;
|
||||
for (int i = 0; i < _layout.size(); ++i) {
|
||||
for (int i = 0; i < rows(); ++i) {
|
||||
TextBlock* t = &_layout[i];
|
||||
t->layout(this);
|
||||
const QRectF* r = &t->boundingRect();
|
||||
|
@ -1424,7 +1424,7 @@ void Text::startEdit(EditData& ed)
|
|||
ted->e = this;
|
||||
ted->cursor = new TextCursor(this);
|
||||
ted->cursor->setText(this);
|
||||
ted->cursor->setLine(0);
|
||||
ted->cursor->setRow(0);
|
||||
ted->cursor->setColumn(0);
|
||||
ted->cursor->clearSelection();
|
||||
|
||||
|
@ -1452,7 +1452,7 @@ void Text::endEdit(EditData&)
|
|||
|
||||
TextBlock& TextCursor::curLine() const
|
||||
{
|
||||
return _text->_layout[_line];
|
||||
return _text->_layout[_row];
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -1464,7 +1464,7 @@ void Text::editInsertText(TextCursor* cursor, const QString& s)
|
|||
textInvalid = true;
|
||||
|
||||
if (s.size() == 1 && (s[0] == QChar::CarriageReturn)) {
|
||||
int line = cursor->line();
|
||||
int line = cursor->row();
|
||||
_layout.insert(line + 1, cursor->curLine().split(cursor->column()));
|
||||
_layout[line].setEol(true);
|
||||
if (_layout.last() != _layout[line+1])
|
||||
|
@ -1492,7 +1492,7 @@ void Text::endHexState()
|
|||
int c2 = _cursor->column();
|
||||
int c1 = c2 - (hexState + 1);
|
||||
|
||||
TextBlock& t = _layout[_cursor->line()];
|
||||
TextBlock& t = _layout[_cursor->row()];
|
||||
QString ss = t.remove(c1, hexState + 1);
|
||||
bool ok;
|
||||
int code = ss.mid(1).toInt(&ok, 16);
|
||||
|
@ -1517,7 +1517,7 @@ void Text::selectAll(TextCursor* _cursor)
|
|||
{
|
||||
_cursor->setSelectLine(0);
|
||||
_cursor->setSelectColumn(0);
|
||||
_cursor->setLine(_layout.size() - 1);
|
||||
_cursor->setRow(rows() - 1);
|
||||
_cursor->setColumn(_cursor->curLine().columns());
|
||||
}
|
||||
|
||||
|
@ -1532,7 +1532,7 @@ bool TextCursor::movePosition(QTextCursor::MoveOperation op, QTextCursor::MoveMo
|
|||
case QTextCursor::Left:
|
||||
if (hasSelection() && mode == QTextCursor::MoveAnchor) {
|
||||
int r1 = selectLine();
|
||||
int r2 = line();
|
||||
int r2 = row();
|
||||
int c1 = selectColumn();
|
||||
int c2 = column();
|
||||
|
||||
|
@ -1545,13 +1545,13 @@ bool TextCursor::movePosition(QTextCursor::MoveOperation op, QTextCursor::MoveMo
|
|||
qSwap(c1, c2);
|
||||
}
|
||||
clearSelection();
|
||||
setLine(r1);
|
||||
setRow(r1);
|
||||
setColumn(c1);
|
||||
}
|
||||
else if (column() == 0) {
|
||||
if (line() == 0)
|
||||
if (row() == 0)
|
||||
return false;
|
||||
setLine(line()-1);
|
||||
--_row;
|
||||
setColumn(curLine().columns());
|
||||
}
|
||||
else
|
||||
|
@ -1561,7 +1561,7 @@ bool TextCursor::movePosition(QTextCursor::MoveOperation op, QTextCursor::MoveMo
|
|||
case QTextCursor::Right:
|
||||
if (hasSelection() && mode == QTextCursor::MoveAnchor) {
|
||||
int r1 = selectLine();
|
||||
int r2 = line();
|
||||
int r2 = _row;
|
||||
int c1 = selectColumn();
|
||||
int c2 = column();
|
||||
|
||||
|
@ -1574,13 +1574,13 @@ bool TextCursor::movePosition(QTextCursor::MoveOperation op, QTextCursor::MoveMo
|
|||
qSwap(c1, c2);
|
||||
}
|
||||
clearSelection();
|
||||
setLine(r2);
|
||||
setRow(r2);
|
||||
setColumn(c2);
|
||||
}
|
||||
else if (column() >= curLine().columns()) {
|
||||
if (line() >= _text->_layout.size()-1)
|
||||
if (_row >= _text->rows() - 1)
|
||||
return false;
|
||||
setLine(line()+1);
|
||||
setRow(row()+1);
|
||||
setColumn(0);
|
||||
}
|
||||
else
|
||||
|
@ -1588,28 +1588,28 @@ bool TextCursor::movePosition(QTextCursor::MoveOperation op, QTextCursor::MoveMo
|
|||
break;
|
||||
|
||||
case QTextCursor::Up:
|
||||
if (line() == 0)
|
||||
if (_row == 0)
|
||||
return false;
|
||||
setLine(line()-1);
|
||||
setRow(row()-1);
|
||||
if (column() > curLine().columns())
|
||||
setColumn(curLine().columns());
|
||||
break;
|
||||
|
||||
case QTextCursor::Down:
|
||||
if (line() >= _text->_layout.size()-1)
|
||||
if (_row >= _text->rows() - 1)
|
||||
return false;
|
||||
setLine(line()+1);
|
||||
++_row;
|
||||
if (column() > curLine().columns())
|
||||
setColumn(curLine().columns());
|
||||
break;
|
||||
|
||||
case QTextCursor::Start:
|
||||
setLine(0);
|
||||
setRow(0);
|
||||
setColumn(0);
|
||||
break;
|
||||
|
||||
case QTextCursor::End:
|
||||
setLine(_text->_layout.size() - 1);
|
||||
setRow(_text->rows() - 1);
|
||||
setColumn(curLine().columns());
|
||||
break;
|
||||
|
||||
|
@ -1666,11 +1666,11 @@ bool TextCursor::set(const QPointF& p, QTextCursor::MoveMode mode)
|
|||
QPointF pt = p - _text->canvasPos();
|
||||
if (!_text->bbox().contains(pt))
|
||||
return false;
|
||||
setLine(0);
|
||||
for (int row = 0; row < _text->_layout.size(); ++row) {
|
||||
_row = 0;
|
||||
for (int row = 0; row < _text->rows(); ++row) {
|
||||
const TextBlock& l = _text->_layout.at(row);
|
||||
if (l.y() > pt.y()) {
|
||||
setLine(row);
|
||||
setRow(row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1694,7 +1694,7 @@ QString TextCursor::selectedText() const
|
|||
{
|
||||
QString s;
|
||||
int r1 = selectLine();
|
||||
int r2 = line();
|
||||
int r2 = _row;
|
||||
int c1 = selectColumn();
|
||||
int c2 = column();
|
||||
|
||||
|
@ -1706,7 +1706,7 @@ QString TextCursor::selectedText() const
|
|||
if (c1 > c2)
|
||||
qSwap(c1, c2);
|
||||
}
|
||||
int rows = _text->_layout.size();
|
||||
int rows = _text->rows();
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
const TextBlock& t = _text->_layout.at(row);
|
||||
if (row >= r1 && row <= r2) {
|
||||
|
@ -1740,7 +1740,7 @@ bool Text::deleteSelectedText(EditData& ed)
|
|||
int r1 = _cursor->selectLine();
|
||||
int c1 = _cursor->selectColumn();
|
||||
#if 0
|
||||
int r2 = _cursor->line();
|
||||
int r2 = _cursor->row();
|
||||
int c2 = _cursor->column();
|
||||
|
||||
if (r1 > r2) {
|
||||
|
@ -1751,7 +1751,7 @@ bool Text::deleteSelectedText(EditData& ed)
|
|||
if (c1 > c2)
|
||||
qSwap(c1, c2);
|
||||
}
|
||||
int rows = _layout.size();
|
||||
int rows = Text::rows();
|
||||
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
TextBlock& t = _layout[row];
|
||||
|
@ -1774,7 +1774,7 @@ bool Text::deleteSelectedText(EditData& ed)
|
|||
l1.setEol(false);
|
||||
}
|
||||
#endif
|
||||
_cursor->setLine(r1);
|
||||
_cursor->setRow(r1);
|
||||
_cursor->setColumn(c1);
|
||||
_cursor->clearSelection();
|
||||
return true;
|
||||
|
@ -2201,7 +2201,7 @@ void TextCursor::changeSelectionFormat(FormatId id, QVariant val)
|
|||
if (!hasSelection())
|
||||
return;
|
||||
int r1 = selectLine();
|
||||
int r2 = line();
|
||||
int r2 = row();
|
||||
int c1 = selectColumn();
|
||||
int c2 = column();
|
||||
|
||||
|
@ -2213,7 +2213,7 @@ void TextCursor::changeSelectionFormat(FormatId id, QVariant val)
|
|||
if (c1 > c2)
|
||||
qSwap(c1, c2);
|
||||
}
|
||||
int rows = _text->_layout.size();
|
||||
int rows = _text->rows();
|
||||
QList<TextBlock> toDelete;
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
TextBlock& t = _text->_layout[row];
|
||||
|
@ -3034,7 +3034,7 @@ void Text::drawEditMode(QPainter* p, EditData& ed)
|
|||
p->setBrush(Qt::NoBrush);
|
||||
p->setPen(textColor());
|
||||
int r1 = _cursor->selectLine();
|
||||
int r2 = _cursor->line();
|
||||
int r2 = _cursor->row();
|
||||
int c1 = _cursor->selectColumn();
|
||||
int c2 = _cursor->column();
|
||||
|
||||
|
@ -3090,11 +3090,11 @@ bool TextCursor::deleteChar() const
|
|||
{
|
||||
TextBlock& l1 = curLine();
|
||||
if (_column == l1.columns()) {
|
||||
if (_line + 1 < _text->_layout.size()) {
|
||||
const TextBlock& l2 = _text->_layout[_line + 1];
|
||||
if (_row + 1 < _text->rows()) {
|
||||
const TextBlock& l2 = _text->_layout[_row + 1];
|
||||
for (const TextFragment& f : l2.fragments())
|
||||
l1.fragments().append(f);
|
||||
_text->_layout.removeAt(_line + 1);
|
||||
_text->_layout.removeAt(_row + 1);
|
||||
if (_text->_layout.last() == l1)
|
||||
l1.setEol(false);
|
||||
}
|
||||
|
@ -3171,9 +3171,13 @@ bool Text::edit(EditData& ed)
|
|||
|
||||
case Qt::Key_Backspace:
|
||||
if (!deleteSelectedText(ed)) {
|
||||
if (!_cursor->movePosition(QTextCursor::Left))
|
||||
return false;
|
||||
score()->undo(new RemoveText(_cursor, QString(_cursor->currentCharacter())));
|
||||
if (_cursor->column() == 0 && _cursor->row() != 0)
|
||||
score()->undo(new JoinText(_cursor), &ed);
|
||||
else {
|
||||
if (!_cursor->movePosition(QTextCursor::Left))
|
||||
return false;
|
||||
score()->undo(new RemoveText(_cursor, QString(_cursor->currentCharacter())));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ class CharFormat {
|
|||
class TextCursor {
|
||||
Text* _text;
|
||||
CharFormat _format;
|
||||
int _line { 0 };
|
||||
int _row { 0 };
|
||||
int _column { 0 };
|
||||
int _selectLine { 0 }; // start of selection
|
||||
int _selectColumn { 0 };
|
||||
|
@ -81,18 +81,18 @@ class TextCursor {
|
|||
TextCursor(Text* t) : _text(t) {}
|
||||
|
||||
Text* text() const { return _text; }
|
||||
bool hasSelection() const { return (_selectLine != _line) || (_selectColumn != _column); }
|
||||
bool hasSelection() const { return (_selectLine != _row) || (_selectColumn != _column); }
|
||||
void clearSelection();
|
||||
|
||||
CharFormat* format() { return &_format; }
|
||||
const CharFormat* format() const { return &_format; }
|
||||
void setFormat(const CharFormat& f) { _format = f; }
|
||||
|
||||
int line() const { return _line; }
|
||||
int row() const { return _row; }
|
||||
int column() const { return _column; }
|
||||
int selectLine() const { return _selectLine; }
|
||||
int selectColumn() const { return _selectColumn; }
|
||||
void setLine(int val) { _line = val; }
|
||||
void setRow(int val) { _row = val; }
|
||||
void setColumn(int val) { _column = val; }
|
||||
void setSelectLine(int val) { _selectLine = val; }
|
||||
void setSelectColumn(int val) { _selectColumn = val; }
|
||||
|
@ -359,6 +359,7 @@ class Text : public Element {
|
|||
const TextBlock& textBlock(int line) const { return _layout[line]; }
|
||||
TextBlock& textBlock(int line) { return _layout[line]; }
|
||||
QList<TextBlock>& textBlockList() { return _layout; }
|
||||
int rows() const { return _layout.size(); }
|
||||
|
||||
void setTextInvalid() { textInvalid = true; };
|
||||
|
||||
|
|
|
@ -2187,7 +2187,7 @@ void SplitText::redo(EditData* ed)
|
|||
{
|
||||
TextCursor tc = c;
|
||||
Text* t = tc.text();
|
||||
int line = tc.line();
|
||||
int line = tc.row();
|
||||
|
||||
CharFormat* charFmt = tc.format(); // take current format
|
||||
t->textBlockList().insert(line + 1, tc.curLine().split(tc.column()));
|
||||
|
@ -2198,11 +2198,58 @@ void SplitText::redo(EditData* ed)
|
|||
|
||||
c.text()->triggerLayout();
|
||||
if (ed) {
|
||||
tc.setLine(line+1);
|
||||
tc.setRow(line+1);
|
||||
tc.setColumn(0);
|
||||
tc.setFormat(*charFmt); // restore orig. format at new line
|
||||
*c.text()->cursor(*ed) = tc;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// JoinText
|
||||
//---------------------------------------------------------
|
||||
|
||||
void JoinText::redo(EditData* ed)
|
||||
{
|
||||
Text* t = c.text();
|
||||
int line = c.row();
|
||||
t->setTextInvalid();
|
||||
t->triggerLayout();
|
||||
|
||||
CharFormat* charFmt = c.format(); // take current format
|
||||
int col = t->textBlock(line-1).columns();
|
||||
int eol = t->textBlock(line).eol();
|
||||
t->textBlock(line-1).fragments().append(t->textBlock(line).fragments());
|
||||
int lines = t->rows();
|
||||
if (line < lines)
|
||||
t->textBlock(line).setEol(eol);
|
||||
t->textBlockList().removeAt(line);
|
||||
c.setRow(line-1);
|
||||
c.setColumn(col);
|
||||
c.setFormat(*charFmt); // restore orig. format at new line
|
||||
c.clearSelection();
|
||||
if (ed)
|
||||
*t->cursor(*ed) = c;
|
||||
}
|
||||
|
||||
void JoinText::undo(EditData* ed)
|
||||
{
|
||||
Text* t = c.text();
|
||||
int line = c.row();
|
||||
t->setTextInvalid();
|
||||
t->triggerLayout();
|
||||
|
||||
CharFormat* charFmt = c.format(); // take current format
|
||||
t->textBlockList().insert(line + 1, c.curLine().split(c.column()));
|
||||
c.curLine().setEol(true);
|
||||
|
||||
c.setRow(line+1);
|
||||
c.setColumn(0);
|
||||
c.setFormat(*charFmt); // restore orig. format at new line
|
||||
c.clearSelection();
|
||||
|
||||
if (ed)
|
||||
*t->cursor(*ed) = c;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1307,6 +1307,21 @@ class SplitText : public UndoCommand {
|
|||
UNDO_NAME("SplitText");
|
||||
};
|
||||
|
||||
//---------------------------------------------------------
|
||||
// JoinText
|
||||
//---------------------------------------------------------
|
||||
|
||||
class JoinText : public UndoCommand {
|
||||
TextCursor c;
|
||||
|
||||
virtual void undo(EditData*) override;
|
||||
virtual void redo(EditData*) override;
|
||||
|
||||
public:
|
||||
JoinText(const TextCursor* tc) : c(*tc) {}
|
||||
UNDO_NAME("JoinText");
|
||||
};
|
||||
|
||||
|
||||
} // namespace Ms
|
||||
#endif
|
||||
|
|
|
@ -3677,7 +3677,8 @@ void MuseScore::undoRedo(bool undo)
|
|||
{
|
||||
Q_ASSERT(cv);
|
||||
Q_ASSERT(cs);
|
||||
if (_sstate & (STATE_EDIT | STATE_TEXT_EDIT | STATE_HARMONY_FIGBASS_EDIT | STATE_LYRICS_EDIT))
|
||||
// if (_sstate & (STATE_EDIT | STATE_TEXT_EDIT | STATE_HARMONY_FIGBASS_EDIT | STATE_LYRICS_EDIT))
|
||||
if (_sstate & (STATE_EDIT | STATE_HARMONY_FIGBASS_EDIT | STATE_LYRICS_EDIT))
|
||||
cv->changeState(ViewState::NORMAL);
|
||||
cv->startUndoRedo(undo);
|
||||
updateInputState(cs);
|
||||
|
|
Loading…
Reference in a new issue