Allow header row editing

This commit is contained in:
Gavin MacGregor
2025-03-18 14:48:03 +00:00
parent 1d462f4355
commit 0493f0e270
8 changed files with 89 additions and 15 deletions

View File

@@ -68,6 +68,7 @@ TeletextDocument::TeletextDocument()
m_undoStack = new QUndoStack(this);
m_cursorRow = 1;
m_cursorColumn = 0;
m_rowZeroAllowed = false;
m_selectionCornerRow = m_selectionCornerColumn = -1;
m_selectionSubPage = nullptr;
@@ -252,7 +253,7 @@ void TeletextDocument::cursorUp(bool shiftKey)
if (shiftKey && !selectionActive())
setSelectionCorner(m_cursorRow, m_cursorColumn);
if (--m_cursorRow == 0)
if (--m_cursorRow == 0 - (int)m_rowZeroAllowed)
m_cursorRow = 24;
if (shiftKey)
@@ -269,7 +270,7 @@ void TeletextDocument::cursorDown(bool shiftKey)
setSelectionCorner(m_cursorRow, m_cursorColumn);
if (++m_cursorRow == 25)
m_cursorRow = 1;
m_cursorRow = (int)!m_rowZeroAllowed;
if (shiftKey)
emit selectionMoved();
@@ -333,6 +334,13 @@ void TeletextDocument::moveCursor(int cursorRow, int cursorColumn, bool selectio
emit cursorMoved();
}
void TeletextDocument::setRowZeroAllowed(bool allowed)
{
m_rowZeroAllowed = allowed;
if (m_cursorRow == 0 && !allowed)
cursorDown();
}
void TeletextDocument::setSelectionCorner(int row, int column)
{
if (m_selectionCornerRow != row || m_selectionCornerColumn != column) {

View File

@@ -89,6 +89,8 @@ public:
void cursorLeft(bool shiftKey=false);
void cursorRight(bool shiftKey=false);
void moveCursor(int cursorRow, int cursorColumn, bool selectionInProgress=false);
bool rowZeroAllowed() const { return m_rowZeroAllowed; };
void setRowZeroAllowed(bool allowed);
int selectionTopRow() const { return m_selectionCornerRow == -1 ? m_cursorRow : qMin(m_selectionCornerRow, m_cursorRow); }
int selectionBottomRow() const { return qMax(m_selectionCornerRow, m_cursorRow); }
int selectionLeftColumn() const { return m_selectionCornerColumn == -1 ? m_cursorColumn : qMin(m_selectionCornerColumn, m_cursorColumn); }
@@ -123,6 +125,7 @@ private:
std::vector<LevelOnePage *> m_recycleSubPages;
QUndoStack *m_undoStack;
int m_cursorRow, m_cursorColumn, m_selectionCornerRow, m_selectionCornerColumn;
bool m_rowZeroAllowed;
LevelOnePage *m_selectionSubPage;
ClutModel *m_clutModel;
};

View File

@@ -274,6 +274,22 @@ bool LoadT42Format::load(QFile *inFile, TeletextDocument *document)
document->subPage(0)->setControlBit(PageBase::C13NOS, m_inLine[9] & 0x04);
document->subPage(0)->setControlBit(PageBase::C14NOS, m_inLine[9] & 0x02);
// See if there's text in the header row
bool headerText = false;
for (int i=10; i<42; i++)
if (m_inLine[i] != 0x20) {
// TODO - obey odd parity?
m_inLine[i] &= 0x7f;
headerText = true;
}
if (headerText) {
// Clear the page address and control bits to spaces before putting the row in
for (int i=0; i<10; i++)
m_inLine[i] = 0x20;
document->subPage(0)->setPacket(0, QByteArray((const char *)&m_inLine[2], 40));
}
continue;
}
}

View File

