Compare commits
9 Commits
0.5.4-alph
...
0.5.5-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06e0b401ca | ||
|
|
bc8780608c | ||
|
|
536c231941 | ||
|
|
4faed597c0 | ||
|
|
75816e7750 | ||
|
|
8b655afb2d | ||
|
|
abf649d2ab | ||
|
|
a8f2152c92 | ||
|
|
9d05126e8f |
@@ -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.
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
19
document.cpp
19
document.cpp
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
main.cpp
2
main.cpp
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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"));
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ¤t, 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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
16
x26model.cpp
16
x26model.cpp
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user