Compare commits
16 Commits
0.8-beta
...
0.8.2-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7e93f463a | ||
|
|
fcca93e5a5 | ||
|
|
dbbeea9d30 | ||
|
|
53fb6f0aad | ||
|
|
eea73592f9 | ||
|
|
f708765d7b | ||
|
|
7ce848b4cf | ||
|
|
e6a90c061e | ||
|
|
973aeaa6cf | ||
|
|
1efa8c196d | ||
|
|
1b3623d61b | ||
|
|
6c46aba687 | ||
|
|
07abbdf928 | ||
|
|
30bff43a14 | ||
|
|
d9c93cfe66 | ||
|
|
f18cf60b27 |
2
3rdparty/QtGifImage/CMakeLists.txt
vendored
2
3rdparty/QtGifImage/CMakeLists.txt
vendored
@@ -13,7 +13,7 @@ set(GIF_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include/3rdparty/giflib)
|
||||
|
||||
# Next line was "add_library(${PROJECT_NAME} SHARED"
|
||||
# but it breaks MXE static compilation
|
||||
add_library(${PROJECT_NAME}
|
||||
add_library(${PROJECT_NAME} STATIC
|
||||
${GIF_IMAGE_DIR}/qgifglobal.h ${GIF_IMAGE_DIR}/qgifimage.cpp
|
||||
${GIF_IMAGE_DIR}/qgifimage.h ${GIF_IMAGE_DIR}/qgifimage_p.h
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ bool QGifImagePrivate::save(QIODevice *device) const {
|
||||
}
|
||||
|
||||
GraphicsControlBlock gcbBlock;
|
||||
gcbBlock.DisposalMode = 0;
|
||||
gcbBlock.DisposalMode = 2;
|
||||
gcbBlock.UserInputFlag = false;
|
||||
gcbBlock.TransparentColor = getFrameTransparentColorIndex(frameInfo);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
file (GLOB SOURCES *.cpp)
|
||||
|
||||
add_library(qteletextdecoder ${SOURCES} teletextfonts.qrc)
|
||||
add_library(qteletextdecoder STATIC ${SOURCES} teletextfonts.qrc)
|
||||
|
||||
target_include_directories(qteletextdecoder PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ DRCSPage::DRCSPage(const PageBase &other)
|
||||
setControlBit(b, other.controlBit(b));
|
||||
}
|
||||
|
||||
PageBase::PageFunctionEnum DRCSPage::pageFunction() const
|
||||
{
|
||||
return PFGlobalPOP;
|
||||
}
|
||||
|
||||
int DRCSPage::drcsMode(int c) const
|
||||
{
|
||||
if (!packetExists(28, 3))
|
||||
|
||||
@@ -30,8 +30,7 @@ public:
|
||||
DRCSPage(const PageBase &other);
|
||||
|
||||
// TODO PFNormalPOP as well?
|
||||
PageFunctionEnum pageFunction() const { return PFGlobalPOP; }
|
||||
PacketCodingEnum packetCoding() const override { return Coding7bit; }
|
||||
PageFunctionEnum pageFunction() const;
|
||||
|
||||
int drcsMode(int c) const;
|
||||
bool ptu(int c, uchar *data) const;
|
||||
|
||||
@@ -295,10 +295,47 @@ bool LevelOnePage::setControlBit(int b, bool active)
|
||||
return PageX26Base::setControlBit(b, active);
|
||||
}
|
||||
|
||||
int LevelOnePage::maxEnhancements() const
|
||||
{
|
||||
return 208;
|
||||
}
|
||||
|
||||
/* void LevelOnePage::setSubPageNumber(int newSubPageNumber) { m_subPageNumber = newSubPageNumber; } */
|
||||
void LevelOnePage::setCycleValue(int newValue) { m_cycleValue = newValue; };
|
||||
void LevelOnePage::setCycleType(CycleTypeEnum newType) { m_cycleType = newType; }
|
||||
void LevelOnePage::setDefaultCharSet(int newDefaultCharSet) { m_defaultCharSet = newDefaultCharSet; }
|
||||
|
||||
int LevelOnePage::cycleValue() const
|
||||
{
|
||||
return m_cycleValue;
|
||||
}
|
||||
|
||||
void LevelOnePage::setCycleValue(int newValue)
|
||||
{
|
||||
m_cycleValue = newValue;
|
||||
}
|
||||
|
||||
LevelOnePage::CycleTypeEnum LevelOnePage::cycleType() const
|
||||
{
|
||||
return m_cycleType;
|
||||
}
|
||||
|
||||
void LevelOnePage::setCycleType(CycleTypeEnum newType)
|
||||
{
|
||||
m_cycleType = newType;
|
||||
}
|
||||
|
||||
int LevelOnePage::defaultCharSet() const
|
||||
{
|
||||
return m_defaultCharSet;
|
||||
}
|
||||
|
||||
void LevelOnePage::setDefaultCharSet(int newDefaultCharSet)
|
||||
{
|
||||
m_defaultCharSet = newDefaultCharSet;
|
||||
}
|
||||
|
||||
int LevelOnePage::defaultNOS() const
|
||||
{
|
||||
return m_defaultNOS;
|
||||
}
|
||||
|
||||
void LevelOnePage::setDefaultNOS(int defaultNOS)
|
||||
{
|
||||
@@ -309,6 +346,11 @@ void LevelOnePage::setDefaultNOS(int defaultNOS)
|
||||
PageX26Base::setControlBit(C14NOS, m_defaultNOS & 0x4);
|
||||
}
|
||||
|
||||
int LevelOnePage::secondCharSet() const
|
||||
{
|
||||
return m_secondCharSet;
|
||||
}
|
||||
|
||||
void LevelOnePage::setSecondCharSet(int newSecondCharSet)
|
||||
{
|
||||
m_secondCharSet = newSecondCharSet;
|
||||
@@ -316,8 +358,18 @@ void LevelOnePage::setSecondCharSet(int newSecondCharSet)
|
||||
m_secondNOS = 0x7;
|
||||
}
|
||||
|
||||
int LevelOnePage::secondNOS() const
|
||||
{
|
||||
return m_secondNOS;
|
||||
}
|
||||
|
||||
void LevelOnePage::setSecondNOS(int newSecondNOS) { m_secondNOS = newSecondNOS; }
|
||||
|
||||
unsigned char LevelOnePage::character(int r, int c) const
|
||||
{
|
||||
return PageX26Base::packetExists(r) ? PageX26Base::packet(r).at(c) : 0x20;
|
||||
}
|
||||
|
||||
void LevelOnePage::setCharacter(int r, int c, unsigned char newCharacter)
|
||||
{
|
||||
QByteArray pkt;
|
||||
@@ -338,10 +390,45 @@ void LevelOnePage::setCharacter(int r, int c, unsigned char newCharacter)
|
||||
}
|
||||
}
|
||||
|
||||
void LevelOnePage::setDefaultScreenColour(int newDefaultScreenColour) { m_defaultScreenColour = newDefaultScreenColour; }
|
||||
void LevelOnePage::setDefaultRowColour(int newDefaultRowColour) { m_defaultRowColour = newDefaultRowColour; }
|
||||
void LevelOnePage::setColourTableRemap(int newColourTableRemap) { m_colourTableRemap = newColourTableRemap; }
|
||||
void LevelOnePage::setBlackBackgroundSubst(bool newBlackBackgroundSubst) { m_blackBackgroundSubst = newBlackBackgroundSubst; }
|
||||
int LevelOnePage::defaultScreenColour() const
|
||||
{
|
||||
return m_defaultScreenColour;
|
||||
}
|
||||
|
||||
void LevelOnePage::setDefaultScreenColour(int newDefaultScreenColour)
|
||||
{
|
||||
m_defaultScreenColour = newDefaultScreenColour;
|
||||
}
|
||||
|
||||
int LevelOnePage::defaultRowColour() const
|
||||
{
|
||||
return m_defaultRowColour;
|
||||
}
|
||||
|
||||
void LevelOnePage::setDefaultRowColour(int newDefaultRowColour)
|
||||
{
|
||||
m_defaultRowColour = newDefaultRowColour;
|
||||
}
|
||||
|
||||
int LevelOnePage::colourTableRemap() const
|
||||
{
|
||||
return m_colourTableRemap;
|
||||
}
|
||||
|
||||
void LevelOnePage::setColourTableRemap(int newColourTableRemap)
|
||||
{
|
||||
m_colourTableRemap = newColourTableRemap;
|
||||
}
|
||||
|
||||
bool LevelOnePage::blackBackgroundSubst() const
|
||||
{
|
||||
return m_blackBackgroundSubst;
|
||||
}
|
||||
|
||||
void LevelOnePage::setBlackBackgroundSubst(bool newBlackBackgroundSubst)
|
||||
{
|
||||
m_blackBackgroundSubst = newBlackBackgroundSubst;
|
||||
}
|
||||
|
||||
int LevelOnePage::CLUT(int index, int renderLevel) const
|
||||
{
|
||||
@@ -420,7 +507,8 @@ int LevelOnePage::dCLUT(bool globalDrcs, int mode, int index) const
|
||||
|
||||
void LevelOnePage::setDCLUT(bool globalDrcs, int mode, int index, int colour)
|
||||
{
|
||||
const QByteArray defaultPkt = QByteArray("\x01\x00\x00\x00\x20\x20\x18\x00\x02\x22\x01\x08\x08\x06\x24\x22\x39\x20\x12\x2a\x05\x2b\x39\x1e\x20\x20\x18\x10\x0a\x26\x03\x0a\x29\x16\x2c\x26\x3b\x01\x00\x00", 40);
|
||||
// Default DCLUT as per D.1.6 and D.2.2 in the ETSI spec
|
||||
const QByteArray defaultPkt = QByteArrayLiteral("\x01\x00\x00\x00\x20\x20\x18\x00\x02\x22\x01\x08\x08\x06\x24\x22\x39\x20\x12\x2a\x05\x2b\x39\x1e\x20\x20\x18\x10\x0a\x26\x03\x0a\x29\x16\x2c\x26\x3b\x01\x00\x00");
|
||||
|
||||
if (!packetExists(28, 1))
|
||||
setPacket(28, 1, defaultPkt);
|
||||
@@ -552,36 +640,101 @@ int LevelOnePage::levelRequired() const
|
||||
return levelSeen;
|
||||
}
|
||||
|
||||
void LevelOnePage::setLeftSidePanelDisplayed(bool newLeftSidePanelDisplayed) { m_leftSidePanelDisplayed = newLeftSidePanelDisplayed; }
|
||||
void LevelOnePage::setRightSidePanelDisplayed(bool newRightSidePanelDisplayed) { m_rightSidePanelDisplayed = newRightSidePanelDisplayed; }
|
||||
void LevelOnePage::setSidePanelColumns(int newSidePanelColumns) { m_sidePanelColumns = newSidePanelColumns; }
|
||||
void LevelOnePage::setSidePanelStatusL25(bool newSidePanelStatusL25) { m_sidePanelStatusL25 = newSidePanelStatusL25; }
|
||||
bool LevelOnePage::leftSidePanelDisplayed() const
|
||||
{
|
||||
return m_leftSidePanelDisplayed;
|
||||
}
|
||||
|
||||
void LevelOnePage::setLeftSidePanelDisplayed(bool newLeftSidePanelDisplayed)
|
||||
{
|
||||
m_leftSidePanelDisplayed = newLeftSidePanelDisplayed;
|
||||
}
|
||||
|
||||
bool LevelOnePage::rightSidePanelDisplayed() const
|
||||
{
|
||||
return m_rightSidePanelDisplayed;
|
||||
}
|
||||
|
||||
void LevelOnePage::setRightSidePanelDisplayed(bool newRightSidePanelDisplayed)
|
||||
{
|
||||
m_rightSidePanelDisplayed = newRightSidePanelDisplayed;
|
||||
}
|
||||
|
||||
int LevelOnePage::sidePanelColumns() const
|
||||
{
|
||||
return m_sidePanelColumns;
|
||||
}
|
||||
|
||||
void LevelOnePage::setSidePanelColumns(int newSidePanelColumns)
|
||||
{
|
||||
m_sidePanelColumns = newSidePanelColumns;
|
||||
}
|
||||
|
||||
bool LevelOnePage::sidePanelStatusL25() const
|
||||
{
|
||||
return m_sidePanelStatusL25;
|
||||
}
|
||||
|
||||
void LevelOnePage::setSidePanelStatusL25(bool newSidePanelStatusL25)
|
||||
{
|
||||
m_sidePanelStatusL25 = newSidePanelStatusL25;
|
||||
}
|
||||
|
||||
int LevelOnePage::fastTextLinkPageNumber(int linkNumber) const
|
||||
{
|
||||
return m_fastTextLink[linkNumber].pageNumber;
|
||||
}
|
||||
|
||||
void LevelOnePage::setFastTextLinkPageNumber(int linkNumber, int pageNumber)
|
||||
{
|
||||
m_fastTextLink[linkNumber].pageNumber = pageNumber;
|
||||
}
|
||||
|
||||
int LevelOnePage::composeLinkFunction(int linkNumber) const
|
||||
{
|
||||
return m_composeLink[linkNumber].function;
|
||||
}
|
||||
|
||||
void LevelOnePage::setComposeLinkFunction(int linkNumber, int newFunction)
|
||||
{
|
||||
m_composeLink[linkNumber].function = newFunction;
|
||||
}
|
||||
|
||||
bool LevelOnePage::composeLinkLevel2p5(int linkNumber) const
|
||||
{
|
||||
return m_composeLink[linkNumber].level2p5;
|
||||
}
|
||||
|
||||
void LevelOnePage::setComposeLinkLevel2p5(int linkNumber, bool newRequired)
|
||||
{
|
||||
m_composeLink[linkNumber].level2p5 = newRequired;
|
||||
}
|
||||
|
||||
bool LevelOnePage::composeLinkLevel3p5(int linkNumber) const
|
||||
{
|
||||
return m_composeLink[linkNumber].level3p5;
|
||||
}
|
||||
|
||||
void LevelOnePage::setComposeLinkLevel3p5(int linkNumber, bool newRequired)
|
||||
{
|
||||
m_composeLink[linkNumber].level3p5 = newRequired;
|
||||
}
|
||||
|
||||
int LevelOnePage::composeLinkPageNumber(int linkNumber) const
|
||||
{
|
||||
return m_composeLink[linkNumber].pageNumber;
|
||||
}
|
||||
|
||||
void LevelOnePage::setComposeLinkPageNumber(int linkNumber, int newPageNumber)
|
||||
{
|
||||
m_composeLink[linkNumber].pageNumber = newPageNumber;
|
||||
}
|
||||
|
||||
int LevelOnePage::composeLinkSubPageCodes(int linkNumber) const
|
||||
{
|
||||
return m_composeLink[linkNumber].subPageCodes;
|
||||
}
|
||||
|
||||
void LevelOnePage::setComposeLinkSubPageCodes(int linkNumber, int newSubPageCodes)
|
||||
{
|
||||
m_composeLink[linkNumber].subPageCodes = newSubPageCodes;
|
||||
|
||||
@@ -42,9 +42,6 @@ public:
|
||||
LevelOnePage();
|
||||
LevelOnePage(const PageBase &other);
|
||||
|
||||
PageFunctionEnum pageFunction() const override { return PFLevelOnePage; }
|
||||
PacketCodingEnum packetCoding() const override { return Coding7bit; }
|
||||
|
||||
bool isEmpty() const override;
|
||||
|
||||
QByteArray packet(int y, int d) const override;
|
||||
@@ -55,30 +52,30 @@ public:
|
||||
|
||||
void clearPage();
|
||||
|
||||
int maxEnhancements() const override { return 208; };
|
||||
int maxEnhancements() const override;
|
||||
|
||||
/* void setSubPageNumber(int); */
|
||||
int cycleValue() const { return m_cycleValue; };
|
||||
int cycleValue() const;
|
||||
void setCycleValue(int newValue);
|
||||
CycleTypeEnum cycleType() const { return m_cycleType; };
|
||||
CycleTypeEnum cycleType() const;
|
||||
void setCycleType(CycleTypeEnum newType);
|
||||
int defaultCharSet() const { return m_defaultCharSet; }
|
||||
int defaultCharSet() const;
|
||||
void setDefaultCharSet(int newDefaultCharSet);
|
||||
int defaultNOS() const { return m_defaultNOS; }
|
||||
int defaultNOS() const;
|
||||
void setDefaultNOS(int defaultNOS);
|
||||
int secondCharSet() const { return m_secondCharSet; }
|
||||
int secondCharSet() const;
|
||||
void setSecondCharSet(int newSecondCharSet);
|
||||
int secondNOS() const { return m_secondNOS; }
|
||||
int secondNOS() const;
|
||||
void setSecondNOS(int newSecondNOS);
|
||||
unsigned char character(int r, int c) const { return PageX26Base::packetExists(r) ? PageX26Base::packet(r).at(c) : 0x20; }
|
||||
unsigned char character(int r, int c) const;
|
||||
void setCharacter(int r, int c, unsigned char newChar);
|
||||
int defaultScreenColour() const { return m_defaultScreenColour; }
|
||||
int defaultScreenColour() const;
|
||||
void setDefaultScreenColour(int newDefaultScreenColour);
|
||||
int defaultRowColour() const { return m_defaultRowColour; }
|
||||
int defaultRowColour() const;
|
||||
void setDefaultRowColour(int newDefaultRowColour);
|
||||
int colourTableRemap() const { return m_colourTableRemap; }
|
||||
int colourTableRemap() const;
|
||||
void setColourTableRemap(int newColourTableRemap);
|
||||
bool blackBackgroundSubst() const { return m_blackBackgroundSubst; }
|
||||
bool blackBackgroundSubst() const;
|
||||
void setBlackBackgroundSubst(bool newBlackBackgroundSubst);
|
||||
int CLUT(int index, int renderLevel=3) const;
|
||||
void setCLUT(int index, int newColour);
|
||||
@@ -88,25 +85,25 @@ public:
|
||||
int dCLUT(bool globalDrcs, int mode, int index) const;
|
||||
void setDCLUT(bool globalDrcs, int mode, int index, int colour);
|
||||
int levelRequired() const;
|
||||
bool leftSidePanelDisplayed() const { return m_leftSidePanelDisplayed; }
|
||||
bool leftSidePanelDisplayed() const;
|
||||
void setLeftSidePanelDisplayed(bool newLeftSidePanelDisplayed);
|
||||
bool rightSidePanelDisplayed() const { return m_rightSidePanelDisplayed; }
|
||||
bool rightSidePanelDisplayed() const;
|
||||
void setRightSidePanelDisplayed(bool newRightSidePanelDisplayed);
|
||||
int sidePanelColumns() const { return m_sidePanelColumns; }
|
||||
int sidePanelColumns() const;
|
||||
void setSidePanelColumns(int newSidePanelColumns);
|
||||
bool sidePanelStatusL25() const { return m_sidePanelStatusL25; }
|
||||
bool sidePanelStatusL25() const;
|
||||
void setSidePanelStatusL25(bool newSidePanelStatusL25);
|
||||
int fastTextLinkPageNumber(int linkNumber) const { return m_fastTextLink[linkNumber].pageNumber; }
|
||||
int fastTextLinkPageNumber(int linkNumber) const;
|
||||
void setFastTextLinkPageNumber(int linkNumber, int pageNumber);
|
||||
int composeLinkFunction(int linkNumber) const { return m_composeLink[linkNumber].function; }
|
||||
int composeLinkFunction(int linkNumber) const;
|
||||
void setComposeLinkFunction(int linkNumber, int newFunction);
|
||||
bool composeLinkLevel2p5(int linkNumber) const { return m_composeLink[linkNumber].level2p5; }
|
||||
bool composeLinkLevel2p5(int linkNumber) const;
|
||||
void setComposeLinkLevel2p5(int linkNumber, bool newRequired);
|
||||
bool composeLinkLevel3p5(int linkNumber) const { return m_composeLink[linkNumber].level3p5; }
|
||||
bool composeLinkLevel3p5(int linkNumber) const;
|
||||
void setComposeLinkLevel3p5(int linkNumber, bool newRequired);
|
||||
int composeLinkPageNumber(int linkNumber) const { return m_composeLink[linkNumber].pageNumber; }
|
||||
int composeLinkPageNumber(int linkNumber) const;
|
||||
void setComposeLinkPageNumber(int linkNumber, int newPageNumber);
|
||||
int composeLinkSubPageCodes(int linkNumber) const { return m_composeLink[linkNumber].subPageCodes; }
|
||||
int composeLinkSubPageCodes(int linkNumber) const;
|
||||
void setComposeLinkSubPageCodes(int linkNumber, int newSubPageCodes);
|
||||
|
||||
private:
|
||||
|
||||
@@ -27,6 +27,24 @@ PageBase::PageBase()
|
||||
m_controlBits[b] = false;
|
||||
}
|
||||
|
||||
PageBase::PageFunctionEnum PageBase::pageFunction() const
|
||||
{
|
||||
return PFLevelOnePage;
|
||||
}
|
||||
|
||||
PageBase::PacketCodingEnum PageBase::packetCoding() const
|
||||
{
|
||||
return Coding7bit;
|
||||
}
|
||||
|
||||
PageBase::PacketCodingEnum PageBase::packetCoding(int y, int d) const
|
||||
{
|
||||
if (y == 27 && d < 4)
|
||||
return Coding4bit;
|
||||
else
|
||||
return Coding18bit;
|
||||
}
|
||||
|
||||
bool PageBase::isEmpty() const
|
||||
{
|
||||
for (int y=0; y<26; y++)
|
||||
@@ -40,6 +58,16 @@ bool PageBase::isEmpty() const
|
||||
return true;
|
||||
}
|
||||
|
||||
QByteArray PageBase::packet(int y) const
|
||||
{
|
||||
return m_displayPackets[y];
|
||||
}
|
||||
|
||||
QByteArray PageBase::packet(int y, int d) const
|
||||
{
|
||||
return m_designationPackets[y-26][d];
|
||||
}
|
||||
|
||||
bool PageBase::setPacket(int y, QByteArray pkt)
|
||||
{
|
||||
m_displayPackets[y] = pkt;
|
||||
@@ -54,6 +82,16 @@ bool PageBase::setPacket(int y, int d, QByteArray pkt)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PageBase::packetExists(int y) const
|
||||
{
|
||||
return !m_displayPackets[y].isEmpty();
|
||||
}
|
||||
|
||||
bool PageBase::packetExists(int y, int d) const
|
||||
{
|
||||
return !m_designationPackets[y-26][d].isEmpty();
|
||||
}
|
||||
|
||||
bool PageBase::clearPacket(int y)
|
||||
{
|
||||
m_displayPackets[y] = QByteArray();
|
||||
@@ -77,6 +115,11 @@ void PageBase::clearAllPackets()
|
||||
clearPacket(y, d);
|
||||
}
|
||||
|
||||
bool PageBase::controlBit(int b) const
|
||||
{
|
||||
return m_controlBits[b];
|
||||
}
|
||||
|
||||
bool PageBase::setControlBit(int b, bool active)
|
||||
{
|
||||
m_controlBits[b] = active;
|
||||
|
||||
@@ -22,36 +22,34 @@
|
||||
|
||||
#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
|
||||
class PageBase
|
||||
{
|
||||
//Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ControlBitsEnum { C4ErasePage, C5Newsflash, C6Subtitle, C7SuppressHeader, C8Update, C9InterruptedSequence, C10InhibitDisplay, C11SerialMagazine, C12NOS, C13NOS, C14NOS };
|
||||
// Available Page Functions according to 9.4.2.1 of the spec
|
||||
enum PageFunctionEnum { PFUnknown = -1, PFLevelOnePage, PFDataBroadcasting, PFGlobalPOP, PFNormalPOP, PFGlobalDRCS, PFNormalDRCS, PFMOT, PFMIP, PFBasicTOPTable, PFAdditionalInformationTable, PFMultiPageTable, PFMultiPageExtensionTable, PFTriggerMessages };
|
||||
enum PageFunctionEnum { PFLevelOnePage, PFDataBroadcasting, PFGlobalPOP, PFNormalPOP, PFGlobalDRCS, PFNormalDRCS, PFMOT, PFMIP, PFBasicTOPTable, PFAdditionalInformationTable, PFMultiPageTable, PFMultiPageExtensionTable, PFTriggerMessages };
|
||||
// Available Page Codings of X/1 to X/25 according to 9.4.2.1 of the spec
|
||||
enum PacketCodingEnum { CodingUnknown = -1, Coding7bit, Coding8bit, Coding18bit, Coding4bit, Coding4bitThen7bit, CodingPerPacket };
|
||||
enum PacketCodingEnum { Coding7bit, Coding8bit, Coding18bit, Coding4bit, Coding4bitThen7bit, CodingPerPacket };
|
||||
|
||||
PageBase();
|
||||
|
||||
virtual PageFunctionEnum pageFunction() const { return PFUnknown; }
|
||||
virtual PacketCodingEnum packetCoding() const { return CodingUnknown; }
|
||||
virtual PageFunctionEnum pageFunction() const;
|
||||
virtual PacketCodingEnum packetCoding() const;
|
||||
virtual PacketCodingEnum packetCoding(int y, int d) const;
|
||||
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
virtual QByteArray packet(int y) const { return m_displayPackets[y]; }
|
||||
virtual QByteArray packet(int y, int d) const { return m_designationPackets[y-26][d]; }
|
||||
virtual QByteArray packet(int y) const;
|
||||
virtual QByteArray packet(int y, int d) const;
|
||||
virtual bool setPacket(int y, QByteArray pkt);
|
||||
virtual bool setPacket(int y, int d, QByteArray pkt);
|
||||
virtual bool packetExists(int y) const { return !m_displayPackets[y].isEmpty(); }
|
||||
virtual bool packetExists(int y, int d) const { return !m_designationPackets[y-26][d].isEmpty(); }
|
||||
virtual bool packetExists(int y) const;
|
||||
virtual bool packetExists(int y, int d) const;
|
||||
virtual bool clearPacket(int y);
|
||||
virtual bool clearPacket(int y, int d);
|
||||
virtual void clearAllPackets();
|
||||
|
||||
virtual bool controlBit(int b) const { return m_controlBits[b]; }
|
||||
virtual bool controlBit(int b) const;
|
||||
virtual bool setControlBit(int b, bool active);
|
||||
|
||||
private:
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
|
||||
#include "pagex26base.h"
|
||||
|
||||
X26TripletList *PageX26Base::enhancements()
|
||||
{
|
||||
return &m_enhancements;
|
||||
}
|
||||
|
||||
QByteArray PageX26Base::packetFromEnhancementList(int p) const
|
||||
{
|
||||
QByteArray result(40, 0x00);
|
||||
@@ -31,9 +36,13 @@ QByteArray PageX26Base::packetFromEnhancementList(int p) const
|
||||
const int enhanceListPointer = p*13+t;
|
||||
|
||||
if (enhanceListPointer < m_enhancements.size()) {
|
||||
if (!m_enhancements.at(enhanceListPointer).isValid())
|
||||
result[t*3+1] = result[t*3+2] = result[t*3+3] = 0xff;
|
||||
else {
|
||||
result[t*3+1] = m_enhancements.at(enhanceListPointer).address();
|
||||
result[t*3+2] = m_enhancements.at(enhanceListPointer).mode() | ((m_enhancements.at(enhanceListPointer).data() & 1) << 5);
|
||||
result[t*3+3] = m_enhancements.at(enhanceListPointer).data() >> 1;
|
||||
}
|
||||
|
||||
// If this is the last triplet, get a copy to repeat to the end of the packet
|
||||
if (enhanceListPointer == m_enhancements.size()-1) {
|
||||
@@ -59,19 +68,24 @@ QByteArray PageX26Base::packetFromEnhancementList(int p) const
|
||||
void PageX26Base::setEnhancementListFromPacket(int p, QByteArray pkt)
|
||||
{
|
||||
// Preallocate entries in the m_enhancements list to hold our incoming triplets.
|
||||
// We write "dummy" reserved 11110 Row Triplets in the allocated entries which then get overwritten by the packet contents.
|
||||
// We write invalid triplets in the allocated entries which then get overwritten by the packet contents.
|
||||
// This is in case of missing packets so we can keep Local Object pointers valid.
|
||||
while (m_enhancements.size() < (p+1)*13)
|
||||
m_enhancements.append( X26Triplet{ 41, 0x1e, 0 } );
|
||||
m_enhancements.append( X26Triplet{ 0xff, 0xff, 0xff } );
|
||||
|
||||
X26Triplet newX26Triplet;
|
||||
|
||||
for (int t=0; t<13; t++) {
|
||||
const int enhanceListPointer = p*13+t;
|
||||
|
||||
// Need the "& 0xff" since QByteArray.at() returns (signed) chars
|
||||
if ((pkt.at(t*3+2) & 0xff) == 0xff)
|
||||
newX26Triplet.setInvalid();
|
||||
else {
|
||||
newX26Triplet.setAddress(pkt.at(t*3+1) & 0x3f);
|
||||
newX26Triplet.setMode(pkt.at(t*3+2) & 0x1f);
|
||||
newX26Triplet.setData(((pkt.at(t*3+3) & 0x3f) << 1) | ((pkt.at(t*3+2) & 0x20) >> 5));
|
||||
}
|
||||
m_enhancements.replace(enhanceListPointer, newX26Triplet);
|
||||
}
|
||||
if (newX26Triplet.mode() == 0x1f && newX26Triplet.address() == 0x3f && newX26Triplet.data() & 0x01)
|
||||
@@ -79,3 +93,8 @@ void PageX26Base::setEnhancementListFromPacket(int p, QByteArray pkt)
|
||||
while (m_enhancements.size()>1 && m_enhancements.at(m_enhancements.size()-2).mode() == 0x1f && m_enhancements.at(m_enhancements.size()-2).address() == 0x3f && m_enhancements.at(m_enhancements.size()-2).data() == newX26Triplet.data())
|
||||
m_enhancements.removeLast();
|
||||
}
|
||||
|
||||
bool PageX26Base::packetFromEnhancementListNeeded(int n) const
|
||||
{
|
||||
return ((m_enhancements.size()+12) / 13) > n;
|
||||
}
|
||||
|
||||
@@ -26,18 +26,16 @@
|
||||
#include "pagebase.h"
|
||||
#include "x26triplets.h"
|
||||
|
||||
class PageX26Base : public PageBase //: public QObject
|
||||
class PageX26Base : public PageBase
|
||||
{
|
||||
//Q_OBJECT
|
||||
|
||||
public:
|
||||
X26TripletList *enhancements() { return &m_enhancements; };
|
||||
X26TripletList *enhancements();
|
||||
virtual int maxEnhancements() const =0;
|
||||
|
||||
protected:
|
||||
QByteArray packetFromEnhancementList(int p) const;
|
||||
void setEnhancementListFromPacket(int p, QByteArray pkt);
|
||||
bool packetFromEnhancementListNeeded(int n) const { return ((m_enhancements.size()+12) / 13) > n; };
|
||||
bool packetFromEnhancementListNeeded(int n) const;
|
||||
|
||||
X26TripletList m_enhancements;
|
||||
};
|
||||
|
||||
@@ -26,6 +26,51 @@ X26Triplet::X26Triplet(int address, int mode, int data)
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
bool X26Triplet::isValid() const
|
||||
{
|
||||
return m_mode != 0xff;
|
||||
}
|
||||
|
||||
int X26Triplet::address() const
|
||||
{
|
||||
return m_address;
|
||||
}
|
||||
|
||||
int X26Triplet::mode() const
|
||||
{
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
int X26Triplet::modeExt() const
|
||||
{
|
||||
return (m_address >= 40) ? m_mode : (m_mode | 0x20);
|
||||
}
|
||||
|
||||
int X26Triplet::data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
int X26Triplet::addressRow() const
|
||||
{
|
||||
return (m_address == 40) ? 24 :m_address-40;
|
||||
}
|
||||
|
||||
int X26Triplet::addressColumn() const
|
||||
{
|
||||
return (m_address);
|
||||
}
|
||||
|
||||
bool X26Triplet::isRowTriplet() const
|
||||
{
|
||||
return (m_address >= 40);
|
||||
}
|
||||
|
||||
void X26Triplet::setInvalid()
|
||||
{
|
||||
m_address = m_mode = m_data = 0xff;
|
||||
}
|
||||
|
||||
void X26Triplet::setAddress(int address)
|
||||
{
|
||||
m_address = address;
|
||||
@@ -51,6 +96,26 @@ void X26Triplet::setAddressColumn(int addressColumn)
|
||||
m_address = addressColumn;
|
||||
}
|
||||
|
||||
int X26Triplet::objectSource() const
|
||||
{
|
||||
return (m_address & 0x18) >> 3;
|
||||
}
|
||||
|
||||
int X26Triplet::objectLocalDesignationCode() const
|
||||
{
|
||||
return (((m_address & 0x01) << 3) | (m_data >> 4));
|
||||
}
|
||||
|
||||
int X26Triplet::objectLocalTripletNumber() const
|
||||
{
|
||||
return m_data & 0x0f;
|
||||
}
|
||||
|
||||
int X26Triplet::objectLocalIndex() const
|
||||
{
|
||||
return objectLocalDesignationCode() * 13 + objectLocalTripletNumber();
|
||||
}
|
||||
|
||||
void X26Triplet::setObjectLocalDesignationCode(int i)
|
||||
{
|
||||
m_address = (m_address & 0x38) | (i >> 3);
|
||||
@@ -68,6 +133,46 @@ void X26Triplet::setObjectLocalIndex(int i)
|
||||
m_data = (((i / 13) & 0x07) << 4) | (i % 13);
|
||||
}
|
||||
|
||||
int X26Triplet::activePositionRow() const
|
||||
{
|
||||
return m_activePositionRow;
|
||||
}
|
||||
|
||||
int X26Triplet::activePositionColumn() const
|
||||
{
|
||||
return m_activePositionColumn;
|
||||
}
|
||||
|
||||
int X26Triplet::activePositionRow1p5() const
|
||||
{
|
||||
return m_activePositionRow1p5;
|
||||
}
|
||||
|
||||
int X26Triplet::activePositionColumn1p5() const
|
||||
{
|
||||
return m_activePositionColumn1p5;
|
||||
}
|
||||
|
||||
X26Triplet::X26TripletError X26Triplet::error() const
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
bool X26Triplet::reservedMode() const
|
||||
{
|
||||
return m_reservedMode;
|
||||
}
|
||||
|
||||
bool X26Triplet::reservedData() const
|
||||
{
|
||||
return m_reservedData;
|
||||
}
|
||||
|
||||
bool X26Triplet::activePosition1p5Differs() const
|
||||
{
|
||||
return m_activePosition1p5Differs;
|
||||
}
|
||||
|
||||
|
||||
void X26TripletList::updateInternalData()
|
||||
{
|
||||
@@ -85,7 +190,9 @@ void X26TripletList::updateInternalData()
|
||||
triplet->m_reservedMode = false;
|
||||
triplet->m_reservedData = false;
|
||||
|
||||
if (triplet->isRowTriplet()) {
|
||||
if (!triplet->isValid())
|
||||
triplet->m_error = X26Triplet::ErrorDecodingTriplet;
|
||||
else if (triplet->isRowTriplet()) {
|
||||
switch (triplet->modeExt()) {
|
||||
case 0x00: // Full screen colour
|
||||
if (activePosition.isDeployed())
|
||||
@@ -282,6 +389,35 @@ void X26TripletList::replace(int i, const X26Triplet &value)
|
||||
updateInternalData();
|
||||
}
|
||||
|
||||
void X26TripletList::removeLast()
|
||||
{
|
||||
m_list.removeLast();
|
||||
}
|
||||
|
||||
const X26Triplet &X26TripletList::at(int i) const
|
||||
{
|
||||
return m_list.at(i);
|
||||
}
|
||||
|
||||
bool X26TripletList::isEmpty() const
|
||||
{
|
||||
return m_list.isEmpty();
|
||||
}
|
||||
|
||||
void X26TripletList::reserve(int alloc)
|
||||
{
|
||||
m_list.reserve(alloc);
|
||||
}
|
||||
|
||||
int X26TripletList::size() const
|
||||
{
|
||||
return m_list.size();
|
||||
}
|
||||
|
||||
const QList<int> &X26TripletList::objects(int t) const
|
||||
{
|
||||
return m_objects[t];
|
||||
};
|
||||
|
||||
X26TripletList::ActivePosition::ActivePosition()
|
||||
{
|
||||
@@ -293,6 +429,21 @@ void X26TripletList::ActivePosition::reset()
|
||||
m_row = m_column = -1;
|
||||
}
|
||||
|
||||
int X26TripletList::ActivePosition::row() const
|
||||
{
|
||||
return m_row; // return (m_row == -1) ? 0 : m_row;
|
||||
}
|
||||
|
||||
int X26TripletList::ActivePosition::column() const
|
||||
{
|
||||
return m_column; // return (m_column == -1) ? 0 : m_column;
|
||||
}
|
||||
|
||||
bool X26TripletList::ActivePosition::isDeployed() const
|
||||
{
|
||||
return m_row != -1;
|
||||
}
|
||||
|
||||
bool X26TripletList::ActivePosition::setRow(int row)
|
||||
{
|
||||
if (row < m_row)
|
||||
|
||||
@@ -26,7 +26,7 @@ class X26Triplet
|
||||
{
|
||||
public:
|
||||
// x26model.h has the Plain English descriptions of these errors
|
||||
enum X26TripletError { NoError, ActivePositionMovedUp, ActivePositionMovedLeft, InvokePointerInvalid, InvokeTypeMismatch, OriginModifierAlone };
|
||||
enum X26TripletError { NoError, ErrorDecodingTriplet, ActivePositionMovedUp, ActivePositionMovedLeft, InvokePointerInvalid, InvokeTypeMismatch, OriginModifierAlone };
|
||||
enum ObjectSource { InvalidObjectSource, LocalObject, POPObject, GPOPObject };
|
||||
|
||||
X26Triplet() {}
|
||||
@@ -36,37 +36,39 @@ public:
|
||||
|
||||
X26Triplet(int address, int mode, int data);
|
||||
|
||||
int address() const { return m_address; }
|
||||
int mode() const { return m_mode; }
|
||||
int modeExt() const { return (m_address >= 40) ? m_mode : (m_mode | 0x20); }
|
||||
int data() const { return m_data; }
|
||||
int addressRow() const { return (m_address == 40) ? 24 :m_address-40; }
|
||||
int addressColumn() const { return (m_address); }
|
||||
bool isRowTriplet() const { return (m_address >= 40); }
|
||||
bool isValid() const;
|
||||
int address() const;
|
||||
int mode() const;
|
||||
int modeExt() const;
|
||||
int data() const;
|
||||
int addressRow() const;
|
||||
int addressColumn() const;
|
||||
bool isRowTriplet() const;
|
||||
|
||||
void setInvalid();
|
||||
void setAddress(int address);
|
||||
void setMode(int mode);
|
||||
void setData(int data);
|
||||
void setAddressRow(int addressRow);
|
||||
void setAddressColumn(int addressColumn);
|
||||
|
||||
int objectSource() const { return (m_address & 0x18) >> 3; }
|
||||
int objectSource() const;
|
||||
|
||||
int objectLocalDesignationCode() const { return (((m_address & 0x01) << 3) | (m_data >> 4)); }
|
||||
int objectLocalTripletNumber() const { return m_data & 0x0f; }
|
||||
int objectLocalIndex() const { return objectLocalDesignationCode() * 13 + objectLocalTripletNumber(); }
|
||||
int objectLocalDesignationCode() const;
|
||||
int objectLocalTripletNumber() const;
|
||||
int objectLocalIndex() const;
|
||||
void setObjectLocalDesignationCode(int i);
|
||||
void setObjectLocalTripletNumber(int i);
|
||||
void setObjectLocalIndex(int i);
|
||||
|
||||
int activePositionRow() const { return m_activePositionRow; }
|
||||
int activePositionColumn() const { return m_activePositionColumn; }
|
||||
int activePositionRow1p5() const { return m_activePositionRow1p5; }
|
||||
int activePositionColumn1p5() const { return m_activePositionColumn1p5; }
|
||||
X26TripletError error() const { return m_error; }
|
||||
bool reservedMode() const { return m_reservedMode; }
|
||||
bool reservedData() const { return m_reservedData; }
|
||||
bool activePosition1p5Differs() const { return m_activePosition1p5Differs; }
|
||||
int activePositionRow() const;
|
||||
int activePositionColumn() const;
|
||||
int activePositionRow1p5() const;
|
||||
int activePositionColumn1p5() const;
|
||||
X26TripletError error() const;
|
||||
bool reservedMode() const;
|
||||
bool reservedData() const;
|
||||
bool activePosition1p5Differs() const;
|
||||
|
||||
friend class X26TripletList;
|
||||
|
||||
@@ -91,14 +93,13 @@ public:
|
||||
void insert(int i, const X26Triplet &value);
|
||||
void removeAt(int i);
|
||||
void replace(int i, const X26Triplet &value);
|
||||
void removeLast();
|
||||
const X26Triplet &at(int i) const;
|
||||
bool isEmpty() const;
|
||||
void reserve(int alloc);
|
||||
int size() const;
|
||||
|
||||
void removeLast() { m_list.removeLast(); }
|
||||
|
||||
const X26Triplet &at(int i) const { return m_list.at(i); }
|
||||
bool isEmpty() const { return m_list.isEmpty(); }
|
||||
void reserve(int alloc) { m_list.reserve(alloc); }
|
||||
int size() const { return m_list.size(); }
|
||||
const QList<int> &objects(int t) const { return m_objects[t]; };
|
||||
const QList<int> &objects(int t) const;
|
||||
|
||||
private:
|
||||
void updateInternalData();
|
||||
@@ -111,11 +112,9 @@ private:
|
||||
public:
|
||||
ActivePosition();
|
||||
void reset();
|
||||
// int row() const { return (m_row == -1) ? 0 : m_row; }
|
||||
// int column() const { return (m_column == -1) ? 0 : m_column; }
|
||||
int row() const { return m_row; }
|
||||
int column() const { return m_column; }
|
||||
bool isDeployed() const { return m_row != -1; }
|
||||
int row() const;
|
||||
int column() const;
|
||||
bool isDeployed() const;
|
||||
bool setRow(int);
|
||||
bool setColumn(int);
|
||||
// bool setRowAndColumn(int, int);
|
||||
|
||||
@@ -139,11 +139,11 @@ bool LoadTTIFormat::load(QFile *inFile, QList<PageBase>& subPages, QVariantHash
|
||||
fastTextPacket[i*6+2] = (fastTextLinkRead & 0x0f0) >> 4;
|
||||
fastTextPacket[i*6+4] = 0x7 | ((fastTextLinkRead & 0x100) >> 5);
|
||||
fastTextPacket[i*6+6] = 0x3 | ((fastTextLinkRead & 0x600) >> 7);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
loadingPage->setPacket(27, 0, fastTextPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata != nullptr)
|
||||
metadata->insert(QString("fastextAbsolute"), true);
|
||||
}
|
||||
@@ -227,6 +227,9 @@ bool LoadT42Format::load(QFile *inFile, QList<PageBase>& subPages, QVariantHash
|
||||
int foundPageNumber = -1;
|
||||
bool firstPacket0Found = false;
|
||||
bool pageBodyPacketsFound = false;
|
||||
bool errorEnhancements = false;
|
||||
bool errorLinks = false;
|
||||
bool errorPresentation = false;
|
||||
|
||||
m_inFile = inFile;
|
||||
|
||||
@@ -374,6 +377,7 @@ bool LoadT42Format::load(QFile *inFile, QList<PageBase>& subPages, QVariantHash
|
||||
// Error found in at least one byte of the link
|
||||
// Neutralise the whole link to same magazine, page FF, subcode 3F7F
|
||||
qDebug("X/27/%d link %d decoding error", readDesignationCode, i);
|
||||
errorLinks = true;
|
||||
m_inLine[b] = 0xf;
|
||||
m_inLine[b+1] = 0xf;
|
||||
m_inLine[b+2] = 0xf;
|
||||
@@ -416,15 +420,17 @@ bool LoadT42Format::load(QFile *inFile, QList<PageBase>& subPages, QVariantHash
|
||||
// Error decoding Hamming 24/18
|
||||
qDebug("X/%d/%d triplet %d decoding error", readPacketNumber, readDesignationCode, i);
|
||||
if (readPacketNumber == 26) {
|
||||
// Enhancements packet, set to "dummy" Address 41, Mode 0x1e, Data 0
|
||||
m_inLine[b] = 41;
|
||||
m_inLine[b+1] = 0x1e;
|
||||
m_inLine[b+2] = 0;
|
||||
// Enhancements packet, set to invalid triplet
|
||||
m_inLine[b] = 0xff;
|
||||
m_inLine[b+1] = 0xff;
|
||||
m_inLine[b+2] = 0xff;
|
||||
errorEnhancements = true;
|
||||
} else {
|
||||
// Zero out whole decoded triplet, bound to make things go wrong...
|
||||
m_inLine[b] = 0x00;
|
||||
m_inLine[b+1] = 0x00;
|
||||
m_inLine[b+2] = 0x00;
|
||||
errorPresentation = true;
|
||||
}
|
||||
} else {
|
||||
m_inLine[b] = d & 0x0003f;
|
||||
@@ -441,7 +447,14 @@ bool LoadT42Format::load(QFile *inFile, QList<PageBase>& subPages, QVariantHash
|
||||
} else if (!pageBodyPacketsFound) {
|
||||
m_error = "X/0 found, but no page body packets were found.";
|
||||
return false;
|
||||
} else
|
||||
}
|
||||
|
||||
if (errorEnhancements)
|
||||
m_warnings.append("Error decoding triplet(s) in enhancement data.");
|
||||
if (errorLinks)
|
||||
m_warnings.append("Error decoding FLOF links.");
|
||||
if (errorPresentation)
|
||||
m_warnings.append("Error decoding triplet(s) in presentation data.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ int main(int argc, char *argv[])
|
||||
QApplication::setApplicationDisplayName(QApplication::applicationName());
|
||||
QApplication::setOrganizationName("gkmac.co.uk");
|
||||
QApplication::setOrganizationDomain("gkmac.co.uk");
|
||||
QApplication::setApplicationVersion("0.8-beta");
|
||||
QApplication::setApplicationVersion("0.8.2-beta");
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QApplication::applicationName());
|
||||
parser.addHelpOption();
|
||||
|
||||
@@ -539,6 +539,11 @@ void TeletextWidget::paste()
|
||||
m_teletextDocument->undoStack()->push(new PasteCommand(m_teletextDocument, m_pageDecode.level1CharSet(m_teletextDocument->cursorRow(), m_teletextDocument->cursorColumn())));
|
||||
}
|
||||
|
||||
void TeletextWidget::selectAll()
|
||||
{
|
||||
m_teletextDocument->setSelection((int)!m_teletextDocument->rowZeroAllowed(), 0, 24, 39);
|
||||
}
|
||||
|
||||
QPair<int, int> TeletextWidget::mouseToRowAndColumn(const QPoint &mousePosition)
|
||||
{
|
||||
int row = mousePosition.y() / 10;
|
||||
|
||||
@@ -82,6 +82,8 @@ public slots:
|
||||
void copy();
|
||||
void paste();
|
||||
|
||||
void selectAll();
|
||||
|
||||
void changeSize();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -191,6 +191,9 @@ void MainWindow::extractImages(QImage sceneImage[], bool smooth, bool flashExtra
|
||||
// Prepare widget image for extraction
|
||||
m_textScene->hideGUIElements(true);
|
||||
|
||||
if (m_textWidget->pageRender()->renderMode() == TeletextPageRender::RenderMix)
|
||||
m_textScene->setBackgroundBrush(Qt::NoBrush);
|
||||
|
||||
const int flashTiming = flashExtract ? m_textWidget->flashTiming() : 0;
|
||||
|
||||
// Allocate initial image, with additional images for flashing if necessary
|
||||
@@ -221,6 +224,9 @@ void MainWindow::extractImages(QImage sceneImage[], bool smooth, bool flashExtra
|
||||
}
|
||||
|
||||
// Now we've extracted the image we can put the GUI things back
|
||||
if (m_textWidget->pageRender()->renderMode() == TeletextPageRender::RenderMix)
|
||||
m_textScene->setBackgroundBrush(QColor(40, 54, 96));
|
||||
|
||||
m_textScene->hideGUIElements(false);
|
||||
m_textWidget->resumeFlash();
|
||||
|
||||
@@ -397,16 +403,66 @@ void MainWindow::init()
|
||||
createActions();
|
||||
createStatusBar();
|
||||
|
||||
readSettings();
|
||||
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
|
||||
const int settingsSchema = settings.value("schema", 1).toInt();
|
||||
|
||||
// Don't restore geometry/states from pre 0.8.1 versions: they had a bug which sometimes squashed the
|
||||
// page view unusably small and forgetting the layout could be the only way out of it
|
||||
const QByteArray geometry = settingsSchema >= 2 ? settings.value("geometry", QByteArray()).toByteArray() : QByteArray();
|
||||
const QByteArray windowState = settingsSchema >= 2 ? settings.value("windowState", QByteArray()).toByteArray() : QByteArray();
|
||||
|
||||
m_viewBorder = settings.value("border", 1).toInt();
|
||||
m_viewBorder = (m_viewBorder < 0 || m_viewBorder > 2) ? 1 : m_viewBorder;
|
||||
m_borderActs[m_viewBorder]->setChecked(true);
|
||||
m_viewAspectRatio = settings.value("aspectratio", 0).toInt();
|
||||
m_viewAspectRatio = (m_viewAspectRatio < 0 || m_viewAspectRatio > 3) ? 0 : m_viewAspectRatio;
|
||||
m_aspectRatioActs[m_viewAspectRatio]->setChecked(true);
|
||||
m_viewSmoothTransform = settings.value("smoothTransform", 0).toBool();
|
||||
m_smoothTransformAction->blockSignals(true);
|
||||
m_smoothTransformAction->setChecked(m_viewSmoothTransform);
|
||||
m_smoothTransformAction->blockSignals(false);
|
||||
int zoomSliderInit = settings.value("zoom", 2).toInt();
|
||||
zoomSliderInit = (zoomSliderInit < 0 || zoomSliderInit > 8) ? 2 : zoomSliderInit;
|
||||
|
||||
m_textView = new QGraphicsView(this);
|
||||
m_textView->setScene(m_textScene);
|
||||
if (m_viewSmoothTransform)
|
||||
m_textView->setRenderHints(QPainter::SmoothPixmapTransform);
|
||||
m_zoomSlider->setValue(m_viewZoom);
|
||||
m_zoomSlider->setValue(zoomSliderInit);
|
||||
setSceneDimensions();
|
||||
setCentralWidget(m_textView);
|
||||
|
||||
// zoom 0 = 430,385px, 1 = 500,530px, 2 = 650,670px
|
||||
if (geometry.isEmpty()) {
|
||||
const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
|
||||
if (availableGeometry.width() < 500 || availableGeometry.height() < 530) {
|
||||
resize(430, 385);
|
||||
m_viewZoom = 0;
|
||||
} else if (availableGeometry.width() < 650 || availableGeometry.height() < 670) {
|
||||
resize(500, 530);
|
||||
m_viewZoom = 1;
|
||||
} else
|
||||
resize(650, 670);
|
||||
// m_viewZoom = 2;
|
||||
move((availableGeometry.width() - width()) / 2, (availableGeometry.height() - height()) / 2);
|
||||
} else
|
||||
restoreGeometry(geometry);
|
||||
if (windowState.isEmpty()) {
|
||||
m_pageOptionsDockWidget->hide();
|
||||
m_pageOptionsDockWidget->setFloating(true);
|
||||
m_pageEnhancementsDockWidget->hide();
|
||||
m_pageEnhancementsDockWidget->setFloating(true);
|
||||
m_x26DockWidget->hide();
|
||||
m_x26DockWidget->setFloating(true);
|
||||
m_paletteDockWidget->hide();
|
||||
m_paletteDockWidget->setFloating(true);
|
||||
m_dClutDockWidget->hide();
|
||||
m_dClutDockWidget->setFloating(true);
|
||||
m_pageComposeLinksDockWidget->hide();
|
||||
m_pageComposeLinksDockWidget->setFloating(true);
|
||||
} else
|
||||
restoreState(windowState);
|
||||
|
||||
connect(m_textWidget->document(), &TeletextDocument::cursorMoved, this, &MainWindow::updateCursorPosition);
|
||||
connect(m_textWidget->document(), &TeletextDocument::selectionMoved, m_textScene, &LevelOneScene::updateSelection);
|
||||
connect(m_textWidget->document()->undoStack(), &QUndoStack::cleanChanged, this, [=]() { setWindowModified(!m_textWidget->document()->undoStack()->isClean()); } );
|
||||
@@ -452,6 +508,8 @@ void MainWindow::createActions()
|
||||
QToolBar *fileToolBar = addToolBar(tr("File"));
|
||||
fileToolBar->setObjectName("fileToolBar");
|
||||
|
||||
connect(fileMenu, &QMenu::aboutToShow, this, &MainWindow::updateRecentFileActions);
|
||||
|
||||
const QIcon newIcon = QIcon::fromTheme("document-new", QIcon(":/images/new.png"));
|
||||
QAction *newAct = new QAction(newIcon, tr("&New"), this);
|
||||
newAct->setShortcuts(QKeySequence::New);
|
||||
@@ -468,6 +526,18 @@ void MainWindow::createActions()
|
||||
fileMenu->addAction(openAct);
|
||||
fileToolBar->addAction(openAct);
|
||||
|
||||
const QIcon recentIcon = QIcon::fromTheme("document-open-recent");
|
||||
QMenu *recentMenu = fileMenu->addMenu(recentIcon, tr("Open recent"));
|
||||
m_recentFileSubMenuAct = recentMenu->menuAction();
|
||||
|
||||
for (int i = 0; i < m_MaxRecentFiles; ++i) {
|
||||
m_recentFileActs[i] = recentMenu->addAction(QString(), this, &MainWindow::openRecentFile);
|
||||
m_recentFileActs[i]->setVisible(false);
|
||||
}
|
||||
recentMenu->addSeparator();
|
||||
const QIcon clearRecentIcon = QIcon::fromTheme("edit-clear-history");
|
||||
recentMenu->addAction(clearRecentIcon, tr("Clear list"), this, &MainWindow::clearRecentFiles);
|
||||
|
||||
const QIcon saveIcon = QIcon::fromTheme("document-save", QIcon(":/images/save.png"));
|
||||
QAction *saveAct = new QAction(saveIcon, tr("&Save"), this);
|
||||
saveAct->setShortcuts(QKeySequence::Save);
|
||||
@@ -488,19 +558,6 @@ void MainWindow::createActions()
|
||||
|
||||
fileMenu->addSeparator();
|
||||
|
||||
QMenu *recentMenu = fileMenu->addMenu(tr("Recent"));
|
||||
connect(recentMenu, &QMenu::aboutToShow, this, &MainWindow::updateRecentFileActions);
|
||||
m_recentFileSubMenuAct = recentMenu->menuAction();
|
||||
|
||||
for (int i = 0; i < m_MaxRecentFiles; ++i) {
|
||||
m_recentFileActs[i] = recentMenu->addAction(QString(), this, &MainWindow::openRecentFile);
|
||||
m_recentFileActs[i]->setVisible(false);
|
||||
}
|
||||
|
||||
m_recentFileSeparator = fileMenu->addSeparator();
|
||||
|
||||
setRecentFilesVisible(MainWindow::hasRecentFiles());
|
||||
|
||||
m_exportAutoAct = fileMenu->addAction(tr("Export subpage..."));
|
||||
m_exportAutoAct->setEnabled(false);
|
||||
m_exportAutoAct->setShortcut(tr("Ctrl+E"));
|
||||
@@ -586,6 +643,13 @@ void MainWindow::createActions()
|
||||
editMenu->addAction(pasteAct);
|
||||
editToolBar->addAction(pasteAct);
|
||||
|
||||
const QIcon selectAllIcon = QIcon::fromTheme("edit-select-all");
|
||||
QAction *selectAllAct = new QAction(selectAllIcon, tr("Select &all"), this);
|
||||
selectAllAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_A));
|
||||
selectAllAct->setStatusTip(tr("Select the whole subpage"));
|
||||
connect(selectAllAct, &QAction::triggered, m_textWidget, &TeletextWidget::selectAll);
|
||||
editMenu->addAction(selectAllAct);
|
||||
|
||||
QAction *copyImageAct = editMenu->addAction(tr("Copy as image"));
|
||||
copyImageAct->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C));
|
||||
copyImageAct->setStatusTip(tr("Copy this subpage as an image to the clipboard"));
|
||||
@@ -773,16 +837,23 @@ void MainWindow::createActions()
|
||||
QMenu *alphaColourSubMenu = insertMenu->addMenu(tr("Alphanumeric colour"));
|
||||
QMenu *mosaicColourSubMenu = insertMenu->addMenu(tr("Mosaic colour"));
|
||||
for (int i=0; i<=7; i++) {
|
||||
const char *colours[] = { "Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White" };
|
||||
const char *colourNames[] = { "Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White" };
|
||||
const QChar azertyKeys[] = { 'P', 'A', 'Z', 'E', 'R', 'T', 'Y', 'U' };
|
||||
|
||||
QAction *alphaColour = alphaColourSubMenu->addAction(tr(colours[i]));
|
||||
alphaColour->setShortcut(QKeySequence(QString("Esc, %1").arg(i)));
|
||||
alphaColour->setStatusTip(QString("Insert alphanumeric %1 attribute").arg(QString(colours[i]).toLower()));
|
||||
QAction *alphaColour = alphaColourSubMenu->addAction(tr(colourNames[i]));
|
||||
alphaColour->setShortcuts(QList<QKeySequence> {
|
||||
QKeySequence(QString("Esc, %1").arg(i)),
|
||||
QKeySequence(QString("Esc, %1").arg(azertyKeys[i]))
|
||||
} );
|
||||
alphaColour->setStatusTip(QString("Insert alphanumeric %1 attribute").arg(QString(colourNames[i]).toLower()));
|
||||
connect(alphaColour, &QAction::triggered, [=]() { m_textWidget->setCharacter(i); });
|
||||
|
||||
QAction *mosaicColour = mosaicColourSubMenu->addAction(tr(colours[i]));
|
||||
mosaicColour->setShortcut(QKeySequence(QString("Esc, Shift+%1").arg(i)));
|
||||
mosaicColour->setStatusTip(QString("Insert mosaic %1 attribute").arg(QString(colours[i]).toLower()));
|
||||
QAction *mosaicColour = mosaicColourSubMenu->addAction(tr(colourNames[i]));
|
||||
mosaicColour->setShortcuts(QList<QKeySequence> {
|
||||
QKeySequence(QString("Esc, Shift+%1").arg(i)),
|
||||
QKeySequence(QString("Esc, Shift+%1").arg(azertyKeys[i]))
|
||||
} );
|
||||
mosaicColour->setStatusTip(QString("Insert mosaic %1 attribute").arg(QString(colourNames[i]).toLower()));
|
||||
connect(mosaicColour, &QAction::triggered, [=]() { m_textWidget->setCharacter(i+0x10); });
|
||||
}
|
||||
|
||||
@@ -1173,67 +1244,16 @@ void MainWindow::createStatusBar()
|
||||
connect(m_levelRadioButton[3], &QAbstractButton::clicked, [=]() { m_textWidget->pageDecode()->setLevel(3); m_textWidget->update(); m_paletteDockWidget->setLevel3p5Accepted(true);});
|
||||
}
|
||||
|
||||
void MainWindow::readSettings()
|
||||
{
|
||||
//TODO window sizing
|
||||
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
|
||||
const QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray();
|
||||
const QByteArray windowState = settings.value("windowState", QByteArray()).toByteArray();
|
||||
|
||||
m_viewBorder = settings.value("border", 1).toInt();
|
||||
m_viewBorder = (m_viewBorder < 0 || m_viewBorder > 2) ? 1 : m_viewBorder;
|
||||
m_borderActs[m_viewBorder]->setChecked(true);
|
||||
m_viewAspectRatio = settings.value("aspectratio", 0).toInt();
|
||||
m_viewAspectRatio = (m_viewAspectRatio < 0 || m_viewAspectRatio > 3) ? 0 : m_viewAspectRatio;
|
||||
m_aspectRatioActs[m_viewAspectRatio]->setChecked(true);
|
||||
m_viewSmoothTransform = settings.value("smoothTransform", 0).toBool();
|
||||
m_smoothTransformAction->blockSignals(true);
|
||||
m_smoothTransformAction->setChecked(m_viewSmoothTransform);
|
||||
m_smoothTransformAction->blockSignals(false);
|
||||
m_viewZoom = settings.value("zoom", 2).toInt();
|
||||
m_viewZoom = (m_viewZoom < 0 || m_viewZoom > 12) ? 2 : m_viewZoom;
|
||||
|
||||
// zoom 0 = 430,385px, 1 = 500,530px, 2 = 650,670px
|
||||
if (geometry.isEmpty()) {
|
||||
const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
|
||||
if (availableGeometry.width() < 500 || availableGeometry.height() < 530) {
|
||||
resize(430, 385);
|
||||
m_viewZoom = 0;
|
||||
} else if (availableGeometry.width() < 650 || availableGeometry.height() < 670) {
|
||||
resize(500, 530);
|
||||
m_viewZoom = 1;
|
||||
} else
|
||||
resize(650, 670);
|
||||
// m_viewZoom = 2;
|
||||
move((availableGeometry.width() - width()) / 2, (availableGeometry.height() - height()) / 2);
|
||||
} else
|
||||
restoreGeometry(geometry);
|
||||
if (windowState.isEmpty()) {
|
||||
m_pageOptionsDockWidget->hide();
|
||||
m_pageOptionsDockWidget->setFloating(true);
|
||||
m_pageEnhancementsDockWidget->hide();
|
||||
m_pageEnhancementsDockWidget->setFloating(true);
|
||||
m_x26DockWidget->hide();
|
||||
m_x26DockWidget->setFloating(true);
|
||||
m_paletteDockWidget->hide();
|
||||
m_paletteDockWidget->setFloating(true);
|
||||
m_dClutDockWidget->hide();
|
||||
m_dClutDockWidget->setFloating(true);
|
||||
m_pageComposeLinksDockWidget->hide();
|
||||
m_pageComposeLinksDockWidget->setFloating(true);
|
||||
} else
|
||||
restoreState(windowState);
|
||||
}
|
||||
|
||||
void MainWindow::writeSettings()
|
||||
{
|
||||
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
|
||||
settings.setValue("schema", 2);
|
||||
settings.setValue("geometry", saveGeometry());
|
||||
settings.setValue("windowState", saveState());
|
||||
settings.setValue("border", m_viewBorder);
|
||||
settings.setValue("aspectratio", m_viewAspectRatio);
|
||||
settings.setValue("smoothTransform", m_viewSmoothTransform);
|
||||
settings.setValue("zoom", m_viewZoom);
|
||||
settings.setValue("zoom", m_zoomSlider->value());
|
||||
}
|
||||
|
||||
bool MainWindow::maybeSave()
|
||||
@@ -1318,12 +1338,6 @@ void MainWindow::loadFile(const QString &fileName)
|
||||
statusBar()->showMessage(tr("File loaded"), 2000);
|
||||
}
|
||||
|
||||
void MainWindow::setRecentFilesVisible(bool visible)
|
||||
{
|
||||
m_recentFileSubMenuAct->setVisible(visible);
|
||||
m_recentFileSeparator->setVisible(visible);
|
||||
}
|
||||
|
||||
static inline QString recentFilesKey() { return QStringLiteral("recentFileList"); }
|
||||
static inline QString fileKey() { return QStringLiteral("file"); }
|
||||
|
||||
@@ -1350,14 +1364,6 @@ static void writeRecentFiles(const QStringList &files, QSettings &settings)
|
||||
settings.endArray();
|
||||
}
|
||||
|
||||
bool MainWindow::hasRecentFiles()
|
||||
{
|
||||
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
|
||||
const int count = settings.beginReadArray(recentFilesKey());
|
||||
settings.endArray();
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
void MainWindow::prependToRecentFiles(const QString &fileName)
|
||||
{
|
||||
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
|
||||
@@ -1369,7 +1375,7 @@ void MainWindow::prependToRecentFiles(const QString &fileName)
|
||||
if (oldRecentFiles != recentFiles)
|
||||
writeRecentFiles(recentFiles, settings);
|
||||
|
||||
setRecentFilesVisible(!recentFiles.isEmpty());
|
||||
m_recentFileSubMenuAct->setEnabled(!recentFiles.isEmpty());
|
||||
}
|
||||
|
||||
void MainWindow::updateRecentFileActions()
|
||||
@@ -1387,6 +1393,15 @@ void MainWindow::updateRecentFileActions()
|
||||
}
|
||||
for ( ; i < m_MaxRecentFiles; ++i)
|
||||
m_recentFileActs[i]->setVisible(false);
|
||||
|
||||
m_recentFileSubMenuAct->setEnabled(recentFiles.size() != 0);
|
||||
}
|
||||
|
||||
void MainWindow::clearRecentFiles()
|
||||
{
|
||||
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
|
||||
|
||||
writeRecentFiles(QStringList(), settings);
|
||||
}
|
||||
|
||||
void MainWindow::updateExportAutoAction()
|
||||
|
||||
@@ -74,6 +74,7 @@ private slots:
|
||||
void exportImage();
|
||||
void exportM29();
|
||||
void updateRecentFileActions();
|
||||
void clearRecentFiles();
|
||||
void updateExportAutoAction();
|
||||
void openRecentFile();
|
||||
void about();
|
||||
@@ -112,15 +113,12 @@ private:
|
||||
void init();
|
||||
void createActions();
|
||||
void createStatusBar();
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
bool maybeSave();
|
||||
void openFile(const QString &fileName);
|
||||
void loadFile(const QString &fileName);
|
||||
void extractImages(QImage sceneImage[], bool smooth = false, bool flashExtract = false);
|
||||
static bool hasRecentFiles();
|
||||
void prependToRecentFiles(const QString &fileName);
|
||||
void setRecentFilesVisible(bool visible);
|
||||
bool saveFile(const QString &fileName);
|
||||
void setCurrentFile(const QString &fileName);
|
||||
static QString strippedName(const QString &fullFileName);
|
||||
@@ -144,7 +142,6 @@ private:
|
||||
DClutDockWidget *m_dClutDockWidget;
|
||||
|
||||
QAction *m_recentFileActs[m_MaxRecentFiles];
|
||||
QAction *m_recentFileSeparator;
|
||||
QAction *m_recentFileSubMenuAct;
|
||||
QAction *m_exportAutoAct;
|
||||
QAction *m_deleteSubPageAction;
|
||||
|
||||
@@ -160,8 +160,23 @@ QByteArray SaveTTIFormat::format18BitPacket(QByteArray packet)
|
||||
// TTI stores the triplets 6 bits at a time like we do, without Hamming encoding
|
||||
// We don't touch the first byte; the caller replaces it with the designation code
|
||||
// unless it's X/1-X/25 used in (G)POP pages
|
||||
for (int i=1; i<packet.size(); i++)
|
||||
for (int i=1; i<packet.size(); i++) {
|
||||
// Save invalid triplets as address 41, mode 0x1e, data 0
|
||||
// which hopefully won't do anything when parsed as X/26 enhancements
|
||||
if ((packet.at(i) & 0xff) == 0xff)
|
||||
switch (i % 3) {
|
||||
case 1:
|
||||
packet[i] = 41;
|
||||
break;
|
||||
case 2:
|
||||
packet[i] = 0x1e;
|
||||
break;
|
||||
case 0:
|
||||
packet[i] = 0;
|
||||
break;
|
||||
}
|
||||
packet[i] = packet.at(i) | 0x40;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
@@ -322,7 +337,11 @@ QByteArray SaveT42Format::format4BitPacket(QByteArray packet)
|
||||
|
||||
QByteArray SaveT42Format::format18BitPacket(QByteArray packet)
|
||||
{
|
||||
for (int c=1; c<packet.size(); c+=3) {
|
||||
for (int c=1; c<packet.size(); c+=3)
|
||||
// For invalid packets, save as all zeroes which will fail Hamming 24/18 decoding
|
||||
if ((packet.at(c) & 0xff) == 0xff)
|
||||
packet[c] = packet[c+1] = packet[c+2] = 0;
|
||||
else {
|
||||
unsigned int D5_D11;
|
||||
unsigned int D12_D18;
|
||||
unsigned int P5, P6;
|
||||
@@ -440,7 +459,14 @@ bool SaveEP1Format::getWarnings(const PageBase &subPage)
|
||||
|
||||
QByteArray SaveEP1Format::format18BitPacket(QByteArray packet)
|
||||
{
|
||||
for (int c=1; c<packet.size(); c+=3) {
|
||||
for (int c=1; c<packet.size(); c+=3)
|
||||
if ((packet.at(c+1) & 0xff) == 0xff) {
|
||||
// Save invalid triplets as address 41, mode 0x1e, data 0
|
||||
// which hopefully won't do anything when parsed as X/26 enhancements
|
||||
packet[c] = 41;
|
||||
packet[c+1] = 0x1e;
|
||||
packet[c+2] = 0;
|
||||
} else {
|
||||
// Shuffle triplet bits to 6 bit address, 5 bit mode, 7 bit data
|
||||
packet[c+2] = ((packet.at(c+2) & 0x3f) << 1) | ((packet.at(c+1) & 0x20) >> 5);
|
||||
packet[c+1] = packet.at(c+1) & 0x1f;
|
||||
|
||||
@@ -678,6 +678,13 @@ void X26DockWidget::updateAllCookedTripletWidgets(const QModelIndex &index)
|
||||
{
|
||||
const int modeExt = index.model()->data(index.model()->index(index.row(), 2), Qt::EditRole).toInt();
|
||||
|
||||
if (modeExt == 0xff) {
|
||||
disableTripletWidgets();
|
||||
m_cookedModePushButton->setEnabled(true);
|
||||
m_cookedModePushButton->setText("Replace...");
|
||||
return;
|
||||
}
|
||||
|
||||
m_cookedModePushButton->setEnabled(true);
|
||||
m_cookedModePushButton->setText(m_modeTripletNames.modeName(modeExt));
|
||||
|
||||
@@ -1034,7 +1041,7 @@ void X26DockWidget::insertTriplet(int modeExt, int row)
|
||||
if (modeExt >= 0x20 && modeExt != 0x24 && modeExt != 0x25 && modeExt != 0x26 && modeExt != 0x2a) {
|
||||
const int existingTripletModeExt = index.model()->data(index.model()->index(index.row(), 2), Qt::EditRole).toInt();
|
||||
|
||||
if (existingTripletModeExt >= 0x20 && existingTripletModeExt != 0x24 && existingTripletModeExt != 0x25 && existingTripletModeExt != 0x26 && existingTripletModeExt != 0x2a)
|
||||
if (existingTripletModeExt >= 0x20 && existingTripletModeExt <= 0x3f && existingTripletModeExt != 0x24 && existingTripletModeExt != 0x25 && existingTripletModeExt != 0x26 && existingTripletModeExt != 0x2a)
|
||||
newTriplet.setAddress(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole).toInt());
|
||||
}
|
||||
// If we're inserting a Set Active Position or Full Row Colour triplet,
|
||||
|
||||
@@ -108,7 +108,7 @@ QVariant X26Model::data(const QModelIndex &index, int role) const
|
||||
else
|
||||
return QVariant();
|
||||
case 1:
|
||||
if (!triplet.isRowTriplet())
|
||||
if (triplet.isValid() && !triplet.isRowTriplet())
|
||||
return triplet.addressColumn();
|
||||
// For Set Active Position and Origin Modifier, data is the column
|
||||
else if (triplet.modeExt() == 0x04)
|
||||
@@ -122,9 +122,14 @@ QVariant X26Model::data(const QModelIndex &index, int role) const
|
||||
QString result;
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (index.column() == 2)
|
||||
if (index.column() == 2) {
|
||||
if (!triplet.isValid())
|
||||
return "Error decoding triplet";
|
||||
return (m_modeTripletNames.modeName(triplet.modeExt()));
|
||||
}
|
||||
// Column 3 - describe effects of data/address triplet parameters in plain English
|
||||
if (!triplet.isValid())
|
||||
return QVariant();
|
||||
switch (triplet.modeExt()) {
|
||||
case 0x01: // Full row colour
|
||||
case 0x07: // Address row 0
|
||||
@@ -609,12 +614,15 @@ bool X26Model::setData(const QModelIndex &index, const QVariant &value, int role
|
||||
return true;
|
||||
|
||||
case 2: // Cooked triplet mode
|
||||
if (intValue < 0x20 && !triplet.isRowTriplet()) {
|
||||
if (!triplet.isValid()) {
|
||||
// Changing from invalid triplet
|
||||
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, intValue < 0x20 ? 41 : 0, role));
|
||||
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 32, role));
|
||||
} else if (intValue < 0x20 && !triplet.isRowTriplet()) {
|
||||
// Changing mode from column triplet to row triplet
|
||||
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 41, role));
|
||||
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0, role));
|
||||
}
|
||||
if (intValue >= 0x20 && triplet.isRowTriplet()) {
|
||||
} else if (intValue >= 0x20 && triplet.isRowTriplet()) {
|
||||
// Changing mode from row triplet to column triplet
|
||||
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 0, role));
|
||||
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0, role));
|
||||
|
||||
@@ -60,8 +60,9 @@ private:
|
||||
};
|
||||
|
||||
// Needs to be in the same order as enum X26TripletError in x26triplets.h
|
||||
const tripletErrorShow m_tripletErrors[6] {
|
||||
const tripletErrorShow m_tripletErrors[7] {
|
||||
{ "", 0 }, // No error
|
||||
{ "Error decoding triplet", 2 },
|
||||
{ "Active Position can't move up", 0 },
|
||||
{ "Active Position can't move left within row", 1 },
|
||||
{ "Invocation not pointing to Object Definition", 3 },
|
||||
|
||||
Reference in New Issue
Block a user