Begin refactoring of page class

This commit is contained in:
G.K.MacGregor
2020-09-11 12:06:06 +01:00
parent ac2e86f5e5
commit fcc9280391
10 changed files with 258 additions and 118 deletions

View File

@@ -23,7 +23,7 @@
#include "document.h"
#include "page.h"
#include "levelonepage.h"
TeletextDocument::TeletextDocument()
{

View File

@@ -26,8 +26,7 @@
#include <QUndoCommand>
#include <QUndoStack>
#include <vector>
#include "document.h"
#include "page.h"
#include "levelonepage.h"
class TeletextDocument : public QObject
{

View File

@@ -23,7 +23,7 @@
#include <QString>
#include <algorithm>
#include "page.h"
#include "levelonepage.h"
TeletextPage::TeletextPage()
{
@@ -57,6 +57,36 @@ void TeletextPage::clearPage()
// If clearPage() is called outside constructor, we need to implement localEnhance.clear();
}
bool TeletextPage::packetNeeded(int packetNumber, int designationCode) const
{
if (packetNumber <= 24) {
for (int c=0; c<40; c++)
if (m_level1Page[packetNumber][c] != 0x20)
return true;
return false;
}
// TODO packets 26 and 27
if (packetNumber == 28) {
if (designationCode == 0) {
if (m_leftSidePanelDisplayed || m_rightSidePanelDisplayed || m_defaultScreenColour !=0 || m_defaultRowColour !=0 || m_blackBackgroundSubst || m_colourTableRemap !=0 || m_defaultCharSet != 0 || m_secondCharSet != 0xf)
return true;
for (int i=16; i<32; i++)
if (m_CLUT[i] != defaultCLUT[i])
return true;
return false;
}
if (designationCode == 4) {
for (int i=0; i<16; i++)
if (m_CLUT[i] != defaultCLUT[i])
return true;
return false;
}
}
return true;
}
// At the moment this awkwardly combines parsing a TTI file and making sense of the packets within it.
// This will be gradually converted to just parsing a TTI file and passing the raw packets to the Page class.
void TeletextPage::loadPagePacket(QByteArray &inLine)
{
bool lineNumberOk;
@@ -65,9 +95,13 @@ void TeletextPage::loadPagePacket(QByteArray &inLine)
secondCommaPosition = inLine.indexOf(",", 3);
if (secondCommaPosition != 4 && secondCommaPosition != 5)
return;
lineNumber = inLine.mid(3, secondCommaPosition-3).toInt(&lineNumberOk, 10);
if (lineNumberOk && lineNumber>=0 && lineNumber<=31) {
if (lineNumberOk && lineNumber>=0 && lineNumber<=29) {
inLine.remove(0, secondCommaPosition+1);
// Won't be a designation code for line numbers below 25!
int designationCode = inLine.at(0) & 0x3f;
if (lineNumber <= 24) {
for (int i=0, j=0; j<=39; i++, j++) {
if (i == inLine.size())
@@ -83,10 +117,7 @@ void TeletextPage::loadPagePacket(QByteArray &inLine)
}
setCharacter(lineNumber, j, myChar);
}
}
if (lineNumber == 26) {
int designationCode = inLine.at(0) & 0x3f;
} else if (lineNumber == 26) {
// TODO deal with gaps or out of order X26 designation codes in a more graceful way
// At the moment gaps are dealt with by simply inserting "dummy" reserved 11110 Row
// Triplets in case Local Objects are referenced within.
@@ -116,28 +147,13 @@ void TeletextPage::loadPagePacket(QByteArray &inLine)
if (newX26Triplet.mode() == 0x1f && newX26Triplet.address() == 0x3f && newX26Triplet.data() & 0x01)
break;
}
}
if (lineNumber == 28) {
int offset;
} else if (lineNumber == 28 && (designationCode == 0 || designationCode == 4)) {
int offset = (designationCode == 0) ? 16 : 0;
int designationCode = inLine.at(0) & 0x3f;
switch (designationCode) {
case 0:
offset = 16;
break;
case 4:
offset = 0;
break;
default:
offset = -1;
break;
}
if (offset >= 0) {
int x28Triplets[13];
for (int i=1, j=0; i<39; i+=3, j++) {
for (int i=1, j=0; i<39; i+=3, j++)
x28Triplets[j] = ((inLine.at(i+2) & 0x3f) << 12) | ((inLine.at(i+1) & 0x3f) << 6) | (inLine.at(i) & 0x3f);
}
m_defaultCharSet = (x28Triplets[0] >> 10) & 0xF;
m_defaultNOS = (x28Triplets[0] >> 7) & 0x7;
@@ -174,11 +190,12 @@ void TeletextPage::loadPagePacket(QByteArray &inLine)
m_defaultRowColour = (x28Triplets[12] >> 9) & 0x1f;
m_blackBackgroundSubst = ((x28Triplets[12] >> 14) & 1);
m_colourTableRemap = (x28Triplets[12] >> 15) & 7;
}
}
} else
qDebug("Packet X/%d/%d unhandled (yet?)", lineNumber, designationCode);
} //TODO panic if invalid line number is encountered
}
// This will be gradually be converted to just getting the raw packets from the Page class and writing out a TTI file.
void TeletextPage::savePage(QTextStream *outStream, int pageNumber, int subPageNumber)
{
// int pageStatus = 0x8000 | (controlBits[0] << 14) | ((defaultPageNOS & 1) << 9) | ((defaultPageNOS & 2) << 7) | ((defaultPageNOS & 4) << 5);
@@ -189,12 +206,12 @@ void TeletextPage::savePage(QTextStream *outStream, int pageNumber, int subPageN
*outStream << QString("PS,%1").arg(0x8000 | controlBitsToPS(), 4, 16, QChar('0')) << endl;
*outStream << QString("CT,%1,%2").arg(m_cycleValue).arg(m_cycleType==CTcycles ? 'C' : 'T') << endl;
//TODO RE and maybe FLOF?
if (int x28Result = x28Needed()) {
if (x28Result & 1)
if (packetNeeded(28, 0))
*outStream << "OL,28," << x28toTTI(0) << endl;
if (x28Result & 2)
if (packetNeeded(28, 4))
*outStream << "OL,28," << x28toTTI(4) << endl;
}
if (!localEnhance.isEmpty()) {
int tripletNumber = 0;
X26Triplet lastTriplet = localEnhance.at(localEnhance.size()-1);
@@ -235,22 +252,19 @@ void TeletextPage::savePage(QTextStream *outStream, int pageNumber, int subPageN
break;
}
}
for (int r=1; r<25; r++) {
bool blankRow = true;
for (int r=1; r<25; r++)
if (packetNeeded(r)) {
QString rowString;
rowString.append(QString("OL,%1,").arg(r));
for (int c=0; c<40; c++) {
unsigned char myChar = m_level1Page[r][c];
if (myChar != 0x20)
blankRow = false;
if (myChar < 32) {
rowString.append((char)0x1b);
rowString.append((char)(myChar+0x40));
} else
rowString.append((char)myChar);
}
if (!blankRow)
*outStream << rowString << endl;
}
}
@@ -341,7 +355,7 @@ QString TeletextPage::exportURLHash(QString pageHash)
// CLUTChangedResult = CLUTChanged();
// if (leftSidePanel || rightSidePanel || defaultScreenColour !=0 || defaultRowColour !=0 || blackBackgroundSubst || colourTableRemap !=0 || CLUTChangedResult) {
if (int x28Result = x28Needed()) {
if (packetNeeded(28,0) || packetNeeded(28,4)) {
QString x28StringBegin, x28StringEnd;
x28StringBegin.append(QString("00%1").arg((m_defaultCharSet << 3) | m_defaultNOS, 2, 16, QChar('0')).toUpper());
@@ -350,13 +364,13 @@ QString TeletextPage::exportURLHash(QString pageHash)
x28StringEnd = QString("%1%2%3%4").arg(m_defaultScreenColour, 2, 16, QChar('0')).arg(m_defaultRowColour, 2, 16, QChar('0')).arg(m_blackBackgroundSubst, 1, 10).arg(m_colourTableRemap, 1, 10);
if (x28Result & 1) {
if (packetNeeded(28,0)) {
pageHash.append(":X280=");
pageHash.append(x28StringBegin);
pageHash.append(colourHash(1));
pageHash.append(x28StringEnd);
}
if (x28Result & 2) {
if (packetNeeded(28,4)) {
pageHash.append(":X284=");
pageHash.append(x28StringBegin);
pageHash.append(colourHash(0));
@@ -413,23 +427,6 @@ void TeletextPage::setRightSidePanelDisplayed(bool newRightSidePanelDisplayed) {
void TeletextPage::setSidePanelColumns(int newSidePanelColumns) { m_sidePanelColumns = newSidePanelColumns; }
void TeletextPage::setSidePanelStatusL25(bool newSidePanelStatusL25) { m_sidePanelStatusL25 = newSidePanelStatusL25; }
int TeletextPage::x28Needed()
{
int result = (m_leftSidePanelDisplayed || m_rightSidePanelDisplayed || m_defaultScreenColour !=0 || m_defaultRowColour !=0 || m_blackBackgroundSubst || m_colourTableRemap !=0 || m_defaultCharSet != 0 || m_secondCharSet != 0xf);
for (int i=0; i<16; i++)
if (m_CLUT[i] != defaultCLUT[i]) {
result |= 2;
break;
}
for (int i=16; i<32; i++)
if (m_CLUT[i] != defaultCLUT[i]) {
result |= 1;
break;
}
return result;
}
QString TeletextPage::colourHash(int whichCLUT)
{
QString resultHash;

View File

@@ -17,8 +17,8 @@
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef PAGE_H
#define PAGE_H
#ifndef LEVELONEPAGE_H
#define LEVELONEPAGE_H
#include <QByteArray>
#include <QColor>
@@ -27,12 +27,13 @@
#include <QString>
#include <QTextStream>
#include "pagebase.h"
#include "x26triplets.h"
QColor CLUTtoQColor(int myColour);
// If we inherit from QObject then we can't copy construct, so "make a new subpage that's a copy of this one" wouldn't work
class TeletextPage //: public QObject
class TeletextPage : public PageBase //: public QObject
{
//Q_OBJECT
@@ -40,6 +41,9 @@ public:
enum CycleTypeEnum { CTcycles, CTseconds };
TeletextPage();
bool packetNeeded(int, int=0) const;
void clearPage();
void loadPagePacket(QByteArray &);
void savePage(QTextStream *, int, int);
@@ -80,7 +84,6 @@ public:
void setSidePanelColumns(int);
bool sidePanelStatusL25() const { return m_sidePanelStatusL25; }
void setSidePanelStatusL25(bool);
int x28Needed();
QString colourHash(int);
QList<X26Triplet> localEnhance;

View File

@@ -30,7 +30,7 @@
#include "mainwidget.h"
#include "document.h"
#include "page.h"
#include "levelonepage.h"
#include "render.h"
#include "x26triplets.h"

View File

@@ -26,7 +26,7 @@
#include <vector>
#include "document.h"
#include "page.h"
#include "levelonepage.h"
#include "render.h"
class QPaintEvent;

87
pagebase.cpp Normal file
View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 2020 Gavin MacGregor
*
* This file is part of QTeletextMaker.
*
* QTeletextMaker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QTeletextMaker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
*/
#include <QByteArray>
#include "pagebase.h"
PageBase::PageBase()
{
m_pageFunction = PFLOP;
m_packetCoding = PC7bit;
// We use nullptrs to keep track of allocated packets, so initialise them this way
for (int i=0; i<89; i++)
m_packets[i] = nullptr;
}
PageBase::~PageBase()
{
for (int i=0; i<89; i++)
if (m_packets[i] != nullptr)
delete m_packets[i];
}
bool PageBase::setPacket(int packetNumber, QByteArray packetContents)
{
// X/26 and above need a designation code
if (packetNumber >= 26)
return false;
return setPacket(packetNumber, 0, packetContents);
}
bool PageBase::setPacket(int packetNumber, int designationCode, QByteArray packetContents)
{
if (packetNumber >= 30)
return false;
int packetArrayNumber = packetNumber;
if (packetNumber >= 26)
packetArrayNumber += (packetNumber - 26) * 16;
if (m_packets[packetArrayNumber] == nullptr)
m_packets[packetArrayNumber] = new QByteArray;
*m_packets[packetArrayNumber] = packetContents;
return true;
}
PageBase::PacketCodingEnum PageBase::packetCoding(int packetNumber, int designationCode) const
{
switch (packetNumber) {
case 26:
case 28:
return PC18bit;
case 27:
return PC4bit;
default:
return m_packetCoding;
}
}
bool PageBase::setPageFunction(PageBase::PageFunctionEnum newPageFunction)
{
m_pageFunction = newPageFunction;
return true;
}
bool PageBase::setPacketCoding(PageBase::PacketCodingEnum newPacketEncoding)
{
m_packetCoding = newPacketEncoding;
return true;
}

52
pagebase.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2020 Gavin MacGregor
*
* This file is part of QTeletextMaker.
*
* QTeletextMaker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QTeletextMaker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef PAGEBASE_H
#define PAGEBASE_H
#include <QByteArray>
// If we inherit from QObject then we can't copy construct, so "make a new subpage that's a copy of this one" wouldn't work
class PageBase //: public QObject
{
//Q_OBJECT
public:
// Available Page Functions according to 9.4.2.1 of the spec
enum PageFunctionEnum { PFLOP, PFData, PFGPOP, PFPOP, PFGDRCS, PFDRCS, PFMOT, PFMIP, PFBTT, PFAIT, PFMPT, PFMPTEX, PFTriggers };
// Available Page Codings of X/1 to X/25 according to 9.4.2.1 of the spec
enum PacketCodingEnum { PC7bit, PC8bit, PC18bit, PC4bit, PC4bit7bit, PCMixed };
PageBase();
~PageBase();
bool setPacket(int, QByteArray);
bool setPacket(int, int, QByteArray);
PageFunctionEnum pageFunction() const { return m_pageFunction; }
bool setPageFunction(PageFunctionEnum);
PacketCodingEnum packetCoding(int=0, int=0) const;
bool setPacketCoding(PacketCodingEnum);
bool packetNeeded(int, int=0) const { return true; }
private:
PageFunctionEnum m_pageFunction;
PacketCodingEnum m_packetCoding;
QByteArray *m_packets[89]; // X/1 to X/25, plus 16 packets for X/26, another 16 for X/27, for X28 and for X/29
};
#endif

View File

@@ -2,9 +2,10 @@ QT += widgets
requires(qtConfig(filedialog))
HEADERS = document.h \
levelonepage.h \
mainwidget.h \
mainwindow.h \
page.h \
pagebase.h \
pageenhancementsdockwidget.h \
pageoptionsdockwidget.h \
palettedockwidget.h \
@@ -13,13 +14,14 @@ HEADERS = document.h \
x26model.h \
x26triplets.h
SOURCES = document.cpp \
levelonepage.cpp \
main.cpp \
mainwidget.cpp \
mainwindow.cpp \
pagebase.cpp \
pageenhancementsdockwidget.cpp \
pageoptionsdockwidget.cpp \
palettedockwidget.cpp \
page.cpp \
render.cpp \
x26dockwidget.cpp \
x26model.cpp \

View File

@@ -25,7 +25,7 @@
#include <QMultiMap>
#include <vector>
#include "page.h"
#include "levelonepage.h"
struct textCharacter {