Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06970fd448 | ||
|
|
a3d4783796 | ||
|
|
c8e57150eb | ||
|
|
23c2623bcf |
@@ -5,6 +5,8 @@ Features
|
||||
- Load and save teletext pages in .tti format.
|
||||
- Rendering of teletext pages in Levels 1, 1.5, 2.5 and 3.5
|
||||
- Rendering of Local Objects and side panels.
|
||||
- Export PNG images of teletext pages.
|
||||
- Undo and redo of editing actions.
|
||||
- Interactive X/26 Local Enhancement Data triplet editor.
|
||||
- Editing of X/27/4 and X/27/5 compositional links to enhancement data pages.
|
||||
- Palette editor.
|
||||
|
||||
2
main.cpp
2
main.cpp
@@ -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.2-alpha");
|
||||
QApplication::setApplicationVersion("0.3-alpha");
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QApplication::applicationName());
|
||||
parser.addHelpOption();
|
||||
|
||||
@@ -140,6 +140,16 @@ void TeletextWidget::timerEvent(QTimerEvent *event)
|
||||
QWidget::timerEvent(event);
|
||||
}
|
||||
|
||||
void TeletextWidget::pauseFlash(bool pauseNow)
|
||||
{
|
||||
if (pauseNow && m_flashTiming != 0) {
|
||||
m_flashTimer.stop();
|
||||
m_flashPhase = 0;
|
||||
update();
|
||||
} else if (m_flashTiming != 0)
|
||||
m_flashTimer.start((m_flashTiming == 1) ? 500 : 167, this);
|
||||
}
|
||||
|
||||
void TeletextWidget::setInsertMode(bool insertMode)
|
||||
{
|
||||
m_insertMode = insertMode;
|
||||
@@ -654,6 +664,24 @@ void LevelOneScene::toggleGrid(bool gridOn)
|
||||
m_sidePanelGridItemGroup[i]->setVisible(gridOn);
|
||||
}
|
||||
|
||||
void LevelOneScene::hideGUIElements(bool hidden)
|
||||
{
|
||||
if (hidden) {
|
||||
m_mainGridItemGroup->setVisible(false);
|
||||
m_cursorRectItem->setVisible(false);
|
||||
m_selectionRectItem->setVisible(false);
|
||||
for (int i=0; i<32; i++)
|
||||
if (m_sidePanelGridNeeded[i])
|
||||
m_sidePanelGridItemGroup[i]->setVisible(false);
|
||||
} else {
|
||||
if (static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->selectionActive())
|
||||
m_selectionRectItem->setVisible(true);
|
||||
|
||||
m_cursorRectItem->setVisible(true);
|
||||
toggleGrid(m_grid);
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelOneScene::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
Q_UNUSED(object);
|
||||
|
||||
@@ -64,6 +64,7 @@ public slots:
|
||||
void toggleReveal(bool);
|
||||
void toggleMix(bool);
|
||||
void updateFlashTimer(int);
|
||||
void pauseFlash(bool);
|
||||
void refreshRow(int);
|
||||
|
||||
void setControlBit(int, bool);
|
||||
@@ -119,6 +120,7 @@ public slots:
|
||||
void updateCursor();
|
||||
void updateSelection();
|
||||
void toggleGrid(bool);
|
||||
void hideGUIElements(bool);
|
||||
void setFullScreenColour(const QColor &);
|
||||
void setFullRowColour(int, const QColor &);
|
||||
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
#include <QApplication>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileDialog>
|
||||
#include <QImage>
|
||||
#include <QList>
|
||||
#include <QMenuBar>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QSaveFile>
|
||||
@@ -120,6 +122,56 @@ bool MainWindow::saveAs()
|
||||
return saveFile(fileName);
|
||||
}
|
||||
|
||||
void MainWindow::exportPNG()
|
||||
{
|
||||
QString exportFileName = QFileDialog::getSaveFileName(this, tr("Export PNG"), QString(), "PNG image (*.png)");
|
||||
if (exportFileName.isEmpty())
|
||||
return;
|
||||
|
||||
// Prepare widget image for extraction
|
||||
m_textWidget->pauseFlash(true);
|
||||
m_textScene->hideGUIElements(true);
|
||||
bool reshowCodes = m_textWidget->pageRender()->showCodes();
|
||||
if (reshowCodes)
|
||||
m_textWidget->pageRender()->setShowCodes(false);
|
||||
// Disable exporting in Mix mode as it corrupts the background
|
||||
bool reMix = m_textWidget->pageRender()->mix();
|
||||
if (reMix)
|
||||
m_textWidget->pageRender()->setMix(false);
|
||||
|
||||
// Extract the image from the scene
|
||||
QImage interImage = QImage(m_textScene->sceneRect().size().toSize(), QImage::Format_RGB32);
|
||||
// This ought to make the background transparent in Mix mode, but it doesn't
|
||||
// if (m_textWidget->pageRender()->mix())
|
||||
// interImage.fill(QColor(0, 0, 0, 0));
|
||||
QPainter interPainter(&interImage);
|
||||
m_textScene->render(&interPainter);
|
||||
|
||||
// Now we've extracted the image we can put the GUI things back
|
||||
m_textScene->hideGUIElements(false);
|
||||
if (reshowCodes)
|
||||
m_textWidget->pageRender()->setShowCodes(true);
|
||||
if (reMix)
|
||||
m_textWidget->pageRender()->setMix(true);
|
||||
m_textWidget->pauseFlash(false);
|
||||
|
||||
// Now scale the extracted image to the selected aspect ratio
|
||||
// We do this in two steps so that anti-aliasing only occurs on vertical lines
|
||||
|
||||
// Double the vertical height first
|
||||
const QImage doubleHeightImage = interImage.scaled(interImage.width(), interImage.height()*2, Qt::IgnoreAspectRatio, Qt::FastTransformation);
|
||||
|
||||
// If aspect ratio is Pixel 1:2 we're already at the correct scale
|
||||
if (m_viewAspectRatio != 3) {
|
||||
// Scale it horizontally to the selected aspect ratio
|
||||
const QImage scaledImage = doubleHeightImage.scaled((int)((float)doubleHeightImage.width() * aspectRatioHorizontalScaling[m_viewAspectRatio] * 2), doubleHeightImage.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
if (!scaledImage.save(exportFileName, "PNG"))
|
||||
QMessageBox::warning(this, tr("QTeletextMaker"), tr("Cannot export file %1.").arg(QDir::toNativeSeparators(exportFileName)));
|
||||
} else if (!doubleHeightImage.save(exportFileName, "PNG"))
|
||||
QMessageBox::warning(this, tr("QTeletextMaker"), tr("Cannot export file %1.").arg(QDir::toNativeSeparators(exportFileName)));
|
||||
}
|
||||
|
||||
void MainWindow::exportZXNet()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl("http://zxnet.co.uk/teletext/editor/" + exportHashStringPage(m_textWidget->document()->currentSubPage()) + exportHashStringPackets(m_textWidget->document()->currentSubPage())));
|
||||
@@ -166,7 +218,8 @@ void MainWindow::init()
|
||||
|
||||
m_textView = new QGraphicsView(this);
|
||||
m_textView->setScene(m_textScene);
|
||||
m_textView->setRenderHints(QPainter::SmoothPixmapTransform);
|
||||
if (m_viewSmoothTransform)
|
||||
m_textView->setRenderHints(QPainter::SmoothPixmapTransform);
|
||||
m_textView->setBackgroundBrush(QBrush(QColor(32, 48, 96)));
|
||||
setSceneDimensions();
|
||||
setCentralWidget(m_textView);
|
||||
@@ -257,14 +310,18 @@ void MainWindow::createActions()
|
||||
|
||||
setRecentFilesVisible(MainWindow::hasRecentFiles());
|
||||
|
||||
QMenu *exportHashStringSubMenu = fileMenu->addMenu(tr("Export to online editor"));
|
||||
QAction *exportPNGAct = fileMenu->addAction(tr("Export subpage as PNG..."));
|
||||
exportPNGAct->setStatusTip("Export a PNG image of this subpage");
|
||||
connect(exportPNGAct, &QAction::triggered, this, &MainWindow::exportPNG);
|
||||
|
||||
QMenu *exportHashStringSubMenu = fileMenu->addMenu(tr("Export subpage to online editor"));
|
||||
|
||||
QAction *exportZXNetAct = exportHashStringSubMenu->addAction(tr("Open in zxnet.co.uk"));
|
||||
exportZXNetAct->setStatusTip("Export and open page in zxnet.co.uk online editor");
|
||||
exportZXNetAct->setStatusTip("Export and open this subpage in the zxnet.co.uk online editor");
|
||||
connect(exportZXNetAct, &QAction::triggered, this, &MainWindow::exportZXNet);
|
||||
|
||||
QAction *exportEditTFAct = exportHashStringSubMenu->addAction(tr("Open in edit.tf"));
|
||||
exportEditTFAct->setStatusTip("Export and open page in edit.tf online editor");
|
||||
exportEditTFAct->setStatusTip("Export and open this subpage in the edit.tf online editor");
|
||||
connect(exportEditTFAct, &QAction::triggered, this, &MainWindow::exportEditTF);
|
||||
|
||||
fileMenu->addSeparator();
|
||||
@@ -418,6 +475,13 @@ void MainWindow::createActions()
|
||||
borderGroup->addAction(m_borderActs[i]);
|
||||
}
|
||||
|
||||
viewMenu->addSeparator();
|
||||
|
||||
m_smoothTransformAction = viewMenu->addAction(tr("Smooth font scaling"));
|
||||
m_smoothTransformAction->setCheckable(true);
|
||||
m_smoothTransformAction->setStatusTip(tr("Toggle smooth font scaling"));
|
||||
connect(m_smoothTransformAction, &QAction::toggled, this, &MainWindow::setSmoothTransform);
|
||||
|
||||
QAction *zoomInAct = viewMenu->addAction(tr("Zoom In"));
|
||||
zoomInAct->setShortcuts(QKeySequence::ZoomIn);
|
||||
zoomInAct->setStatusTip(tr("Zoom in"));
|
||||
@@ -555,7 +619,6 @@ void MainWindow::createActions()
|
||||
|
||||
void MainWindow::setSceneDimensions()
|
||||
{
|
||||
const float aspectRatioHorizontalScaling[4] = { 0.6, 0.6, 0.8, 0.5 };
|
||||
const int topBottomBorders[3] = { 0, 10, 19 };
|
||||
const int pillarBoxSizes[3] = { 672, 720, 854 };
|
||||
const int leftRightBorders[3] = { 0, 24, 77 };
|
||||
@@ -612,6 +675,15 @@ void MainWindow::setAspectRatio(int newViewAspectRatio)
|
||||
setSceneDimensions();
|
||||
}
|
||||
|
||||
void MainWindow::setSmoothTransform(bool smoothTransform)
|
||||
{
|
||||
m_viewSmoothTransform = smoothTransform;
|
||||
if (smoothTransform)
|
||||
m_textView->setRenderHints(QPainter::SmoothPixmapTransform);
|
||||
else
|
||||
m_textView->setRenderHints({ });
|
||||
}
|
||||
|
||||
void MainWindow::zoomIn()
|
||||
{
|
||||
if (m_viewZoom < 4)
|
||||
@@ -705,6 +777,10 @@ void MainWindow::readSettings()
|
||||
m_viewAspectRatio = settings.value("aspectratio", 0).toInt();
|
||||
m_viewAspectRatio = (m_viewAspectRatio < 0 || m_viewAspectRatio > 2) ? 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 > 4) ? 2 : m_viewZoom;
|
||||
|
||||
@@ -743,6 +819,7 @@ void MainWindow::writeSettings()
|
||||
settings.setValue("windowState", saveState());
|
||||
settings.setValue("border", m_viewBorder);
|
||||
settings.setValue("aspectratio", m_viewAspectRatio);
|
||||
settings.setValue("smoothTransform", m_viewSmoothTransform);
|
||||
settings.setValue("zoom", m_viewZoom);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ private slots:
|
||||
void open();
|
||||
bool save();
|
||||
bool saveAs();
|
||||
void exportPNG();
|
||||
void exportZXNet();
|
||||
void exportEditTF();
|
||||
void updateRecentFileActions();
|
||||
@@ -74,6 +75,7 @@ private slots:
|
||||
void setSceneDimensions();
|
||||
void setBorder(int);
|
||||
void setAspectRatio(int);
|
||||
void setSmoothTransform(bool);
|
||||
void zoomIn();
|
||||
void zoomOut();
|
||||
void zoomReset();
|
||||
@@ -82,6 +84,7 @@ private slots:
|
||||
|
||||
private:
|
||||
enum { m_MaxRecentFiles = 10 };
|
||||
const float aspectRatioHorizontalScaling[4] = { 0.6, 0.6, 0.8, 0.5 };
|
||||
|
||||
void init();
|
||||
void createActions();
|
||||
@@ -104,6 +107,7 @@ private:
|
||||
QGraphicsView *m_textView;
|
||||
|
||||
int m_viewBorder, m_viewAspectRatio, m_viewZoom;
|
||||
bool m_viewSmoothTransform;
|
||||
PageOptionsDockWidget *m_pageOptionsDockWidget;
|
||||
PageEnhancementsDockWidget *m_pageEnhancementsDockWidget;
|
||||
X26DockWidget *m_x26DockWidget;
|
||||
@@ -115,6 +119,7 @@ private:
|
||||
QAction *m_deleteSubPageAction;
|
||||
QAction *m_borderActs[3];
|
||||
QAction *m_aspectRatioActs[4];
|
||||
QAction *m_smoothTransformAction;
|
||||
|
||||
QLabel *m_subPageLabel, *m_cursorPositionLabel;
|
||||
QToolButton *m_previousSubPageButton, *m_nextSubPageButton;
|
||||
|
||||
Reference in New Issue
Block a user