9 Commits

Author SHA1 Message Date
G.K.MacGregor
06e0b401ca Tag version 0.5.5-alpha 2022-10-23 15:24:43 +01:00
G.K.MacGregor
bc8780608c Force refresh when switching decode Levels
This should fix palettes not updating when switching in and out of
Level 3.5
2022-10-23 12:43:27 +01:00
G.K.MacGregor
536c231941 Fix detect-on-load of Level 3.5 objects and DRCS mode 2022-10-23 12:30:50 +01:00
G.K.MacGregor
4faed597c0 Disable triplet widgets when no triplet is selected
This fixes a crash that occured when the last triplet in the X/26 list
is deleted.
2022-10-04 21:22:02 +01:00
G.K.MacGregor
75816e7750 Fix reserved data detection in DRCS character triplet 2022-09-22 21:28:29 +01:00
G.K.MacGregor
8b655afb2d Highlight reserved mode and data in X/26 triplet list 2022-08-30 21:07:14 +01:00
G.K.MacGregor
abf649d2ab Add reload from disk
This is typically mapped to the F5 key, so the "secret force refresh"
key has been temporarily moved to F6.
2022-07-17 15:16:53 +01:00
G.K.MacGregor
a8f2152c92 Try fixing the "unknown keypress types a block character" 2022-06-20 18:30:53 +01:00
G.K.MacGregor
9d05126e8f Fix non-flashing when page is force-refreshed 2022-06-18 17:55:19 +01:00
15 changed files with 206 additions and 34 deletions

View File

