8 Commits

Author SHA1 Message Date
Gavin MacGregor
cf4f85cc51 Tag version 0.6.5-beta 2024-12-04 12:33:03 +00:00
Gavin MacGregor
f96b973ff3 Warn when Active Position differs between Levels 2024-12-01 21:51:32 +00:00
Gavin MacGregor
1d889ab724 Update MXE notes 2024-12-01 18:07:43 +00:00
Gavin MacGregor
48a2b48964 Add monochrome rendering modes
These modes can be used to see the inner workings of colourful artworks that
frequently use "foreground colour, new background, foreground colour",
particularly to show exactly which colours are represented by set or clear
sixels.

One mode renders all characters in white on a black background and the other
mode renders black characters on a white background. The latter could be used
to save ink if the resulting image is printed.

Flash is suppressed in these mono modes, this may or may not change.
2024-12-01 17:44:58 +00:00
Gavin MacGregor
26b5974421 Remove duplicate row from template 2024-11-26 18:05:00 +00:00
G.K.MacGregor
4743b26400 Remove duplicate widget disabling 2024-08-28 13:40:43 +01:00
G.K.MacGregor
40fc1e38d8 Port to CMake from qmake, and split decoder into subdirectory
Qt 5 has had to be dropped as CMakeLists.txt uses qt_* specific commands
which are implemented in Qt 6 onwards.

cmake --install is only working on Linux at the moment; it installs the
executable and the bundled example tti files into /usr/local/share/doc

The teletext decoder with its document storage has been moved to a
subdirectory with the intention of making it possible to use in other
projects, but some further separation of editing stuff will be needed.
2024-08-11 15:35:49 +01:00
G.K.MacGregor
cf6c4855ce Disable triplet editing widgets when X/26 list is changed 2024-08-08 22:13:02 +01:00
60 changed files with 230 additions and 149 deletions

8
.gitignore vendored
View File

@@ -1,6 +1,4 @@
.qmake.stash
moc_*
qrc_*
*.o
Makefile Makefile
qteletextmaker build*/
cmake-build-*/
.idea

60
CMakeLists.txt Normal file
View File

