From 27ad6701b4d359ec2a375208a4989762808a78b4 Mon Sep 17 00:00:00 2001 From: "G.K.MacGregor" Date: Sun, 14 Feb 2021 17:35:11 +0000 Subject: [PATCH] Implement insert and overwrite editing modes --- levelonecommands.cpp | 108 ++++++++++++++++++++++++++++--------------- levelonecommands.h | 12 ++--- mainwidget.cpp | 19 ++++---- mainwidget.h | 3 +- mainwindow.cpp | 18 ++++++++ mainwindow.h | 4 ++ 6 files changed, 111 insertions(+), 53 deletions(-) diff --git a/levelonecommands.cpp b/levelonecommands.cpp index 331ab3c..c1e157e 100644 --- a/levelonecommands.cpp +++ b/levelonecommands.cpp @@ -21,26 +21,36 @@ #include "document.h" -OverwriteCharacterCommand::OverwriteCharacterCommand(TeletextDocument *teletextDocument, unsigned char newCharacter, QUndoCommand *parent) : QUndoCommand(parent) +TypeCharacterCommand::TypeCharacterCommand(TeletextDocument *teletextDocument, unsigned char newCharacter, bool insertMode, QUndoCommand *parent) : QUndoCommand(parent) { m_teletextDocument = teletextDocument; m_subPageIndex = teletextDocument->currentSubPageIndex(); m_row = teletextDocument->cursorRow(); m_columnStart = m_columnEnd = teletextDocument->cursorColumn(); + m_newCharacter = newCharacter; + m_insertMode = insertMode; + for (int c=0; c<40; c++) m_oldRowContents[c] = m_newRowContents[c] = m_teletextDocument->currentSubPage()->character(m_row, c); - m_newCharacter = newCharacter; - setText(QObject::tr("overwrite char")); + if (m_insertMode) + setText(QObject::tr("insert character")); + else + setText(QObject::tr("overwrite character")); m_firstDo = true; } -void OverwriteCharacterCommand::redo() +void TypeCharacterCommand::redo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); // Only apply the typed character on the first do, m_newRowContents will remember it if we redo if (m_firstDo) { + if (m_insertMode) { + // Insert - Move characters rightwards + for (int c=39; c>m_columnEnd; c--) + m_newRowContents[c] = m_newRowContents[c-1]; + } m_newRowContents[m_columnEnd] = m_newCharacter; m_firstDo = false; } @@ -52,7 +62,7 @@ void OverwriteCharacterCommand::redo() emit m_teletextDocument->contentsChange(m_row); } -void OverwriteCharacterCommand::undo() +void TypeCharacterCommand::undo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); @@ -63,9 +73,9 @@ void OverwriteCharacterCommand::undo() emit m_teletextDocument->contentsChange(m_row); } -bool OverwriteCharacterCommand::mergeWith(const QUndoCommand *command) +bool TypeCharacterCommand::mergeWith(const QUndoCommand *command) { - const OverwriteCharacterCommand *newerCommand = static_cast(command); + const TypeCharacterCommand *newerCommand = static_cast(command); // Has to be the next typed column on the same row if (m_subPageIndex != newerCommand->m_subPageIndex || m_row != newerCommand->m_row || m_columnEnd != newerCommand->m_columnEnd-1) @@ -90,14 +100,17 @@ ToggleMosaicBitCommand::ToggleMosaicBitCommand(TeletextDocument *teletextDocumen m_newCharacter = bitToToggle; else m_newCharacter = m_oldCharacter ^ bitToToggle; + + setText(QObject::tr("mosaic")); + } void ToggleMosaicBitCommand::redo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); m_teletextDocument->currentSubPage()->setCharacter(m_row, m_column, m_newCharacter); + m_teletextDocument->moveCursor(m_row, m_column); - setText(QObject::tr("mosaic")); emit m_teletextDocument->contentsChange(m_row); } @@ -105,8 +118,8 @@ void ToggleMosaicBitCommand::undo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); m_teletextDocument->currentSubPage()->setCharacter(m_row, m_column, m_oldCharacter); + m_teletextDocument->moveCursor(m_row, m_column); - setText(QObject::tr("mosaic")); emit m_teletextDocument->contentsChange(m_row); } @@ -121,7 +134,7 @@ bool ToggleMosaicBitCommand::mergeWith(const QUndoCommand *command) } -BackspaceCommand::BackspaceCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : QUndoCommand(parent) +BackspaceKeyCommand::BackspaceKeyCommand(TeletextDocument *teletextDocument, bool insertMode, QUndoCommand *parent) : QUndoCommand(parent) { m_teletextDocument = teletextDocument; m_subPageIndex = teletextDocument->currentSubPageIndex(); @@ -133,6 +146,8 @@ BackspaceCommand::BackspaceCommand(TeletextDocument *teletextDocument, QUndoComm m_row = 24; } m_columnEnd = m_columnStart; + m_insertMode = insertMode; + for (int c=0; c<40; c++) m_oldRowContents[c] = m_newRowContents[c] = m_teletextDocument->currentSubPage()->character(m_row, c); @@ -140,14 +155,22 @@ BackspaceCommand::BackspaceCommand(TeletextDocument *teletextDocument, QUndoComm m_firstDo = true; } -void BackspaceCommand::redo() +void BackspaceKeyCommand::redo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); if (m_firstDo) { - m_newRowContents[m_columnEnd] = 0x20; + if (m_insertMode) { + // Insert - Move characters leftwards and put a space on the far right + for (int c=m_columnEnd; c<39; c++) + m_newRowContents[c] = m_newRowContents[c+1]; + m_newRowContents[39] = 0x20; + } else + // Replace - Overwrite backspaced character with a space + m_newRowContents[m_columnEnd] = 0x20; m_firstDo = false; } + for (int c=0; c<40; c++) m_teletextDocument->currentSubPage()->setCharacter(m_row, c, m_newRowContents[c]); @@ -155,7 +178,7 @@ void BackspaceCommand::redo() emit m_teletextDocument->contentsChange(m_row); } -void BackspaceCommand::undo() +void BackspaceKeyCommand::undo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); @@ -167,9 +190,9 @@ void BackspaceCommand::undo() emit m_teletextDocument->contentsChange(m_row); } -bool BackspaceCommand::mergeWith(const QUndoCommand *command) +bool BackspaceKeyCommand::mergeWith(const QUndoCommand *command) { - const BackspaceCommand *newerCommand = static_cast(command); + const BackspaceKeyCommand *newerCommand = static_cast(command); // Has to be the next backspaced column on the same row if (m_subPageIndex != newerCommand->m_subPageIndex || m_row != newerCommand->m_row || m_columnEnd != newerCommand->m_columnEnd+1) @@ -191,6 +214,7 @@ DeleteKeyCommand::DeleteKeyCommand(TeletextDocument *teletextDocument, QUndoComm m_subPageIndex = teletextDocument->currentSubPageIndex(); m_row = teletextDocument->cursorRow(); m_column = teletextDocument->cursorColumn(); + for (int c=0; c<40; c++) m_oldRowContents[c] = m_newRowContents[c] = m_teletextDocument->currentSubPage()->character(m_row, c); @@ -201,6 +225,7 @@ void DeleteKeyCommand::redo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); + // Move characters leftwards and put a space on the far right for (int c=m_column; c<39; c++) m_newRowContents[c] = m_newRowContents[c+1]; m_newRowContents[39] = 0x20; @@ -243,6 +268,11 @@ InsertRowCommand::InsertRowCommand(TeletextDocument *teletextDocument, bool copy m_subPageIndex = teletextDocument->currentSubPageIndex(); m_row = teletextDocument->cursorRow(); m_copyRow = copyRow; + + if (m_copyRow) + setText(QObject::tr("insert copy row")); + else + setText(QObject::tr("insert blank row")); } void InsertRowCommand::redo() @@ -252,18 +282,15 @@ void InsertRowCommand::redo() // Store copy of the bottom row we're about to push out, for undo for (int c=0; c<40; c++) m_deletedBottomRow[c] = m_teletextDocument->currentSubPage()->character(23, c); - // Shuffle lines below the inserting row downwards without affecting the FastText row + // Move lines below the inserting row downwards without affecting the FastText row for (int r=22; r>=m_row; r--) for (int c=0; c<40; c++) m_teletextDocument->currentSubPage()->setCharacter(r+1, c, m_teletextDocument->currentSubPage()->character(r, c)); - if (m_copyRow) - setText(QObject::tr("insert copy row")); - else { - // The above shuffle leaves a duplicate of the current row, so blank it if requested + if (!m_copyRow) + // The above movement leaves a duplicate of the current row, so blank it if requested for (int c=0; c<40; c++) m_teletextDocument->currentSubPage()->setCharacter(m_row, c, ' '); - setText(QObject::tr("insert blank row")); - } + emit m_teletextDocument->refreshNeeded(); } @@ -271,17 +298,14 @@ void InsertRowCommand::undo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); m_teletextDocument->moveCursor(m_row, -1); - // Shuffle lines below the deleting row upwards without affecting the FastText row + // Move lines below the deleting row upwards without affecting the FastText row for (int r=m_row; r<23; r++) for (int c=0; c<40; c++) m_teletextDocument->currentSubPage()->setCharacter(r, c, m_teletextDocument->currentSubPage()->character(r+1, c)); // Now repair the bottom row we pushed out for (int c=0; c<40; c++) m_teletextDocument->currentSubPage()->setCharacter(23, c, m_deletedBottomRow[c]); - if (m_copyRow) - setText(QObject::tr("insert copy row")); - else - setText(QObject::tr("insert blank row")); + emit m_teletextDocument->refreshNeeded(); } @@ -291,6 +315,8 @@ DeleteRowCommand::DeleteRowCommand(TeletextDocument *teletextDocument, QUndoComm m_teletextDocument = teletextDocument; m_subPageIndex = teletextDocument->currentSubPageIndex(); m_row = teletextDocument->cursorRow(); + + setText(QObject::tr("delete row")); } void DeleteRowCommand::redo() @@ -300,7 +326,7 @@ void DeleteRowCommand::redo() // Store copy of the row we're going to delete, for undo for (int c=0; c<40; c++) m_deletedRow[c] = m_teletextDocument->currentSubPage()->character(m_row, c); - // Shuffle lines below the deleting row upwards without affecting the FastText row + // Move lines below the deleting row upwards without affecting the FastText row for (int r=m_row; r<23; r++) for (int c=0; c<40; c++) m_teletextDocument->currentSubPage()->setCharacter(r, c, m_teletextDocument->currentSubPage()->character(r+1, c)); @@ -308,7 +334,7 @@ void DeleteRowCommand::redo() int blankingRow = (m_row < 24) ? 23 : 24; for (int c=0; c<40; c++) m_teletextDocument->currentSubPage()->setCharacter(blankingRow, c, ' '); - setText(QObject::tr("delete row")); + emit m_teletextDocument->refreshNeeded(); } @@ -316,14 +342,14 @@ void DeleteRowCommand::undo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); m_teletextDocument->moveCursor(m_row, -1); - // Shuffle lines below the inserting row downwards without affecting the FastText row + // Move lines below the inserting row downwards without affecting the FastText row for (int r=22; r>=m_row; r--) for (int c=0; c<40; c++) m_teletextDocument->currentSubPage()->setCharacter(r+1, c, m_teletextDocument->currentSubPage()->character(r, c)); // Now repair the row we deleted for (int c=0; c<40; c++) m_teletextDocument->currentSubPage()->setCharacter(m_row, c, m_deletedRow[c]); - setText(QObject::tr("delete row")); + emit m_teletextDocument->refreshNeeded(); } @@ -333,21 +359,24 @@ InsertSubPageCommand::InsertSubPageCommand(TeletextDocument *teletextDocument, b m_teletextDocument = teletextDocument; m_newSubPageIndex = teletextDocument->currentSubPageIndex()+afterCurrentSubPage; m_copySubPage = copySubPage; + + setText(QObject::tr("insert subpage")); + } void InsertSubPageCommand::redo() { m_teletextDocument->insertSubPage(m_newSubPageIndex, m_copySubPage); + m_teletextDocument->selectSubPageIndex(m_newSubPageIndex, true); - setText(QObject::tr("insert subpage")); } void InsertSubPageCommand::undo() { m_teletextDocument->deleteSubPage(m_newSubPageIndex); //TODO should we always wrench to "subpage viewed when we inserted"? Or just if subpage viewed is being deleted? + m_teletextDocument->selectSubPageIndex(qMin(m_newSubPageIndex, m_teletextDocument->numberOfSubPages()-1), true); - setText(QObject::tr("insert subpage")); } @@ -378,14 +407,17 @@ SetColourCommand::SetColourCommand(TeletextDocument *teletextDocument, int colou m_colourIndex = colourIndex; m_oldColour = teletextDocument->currentSubPage()->CLUT(colourIndex); m_newColour = newColour; + + setText(QObject::tr("colour change")); + } void SetColourCommand::redo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); m_teletextDocument->currentSubPage()->setCLUT(m_colourIndex, m_newColour); + emit m_teletextDocument->colourChanged(m_colourIndex); - setText(QObject::tr("colour change")); emit m_teletextDocument->refreshNeeded(); } @@ -393,8 +425,8 @@ void SetColourCommand::undo() { m_teletextDocument->selectSubPageIndex(m_subPageIndex); m_teletextDocument->currentSubPage()->setCLUT(m_colourIndex, m_oldColour); + emit m_teletextDocument->colourChanged(m_colourIndex); - setText(QObject::tr("colour change")); emit m_teletextDocument->refreshNeeded(); } @@ -406,6 +438,8 @@ ResetCLUTCommand::ResetCLUTCommand(TeletextDocument *teletextDocument, int colou m_colourTable = colourTable; for (int i=m_colourTable*8; icurrentSubPage()->CLUT(i); + + setText(QObject::tr("CLUT %1 reset").arg(m_colourTable)); } void ResetCLUTCommand::redo() @@ -415,7 +449,7 @@ void ResetCLUTCommand::redo() m_teletextDocument->currentSubPage()->setCLUT(i, m_teletextDocument->currentSubPage()->CLUT(i, 0)); emit m_teletextDocument->colourChanged(i); } - setText(QObject::tr("CLUT %1 reset").arg(m_colourTable)); + emit m_teletextDocument->refreshNeeded(); } @@ -426,6 +460,6 @@ void ResetCLUTCommand::undo() m_teletextDocument->currentSubPage()->setCLUT(i, m_oldColourEntry[i&7]); emit m_teletextDocument->colourChanged(i); } - setText(QObject::tr("CLUT %1 reset").arg(m_colourTable)); + emit m_teletextDocument->refreshNeeded(); } diff --git a/levelonecommands.h b/levelonecommands.h index 29a6196..a82dce3 100644 --- a/levelonecommands.h +++ b/levelonecommands.h @@ -24,12 +24,12 @@ #include "document.h" -class OverwriteCharacterCommand : public QUndoCommand +class TypeCharacterCommand : public QUndoCommand { public: enum { Id = 101 }; - OverwriteCharacterCommand(TeletextDocument *, unsigned char, QUndoCommand *parent = 0); + TypeCharacterCommand(TeletextDocument *, unsigned char, bool, QUndoCommand *parent = 0); void redo() override; void undo() override; @@ -40,7 +40,7 @@ private: TeletextDocument *m_teletextDocument; unsigned char m_newCharacter, m_oldRowContents[40], m_newRowContents[40]; int m_subPageIndex, m_row, m_columnStart, m_columnEnd; - bool m_firstDo; + bool m_firstDo, m_insertMode; }; class ToggleMosaicBitCommand : public QUndoCommand @@ -61,12 +61,12 @@ private: int m_subPageIndex, m_row, m_column; }; -class BackspaceCommand : public QUndoCommand +class BackspaceKeyCommand : public QUndoCommand { public: enum { Id = 103 }; - BackspaceCommand(TeletextDocument *, QUndoCommand *parent = 0); + BackspaceKeyCommand(TeletextDocument *, bool insertMode, QUndoCommand *parent = 0); void redo() override; void undo() override; @@ -77,7 +77,7 @@ private: TeletextDocument *m_teletextDocument; unsigned char m_oldRowContents[40], m_newRowContents[40]; int m_subPageIndex, m_row, m_columnStart, m_columnEnd; - bool m_firstDo; + bool m_firstDo, m_insertMode; }; class DeleteKeyCommand : public QUndoCommand diff --git a/mainwidget.cpp b/mainwidget.cpp index 9d09dab..ededacc 100644 --- a/mainwidget.cpp +++ b/mainwidget.cpp @@ -144,6 +144,11 @@ void TeletextWidget::timerEvent(QTimerEvent *event) QWidget::timerEvent(event); } +void TeletextWidget::setInsertMode(bool insertMode) +{ + m_insertMode = insertMode; +} + void TeletextWidget::toggleReveal(bool revealOn) { m_pageRender.setReveal(revealOn); @@ -330,7 +335,10 @@ void TeletextWidget::keyPressEvent(QKeyEvent *event) } switch (event->key()) { case Qt::Key_Backspace: - backspaceEvent(); + m_teletextDocument->undoStack()->push(new BackspaceKeyCommand(m_teletextDocument, m_insertMode)); + break; + case Qt::Key_Tab: + m_teletextDocument->undoStack()->push(new TypeCharacterCommand(m_teletextDocument, 0x20, true)); break; case Qt::Key_Delete: m_teletextDocument->undoStack()->push(new DeleteKeyCommand(m_teletextDocument)); @@ -383,8 +391,7 @@ void TeletextWidget::keyPressEvent(QKeyEvent *event) void TeletextWidget::setCharacter(unsigned char newCharacter) { - QUndoCommand *overwriteCharacterCommand = new OverwriteCharacterCommand(m_teletextDocument, newCharacter); - m_teletextDocument->undoStack()->push(overwriteCharacterCommand); + m_teletextDocument->undoStack()->push(new TypeCharacterCommand(m_teletextDocument, newCharacter, m_insertMode)); } void TeletextWidget::toggleCharacterBit(unsigned char bitToToggle) @@ -393,12 +400,6 @@ void TeletextWidget::toggleCharacterBit(unsigned char bitToToggle) m_teletextDocument->undoStack()->push(toggleMosaicBitCommand); } -void TeletextWidget::backspaceEvent() -{ - QUndoCommand *backspaceCommand = new BackspaceCommand(m_teletextDocument); - m_teletextDocument->undoStack()->push(backspaceCommand); -} - QPair TeletextWidget::mouseToRowAndColumn(const QPoint &mousePosition) { int row = mousePosition.y() / 10; diff --git a/mainwidget.h b/mainwidget.h index 99e248e..52f3c6a 100644 --- a/mainwidget.h +++ b/mainwidget.h @@ -43,7 +43,8 @@ public: ~TeletextWidget(); void setCharacter(unsigned char); void toggleCharacterBit(unsigned char); - void backspaceEvent(); + bool insertMode() const { return m_insertMode; }; + void setInsertMode(bool); QSize sizeHint() { return QSize(480+(pageRender()->leftSidePanelColumns()+pageRender()->rightSidePanelColumns())*12, 250); } diff --git a/mainwindow.cpp b/mainwindow.cpp index f474086..24ea519 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -180,6 +181,8 @@ void MainWindow::init() QShortcut *blockShortCut = new QShortcut(QKeySequence(Qt::Key_Escape, Qt::Key_J), m_textView); connect(blockShortCut, &QShortcut::activated, [=]() { m_textWidget->setCharacter(0x7f); }); + QShortcut *insertModeShortCut = new QShortcut(QKeySequence(Qt::Key_Insert), this); + connect(insertModeShortCut, &QShortcut::activated, this, &MainWindow::toggleInsertMode); setUnifiedTitleAndToolBarOnMac(true); @@ -622,6 +625,15 @@ void MainWindow::zoomReset() setSceneDimensions(); } +void MainWindow::toggleInsertMode() +{ + m_textWidget->setInsertMode(!m_textWidget->insertMode()); + if (m_textWidget->insertMode()) + m_insertModePushButton->setText("INSERT"); + else + m_insertModePushButton->setText("OVERWRITE"); +} + void MainWindow::createStatusBar() { QLabel *subPageLabel = new QLabel("Subpage"); @@ -649,6 +661,12 @@ void MainWindow::createStatusBar() m_cursorPositionLabel = new QLabel("Row 1 Column 1"); statusBar()->insertWidget(4, m_cursorPositionLabel); + m_insertModePushButton = new QPushButton("OVERWRITE"); + m_insertModePushButton->setFlat(true); + m_insertModePushButton->setFocusProxy(m_textWidget); + statusBar()->addPermanentWidget(m_insertModePushButton); + connect(m_insertModePushButton, &QPushButton::clicked, this, &MainWindow::toggleInsertMode); + statusBar()->addPermanentWidget(new QLabel("Level")); m_levelRadioButton[0] = new QRadioButton("1"); diff --git a/mainwindow.h b/mainwindow.h index e05bf04..f6c3113 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "mainwidget.h" @@ -77,6 +78,8 @@ private slots: void zoomOut(); void zoomReset(); + void toggleInsertMode(); + private: enum { m_MaxRecentFiles = 10 }; @@ -115,6 +118,7 @@ private: QLabel *m_subPageLabel, *m_cursorPositionLabel; QToolButton *m_previousSubPageButton, *m_nextSubPageButton; + QPushButton *m_insertModePushButton; QRadioButton *m_levelRadioButton[4]; QString m_curFile;