@@ -14,13 +14,15 @@ Features
- Configurable zoom. - Configurable zoom.
- View teletext pages in 4:3, 16:9 pillar-box and 16:9 stretch aspect ratios. - View teletext pages in 4:3, 16:9 pillar-box and 16:9 stretch aspect ratios.
Although designed on and developed for Linux, the Qt 5 libraries are cross platform so a Windows executable can be built. A Windows executable can be found within the "Releases" link, compiled on a Linux host using [MXE](https://github.com/mxe/mxe) based on [these instructions](https://blog.8bitbuddhism.com/2018/08/22/cross-compiling-windows-applications-with-mxe/). After MXE is installed `make qtbase` should be enough to build QTeletextMaker. Although designed on and developed for Linux, the Qt 5 libraries are cross platform so a Windows executable can be built. A Windows executable can be found within the "Releases" link, compiled on a Linux host using [MXE](https://github.com/mxe/mxe) based on [these instructions](https://blog.8bitbuddhism.com/2018/08/22/cross-compiling-windows-applications-with-mxe/). After MXE is installed `make qtbase` should build and install the required dependencies to build QTeletextMaker.
## Building ## Building
### Linux ### Linux
Install the QtCore, QtGui and QtWidgets libraries and build headers, along with the qmake tool. Then type `qmake5 && make -j3` in a terminal, you can replace -j3 with the number of processor cores used for the compile process. Install the QtCore, QtGui and QtWidgets libraries and build headers, along with the qmake tool. Depending on how qmake is installed, type `qmake && make -j3` or `qmake5 && make -j3` in a terminal to build, you can replace -j3 with the number of processor cores used for the compile process.
The above will place the qteletextmaker executable in the same directory as the source, type `./qteletextmaker` in the terminal to launch. Optionally, type `make install` afterwards to place the executable into /usr/local/bin. The above should place the qteletextmaker executable in the same directory as the source, type `./qteletextmaker` in the terminal to launch. Some Qt installs may place the executable into a "release" directory.
Optionally, type `make install` afterwards to place the executable into /usr/local/bin.
## Current limitations ## Current limitations
The following X/26 enhancement triplets are not rendered by the editor, although the list is fully aware of them. The following X/26 enhancement triplets are not rendered by the editor, although the list is fully aware of them.

View File

@@ -68,7 +68,13 @@ void TeletextPageDecode::setLevel(int level)
{ {
if (level == m_level) if (level == m_level)
return; return;
m_level = level; m_level = level;
for (int r=0; r<25; r++)
for (int c=0; c<72; c++)
m_refresh[r][c] = true;
decodePage(); decodePage();
} }

View File

@@ -94,6 +94,25 @@ bool TeletextDocument::isEmpty() const
return true; return true;
} }
void TeletextDocument::clear()
{
LevelOnePage *blankSubPage = new LevelOnePage;
m_subPages.insert(m_subPages.begin(), blankSubPage);
emit aboutToChangeSubPage();
m_currentSubPageIndex = 0;
m_clutModel->setSubPage(m_subPages[0]);
emit subPageSelected();
cancelSelection();
m_undoStack->clear();
for (int i=m_subPages.size()-1; i>0; i--) {
delete(m_subPages[i]);
m_subPages.erase(m_subPages.begin()+i);
}
}
/* /*
void TeletextDocument::setPageFunction(PageFunctionEnum newPageFunction) void TeletextDocument::setPageFunction(PageFunctionEnum newPageFunction)
{ {

View File

@@ -56,6 +56,7 @@ public:
~TeletextDocument(); ~TeletextDocument();
bool isEmpty() const; bool isEmpty() const;
void clear();
PageFunctionEnum pageFunction() const { return m_pageFunction; } PageFunctionEnum pageFunction() const { return m_pageFunction; }
// void setPageFunction(PageFunctionEnum); // void setPageFunction(PageFunctionEnum);

View File

@@ -25,6 +25,8 @@
#include "levelonepage.h" #include "levelonepage.h"
#include "x26triplets.h"
LevelOnePage::LevelOnePage() LevelOnePage::LevelOnePage()
{ {
m_enhancements.reserve(maxEnhancements()); m_enhancements.reserve(maxEnhancements());
@@ -403,17 +405,21 @@ bool LevelOnePage::isPaletteDefault(int fromColour, int toColour) const
int LevelOnePage::levelRequired() const int LevelOnePage::levelRequired() const
{ {
// X/28/4 present i.e. CLUTs 0 or 1 redefined - Level 3.5
if (!isPaletteDefault(0, 15)) if (!isPaletteDefault(0, 15))
return 3; return 3;
// TODO Check for X/28/1 for DCLUT for mode 1-3 DRCS characters - return 3 // TODO Check for X/28/1 for DCLUT for mode 1-3 DRCS characters - return 3
// Assume Level 2.5 if any X/28 page enhancements are present, otherwise assume Level 1
int levelSeen = (!isPaletteDefault(16,31) || m_leftSidePanelDisplayed || m_rightSidePanelDisplayed || m_defaultScreenColour !=0 || m_defaultRowColour !=0 || m_blackBackgroundSubst || m_colourTableRemap !=0 || m_defaultCharSet != 0 || m_secondCharSet != 0xf) ? 2 : 0; int levelSeen = (!isPaletteDefault(16,31) || m_leftSidePanelDisplayed || m_rightSidePanelDisplayed || m_defaultScreenColour !=0 || m_defaultRowColour !=0 || m_blackBackgroundSubst || m_colourTableRemap !=0 || m_defaultCharSet != 0 || m_secondCharSet != 0xf) ? 2 : 0;
// If there's no X/26 triplets, exit here as Level 1 or 2.5
if (m_enhancements.isEmpty()) if (m_enhancements.isEmpty())
return levelSeen; return levelSeen;
for (int i=0; i<m_enhancements.size(); i++) { for (int i=0; i<m_enhancements.size(); i++) {
// Font style - Level 3.5 only triplet
if (m_enhancements.at(i).modeExt() == 0x2e) // Font style if (m_enhancements.at(i).modeExt() == 0x2e) // Font style
return 3; return 3;
@@ -426,9 +432,10 @@ int LevelOnePage::levelRequired() const
case 0x22: // G3 character @ Level 1.5 case 0x22: // G3 character @ Level 1.5
case 0x2f: // G2 character case 0x2f: // G2 character
case 0x30 ... 0x3f: // G0 character with diacritical case 0x30 ... 0x3f: // G0 character with diacritical
levelSeen = qMax(levelSeen, 1); levelSeen = 1;
break; break;
} }
if (levelSeen < 2) if (levelSeen < 2)
switch (m_enhancements.at(i).modeExt()) { switch (m_enhancements.at(i).modeExt()) {
// Check for Level 2.5 triplets // Check for Level 2.5 triplets
@@ -436,25 +443,26 @@ int LevelOnePage::levelRequired() const
case 0x01: // Full row colour case 0x01: // Full row colour
case 0x10 ... 0x13: // Origin Modifer and Object Invocation case 0x10 ... 0x13: // Origin Modifer and Object Invocation
case 0x15 ... 0x17: // Object Definition case 0x15 ... 0x17: // Object Definition
// Check if Object Definition is required only at Level 3.5
if ((m_enhancements.at(i).address() & 0x18) == 0x10)
return 3;
else
levelSeen = qMax(levelSeen, 2);
break;
case 0x18: // DRCS Mode case 0x18: // DRCS Mode
// Check if DRCS is required only at Level 3.5
if ((m_enhancements.at(i).data() & 0x30) == 0x20)
return 3;
else
levelSeen = qMax(levelSeen, 2);
break;
case 0x20: // Foreground colour case 0x20: // Foreground colour
case 0x21: // G1 character case 0x21: // G1 character
case 0x23: // Background colour case 0x23: // Background colour
case 0x27 ... 0x29: // Flash functions, G0 and G2 charset designation, G0 character @ Level 2.5 case 0x27 ... 0x29: // Flash functions, G0 and G2 charset designation, G0 character @ Level 2.5
case 0x2b ... 0x2d: // G3 character @ Level 2.5, display attributes, DRCS character case 0x2b ... 0x2d: // G3 character @ Level 2.5, display attributes, DRCS character
levelSeen = qMax(levelSeen, 2); levelSeen = 2;
break;
}
if (levelSeen == 2)
switch (m_enhancements.at(i).modeExt()) {
// Check for triplets with "required at Level 3.5 only" parameters
case 0x15 ... 0x17: // Object Definition
if ((m_enhancements.at(i).address() & 0x18) == 0x10)
return 3;
break;
case 0x18: // DRCS Mode
if ((m_enhancements.at(i).data() & 0x30) == 0x20)
return 3;
break; break;
} }
} }

View File

@@ -30,7 +30,7 @@ int main(int argc, char *argv[])
QApplication::setApplicationDisplayName(QApplication::applicationName()); QApplication::setApplicationDisplayName(QApplication::applicationName());
QApplication::setOrganizationName("gkmac.co.uk"); QApplication::setOrganizationName("gkmac.co.uk");
QApplication::setOrganizationDomain("gkmac.co.uk"); QApplication::setOrganizationDomain("gkmac.co.uk");
QApplication::setApplicationVersion("0.5.4-alpha"); QApplication::setApplicationVersion("0.5.5-alpha");
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription(QApplication::applicationName()); parser.setApplicationDescription(QApplication::applicationName());
parser.addHelpOption(); parser.addHelpOption();

View File

@@ -250,8 +250,8 @@ void TeletextWidget::keyPressEvent(QKeyEvent *event)
if (event->key() < 0x01000000) { if (event->key() < 0x01000000) {
// A character-typing key was pressed // A character-typing key was pressed
// Try to keymap it, if not keymapped then plain ASCII code (may be) returned // Try to keymap it, if not keymapped then plain ASCII code (may be) returned
char mappedKeyPress = keymapping[m_pageDecode.level1CharSet(m_teletextDocument->cursorRow(), m_teletextDocument->cursorColumn())].value(event->text().at(0), *qPrintable(event->text())); char mappedKeyPress = keymapping[m_pageDecode.level1CharSet(m_teletextDocument->cursorRow(), m_teletextDocument->cursorColumn())].value(event->text().at(0), *qPrintable(event->text().at(0)));
if (mappedKeyPress < 0x20) if (mappedKeyPress >= 0x00 && mappedKeyPress <= 0x1f)
return; return;
// If outside ASCII map then the character can't be represented by current Level 1 character set // If outside ASCII map then the character can't be represented by current Level 1 character set
// Map it to block character so it doesn't need to be inserted-between later on // Map it to block character so it doesn't need to be inserted-between later on
@@ -386,7 +386,7 @@ void TeletextWidget::keyPressEvent(QKeyEvent *event)
case Qt::Key_PageDown: case Qt::Key_PageDown:
m_teletextDocument->selectSubPagePrevious(); m_teletextDocument->selectSubPagePrevious();
break; break;
case Qt::Key_F5: case Qt::Key_F6:
m_pageDecode.decodePage(); m_pageDecode.decodePage();
m_pageRender.renderPage(true); m_pageRender.renderPage(true);
update(); update();

View File

@@ -149,6 +149,34 @@ bool MainWindow::saveAs()
return saveFile(fileName); return saveFile(fileName);
} }
void MainWindow::reload()
{
if (m_isUntitled)
return;
if (!m_textWidget->document()->undoStack()->isClean()) {
const QMessageBox::StandardButton ret = QMessageBox::warning(this, QApplication::applicationDisplayName(), tr("The document \"%1\" has been modified.\nDo you want to discard your changes?").arg(QFileInfo(m_curFile).fileName()), QMessageBox::Discard | QMessageBox::Cancel);
if (ret != QMessageBox::Discard)
return;
} else {
const QMessageBox::StandardButton ret = QMessageBox::warning(this, QApplication::applicationDisplayName(), tr("Do you want to reload the document \"%1\" from disk?").arg(QFileInfo(m_curFile).fileName()), QMessageBox::Yes | QMessageBox::No);
if (ret != QMessageBox::Yes)
return;
}
int subPageIndex = m_textWidget->document()->currentSubPageIndex();
m_textWidget->document()->clear();
loadFile(m_curFile);
if (subPageIndex >= m_textWidget->document()->numberOfSubPages())
subPageIndex = m_textWidget->document()->numberOfSubPages()-1;
m_textWidget->document()->selectSubPageIndex(subPageIndex, true);
}
void MainWindow::exportPNG() void MainWindow::exportPNG()
{ {
QString exportFileName = QFileDialog::getSaveFileName(this, tr("Export PNG"), QString(), "PNG image (*.png)"); QString exportFileName = QFileDialog::getSaveFileName(this, tr("Export PNG"), QString(), "PNG image (*.png)");
@@ -328,6 +356,11 @@ void MainWindow::createActions()
saveAsAct->setShortcuts(QKeySequence::SaveAs); saveAsAct->setShortcuts(QKeySequence::SaveAs);
saveAsAct->setStatusTip(tr("Save the document under a new name")); saveAsAct->setStatusTip(tr("Save the document under a new name"));
const QIcon reloadIcon = QIcon::fromTheme("document-revert");
QAction *reloadAct = fileMenu->addAction(reloadIcon, tr("Reload"), this, &MainWindow::reload);
reloadAct->setShortcuts(QKeySequence::Refresh);
reloadAct->setStatusTip(tr("Reload the document from disk"));
fileMenu->addSeparator(); fileMenu->addSeparator();
QMenu *recentMenu = fileMenu->addMenu(tr("Recent")); QMenu *recentMenu = fileMenu->addMenu(tr("Recent"));

View File

@@ -59,6 +59,7 @@ private slots:
void open(); void open();
bool save(); bool save();
bool saveAs(); bool saveAs();
void reload();
void exportT42(); void exportT42();
void exportZXNet(); void exportZXNet();
void exportEditTF(); void exportEditTF();

View File

@@ -354,7 +354,9 @@ void TeletextPageRender::renderPage(bool force)
} }
} }
if (!force || m_decoder->cellFlashMode(r, c) == 0) if (force && m_decoder->cellFlashMode(r, c) != 0)
m_decoder->setRefresh(r, c, true);
else
m_decoder->setRefresh(r, c, false); m_decoder->setRefresh(r, c, false);
} }
} }

View File

@@ -623,6 +623,8 @@ X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent)
x26Layout->addLayout(insertDeleteLayout); x26Layout->addLayout(insertDeleteLayout);
disableTripletWidgets();
x26Widget->setLayout(x26Layout); x26Widget->setLayout(x26Layout);
this->setWidget(x26Widget); this->setWidget(x26Widget);
@@ -674,14 +676,48 @@ void X26DockWidget::rowSelected(const QModelIndex &current, const QModelIndex &p
{ {
Q_UNUSED(previous); Q_UNUSED(previous);
updateAllRawTripletSpinBoxes(current); if (current.isValid()) {
updateAllCookedTripletWidgets(current); updateAllRawTripletSpinBoxes(current);
updateAllCookedTripletWidgets(current);
} else
disableTripletWidgets();
}
void X26DockWidget::disableTripletWidgets()
{
m_rawTripletAddressSpinBox->setEnabled(false);
m_rawTripletDataSpinBox->setEnabled(false);
m_rawTripletModeSpinBox->setEnabled(false);
m_rawTripletAddressSpinBox->blockSignals(true);
m_rawTripletModeSpinBox->blockSignals(true);
m_rawTripletDataSpinBox->blockSignals(true);
m_rawTripletAddressSpinBox->setValue(0);
m_rawTripletModeSpinBox->setValue(0);
m_rawTripletDataSpinBox->setValue(0);
m_rawTripletAddressSpinBox->blockSignals(false);
m_rawTripletModeSpinBox->blockSignals(false);
m_rawTripletDataSpinBox->blockSignals(false);
m_cookedRowSpinBox->setEnabled(false);
m_cookedColumnSpinBox->setEnabled(false);
m_cookedRowSpinBox->blockSignals(true);
m_cookedColumnSpinBox->blockSignals(true);
m_cookedRowSpinBox->setValue(1);
m_cookedColumnSpinBox->setValue(0);
m_cookedRowSpinBox->blockSignals(false);
m_cookedColumnSpinBox->blockSignals(false);
m_cookedModePushButton->setEnabled(false);
m_cookedModePushButton->setText(QString());
m_tripletParameterStackedLayout->setCurrentIndex(0);
} }
void X26DockWidget::updateAllCookedTripletWidgets(const QModelIndex &index) void X26DockWidget::updateAllCookedTripletWidgets(const QModelIndex &index)
{ {
const int modeExt = index.model()->data(index.model()->index(index.row(), 2), Qt::EditRole).toInt(); const int modeExt = index.model()->data(index.model()->index(index.row(), 2), Qt::EditRole).toInt();
m_cookedModePushButton->setEnabled(true);
m_cookedModePushButton->setText(m_x26Model->modeTripletName(modeExt)); m_cookedModePushButton->setText(m_x26Model->modeTripletName(modeExt));
switch (modeExt) { switch (modeExt) {

View File

@@ -117,6 +117,9 @@ private:
QPushButton *m_insertBeforePushButton, *m_insertAfterPushButton, *m_insertCopyPushButton, *m_deletePushButton; QPushButton *m_insertBeforePushButton, *m_insertAfterPushButton, *m_insertCopyPushButton, *m_deletePushButton;
TeletextWidget *m_parentMainWidget; TeletextWidget *m_parentMainWidget;
void disableTripletWidgets();
}; };
#endif #endif

View File

@@ -65,11 +65,19 @@ QVariant X26Model::data(const QModelIndex &index, int role) const
} }
// Error colours from KDE Plasma Breeze (light) theme // Error colours from KDE Plasma Breeze (light) theme
if (role == Qt::ForegroundRole && triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight) if (role == Qt::ForegroundRole) {
return QColor(252, 252, 252); if (triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight)
return QColor(252, 252, 252);
else if ((index.column() == 2 && triplet.reservedMode()) || (index.column() == 3 && triplet.reservedData()))
return QColor(35, 38, 39);
}
if (role == Qt::BackgroundRole && triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight) if (role == Qt::BackgroundRole) {
return QColor(218, 68, 63); if (triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight)
return QColor(218, 68, 63);
else if ((index.column() == 2 && triplet.reservedMode()) || (index.column() == 3 && triplet.reservedData()))
return QColor(246, 116, 0);
}
if (role == Qt::ToolTipRole && triplet.error() != X26Triplet::NoError) if (role == Qt::ToolTipRole && triplet.error() != X26Triplet::NoError)
return m_tripletErrors[triplet.error()].message; return m_tripletErrors[triplet.error()].message;

View File

@@ -77,30 +77,45 @@ void X26TripletList::updateInternalData()
for (int i=0; i < m_list.size(); i++) { for (int i=0; i < m_list.size(); i++) {
triplet = &m_list[i]; triplet = &m_list[i];
triplet->m_error = X26Triplet::NoError; triplet->m_error = X26Triplet::NoError;
triplet->m_reservedMode = false;
triplet->m_reservedData = false;
if (triplet->isRowTriplet()) { if (triplet->isRowTriplet()) {
switch (triplet->modeExt()) { switch (triplet->modeExt()) {
case 0x00: // Full screen colour case 0x00: // Full screen colour
if (activePosition.isDeployed()) if (activePosition.isDeployed())
// TODO more specific error needed // TODO more specific error needed
triplet->m_error = X26Triplet::ActivePositionMovedUp; triplet->m_error = X26Triplet::ActivePositionMovedUp;
if (triplet->m_data & 0x60)
triplet->m_reservedData = true;
break; break;
case 0x01: // Full row colour case 0x01: // Full row colour
if (!activePosition.setRow(triplet->addressRow())) if (!activePosition.setRow(triplet->addressRow()))
triplet->m_error = X26Triplet::ActivePositionMovedUp; triplet->m_error = X26Triplet::ActivePositionMovedUp;
if ((triplet->m_data & 0x60) != 0x00 && (triplet->m_data & 0x60) != 0x60)
triplet->m_reservedData = true;
break; break;
case 0x04: // Set Active Position; case 0x04: // Set Active Position;
if (!activePosition.setRow(triplet->addressRow())) if (!activePosition.setRow(triplet->addressRow()))
triplet->m_error = X26Triplet::ActivePositionMovedUp; triplet->m_error = X26Triplet::ActivePositionMovedUp;
else if (triplet->data() >= 40 || !activePosition.setColumn(triplet->data())) else if (triplet->data() >= 40)
// FIXME data column highlighted?
triplet->m_reservedData = true;
else if (!activePosition.setColumn(triplet->data()))
triplet->m_error = X26Triplet::ActivePositionMovedLeft; triplet->m_error = X26Triplet::ActivePositionMovedLeft;
break; break;
case 0x07: // Address row 0 case 0x07: // Address row 0
if (activePosition.isDeployed()) if (triplet->m_address != 63)
// FIXME data column highlighted?
triplet->m_reservedData = true;
else if (activePosition.isDeployed())
triplet->m_error = X26Triplet::ActivePositionMovedUp; triplet->m_error = X26Triplet::ActivePositionMovedUp;
else { else {
activePosition.setRow(0); activePosition.setRow(0);
activePosition.setColumn(8); activePosition.setColumn(8);
} }
if ((triplet->m_data & 0x60) != 0x00 && (triplet->m_data & 0x60) != 0x60)
triplet->m_reservedData = true;
break; break;
case 0x10: // Origin Modifier case 0x10: // Origin Modifier
if (i == m_list.size()-1 || if (i == m_list.size()-1 ||
@@ -125,11 +140,45 @@ void X26TripletList::updateInternalData()
// otherwise the object won't appear // otherwise the object won't appear
triplet->setObjectLocalIndex(i); triplet->setObjectLocalIndex(i);
break; break;
case 0x18: // DRCS mode
if ((triplet->m_data & 0x30) == 0x00)
triplet->m_reservedData = true;
case 0x1f: // Termination marker
case 0x08 ... 0x0d: // PDC
break;
default:
triplet->m_reservedMode = true;
}; };
// Column triplet: make sure that PDC and reserved triplets don't affect the Active Position // Column triplet: all triplets modes except PDC and reserved move the Active Position
} else if (triplet->modeExt() != 0x24 && triplet->modeExt() != 0x25 && triplet->modeExt() != 0x26 && triplet->modeExt() != 0x2a) } else if (triplet->modeExt() == 0x24 || triplet->modeExt() == 0x25 || triplet->modeExt() == 0x2a)
if (!activePosition.setColumn(triplet->addressColumn())) triplet->m_reservedMode = true;
triplet->m_error = X26Triplet::ActivePositionMovedLeft; else if (triplet->modeExt() != 0x26 && !activePosition.setColumn(triplet->addressColumn()))
triplet->m_error = X26Triplet::ActivePositionMovedLeft;
else
switch (triplet->modeExt()) {
case 0x20: // Foreground colour
case 0x23: // Foreground colour
if (triplet->m_data & 0x60)
triplet->m_reservedData = true;
break;
case 0x21: // G1 mosaic character
case 0x22: // G3 mosaic character at level 1.5
case 0x29: // G0 character
case 0x2b: // G3 mosaic character at level >=2.5
case 0x2f ... 0x3f: // G2 character or G0 diacritical mark
if (triplet->m_data < 0x20)
triplet->m_reservedData = true;
break;
case 0x27: // Additional flash functions
if (triplet->m_data >= 0x18)
triplet->m_reservedData = true;
break;
case 0x2d: // DRCS character
if ((triplet->m_data & 0x3f) >= 48)
// Should really be an error?
triplet->m_reservedData = true;
}
triplet->m_activePositionRow = activePosition.row(); triplet->m_activePositionRow = activePosition.row();
triplet->m_activePositionColumn = activePosition.column(); triplet->m_activePositionColumn = activePosition.column();
} }

View File

@@ -62,6 +62,8 @@ public:
int activePositionRow() const { return m_activePositionRow; } int activePositionRow() const { return m_activePositionRow; }
int activePositionColumn() const { return m_activePositionColumn; } int activePositionColumn() const { return m_activePositionColumn; }
X26TripletError error() const { return m_error; } X26TripletError error() const { return m_error; }
bool reservedMode() const { return m_reservedMode; }
bool reservedData() const { return m_reservedData; }
friend class X26TripletList; friend class X26TripletList;
@@ -70,6 +72,8 @@ private:
int m_activePositionRow = -1; int m_activePositionRow = -1;
int m_activePositionColumn = -1; int m_activePositionColumn = -1;
X26TripletError m_error = NoError; X26TripletError m_error = NoError;
bool m_reservedMode = false;
bool m_reservedData = false;
}; };
class X26TripletList class X26TripletList