@@ -0,0 +1,60 @@
cmake_minimum_required(VERSION 3.16.0)
project(qteletextmaker VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt6 COMPONENTS Core Widgets REQUIRED)
qt_standard_project_setup()
add_subdirectory(src/qteletextdecoder)
file (GLOB SOURCES src/qteletextmaker/*.cpp)
qt_add_executable(qteletextmaker ${SOURCES} src/qteletextmaker/actionicons.qrc)
target_link_libraries(qteletextmaker PRIVATE qteletextdecoder Qt::Widgets)
set_target_properties(qteletextmaker PROPERTIES
WIN32_EXECUTABLE ON
)
if(UNIX)
include(GNUInstallDirs)
set(BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}")
set(DOC_INSTALL_DIR "${CMAKE_INSTALL_DOCDIR}")
set(EXAMPLES_INSTALL_DIR "${DOC_INSTALL_DIR}/examples")
else()
set(BIN_INSTALL_DIR ".")
set(DOC_INSTALL_DIR ".")
set(EXAMPLES_INSTALL_DIR "./examples")
endif()
install(TARGETS qteletextmaker
BUNDLE DESTINATION .
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
)
install(FILES
${CMAKE_CURRENT_LIST_DIR}/README.md
${CMAKE_CURRENT_LIST_DIR}/LICENSE
DESTINATION ${DOC_INSTALL_DIR}
)
install(DIRECTORY
${CMAKE_CURRENT_LIST_DIR}/examples/
DESTINATION ${EXAMPLES_INSTALL_DIR}
)
qt_generate_deploy_app_script(
TARGET qteletextmaker
FILENAME_VARIABLE deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})

View File

@@ -1,7 +1,7 @@
# QTeletextMaker # QTeletextMaker
QTeletextMaker is a teletext page editor with an emphasis on Level 2.5 enhancement editing, released under the GNU General Public License v3.0 QTeletextMaker is a teletext page editor with an emphasis on Level 2.5 enhancement editing, released under the GNU General Public License v3.0
It is written in C++ using the Qt 5 widget libraries but should also compile with Qt 6. It is written in C++ using the Qt 6 widget libraries.
Features Features
- Load and save teletext pages in .tti format. - Load and save teletext pages in .tti format.
@@ -16,15 +16,23 @@ 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 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. Although designed on and developed for Linux, the Qt 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://web.archive.org/web/20230606021352/https://blog.8bitbuddhism.com/2018/08/22/cross-compiling-windows-applications-with-mxe/). After MXE is installed `make qt6-qtbase` should build and install the required dependencies to build QTeletextMaker.
## Building ## Building
### Linux ### Linux
Install version 5 or 6 of 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` or `qmake6 && make -j3` in a terminal to build, you can replace -j3 with the number of processor cores used for the compile process. Install version 6 of the QtCore, QtGui and QtWidgets libraries and build headers, along with CMake.
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. Change into the source directory and run the following commands. -j8 can be replaced with the number of processor cores used for the compile process
```
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j8
```
Optionally, type `make install` afterwards to place the executable into /usr/local/bin. The above should place the qteletextmaker executable into the build directory created by the above commands. Within the build directory type `./qteletextmaker` in the terminal to launch.
Optionally, type `cmake --install .` to place the executable into /usr/local/bin and the example .tti files into /usr/local/share/doc/qteletextmaker.
## Current limitations ## Current limitations
The following X/26 enhancement triplets are not rendered by the editor, although the list is fully aware of them. The following X/26 enhancement triplets are not rendered by the editor, although the list is fully aware of them.

View File

@@ -4,6 +4,6 @@ PS,8000
CT,8,T CT,8,T
OL,26,@iD@@kfjD@@kfkD@@kflD@@kfmD@@kfnD@@kfoD@ OL,26,@iD@@kfjD@@kfkD@@kflD@@kfmD@@kfnD@@kfoD@
OL,26,A@kfpD@@kfqD@@kfrD@@kfsD@@kftD@@kfuD@@kf OL,26,A@kfpD@@kfqD@@kfrD@@kfsD@@kftD@@kfuD@@kf
OL,26,BvD@@kfwD@@kfxD@@kfxD@@kfyD@@kfzD@@kf{D@ OL,26,BvD@@kfwD@@kfxD@@kfyD@@kfzD@@kf{D@@kf|D@
OL,26,C@kf|D@@kf}D@@kf~D@@kfD@@kfCCCC OL,26,C@kf}D@@kf~D@@kfD@@kfCCCCCC
OL,1, Active Position across every row OL,1, Active Position across every row

View File

@@ -1,51 +0,0 @@
QT += widgets
requires(qtConfig(filedialog))
HEADERS = decode.h \
document.h \
hamming.h \
keymap.h \
levelonecommands.h \
levelonepage.h \
loadsave.h \
mainwidget.h \
mainwindow.h \
pagebase.h \
pagex26base.h \
pagecomposelinksdockwidget.h \
pageenhancementsdockwidget.h \
pageoptionsdockwidget.h \
palettedockwidget.h \
render.h \
x26commands.h \
x26dockwidget.h \
x26menus.h \
x26model.h \
x26triplets.h \
x28commands.h
SOURCES = decode.cpp \
document.cpp \
levelonecommands.cpp \
levelonepage.cpp \
loadsave.cpp \
main.cpp \
mainwidget.cpp \
mainwindow.cpp \
pagebase.cpp \
pagex26base.cpp \
pagecomposelinksdockwidget.cpp \
pageenhancementsdockwidget.cpp \
pageoptionsdockwidget.cpp \
palettedockwidget.cpp \
render.cpp \
x26commands.cpp \
x26dockwidget.cpp \
x26menus.cpp \
x26model.cpp \
x26triplets.cpp \
x28commands.cpp
RESOURCES = qteletextmaker.qrc
# install
target.path = /usr/local/bin
INSTALLS += target

View File

@@ -0,0 +1,7 @@
file (GLOB SOURCES *.cpp)
add_library(qteletextdecoder ${SOURCES} teletextfonts.qrc)
target_include_directories(qteletextdecoder PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(qteletextdecoder Qt::Widgets)

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -19,6 +19,7 @@
#include <QBitmap> #include <QBitmap>
#include <QColor> #include <QColor>
#include <QDir>
#include <QImage> #include <QImage>
#include <QPainter> #include <QPainter>
#include <QPixmap> #include <QPixmap>
@@ -34,8 +35,10 @@ QImage *TeletextFontBitmap::s_fontImage = nullptr;
TeletextFontBitmap::TeletextFontBitmap() TeletextFontBitmap::TeletextFontBitmap()
{ {
Q_INIT_RESOURCE(teletextfonts);
if (s_instances == 0) { if (s_instances == 0) {
s_fontBitmap = new QBitmap(":/images/teletextfont.png"); s_fontBitmap = new QBitmap(":/fontimages/teletextfont.png");
s_fontImage = new QImage(s_fontBitmap->toImage()); s_fontImage = new QImage(s_fontBitmap->toImage());
} }
s_instances++; s_instances++;
@@ -57,7 +60,7 @@ TeletextPageRender::TeletextPageRender()
m_pageImage[i] = new QImage(864, 250, QImage::Format_ARGB32_Premultiplied); m_pageImage[i] = new QImage(864, 250, QImage::Format_ARGB32_Premultiplied);
m_reveal = false; m_reveal = false;
m_mix = false; m_renderMode = RenderNormal;
m_showControlCodes = false; m_showControlCodes = false;
m_flashBuffersHz = 0; m_flashBuffersHz = 0;
@@ -223,6 +226,13 @@ inline void TeletextPageRender::drawBoldOrItalicCharacter(QPainter &painter, int
void TeletextPageRender::renderPage(bool force) void TeletextPageRender::renderPage(bool force)
{ {
if (m_renderMode == RenderWhiteOnBlack) {
m_foregroundQColor = Qt::white;
m_backgroundQColor = Qt::black;
} else if (m_renderMode == RenderBlackOnWhite) {
m_foregroundQColor = Qt::black;
m_backgroundQColor = Qt::white;
}
for (int r=0; r<25; r++) for (int r=0; r<25; r++)
renderRow(r, 0, force); renderRow(r, 0, force);
} }
@@ -250,9 +260,11 @@ void TeletextPageRender::renderRow(int r, int ph, bool force)
} }
} }
if (ph == 0) { // Second part of "if" suppresses all flashing on monochrome render modes
if (ph == 0 && m_renderMode < RenderWhiteOnBlack) {
if (m_decoder->cellFlashMode(r, c) != 0) if (m_decoder->cellFlashMode(r, c) != 0)
flashingRow = qMax(flashingRow, (m_decoder->cellFlashRatePhase(r, c) == 0) ? 1 : 2); flashingRow = qMax(flashingRow, (m_decoder->cellFlashRatePhase(r, c) == 0) ? 1 : 2);
// } else if (!force)
} else } else
force = m_decoder->cellFlashMode(r, c) != 0; force = m_decoder->cellFlashMode(r, c) != 0;
@@ -275,36 +287,38 @@ void TeletextPageRender::renderRow(int r, int ph, bool force)
characterDiacritical = m_decoder->cellCharacterDiacritical(r, c); characterDiacritical = m_decoder->cellCharacterDiacritical(r, c);
} }
if (m_decoder->cellFlashMode(r, c) == 0) if (m_renderMode < RenderWhiteOnBlack) {
m_foregroundQColor = m_decoder->cellForegroundQColor(r, c); if (m_decoder->cellFlashMode(r, c) == 0)
else {
// Flashing cell, decide if phase in this cycle is on or off
bool phaseOn;
if (m_decoder->cellFlashRatePhase(r, c) == 0)
phaseOn = (ph < 3) ^ (m_decoder->cellFlashMode(r, c) == 2);
else
phaseOn = ((ph == m_decoder->cellFlash2HzPhaseNumber(r, c)-1) || (ph == m_decoder->cellFlash2HzPhaseNumber(r, c)+2)) ^ (m_decoder->cellFlashMode(r, c) == 2);
// If flashing to adjacent CLUT select the appropriate foreground colour
if (m_decoder->cellFlashMode(r, c) == 3 && !phaseOn)
m_foregroundQColor = m_decoder->cellFlashForegroundQColor(r, c);
else
m_foregroundQColor = m_decoder->cellForegroundQColor(r, c); m_foregroundQColor = m_decoder->cellForegroundQColor(r, c);
else {
// Flashing cell, decide if phase in this cycle is on or off
bool phaseOn;
// If flashing mode is Normal or Invert, draw a space instead of a character on phase if (m_decoder->cellFlashRatePhase(r, c) == 0)
if ((m_decoder->cellFlashMode(r, c) == 1 || m_decoder->cellFlashMode(r, c) == 2) && !phaseOn) { phaseOn = (ph < 3) ^ (m_decoder->cellFlashMode(r, c) == 2);
// Character 0x00 draws space without underline else
characterCode = 0x00; phaseOn = ((ph == m_decoder->cellFlash2HzPhaseNumber(r, c)-1) || (ph == m_decoder->cellFlash2HzPhaseNumber(r, c)+2)) ^ (m_decoder->cellFlashMode(r, c) == 2);
characterSet = 0;
characterDiacritical = 0; // If flashing to adjacent CLUT select the appropriate foreground colour
if (m_decoder->cellFlashMode(r, c) == 3 && !phaseOn)
m_foregroundQColor = m_decoder->cellFlashForegroundQColor(r, c);
else
m_foregroundQColor = m_decoder->cellForegroundQColor(r, c);
// If flashing mode is Normal or Invert, draw a space instead of a character on phase
if ((m_decoder->cellFlashMode(r, c) == 1 || m_decoder->cellFlashMode(r, c) == 2) && !phaseOn) {
// Character 0x00 draws space without underline
characterCode = 0x00;
characterSet = 0;
characterDiacritical = 0;
}
} }
}
if (!m_mix || m_decoder->cellBoxed(r, c)) if (m_renderMode != RenderMix || m_decoder->cellBoxed(r, c))
m_backgroundQColor = m_decoder->cellBackgroundQColor(r, c); m_backgroundQColor = m_decoder->cellBackgroundQColor(r, c);
else else
m_backgroundQColor = Qt::transparent; m_backgroundQColor = Qt::transparent;
}
drawCharacter(painter, r, c, characterCode, characterSet, characterDiacritical, m_decoder->cellCharacterFragment(r, c)); drawCharacter(painter, r, c, characterCode, characterSet, characterDiacritical, m_decoder->cellCharacterFragment(r, c));
@@ -436,17 +450,16 @@ void TeletextPageRender::setReveal(bool reveal)
m_decoder->setRefresh(r, c, true); m_decoder->setRefresh(r, c, true);
} }
void TeletextPageRender::setMix(bool mix) void TeletextPageRender::setRenderMode(RenderMode renderMode)
{ {
if (mix == m_mix) if (renderMode == m_renderMode)
return; return;
m_mix = mix; m_renderMode = renderMode;
for (int r=0; r<25; r++) for (int r=0; r<25; r++)
for (int c=0; c<72; c++) for (int c=0; c<72; c++)
if (!m_decoder->cellBoxed(r, c)) m_decoder->setRefresh(r, c, true);
m_decoder->setRefresh(r, c, true);
} }

View File

@@ -49,11 +49,13 @@ class TeletextPageRender : public QObject
Q_OBJECT Q_OBJECT
public: public:
enum RenderMode { RenderNormal, RenderMix, RenderWhiteOnBlack, RenderBlackOnWhite };
TeletextPageRender(); TeletextPageRender();
~TeletextPageRender(); ~TeletextPageRender();
QImage* image(int i) const { return m_pageImage[i]; }; QImage* image(int i) const { return m_pageImage[i]; };
bool mix() const { return m_mix; }; RenderMode renderMode() const { return m_renderMode; };
void setDecoder(TeletextPageDecode *decoder); void setDecoder(TeletextPageDecode *decoder);
void renderPage(bool force=false); void renderPage(bool force=false);
bool showControlCodes() const { return m_showControlCodes; }; bool showControlCodes() const { return m_showControlCodes; };
@@ -61,7 +63,7 @@ public:
public slots: public slots:
void colourChanged(int index); void colourChanged(int index);
void setReveal(bool reveal); void setReveal(bool reveal);
void setMix(bool mix); void setRenderMode(RenderMode renderMode);
void setShowControlCodes(bool showControlCodes); void setShowControlCodes(bool showControlCodes);
signals: signals:
@@ -71,7 +73,8 @@ protected:
TeletextFontBitmap m_fontBitmap; TeletextFontBitmap m_fontBitmap;
QImage* m_pageImage[6]; QImage* m_pageImage[6];
unsigned char m_controlCodeCache[25][40]; unsigned char m_controlCodeCache[25][40];
bool m_reveal, m_mix, m_showControlCodes; RenderMode m_renderMode;
bool m_reveal, m_showControlCodes;
int m_flashBuffersHz; int m_flashBuffersHz;
int m_flashingRow[25]; int m_flashingRow[25];

View File

@@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>fontimages/teletextfont.png</file>
</qresource>
</RCC>

View File

@@ -238,11 +238,18 @@ void X26TripletList::updateInternalData()
case 0x22: // G3 mosaic character at level 1.5 case 0x22: // G3 mosaic character at level 1.5
case 0x2f: // G2 character case 0x2f: // G2 character
activePosition.setColumn(triplet->addressColumn()); activePosition.setColumn(triplet->addressColumn());
if (activePosition.row() != triplet->m_activePositionRow || activePosition.column() != triplet->m_activePositionColumn)
triplet->m_activePosition1p5Differs = true;
break; break;
default: default:
if (triplet->modeExt() >= 0x30 && triplet->modeExt() <= 0x3f) if (triplet->modeExt() >= 0x30 && triplet->modeExt() <= 0x3f) {
// G0 diacritical mark // G0 diacritical mark
activePosition.setColumn(triplet->addressColumn()); activePosition.setColumn(triplet->addressColumn());
if (activePosition.row() != triplet->m_activePositionRow || activePosition.column() != triplet->m_activePositionColumn)
triplet->m_activePosition1p5Differs = true;
}
} }
triplet->m_activePositionRow1p5 = activePosition.row(); triplet->m_activePositionRow1p5 = activePosition.row();

View File

@@ -66,6 +66,7 @@ public:
X26TripletError error() const { return m_error; } X26TripletError error() const { return m_error; }
bool reservedMode() const { return m_reservedMode; } bool reservedMode() const { return m_reservedMode; }
bool reservedData() const { return m_reservedData; } bool reservedData() const { return m_reservedData; }
bool activePosition1p5Differs() const { return m_activePosition1p5Differs; }
friend class X26TripletList; friend class X26TripletList;
@@ -77,6 +78,7 @@ private:
int m_activePositionColumn = -1; int m_activePositionColumn = -1;
int m_activePositionRow1p5 = -1; int m_activePositionRow1p5 = -1;
int m_activePositionColumn1p5 = -1; int m_activePositionColumn1p5 = -1;
bool m_activePosition1p5Differs = false;
X26TripletError m_error = NoError; X26TripletError m_error = NoError;
bool m_reservedMode = false; bool m_reservedMode = false;
bool m_reservedData = false; bool m_reservedData = false;

View File

@@ -1,6 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0"> <!DOCTYPE RCC><RCC version="1.0">
<qresource> <qresource>
<file>images/teletextfont.png</file>
<file>images/copy.png</file> <file>images/copy.png</file>
<file>images/cut.png</file> <file>images/cut.png</file>
<file>images/new.png</file> <file>images/new.png</file>

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 852 B

After

Width:  |  Height:  |  Size: 852 B

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -24,13 +24,13 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
Q_INIT_RESOURCE(qteletextmaker); Q_INIT_RESOURCE(actionicons);
QApplication app(argc, argv); QApplication app(argc, argv);
QApplication::setApplicationName("QTeletextMaker"); QApplication::setApplicationName("QTeletextMaker");
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.6.4-beta"); QApplication::setApplicationVersion("0.6.5-beta");
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription(QApplication::applicationName()); parser.setApplicationDescription(QApplication::applicationName());
parser.addHelpOption(); parser.addHelpOption();

View File

@@ -161,18 +161,18 @@ void TeletextWidget::setReveal(bool reveal)
update(); update();
} }
void TeletextWidget::setMix(bool mix)
{
m_pageRender.setMix(mix);
update();
}
void TeletextWidget::setShowControlCodes(bool showControlCodes) void TeletextWidget::setShowControlCodes(bool showControlCodes)
{ {
m_pageRender.setShowControlCodes(showControlCodes); m_pageRender.setShowControlCodes(showControlCodes);
update(); update();
} }
void TeletextWidget::setRenderMode(TeletextPageRender::RenderMode renderMode)
{
m_pageRender.setRenderMode(renderMode);
update();
}
void TeletextWidget::setControlBit(int bitNumber, bool active) void TeletextWidget::setControlBit(int bitNumber, bool active)
{ {
m_levelOnePage->setControlBit(bitNumber, active); m_levelOnePage->setControlBit(bitNumber, active);
@@ -705,19 +705,34 @@ void LevelOneScene::updateSelection()
m_selectionRectItem->setVisible(true); m_selectionRectItem->setVisible(true);
} }
void LevelOneScene::setMix(bool mix) void LevelOneScene::setRenderMode(TeletextPageRender::RenderMode renderMode)
{ {
if (mix) { static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->setRenderMode(renderMode);
m_fullScreenTopRectItem->setBrush(Qt::transparent);
m_fullScreenBottomRectItem->setBrush(Qt::transparent); QColor fullColour;
for (int r=0; r<25; r++) {
m_fullRowLeftRectItem[r]->setBrush(Qt::transparent); switch (renderMode) {
m_fullRowRightRectItem[r]->setBrush(Qt::transparent); case TeletextPageRender::RenderNormal:
} setFullScreenColour(static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->pageDecode()->fullScreenQColor());
} else { for (int r=0; r<25; r++)
setFullScreenColour(static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->pageDecode()->fullScreenQColor()); setFullRowColour(r, static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->pageDecode()->fullRowQColor(r));
for (int r=0; r<25; r++) return;
setFullRowColour(r, static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->pageDecode()->fullRowQColor(r)); case TeletextPageRender::RenderMix:
fullColour = Qt::transparent;
break;
case TeletextPageRender::RenderWhiteOnBlack:
fullColour = Qt::black;
break;
case TeletextPageRender::RenderBlackOnWhite:
fullColour = Qt::white;
break;
}
m_fullScreenTopRectItem->setBrush(fullColour);
m_fullScreenBottomRectItem->setBrush(fullColour);
for (int r=0; r<25; r++) {
m_fullRowLeftRectItem[r]->setBrush(fullColour);
m_fullRowRightRectItem[r]->setBrush(fullColour);
} }
} }
@@ -782,7 +797,7 @@ void LevelOneScene::keyReleaseEvent(QKeyEvent *keyEvent)
void LevelOneScene::setFullScreenColour(const QColor &newColor) void LevelOneScene::setFullScreenColour(const QColor &newColor)
{ {
if (!static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->pageRender()->mix()) { if (static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->pageRender()->renderMode() == TeletextPageRender::RenderNormal) {
m_fullScreenTopRectItem->setBrush(newColor); m_fullScreenTopRectItem->setBrush(newColor);
m_fullScreenBottomRectItem->setBrush(newColor); m_fullScreenBottomRectItem->setBrush(newColor);
} }
@@ -790,7 +805,7 @@ void LevelOneScene::setFullScreenColour(const QColor &newColor)
void LevelOneScene::setFullRowColour(int row, const QColor &newColor) void LevelOneScene::setFullRowColour(int row, const QColor &newColor)
{ {
if (!static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->pageRender()->mix()) { if (static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->pageRender()->renderMode() == TeletextPageRender::RenderNormal) {
m_fullRowLeftRectItem[row]->setBrush(newColor); m_fullRowLeftRectItem[row]->setBrush(newColor);
m_fullRowRightRectItem[row]->setBrush(newColor); m_fullRowRightRectItem[row]->setBrush(newColor);
} }

View File

@@ -65,8 +65,8 @@ public slots:
void subPageSelected(); void subPageSelected();
void refreshPage(); void refreshPage();
void setReveal(bool reveal); void setReveal(bool reveal);
void setMix(bool mix);
void setShowControlCodes(bool showControlCodes); void setShowControlCodes(bool showControlCodes);
void setRenderMode(TeletextPageRender::RenderMode renderMode);
void updateFlashTimer(int newFlashTimer); void updateFlashTimer(int newFlashTimer);
void pauseFlash(bool pauseNow); void pauseFlash(bool pauseNow);
@@ -120,7 +120,7 @@ public:
public slots: public slots:
void updateCursor(); void updateCursor();
void updateSelection(); void updateSelection();
void setMix(bool mix); void setRenderMode(TeletextPageRender::RenderMode renderMode);
void toggleGrid(bool gridOn); void toggleGrid(bool gridOn);
void hideGUIElements(bool hidden); void hideGUIElements(bool hidden);
void setFullScreenColour(const QColor &newColor); void setFullScreenColour(const QColor &newColor);

View File

@@ -189,11 +189,9 @@ void MainWindow::exportPNG()
m_textWidget->pauseFlash(true); m_textWidget->pauseFlash(true);
m_textScene->hideGUIElements(true); m_textScene->hideGUIElements(true);
// Disable exporting in Mix mode as it corrupts the background // Disable exporting in Mix mode as it corrupts the background
bool reMix = m_textWidget->pageRender()->mix(); bool reMix = m_textWidget->pageRender()->renderMode() == TeletextPageRender::RenderMix;
if (reMix) { if (reMix)
m_textWidget->setMix(false); m_textScene->setRenderMode(TeletextPageRender::RenderNormal);
m_textScene->setMix(false);
}
// Extract the image from the scene // Extract the image from the scene
QImage interImage = QImage(m_textScene->sceneRect().size().toSize(), QImage::Format_RGB32); QImage interImage = QImage(m_textScene->sceneRect().size().toSize(), QImage::Format_RGB32);
@@ -205,10 +203,8 @@ void MainWindow::exportPNG()
// Now we've extracted the image we can put the GUI things back // Now we've extracted the image we can put the GUI things back
m_textScene->hideGUIElements(false); m_textScene->hideGUIElements(false);
if (reMix) { if (reMix)
m_textWidget->setMix(true); m_textScene->setRenderMode(TeletextPageRender::RenderMix);
m_textScene->setMix(true);
}
m_textWidget->pauseFlash(false); m_textWidget->pauseFlash(false);
// Now scale the extracted image to the selected aspect ratio // Now scale the extracted image to the selected aspect ratio
@@ -503,13 +499,6 @@ void MainWindow::createActions()
revealAct->setStatusTip(tr("Toggle reveal")); revealAct->setStatusTip(tr("Toggle reveal"));
connect(revealAct, &QAction::toggled, m_textWidget, &TeletextWidget::setReveal); connect(revealAct, &QAction::toggled, m_textWidget, &TeletextWidget::setReveal);
QAction *mixAct = viewMenu->addAction(tr("&Mix"));
mixAct->setCheckable(true);
mixAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_M));
mixAct->setStatusTip(tr("Toggle mix"));
connect(mixAct, &QAction::toggled, m_textWidget, &TeletextWidget::setMix);
connect(mixAct, &QAction::toggled, m_textScene, &LevelOneScene::setMix);
QAction *gridAct = viewMenu->addAction(tr("&Grid")); QAction *gridAct = viewMenu->addAction(tr("&Grid"));
gridAct->setCheckable(true); gridAct->setCheckable(true);
gridAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_G)); gridAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_G));
@@ -524,6 +513,17 @@ void MainWindow::createActions()
viewMenu->addSeparator(); viewMenu->addSeparator();
QMenu *renderModeSubMenu = viewMenu->addMenu(tr("Render mode"));
QAction *renderModeActs[4];
renderModeActs[0] = renderModeSubMenu->addAction(tr("Normal"));
renderModeActs[0]->setStatusTip(tr("Render page normally"));
renderModeActs[1] = renderModeSubMenu->addAction(tr("Mix"));
renderModeActs[1]->setStatusTip(tr("Render page in mix mode"));
renderModeActs[2] = renderModeSubMenu->addAction(tr("White on black"));
renderModeActs[2]->setStatusTip(tr("Render page with white foreground on black background"));
renderModeActs[3] = renderModeSubMenu->addAction(tr("Black on white"));
renderModeActs[3]->setStatusTip(tr("Render page with black foreground on white background"));
QMenu *borderSubMenu = viewMenu->addMenu(tr("Border")); QMenu *borderSubMenu = viewMenu->addMenu(tr("Border"));
m_borderActs[0] = borderSubMenu->addAction(tr("None")); m_borderActs[0] = borderSubMenu->addAction(tr("None"));
m_borderActs[0]->setStatusTip(tr("View with no border")); m_borderActs[0]->setStatusTip(tr("View with no border"));
@@ -542,18 +542,26 @@ void MainWindow::createActions()
m_aspectRatioActs[3] = aspectRatioSubMenu->addAction(tr("Pixel 1:2")); m_aspectRatioActs[3] = aspectRatioSubMenu->addAction(tr("Pixel 1:2"));
m_aspectRatioActs[3]->setStatusTip(tr("View with 1:2 pixel mapping")); m_aspectRatioActs[3]->setStatusTip(tr("View with 1:2 pixel mapping"));
QActionGroup *renderModeGroup = new QActionGroup(this);
QActionGroup *borderGroup = new QActionGroup(this); QActionGroup *borderGroup = new QActionGroup(this);
QActionGroup *aspectRatioGroup = new QActionGroup(this); QActionGroup *aspectRatioGroup = new QActionGroup(this);
for (int i=0; i<=3; i++) { for (int i=0; i<=3; i++) {
renderModeActs[i]->setCheckable(true);
connect(renderModeActs[i], &QAction::triggered, [=]() { m_textScene->setRenderMode(static_cast<TeletextPageRender::RenderMode>(i)); });
renderModeGroup->addAction(renderModeActs[i]);
m_aspectRatioActs[i]->setCheckable(true); m_aspectRatioActs[i]->setCheckable(true);
connect(m_aspectRatioActs[i], &QAction::triggered, [=]() { setAspectRatio(i); }); connect(m_aspectRatioActs[i], &QAction::triggered, [=]() { setAspectRatio(i); });
aspectRatioGroup->addAction(m_aspectRatioActs[i]); aspectRatioGroup->addAction(m_aspectRatioActs[i]);
if (i == 3) if (i == 3)
break; break;
m_borderActs[i]->setCheckable(true); m_borderActs[i]->setCheckable(true);
connect(m_borderActs[i], &QAction::triggered, [=]() { setBorder(i); }); connect(m_borderActs[i], &QAction::triggered, [=]() { setBorder(i); });
borderGroup->addAction(m_borderActs[i]); borderGroup->addAction(m_borderActs[i]);
} }
renderModeActs[0]->setChecked(true);
viewMenu->addSeparator(); viewMenu->addSeparator();

View File

@@ -602,15 +602,14 @@ void X26DockWidget::selectX26ListRow(int row)
void X26DockWidget::loadX26List() void X26DockWidget::loadX26List()
{ {
disableTripletWidgets();
m_x26Model->setX26ListLoaded(true); m_x26Model->setX26ListLoaded(true);
} }
void X26DockWidget::unloadX26List() void X26DockWidget::unloadX26List()
{ {
disableTripletWidgets();
m_x26Model->setX26ListLoaded(false); m_x26Model->setX26ListLoaded(false);
m_rawTripletAddressSpinBox->setEnabled(false);
m_rawTripletDataSpinBox->setEnabled(false);
m_rawTripletModeSpinBox->setEnabled(false);
} }
void X26DockWidget::rowSelected(const QModelIndex &current, const QModelIndex &previous) void X26DockWidget::rowSelected(const QModelIndex &current, const QModelIndex &previous)

View File

@@ -69,19 +69,27 @@ QVariant X26Model::data(const QModelIndex &index, int role) const
if (role == Qt::ForegroundRole) { if (role == Qt::ForegroundRole) {
if (triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight) if (triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight)
return QColor(252, 252, 252); return QColor(252, 252, 252);
else if ((index.column() == 2 && triplet.reservedMode()) || (index.column() == 3 && triplet.reservedData())) if ((index.column() == 2 && triplet.reservedMode()) || (index.column() == 3 && triplet.reservedData()))
return QColor(35, 38, 39);
if (index.column() <= 1 && triplet.activePosition1p5Differs())
return QColor(35, 38, 39); return QColor(35, 38, 39);
} }
if (role == Qt::BackgroundRole) { if (role == Qt::BackgroundRole) {
if (triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight) if (triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight)
return QColor(218, 68, 63); return QColor(218, 68, 63);
else if ((index.column() == 2 && triplet.reservedMode()) || (index.column() == 3 && triplet.reservedData())) if ((index.column() == 2 && triplet.reservedMode()) || (index.column() == 3 && triplet.reservedData()))
return QColor(246, 116, 0);
if (index.column() <= 1 && triplet.activePosition1p5Differs())
return QColor(246, 116, 0); return QColor(246, 116, 0);
} }
if (role == Qt::ToolTipRole && triplet.error() != X26Triplet::NoError) if (role == Qt::ToolTipRole) {
return m_tripletErrors[triplet.error()].message; if (triplet.error() != X26Triplet::NoError)
return m_tripletErrors[triplet.error()].message;
if (triplet.activePosition1p5Differs())
return "Active Position differs between Level 1.5 and higher levels";
}
if (role == Qt::DisplayRole || role == Qt::EditRole) if (role == Qt::DisplayRole || role == Qt::EditRole)
switch (index.column()) { switch (index.column()) {