@@ -543,8 +543,10 @@ QPair<int, int> TeletextWidget::mouseToRowAndColumn(const QPoint &mousePosition)
{
int row = mousePosition.y() / 10;
int column = mousePosition.x() / 12 - m_pageDecode.leftSidePanelColumns();
if (row < 1)
row = 1;
const int topRow = (int)!m_teletextDocument->rowZeroAllowed();
if (row < topRow)
row = topRow;
if (row > 24)
row = 24;
if (column < 0)
@@ -647,6 +649,9 @@ LevelOneScene::LevelOneScene(QWidget *levelOneWidget, QObject *parent) : QGraphi
m_mainGridItemGroup = new QGraphicsItemGroup;
m_mainGridItemGroup->setVisible(false);
addItem(m_mainGridItemGroup);
m_rowZeroGridItemGroup = new QGraphicsItemGroup;
m_rowZeroGridItemGroup->setVisible(false);
addItem(m_rowZeroGridItemGroup);
// Additional vertical pieces of grid for side panels
for (int i=0; i<32; i++) {
m_sidePanelGridNeeded[i] = false;
@@ -654,14 +659,17 @@ LevelOneScene::LevelOneScene(QWidget *levelOneWidget, QObject *parent) : QGraphi
m_sidePanelGridItemGroup[i]->setVisible(false);
addItem(m_sidePanelGridItemGroup[i]);
}
for (int r=1; r<25; r++) {
for (int r=0; r<25; r++) {
for (int c=0; c<40; c++) {
QGraphicsRectItem *gridPiece = new QGraphicsRectItem(c*12, r*10, 12, 10);
gridPiece->setPen(QPen(QBrush(QColor(128, 128, 128, r<24 ? 192 : 128)), 0));
gridPiece->setPen(QPen(QBrush(QColor(128, 128, 128, (r != 0 && r != 24) ? 192 : 128)), 0));
if (r == 0)
m_rowZeroGridItemGroup->addToGroup(gridPiece);
else
m_mainGridItemGroup->addToGroup(gridPiece);
}
if (r < 24)
if (r != 0 && r != 24)
for (int c=0; c<32; c++) {
QGraphicsRectItem *gridPiece = new QGraphicsRectItem(0, r*10, 12, 10);
gridPiece->setPen(QPen(QBrush(QColor(128, 128, 128, 64)), 0));
@@ -686,6 +694,7 @@ void LevelOneScene::setBorderDimensions(int sceneWidth, int sceneHeight, int wid
// Position grid to cover central 40 columns
m_mainGridItemGroup->setPos(leftRightBorders + leftSidePanelColumns*12, topBottomBorders);
m_rowZeroGridItemGroup->setPos(leftRightBorders + leftSidePanelColumns*12, topBottomBorders);
updateCursor();
updateSelection();
@@ -772,12 +781,23 @@ void LevelOneScene::setRenderMode(TeletextPageRender::RenderMode renderMode)
void LevelOneScene::toggleGrid(bool gridOn)
{
m_grid = gridOn;
m_mainGridItemGroup->setVisible(gridOn);
if (static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->rowZeroAllowed())
m_rowZeroGridItemGroup->setVisible(gridOn);
for (int i=0; i<32; i++)
if (m_sidePanelGridNeeded[i])
m_sidePanelGridItemGroup[i]->setVisible(gridOn);
}
void LevelOneScene::toggleRowZeroAllowed(bool allowed)
{
static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->setRowZeroAllowed(allowed);
if (m_grid)
m_rowZeroGridItemGroup->setVisible(allowed);
}
void LevelOneScene::hideGUIElements(bool hidden)
{
if (hidden) {

View File

@@ -125,6 +125,7 @@ public slots:
void updateSelection();
void setRenderMode(TeletextPageRender::RenderMode renderMode);
void toggleGrid(bool gridOn);
void toggleRowZeroAllowed(bool allowed);
void hideGUIElements(bool hidden);
void setFullScreenColour(const QColor &newColor);
void setFullRowColour(int row, const QColor &newColor);
@@ -143,7 +144,7 @@ private:
QGraphicsRectItem *m_fullRowLeftRectItem[25], *m_fullRowRightRectItem[25];
QGraphicsProxyWidget *m_levelOneProxyWidget;
QGraphicsRectItem *m_cursorRectItem, *m_selectionRectItem;
QGraphicsItemGroup *m_mainGridItemGroup, *m_sidePanelGridItemGroup[32];
QGraphicsItemGroup *m_mainGridItemGroup, *m_rowZeroGridItemGroup, *m_sidePanelGridItemGroup[32];
bool m_grid, m_sidePanelGridNeeded[32];
};

View File

@@ -576,6 +576,13 @@ void MainWindow::createActions()
m_deleteSubPageAction->setStatusTip(tr("Delete this subpage"));
connect(m_deleteSubPageAction, &QAction::triggered, this, &MainWindow::deleteSubPage);
editMenu->addSeparator();
m_rowZeroAct = editMenu->addAction(tr("Edit header row"));
m_rowZeroAct->setCheckable(true);
m_rowZeroAct->setStatusTip(tr("Allow editing of header row"));
connect(m_rowZeroAct, &QAction::toggled, m_textScene, &LevelOneScene::toggleRowZeroAllowed);
QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
QAction *revealAct = viewMenu->addAction(tr("&Reveal"));
@@ -1090,6 +1097,12 @@ void MainWindow::loadFile(const QString &fileName)
m_reExportWarning = loadingFormat->reExportWarning();
for (int i=0; i<m_textWidget->document()->numberOfSubPages(); i++)
if (m_textWidget->document()->subPage(i)->packetExists(0)) {
m_rowZeroAct->setChecked(true);
break;
}
setCurrentFile(fileName);
statusBar()->showMessage(tr("File loaded"), 2000);
}

View File

@@ -131,6 +131,7 @@ private:
QAction *m_borderActs[3];
QAction *m_aspectRatioActs[4];
QAction *m_smoothTransformAction;
QAction *m_rowZeroAct;
QLabel *m_subPageLabel, *m_cursorPositionLabel;
QToolButton *m_previousSubPageButton, *m_nextSubPageButton;

View File

@@ -202,6 +202,10 @@ void SaveTTIFormat::writeSubPageStart(const PageBase &subPage, int subPageNumber
void SaveTTIFormat::writeSubPageBody(const PageBase &subPage)
{
// Header row
if (subPage.packetExists(0))
writePacket(format7BitPacket(subPage.packet(0)), 0);
// FLOF links
bool writeFLCommand = false;
if (m_document->pageFunction() == TeletextDocument::PFLevelOnePage && subPage.packetExists(27,0)) {
@@ -358,19 +362,27 @@ int SaveT42Format::writePacket(QByteArray packet, int packetNumber, int designat
void SaveT42Format::writeSubPageStart(const PageBase &subPage, int subPageNumber)
{
QByteArray packet;
// Convert integer to Binary Coded Decimal
subPageNumber = QString::number(subPageNumber).toInt(nullptr, 16);
// Displayable row header we export as spaces, hence the (odd parity valid) 0x20 init value
QByteArray packet(42, 0x20);
m_magazineNumber = (m_document->pageNumber() & 0xf00) >> 8;
if (m_magazineNumber == 8)
m_magazineNumber = 0;
// Write X/0 separately as it features both Hamming 8/4 and 7-bit odd parity within
packet[0] = m_magazineNumber & 0x07;
packet[1] = 0; // Packet number 0
// Retrieve and apply odd parity to header row if there's text there,
// otherwise create an initial packet of (odd parity valid) spaces
if (subPage.packetExists(0))
packet = format7BitPacket(subPage.packet(0));
else
packet.fill(0x20, 40);
// Byte 1 of MRAG - packet number 0
packet.prepend((char)0);
// Byte 0 of MRAG - magazine number, and packet number 0
packet.prepend(m_magazineNumber & 0x07);
packet[2] = m_document->pageNumber() & 0x00f;
packet[3] = (m_document->pageNumber() & 0x0f0) >> 4;
packet[4] = subPageNumber & 0xf;