Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2ae42701c | ||
|
|
9edaa2fda7 | ||
|
|
2ec4039393 | ||
|
|
69b6ad1976 | ||
|
|
d5a9469df1 | ||
|
|
e7f6a54d8d | ||
|
|
e1a1bcf070 | ||
|
|
cd531bd0a5 | ||
|
|
a54385b8f5 | ||
|
|
38746c7f38 | ||
|
|
f256e4ed28 | ||
|
|
06970fd448 | ||
|
|
a3d4783796 | ||
|
|
c8e57150eb | ||
|
|
23c2623bcf | ||
|
|
72dbe94dc2 | ||
|
|
8d415f1a0f | ||
|
|
2c04c898ab | ||
|
|
a66474b7cf | ||
|
|
3906bfde80 | ||
|
|
19f74a1761 | ||
|
|
8903703064 | ||
|
|
56e7b0500c | ||
|
|
9fa86f8c4c | ||
|
|
551172aed3 | ||
|
|
7a0dbcca2b | ||
|
|
1a7e5aff5f | ||
|
|
c24a6b1fa1 | ||
|
|
4387e9ffbd | ||
|
|
f258c6e095 | ||
|
|
5739474957 | ||
|
|
8bc0c2c886 | ||
|
|
4584ba668d | ||
|
|
d3607f5b00 | ||
|
|
2ad5d45153 | ||
|
|
690f340922 | ||
|
|
dc93fe856d |
@@ -5,6 +5,8 @@ Features
|
|||||||
- Load and save teletext pages in .tti format.
|
- Load and save teletext pages in .tti format.
|
||||||
- Rendering of teletext pages in Levels 1, 1.5, 2.5 and 3.5
|
- Rendering of teletext pages in Levels 1, 1.5, 2.5 and 3.5
|
||||||
- Rendering of Local Objects and side panels.
|
- 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.
|
- Interactive X/26 Local Enhancement Data triplet editor.
|
||||||
- Editing of X/27/4 and X/27/5 compositional links to enhancement data pages.
|
- Editing of X/27/4 and X/27/5 compositional links to enhancement data pages.
|
||||||
- Palette editor.
|
- Palette editor.
|
||||||
@@ -49,11 +51,9 @@ The Active Position, whether set explicitly by a "Set Active Position" triplet o
|
|||||||
- The Active Position can never be moved up to a lesser numbered row.
|
- The Active Position can never be moved up to a lesser numbered row.
|
||||||
- The Active Position can never be moved left *within the same row* to a lesser numbered column, but it can be moved left at the same time as it is moved down to a greater numbered row.
|
- The Active Position can never be moved left *within the same row* to a lesser numbered column, but it can be moved left at the same time as it is moved down to a greater numbered row.
|
||||||
|
|
||||||
If this rule is not followed then triplets in earlier screen addresses will be ignored.
|
If this rule is not followed then triplets in earlier screen addresses will be ignored. Triplets that break this rule will be highlighted red in the X/26 triplet editor.
|
||||||
|
|
||||||
### Objects
|
### Objects
|
||||||
"Define ... Object" triplets need to declare that they are in the correct place in the triplet list e.g. if the Define Object triplet is at `d1 t3` in the list then the data field must show `Local: d1 t3`, otherwise the Object won't appear.
|
Insert and deleting triplets from the list will upset the Object pointers on "Invoke" triplets and will need to be corrected afterwards. A future version of the editor may adjust these pointers automatically.
|
||||||
|
|
||||||
Insert and deleting triplets from the list will upset the Object pointers on both "Define" and "Invoke" triplets and will need to be corrected afterwards. A future version of the editor may adjust these pointers automatically.
|
|
||||||
|
|
||||||
"Invoke ... Object" triplets must point to a "Define ... Object" of the same type e.g. "Invoke *Active* Object" must point to a "Define *Active* Object", otherwise the Object won't appear.
|
"Invoke ... Object" triplets must point to a "Define ... Object" of the same type e.g. "Invoke *Active* Object" must point to a "Define *Active* Object", otherwise the Object won't appear.
|
||||||
|
|||||||
142
document.cpp
142
document.cpp
@@ -17,12 +17,46 @@
|
|||||||
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
|
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
|
|
||||||
#include "levelonepage.h"
|
#include "levelonepage.h"
|
||||||
|
|
||||||
|
ClutModel::ClutModel(QObject *parent): QAbstractListModel(parent)
|
||||||
|
{
|
||||||
|
m_subPage = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClutModel::rowCount(const QModelIndex & /*parent*/) const
|
||||||
|
{
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ClutModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
return QString("CLUT %1:%2").arg(index.row() >> 3).arg(index.row() & 0x07);
|
||||||
|
|
||||||
|
if (role == Qt::DecorationRole && m_subPage != nullptr)
|
||||||
|
return m_subPage->CLUTtoQColor(index.row());
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClutModel::setSubPage(LevelOnePage *subPage)
|
||||||
|
{
|
||||||
|
if (subPage != m_subPage) {
|
||||||
|
m_subPage = subPage;
|
||||||
|
emit dataChanged(createIndex(0, 0), createIndex(31, 0), QVector<int>(Qt::DecorationRole));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TeletextDocument::TeletextDocument()
|
TeletextDocument::TeletextDocument()
|
||||||
{
|
{
|
||||||
m_pageNumber = 0x199;
|
m_pageNumber = 0x199;
|
||||||
@@ -34,11 +68,17 @@ TeletextDocument::TeletextDocument()
|
|||||||
m_undoStack = new QUndoStack(this);
|
m_undoStack = new QUndoStack(this);
|
||||||
m_cursorRow = 1;
|
m_cursorRow = 1;
|
||||||
m_cursorColumn = 0;
|
m_cursorColumn = 0;
|
||||||
|
m_selectionCornerRow = m_selectionCornerColumn = -1;
|
||||||
m_selectionSubPage = nullptr;
|
m_selectionSubPage = nullptr;
|
||||||
|
|
||||||
|
m_clutModel = new ClutModel;
|
||||||
|
m_clutModel->setSubPage(m_subPages[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TeletextDocument::~TeletextDocument()
|
TeletextDocument::~TeletextDocument()
|
||||||
{
|
{
|
||||||
|
delete m_clutModel;
|
||||||
|
|
||||||
for (auto &subPage : m_subPages)
|
for (auto &subPage : m_subPages)
|
||||||
delete(subPage);
|
delete(subPage);
|
||||||
for (auto &recycleSubPage : m_recycleSubPages)
|
for (auto &recycleSubPage : m_recycleSubPages)
|
||||||
@@ -71,8 +111,12 @@ void TeletextDocument::selectSubPageIndex(int newSubPageIndex, bool forceRefresh
|
|||||||
// forceRefresh overrides "beyond the last subpage" check, so inserting a subpage after the last one still shows - dangerous workaround?
|
// forceRefresh overrides "beyond the last subpage" check, so inserting a subpage after the last one still shows - dangerous workaround?
|
||||||
if (forceRefresh || (newSubPageIndex != m_currentSubPageIndex && newSubPageIndex < m_subPages.size())) {
|
if (forceRefresh || (newSubPageIndex != m_currentSubPageIndex && newSubPageIndex < m_subPages.size())) {
|
||||||
emit aboutToChangeSubPage();
|
emit aboutToChangeSubPage();
|
||||||
|
|
||||||
m_currentSubPageIndex = newSubPageIndex;
|
m_currentSubPageIndex = newSubPageIndex;
|
||||||
|
|
||||||
|
m_clutModel->setSubPage(m_subPages[m_currentSubPageIndex]);
|
||||||
emit subPageSelected();
|
emit subPageSelected();
|
||||||
|
emit selectionMoved();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,8 +125,12 @@ void TeletextDocument::selectSubPageNext()
|
|||||||
{
|
{
|
||||||
if (m_currentSubPageIndex < m_subPages.size()-1) {
|
if (m_currentSubPageIndex < m_subPages.size()-1) {
|
||||||
emit aboutToChangeSubPage();
|
emit aboutToChangeSubPage();
|
||||||
|
|
||||||
m_currentSubPageIndex++;
|
m_currentSubPageIndex++;
|
||||||
|
|
||||||
|
m_clutModel->setSubPage(m_subPages[m_currentSubPageIndex]);
|
||||||
emit subPageSelected();
|
emit subPageSelected();
|
||||||
|
emit selectionMoved();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,8 +138,12 @@ void TeletextDocument::selectSubPagePrevious()
|
|||||||
{
|
{
|
||||||
if (m_currentSubPageIndex > 0) {
|
if (m_currentSubPageIndex > 0) {
|
||||||
emit aboutToChangeSubPage();
|
emit aboutToChangeSubPage();
|
||||||
|
|
||||||
m_currentSubPageIndex--;
|
m_currentSubPageIndex--;
|
||||||
|
|
||||||
|
m_clutModel->setSubPage(m_subPages[m_currentSubPageIndex]);
|
||||||
emit subPageSelected();
|
emit subPageSelected();
|
||||||
|
emit selectionMoved();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +164,8 @@ void TeletextDocument::insertSubPage(int beforeSubPageIndex, bool copySubPage)
|
|||||||
|
|
||||||
void TeletextDocument::deleteSubPage(int subPageToDelete)
|
void TeletextDocument::deleteSubPage(int subPageToDelete)
|
||||||
{
|
{
|
||||||
|
m_clutModel->setSubPage(nullptr);
|
||||||
|
|
||||||
delete(m_subPages[subPageToDelete]);
|
delete(m_subPages[subPageToDelete]);
|
||||||
m_subPages.erase(m_subPages.begin()+subPageToDelete);
|
m_subPages.erase(m_subPages.begin()+subPageToDelete);
|
||||||
}
|
}
|
||||||
@@ -168,62 +222,124 @@ void TeletextDocument::setFastTextLinkPageNumberOnAllSubPages(int linkNumber, in
|
|||||||
subPage->setFastTextLinkPageNumber(linkNumber, pageNumber);
|
subPage->setFastTextLinkPageNumber(linkNumber, pageNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextDocument::cursorUp()
|
void TeletextDocument::cursorUp(bool shiftKey)
|
||||||
{
|
{
|
||||||
|
if (shiftKey && !selectionActive())
|
||||||
|
setSelectionCorner(m_cursorRow, m_cursorColumn);
|
||||||
|
|
||||||
if (--m_cursorRow == 0)
|
if (--m_cursorRow == 0)
|
||||||
m_cursorRow = 24;
|
m_cursorRow = 24;
|
||||||
|
|
||||||
|
if (shiftKey)
|
||||||
|
emit selectionMoved();
|
||||||
|
else
|
||||||
|
cancelSelection();
|
||||||
|
|
||||||
emit cursorMoved();
|
emit cursorMoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextDocument::cursorDown()
|
void TeletextDocument::cursorDown(bool shiftKey)
|
||||||
{
|
{
|
||||||
|
if (shiftKey && !selectionActive())
|
||||||
|
setSelectionCorner(m_cursorRow, m_cursorColumn);
|
||||||
|
|
||||||
if (++m_cursorRow == 25)
|
if (++m_cursorRow == 25)
|
||||||
m_cursorRow = 1;
|
m_cursorRow = 1;
|
||||||
|
|
||||||
|
if (shiftKey)
|
||||||
|
emit selectionMoved();
|
||||||
|
else
|
||||||
|
cancelSelection();
|
||||||
|
|
||||||
emit cursorMoved();
|
emit cursorMoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextDocument::cursorLeft()
|
void TeletextDocument::cursorLeft(bool shiftKey)
|
||||||
{
|
{
|
||||||
|
if (shiftKey && !selectionActive())
|
||||||
|
setSelectionCorner(m_cursorRow, m_cursorColumn);
|
||||||
|
|
||||||
if (--m_cursorColumn == -1) {
|
if (--m_cursorColumn == -1) {
|
||||||
m_cursorColumn = 39;
|
m_cursorColumn = 39;
|
||||||
cursorUp();
|
cursorUp(shiftKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shiftKey)
|
||||||
|
emit selectionMoved();
|
||||||
|
else
|
||||||
|
cancelSelection();
|
||||||
|
|
||||||
emit cursorMoved();
|
emit cursorMoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextDocument::cursorRight()
|
void TeletextDocument::cursorRight(bool shiftKey)
|
||||||
{
|
{
|
||||||
|
if (shiftKey && !selectionActive())
|
||||||
|
setSelectionCorner(m_cursorRow, m_cursorColumn);
|
||||||
|
|
||||||
if (++m_cursorColumn == 40) {
|
if (++m_cursorColumn == 40) {
|
||||||
m_cursorColumn = 0;
|
m_cursorColumn = 0;
|
||||||
cursorDown();
|
cursorDown(shiftKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shiftKey)
|
||||||
|
emit selectionMoved();
|
||||||
|
else
|
||||||
|
cancelSelection();
|
||||||
|
|
||||||
emit cursorMoved();
|
emit cursorMoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextDocument::moveCursor(int cursorRow, int cursorColumn)
|
void TeletextDocument::moveCursor(int cursorRow, int cursorColumn, bool selectionInProgress)
|
||||||
{
|
{
|
||||||
|
if (selectionInProgress && !selectionActive())
|
||||||
|
setSelectionCorner(m_cursorRow, m_cursorColumn);
|
||||||
|
|
||||||
if (cursorRow != -1)
|
if (cursorRow != -1)
|
||||||
m_cursorRow = cursorRow;
|
m_cursorRow = cursorRow;
|
||||||
if (cursorColumn != -1)
|
if (cursorColumn != -1)
|
||||||
m_cursorColumn = cursorColumn;
|
m_cursorColumn = cursorColumn;
|
||||||
|
|
||||||
|
if (selectionInProgress)
|
||||||
|
emit selectionMoved();
|
||||||
|
else
|
||||||
|
cancelSelection();
|
||||||
|
|
||||||
emit cursorMoved();
|
emit cursorMoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TeletextDocument::setSelectionCorner(int row, int column)
|
||||||
|
{
|
||||||
|
if (m_selectionCornerRow != row || m_selectionCornerColumn != column) {
|
||||||
|
m_selectionSubPage = currentSubPage();
|
||||||
|
m_selectionCornerRow = row;
|
||||||
|
m_selectionCornerColumn = column;
|
||||||
|
|
||||||
|
// emit selectionMoved();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TeletextDocument::setSelection(int topRow, int leftColumn, int bottomRow, int rightColumn)
|
void TeletextDocument::setSelection(int topRow, int leftColumn, int bottomRow, int rightColumn)
|
||||||
{
|
{
|
||||||
if (m_selectionTopRow != topRow || m_selectionBottomRow != bottomRow || m_selectionLeftColumn != leftColumn || m_selectionRightColumn != rightColumn) {
|
if (selectionTopRow() != topRow || selectionBottomRow() != bottomRow || selectionLeftColumn() != leftColumn || selectionRightColumn() != rightColumn) {
|
||||||
m_selectionSubPage = currentSubPage();
|
m_selectionSubPage = currentSubPage();
|
||||||
m_selectionTopRow = topRow;
|
m_selectionCornerRow = topRow;
|
||||||
m_selectionBottomRow = bottomRow;
|
m_cursorRow = bottomRow;
|
||||||
m_selectionLeftColumn = leftColumn;
|
m_selectionCornerColumn = leftColumn;
|
||||||
m_selectionRightColumn = rightColumn;
|
m_cursorColumn = rightColumn;
|
||||||
|
|
||||||
emit selectionMoved();
|
emit selectionMoved();
|
||||||
|
emit cursorMoved();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextDocument::cancelSelection()
|
void TeletextDocument::cancelSelection()
|
||||||
{
|
{
|
||||||
m_selectionSubPage = nullptr;
|
if (m_selectionSubPage != nullptr) {
|
||||||
|
m_selectionSubPage = nullptr;
|
||||||
|
emit selectionMoved();
|
||||||
|
m_selectionCornerRow = m_selectionCornerColumn = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int TeletextDocument::levelRequired() const
|
int TeletextDocument::levelRequired() const
|
||||||
|
|||||||
46
document.h
46
document.h
@@ -20,11 +20,28 @@
|
|||||||
#ifndef DOCUMENT_H
|
#ifndef DOCUMENT_H
|
||||||
#define DOCUMENT_H
|
#define DOCUMENT_H
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QUndoStack>
|
#include <QUndoStack>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "levelonepage.h"
|
#include "levelonepage.h"
|
||||||
|
|
||||||
|
class ClutModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClutModel(QObject *parent = 0);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
void setSubPage(LevelOnePage *page);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LevelOnePage *m_subPage;
|
||||||
|
};
|
||||||
|
|
||||||
class TeletextDocument : public QObject
|
class TeletextDocument : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -62,20 +79,24 @@ public:
|
|||||||
void setDescription(QString);
|
void setDescription(QString);
|
||||||
void setFastTextLinkPageNumberOnAllSubPages(int, int);
|
void setFastTextLinkPageNumberOnAllSubPages(int, int);
|
||||||
QUndoStack *undoStack() const { return m_undoStack; }
|
QUndoStack *undoStack() const { return m_undoStack; }
|
||||||
|
ClutModel *clutModel() const { return m_clutModel; }
|
||||||
int cursorRow() const { return m_cursorRow; }
|
int cursorRow() const { return m_cursorRow; }
|
||||||
int cursorColumn() const { return m_cursorColumn; }
|
int cursorColumn() const { return m_cursorColumn; }
|
||||||
void cursorUp();
|
void cursorUp(bool shiftKey=false);
|
||||||
void cursorDown();
|
void cursorDown(bool shiftKey=false);
|
||||||
void cursorLeft();
|
void cursorLeft(bool shiftKey=false);
|
||||||
void cursorRight();
|
void cursorRight(bool shiftKey=false);
|
||||||
void moveCursor(int, int);
|
void moveCursor(int, int, bool selectionInProgress=false);
|
||||||
int selectionTopRow() const { return m_selectionTopRow; }
|
int selectionTopRow() const { return m_selectionCornerRow == -1 ? m_cursorRow : qMin(m_selectionCornerRow, m_cursorRow); }
|
||||||
int selectionBottomRow() const { return m_selectionBottomRow; }
|
int selectionBottomRow() const { return qMax(m_selectionCornerRow, m_cursorRow); }
|
||||||
int selectionLeftColumn() const { return m_selectionLeftColumn; }
|
int selectionLeftColumn() const { return m_selectionCornerColumn == -1 ? m_cursorColumn : qMin(m_selectionCornerColumn, m_cursorColumn); }
|
||||||
int selectionRightColumn() const { return m_selectionRightColumn; }
|
int selectionRightColumn() const { return qMax(m_selectionCornerColumn, m_cursorColumn); }
|
||||||
int selectionWidth() const { return m_selectionRightColumn - m_selectionLeftColumn + 1; }
|
int selectionWidth() const { return m_selectionCornerColumn == -1 ? 1 : selectionRightColumn() - selectionLeftColumn() + 1; }
|
||||||
int selectionHeight() const { return m_selectionBottomRow - m_selectionTopRow + 1; }
|
int selectionHeight() const { return m_selectionCornerRow == -1 ? 1 : selectionBottomRow() - selectionTopRow() + 1; }
|
||||||
bool selectionActive() const { return m_selectionSubPage == currentSubPage(); }
|
bool selectionActive() const { return m_selectionSubPage == currentSubPage(); }
|
||||||
|
int selectionCornerRow() const { return m_selectionCornerRow == -1 ? m_cursorRow : m_selectionCornerRow; }
|
||||||
|
int selectionCornerColumn() const { return m_selectionCornerColumn == -1 ? m_cursorColumn : m_selectionCornerColumn; }
|
||||||
|
void setSelectionCorner(int, int);
|
||||||
void setSelection(int, int, int, int);
|
void setSelection(int, int, int, int);
|
||||||
void cancelSelection();
|
void cancelSelection();
|
||||||
int levelRequired() const;
|
int levelRequired() const;
|
||||||
@@ -99,8 +120,9 @@ private:
|
|||||||
std::vector<LevelOnePage *> m_subPages;
|
std::vector<LevelOnePage *> m_subPages;
|
||||||
std::vector<LevelOnePage *> m_recycleSubPages;
|
std::vector<LevelOnePage *> m_recycleSubPages;
|
||||||
QUndoStack *m_undoStack;
|
QUndoStack *m_undoStack;
|
||||||
int m_cursorRow, m_cursorColumn, m_selectionTopRow, m_selectionBottomRow, m_selectionLeftColumn, m_selectionRightColumn;
|
int m_cursorRow, m_cursorColumn, m_selectionCornerRow, m_selectionCornerColumn;
|
||||||
LevelOnePage *m_selectionSubPage;
|
LevelOnePage *m_selectionSubPage;
|
||||||
|
ClutModel *m_clutModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
23
examples/Level1p5-Defcon.tti
Normal file
23
examples/Level1p5-Defcon.tti
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
PN,11600
|
||||||
|
SC,0000
|
||||||
|
PS,8000
|
||||||
|
CT,8,T
|
||||||
|
OL,26,@lD@Ib\UbTXb\ZbT]b\`B]mD@HB{VBsWB{[Bs\B{
|
||||||
|
OL,26,AaBRnD@`BraB]oD@HBXVBPWBX[BP\BX`B}pD@Iby
|
||||||
|
OL,26,BUbqXbyZbq]byaBruD@KBYLBSRbTVb\ZbT^b\cbY
|
||||||
|
OL,26,CdBSvD@JBYKBSLBywD@Fb\JBTKByLBsVB^ZbX[bU
|
||||||
|
OL,26,D\bS^bxxD@[bx\bu]bsyD@BbqFbyRbqVbyCC
|
||||||
|
OL,3,W <,,,,,,,,,,,,,,,,,,,,,,,,,,,,,l
|
||||||
|
OL,4,W 5t xt xt 5 j
|
||||||
|
OL,5,W 5 " !"/ !" j
|
||||||
|
OL,6,W 5 j5j
|
||||||
|
OL,7,W 5 ` 0`| 0` j
|
||||||
|
OL,8,W 5' +' +' jj
|
||||||
|
OL,9,W -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.
|
||||||
|
OL,12,V<,,,,,lR<,,,,,lS<,,,,,lQ<,,,,,lW<,,,,,l
|
||||||
|
OL,13,V5jR5 `5jS5xtjQ5xtjW5 `~5 j
|
||||||
|
OL,14,V55 jR5 ~75jS5/% jjQ5/% jjW5 #5 j
|
||||||
|
OL,15,V5tjR5z? 5jS5 j5jQ5`x~/jW5 5 j
|
||||||
|
OL,16,V5|4 jjR5jS5|4 jjQ5?# jW5 5 j
|
||||||
|
OL,17,V5+'jR5 5jS5+'jQ5jW5 5 j
|
||||||
|
OL,18,V-,,,,,.R-,,,,,.S-,,,,,.Q-,,,,,.W-,,,,,.
|
||||||
33
examples/SidePanels-PriceChop.tti
Normal file
33
examples/SidePanels-PriceChop.tti
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
PN,13200
|
||||||
|
SC,0000
|
||||||
|
PS,8000
|
||||||
|
CT,8,T
|
||||||
|
OL,28,@@@|H@p_@|wsA@@AfUrLs_w}ww]_}_wM@p
|
||||||
|
OL,26,@rD@Ab|BBpKBxLbtsD@BB{CbqJbyKBstD@Db|EBp
|
||||||
|
OL,26,AHBxIbtuD@EB{FbqGbyHBswD@AbqLbyxD@Bb|CBp
|
||||||
|
OL,26,BJBxKbtyD@CB{DbqIbyJBszD@Eb|FBpGBxHbt{D@
|
||||||
|
OL,26,CFB{GBs}aJ@cJhPThr]hP`hre~aI@cI_Cxv]@It
|
||||||
|
OL,26,DAipBitCIwGi\iD@@@H@irAiyBIzCirDIyxve@Iy
|
||||||
|
OL,26,EAIqCiqDItEipFitGIwiD@@@HAisBIvCipDiyEis
|
||||||
|
OL,26,FFiwGi{BBBBBBBBBBB
|
||||||
|
OL,1, calls cost #5 WZ`p0ppb`p0pp `p0up`p0pp
|
||||||
|
OL,2, 0909 879 0100 WZjp55"jj 1=.(j 15jj 5uz
|
||||||
|
OL,3, GB #9.99 p&p WZ* ! ""#!## "#!!""#!%
|
||||||
|
OL,4, W Zn,h h
|
||||||
|
OL,5,C]Dstart #89 \ W Zjp"d&
|
||||||
|
OL,6,S############
|
||||||
|
OL,7, LIVE
|
||||||
|
OL,8,E]G now at \
|
||||||
|
OL,9,Ussssssssssss
|
||||||
|
OL,10,U+'
|
||||||
|
OL,11,U^"o]G#3U?\!
|
||||||
|
OL,12,U +'
|
||||||
|
OL,13,U "o?!
|
||||||
|
OL,14,Spppppppppppp
|
||||||
|
OL,15,S+]D^leftS\'
|
||||||
|
OL,16,S^"o]D24S?\!
|
||||||
|
OL,17,S +'
|
||||||
|
OL,18,S "o?!
|
||||||
|
OL,19,S
|
||||||
|
OL,21,E]G9ct gold curb chain 9ct gold curb c
|
||||||
|
OL,22,C]DNEW BUYER JOHN london JANET manch
|
||||||
@@ -17,16 +17,29 @@
|
|||||||
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
|
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QByteArrayList>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QMimeData>
|
||||||
|
|
||||||
#include "levelonecommands.h"
|
#include "levelonecommands.h"
|
||||||
|
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
|
#include "keymap.h"
|
||||||
|
|
||||||
TypeCharacterCommand::TypeCharacterCommand(TeletextDocument *teletextDocument, unsigned char newCharacter, bool insertMode, QUndoCommand *parent) : QUndoCommand(parent)
|
LevelOneCommand::LevelOneCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : QUndoCommand(parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
m_teletextDocument = teletextDocument;
|
||||||
m_subPageIndex = teletextDocument->currentSubPageIndex();
|
m_subPageIndex = teletextDocument->currentSubPageIndex();
|
||||||
m_row = teletextDocument->cursorRow();
|
m_row = teletextDocument->cursorRow();
|
||||||
m_columnStart = m_columnEnd = teletextDocument->cursorColumn();
|
m_column = teletextDocument->cursorColumn();
|
||||||
|
m_firstDo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeCharacterCommand::TypeCharacterCommand(TeletextDocument *teletextDocument, unsigned char newCharacter, bool insertMode, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
|
{
|
||||||
|
m_columnStart = m_columnEnd = m_column;
|
||||||
m_newCharacter = newCharacter;
|
m_newCharacter = newCharacter;
|
||||||
m_insertMode = insertMode;
|
m_insertMode = insertMode;
|
||||||
|
|
||||||
@@ -37,7 +50,6 @@ TypeCharacterCommand::TypeCharacterCommand(TeletextDocument *teletextDocument, u
|
|||||||
setText(QObject::tr("insert character"));
|
setText(QObject::tr("insert character"));
|
||||||
else
|
else
|
||||||
setText(QObject::tr("overwrite character"));
|
setText(QObject::tr("overwrite character"));
|
||||||
m_firstDo = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeCharacterCommand::redo()
|
void TypeCharacterCommand::redo()
|
||||||
@@ -89,12 +101,8 @@ bool TypeCharacterCommand::mergeWith(const QUndoCommand *command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ToggleMosaicBitCommand::ToggleMosaicBitCommand(TeletextDocument *teletextDocument, unsigned char bitToToggle, QUndoCommand *parent) : QUndoCommand(parent)
|
ToggleMosaicBitCommand::ToggleMosaicBitCommand(TeletextDocument *teletextDocument, unsigned char bitToToggle, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
|
||||||
m_subPageIndex = teletextDocument->currentSubPageIndex();
|
|
||||||
m_row = teletextDocument->cursorRow();
|
|
||||||
m_column = teletextDocument->cursorColumn();
|
|
||||||
m_oldCharacter = teletextDocument->currentSubPage()->character(m_row, m_column);
|
m_oldCharacter = teletextDocument->currentSubPage()->character(m_row, m_column);
|
||||||
if (bitToToggle == 0x20 || bitToToggle == 0x7f)
|
if (bitToToggle == 0x20 || bitToToggle == 0x7f)
|
||||||
m_newCharacter = bitToToggle;
|
m_newCharacter = bitToToggle;
|
||||||
@@ -134,12 +142,10 @@ bool ToggleMosaicBitCommand::mergeWith(const QUndoCommand *command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BackspaceKeyCommand::BackspaceKeyCommand(TeletextDocument *teletextDocument, bool insertMode, QUndoCommand *parent) : QUndoCommand(parent)
|
BackspaceKeyCommand::BackspaceKeyCommand(TeletextDocument *teletextDocument, bool insertMode, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
m_columnStart = m_column - 1;
|
||||||
m_subPageIndex = teletextDocument->currentSubPageIndex();
|
|
||||||
m_row = teletextDocument->cursorRow();
|
|
||||||
m_columnStart = teletextDocument->cursorColumn()-1;
|
|
||||||
if (m_columnStart == -1) {
|
if (m_columnStart == -1) {
|
||||||
m_columnStart = 39;
|
m_columnStart = 39;
|
||||||
if (--m_row == 0)
|
if (--m_row == 0)
|
||||||
@@ -152,7 +158,6 @@ BackspaceKeyCommand::BackspaceKeyCommand(TeletextDocument *teletextDocument, boo
|
|||||||
m_oldRowContents[c] = m_newRowContents[c] = m_teletextDocument->currentSubPage()->character(m_row, c);
|
m_oldRowContents[c] = m_newRowContents[c] = m_teletextDocument->currentSubPage()->character(m_row, c);
|
||||||
|
|
||||||
setText(QObject::tr("backspace"));
|
setText(QObject::tr("backspace"));
|
||||||
m_firstDo = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackspaceKeyCommand::redo()
|
void BackspaceKeyCommand::redo()
|
||||||
@@ -208,13 +213,8 @@ bool BackspaceKeyCommand::mergeWith(const QUndoCommand *command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DeleteKeyCommand::DeleteKeyCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : QUndoCommand(parent)
|
DeleteKeyCommand::DeleteKeyCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
|
||||||
m_subPageIndex = teletextDocument->currentSubPageIndex();
|
|
||||||
m_row = teletextDocument->cursorRow();
|
|
||||||
m_column = teletextDocument->cursorColumn();
|
|
||||||
|
|
||||||
for (int c=0; c<40; c++)
|
for (int c=0; c<40; c++)
|
||||||
m_oldRowContents[c] = m_newRowContents[c] = m_teletextDocument->currentSubPage()->character(m_row, c);
|
m_oldRowContents[c] = m_newRowContents[c] = m_teletextDocument->currentSubPage()->character(m_row, c);
|
||||||
|
|
||||||
@@ -262,11 +262,8 @@ bool DeleteKeyCommand::mergeWith(const QUndoCommand *command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
InsertRowCommand::InsertRowCommand(TeletextDocument *teletextDocument, bool copyRow, QUndoCommand *parent) : QUndoCommand(parent)
|
InsertRowCommand::InsertRowCommand(TeletextDocument *teletextDocument, bool copyRow, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
|
||||||
m_subPageIndex = teletextDocument->currentSubPageIndex();
|
|
||||||
m_row = teletextDocument->cursorRow();
|
|
||||||
m_copyRow = copyRow;
|
m_copyRow = copyRow;
|
||||||
|
|
||||||
if (m_copyRow)
|
if (m_copyRow)
|
||||||
@@ -310,12 +307,8 @@ void InsertRowCommand::undo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DeleteRowCommand::DeleteRowCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : QUndoCommand(parent)
|
DeleteRowCommand::DeleteRowCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
|
||||||
m_subPageIndex = teletextDocument->currentSubPageIndex();
|
|
||||||
m_row = teletextDocument->cursorRow();
|
|
||||||
|
|
||||||
setText(QObject::tr("delete row"));
|
setText(QObject::tr("delete row"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,10 +347,233 @@ void DeleteRowCommand::undo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
InsertSubPageCommand::InsertSubPageCommand(TeletextDocument *teletextDocument, bool afterCurrentSubPage, bool copySubPage, QUndoCommand *parent) : QUndoCommand(parent)
|
#ifndef QT_NO_CLIPBOARD
|
||||||
|
CutCommand::CutCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
m_selectionTopRow = m_teletextDocument->selectionTopRow();
|
||||||
m_newSubPageIndex = teletextDocument->currentSubPageIndex()+afterCurrentSubPage;
|
m_selectionBottomRow = m_teletextDocument->selectionBottomRow();
|
||||||
|
m_selectionLeftColumn = m_teletextDocument->selectionLeftColumn();
|
||||||
|
m_selectionRightColumn = m_teletextDocument->selectionRightColumn();
|
||||||
|
|
||||||
|
m_selectionCornerRow = m_teletextDocument->selectionCornerRow();
|
||||||
|
m_selectionCornerColumn = m_teletextDocument->selectionCornerColumn();
|
||||||
|
|
||||||
|
// Store copy of the characters that we're about to blank
|
||||||
|
for (int r=m_selectionTopRow; r<=m_selectionBottomRow; r++) {
|
||||||
|
QByteArray rowArray;
|
||||||
|
|
||||||
|
for (int c=m_selectionLeftColumn; c<=m_selectionRightColumn; c++)
|
||||||
|
rowArray.append(m_teletextDocument->currentSubPage()->character(r, c));
|
||||||
|
|
||||||
|
m_deletedCharacters.append(rowArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
setText(QObject::tr("cut"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutCommand::redo()
|
||||||
|
{
|
||||||
|
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
|
||||||
|
|
||||||
|
for (int r=m_selectionTopRow; r<=m_selectionBottomRow; r++) {
|
||||||
|
for (int c=m_selectionLeftColumn; c<=m_selectionRightColumn; c++)
|
||||||
|
m_teletextDocument->currentSubPage()->setCharacter(r, c, 0x20);
|
||||||
|
emit m_teletextDocument->contentsChange(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutCommand::undo()
|
||||||
|
{
|
||||||
|
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
|
||||||
|
|
||||||
|
int arrayR = 0;
|
||||||
|
int arrayC;
|
||||||
|
|
||||||
|
for (int r=m_selectionTopRow; r<=m_selectionBottomRow; r++) {
|
||||||
|
arrayC = 0;
|
||||||
|
for (int c=m_selectionLeftColumn; c<=m_selectionRightColumn; c++)
|
||||||
|
m_teletextDocument->currentSubPage()->setCharacter(r, c, m_deletedCharacters[arrayR].at(arrayC++));
|
||||||
|
|
||||||
|
emit m_teletextDocument->contentsChange(r);
|
||||||
|
arrayR++;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_teletextDocument->setSelectionCorner(m_selectionCornerRow, m_selectionCornerColumn);
|
||||||
|
m_teletextDocument->moveCursor(m_row, m_column, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PasteCommand::PasteCommand(TeletextDocument *teletextDocument, int pageCharSet, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
|
{
|
||||||
|
const QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
const QMimeData *mimeData = clipboard->mimeData();
|
||||||
|
QByteArray nativeData;
|
||||||
|
|
||||||
|
m_selectionActive = m_teletextDocument->selectionActive();
|
||||||
|
if (m_selectionActive) {
|
||||||
|
m_selectionCornerRow = m_teletextDocument->selectionCornerRow();
|
||||||
|
m_selectionCornerColumn = m_teletextDocument->selectionCornerColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_clipboardDataHeight = m_clipboardDataWidth = 0;
|
||||||
|
|
||||||
|
// Try to get something from the clipboard
|
||||||
|
// FIXME is this a correct "custom" mime type? Or should we use vnd?
|
||||||
|
nativeData = mimeData->data("application/x-teletext");
|
||||||
|
if (nativeData.size() > 2) {
|
||||||
|
// Native clipboard data: we put it there ourselves
|
||||||
|
m_clipboardDataHeight = nativeData.at(0);
|
||||||
|
m_clipboardDataWidth = nativeData.at(1);
|
||||||
|
|
||||||
|
// Guard against invalid dimensions or total size not matching stated dimensions
|
||||||
|
if (m_clipboardDataHeight > 0 && m_clipboardDataWidth > 0 && m_clipboardDataHeight <= 25 && m_clipboardDataWidth <= 40 && nativeData.size() == m_clipboardDataHeight * m_clipboardDataWidth + 2)
|
||||||
|
for (int r=0; r<m_clipboardDataHeight; r++)
|
||||||
|
m_pastingCharacters.append(nativeData.mid(2 + r * m_clipboardDataWidth, m_clipboardDataWidth));
|
||||||
|
else
|
||||||
|
// Invalidate
|
||||||
|
m_clipboardDataHeight = m_clipboardDataWidth = 0;
|
||||||
|
} else if (mimeData->hasText()) {
|
||||||
|
// Plain text
|
||||||
|
QStringList plainTextData = mimeData->text().split(QRegExp("\n|\r\n|\r"));
|
||||||
|
|
||||||
|
m_clipboardDataHeight = plainTextData.size();
|
||||||
|
m_clipboardDataWidth = 0;
|
||||||
|
|
||||||
|
for (int r=0; r<m_clipboardDataHeight; r++) {
|
||||||
|
m_pastingCharacters.append(QByteArray());
|
||||||
|
for (int c=0; c<plainTextData.at(r).size(); c++) {
|
||||||
|
// Try to map the unicode character to the current Level 1 character set of this page
|
||||||
|
|
||||||
|
char convertedChar;
|
||||||
|
const QChar charToConvert = plainTextData.at(r).at(c);
|
||||||
|
|
||||||
|
if (keymapping[pageCharSet].contains(charToConvert))
|
||||||
|
// Remapped character or non-Latin character converted successfully
|
||||||
|
convertedChar = keymapping[pageCharSet].value(charToConvert);
|
||||||
|
else {
|
||||||
|
// Either a Latin character or non-Latin character that can't be converted
|
||||||
|
// See if it's a Latin character
|
||||||
|
convertedChar = charToConvert.toLatin1();
|
||||||
|
if (convertedChar == 0)
|
||||||
|
// Couldn't convert - make it a block character so it doesn't need to be inserted-between later on
|
||||||
|
convertedChar = 0x7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pastingCharacters[r].append(convertedChar);
|
||||||
|
}
|
||||||
|
m_clipboardDataWidth = qMax(m_pastingCharacters.at(r).size(), m_clipboardDataWidth);
|
||||||
|
}
|
||||||
|
// Pad short lines with spaces to make a box
|
||||||
|
for (int r=0; r<m_clipboardDataHeight; r++)
|
||||||
|
m_pastingCharacters[r] = m_pastingCharacters.at(r).leftJustified(m_clipboardDataWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_clipboardDataWidth == 0 || m_clipboardDataHeight == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_selectionActive) {
|
||||||
|
m_pasteTopRow = m_teletextDocument->selectionTopRow();
|
||||||
|
m_pasteBottomRow = m_teletextDocument->selectionBottomRow();
|
||||||
|
m_pasteLeftColumn = m_teletextDocument->selectionLeftColumn();
|
||||||
|
m_pasteRightColumn = m_teletextDocument->selectionRightColumn();
|
||||||
|
} else {
|
||||||
|
m_pasteTopRow = m_row;
|
||||||
|
m_pasteBottomRow = m_row + m_clipboardDataHeight - 1;
|
||||||
|
m_pasteLeftColumn = m_column;
|
||||||
|
m_pasteRightColumn = m_column + m_clipboardDataWidth - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store copy of the characters that we're about to overwrite
|
||||||
|
for (int r=m_pasteTopRow; r<=m_pasteBottomRow; r++) {
|
||||||
|
QByteArray rowArray;
|
||||||
|
|
||||||
|
for (int c=m_pasteLeftColumn; c<=m_pasteRightColumn; c++)
|
||||||
|
// Guard against size of pasted block going beyond last line or column
|
||||||
|
if (r < 25 && c < 40)
|
||||||
|
rowArray.append(m_teletextDocument->currentSubPage()->character(r, c));
|
||||||
|
else
|
||||||
|
// Gone beyond last line or column - store a filler character which we won't see
|
||||||
|
// Not sure if this is really necessary as out-of-bounds access might not occur?
|
||||||
|
rowArray.append(0x7f);
|
||||||
|
|
||||||
|
m_deletedCharacters.append(rowArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
setText(QObject::tr("paste"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PasteCommand::redo()
|
||||||
|
{
|
||||||
|
if (m_clipboardDataWidth == 0 || m_clipboardDataHeight == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
|
||||||
|
|
||||||
|
int arrayR = 0;
|
||||||
|
int arrayC;
|
||||||
|
|
||||||
|
for (int r=m_pasteTopRow; r<=m_pasteBottomRow; r++) {
|
||||||
|
arrayC = 0;
|
||||||
|
for (int c=m_pasteLeftColumn; c<=m_pasteRightColumn; c++)
|
||||||
|
// Guard against size of pasted block going beyond last line or column
|
||||||
|
if (r < 25 && c < 40) {
|
||||||
|
m_teletextDocument->currentSubPage()->setCharacter(r, c, m_pastingCharacters[arrayR].at(arrayC++));
|
||||||
|
|
||||||
|
// If paste area is wider than clipboard data, repeat the pattern
|
||||||
|
if (arrayC == m_clipboardDataWidth)
|
||||||
|
arrayC = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r < 25)
|
||||||
|
emit m_teletextDocument->contentsChange(r);
|
||||||
|
|
||||||
|
arrayR++;
|
||||||
|
// If paste area is taller than clipboard data, repeat the pattern
|
||||||
|
if (arrayR == m_clipboardDataHeight)
|
||||||
|
arrayR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_selectionActive) {
|
||||||
|
m_teletextDocument->setSelectionCorner(m_selectionCornerRow, m_selectionCornerColumn);
|
||||||
|
m_teletextDocument->moveCursor(m_row, m_column, true);
|
||||||
|
} else {
|
||||||
|
m_teletextDocument->moveCursor(m_row, qMin(m_column+m_clipboardDataWidth-1, 39));
|
||||||
|
m_teletextDocument->cursorRight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PasteCommand::undo()
|
||||||
|
{
|
||||||
|
if (m_clipboardDataWidth == 0 || m_clipboardDataHeight == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
|
||||||
|
|
||||||
|
int arrayR = 0;
|
||||||
|
int arrayC;
|
||||||
|
|
||||||
|
for (int r=m_pasteTopRow; r<=m_pasteBottomRow; r++) {
|
||||||
|
arrayC = 0;
|
||||||
|
for (int c=m_pasteLeftColumn; c<=m_pasteRightColumn; c++)
|
||||||
|
// Guard against size of pasted block going beyond last line or column
|
||||||
|
if (r < 25 && c < 40)
|
||||||
|
m_teletextDocument->currentSubPage()->setCharacter(r, c, m_deletedCharacters[arrayR].at(arrayC++));
|
||||||
|
|
||||||
|
if (r < 25)
|
||||||
|
emit m_teletextDocument->contentsChange(r);
|
||||||
|
|
||||||
|
arrayR++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_selectionActive)
|
||||||
|
m_teletextDocument->moveCursor(m_row, m_column);
|
||||||
|
}
|
||||||
|
#endif // !QT_NO_CLIPBOARD
|
||||||
|
|
||||||
|
|
||||||
|
InsertSubPageCommand::InsertSubPageCommand(TeletextDocument *teletextDocument, bool afterCurrentSubPage, bool copySubPage, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
|
{
|
||||||
|
m_newSubPageIndex = m_subPageIndex + afterCurrentSubPage;
|
||||||
m_copySubPage = copySubPage;
|
m_copySubPage = copySubPage;
|
||||||
|
|
||||||
setText(QObject::tr("insert subpage"));
|
setText(QObject::tr("insert subpage"));
|
||||||
@@ -380,30 +596,26 @@ void InsertSubPageCommand::undo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DeleteSubPageCommand::DeleteSubPageCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : QUndoCommand(parent)
|
DeleteSubPageCommand::DeleteSubPageCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
|
||||||
m_subPageToDelete = teletextDocument->currentSubPageIndex();
|
|
||||||
setText(QObject::tr("delete subpage"));
|
setText(QObject::tr("delete subpage"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteSubPageCommand::redo()
|
void DeleteSubPageCommand::redo()
|
||||||
{
|
{
|
||||||
m_teletextDocument->deleteSubPageToRecycle(m_subPageToDelete);
|
m_teletextDocument->deleteSubPageToRecycle(m_subPageIndex);
|
||||||
m_teletextDocument->selectSubPageIndex(qMin(m_subPageToDelete, m_teletextDocument->numberOfSubPages()-1), true);
|
m_teletextDocument->selectSubPageIndex(qMin(m_subPageIndex, m_teletextDocument->numberOfSubPages()-1), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteSubPageCommand::undo()
|
void DeleteSubPageCommand::undo()
|
||||||
{
|
{
|
||||||
m_teletextDocument->unDeleteSubPageFromRecycle(m_subPageToDelete);
|
m_teletextDocument->unDeleteSubPageFromRecycle(m_subPageIndex);
|
||||||
m_teletextDocument->selectSubPageIndex(m_subPageToDelete, true);
|
m_teletextDocument->selectSubPageIndex(m_subPageIndex, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SetColourCommand::SetColourCommand(TeletextDocument *teletextDocument, int colourIndex, int newColour, QUndoCommand *parent) : QUndoCommand(parent)
|
SetColourCommand::SetColourCommand(TeletextDocument *teletextDocument, int colourIndex, int newColour, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
|
||||||
m_subPageIndex = teletextDocument->currentSubPageIndex();
|
|
||||||
m_colourIndex = colourIndex;
|
m_colourIndex = colourIndex;
|
||||||
m_oldColour = teletextDocument->currentSubPage()->CLUT(colourIndex);
|
m_oldColour = teletextDocument->currentSubPage()->CLUT(colourIndex);
|
||||||
m_newColour = newColour;
|
m_newColour = newColour;
|
||||||
@@ -431,10 +643,8 @@ void SetColourCommand::undo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ResetCLUTCommand::ResetCLUTCommand(TeletextDocument *teletextDocument, int colourTable, QUndoCommand *parent) : QUndoCommand(parent)
|
ResetCLUTCommand::ResetCLUTCommand(TeletextDocument *teletextDocument, int colourTable, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
|
||||||
{
|
{
|
||||||
m_teletextDocument = teletextDocument;
|
|
||||||
m_subPageIndex = teletextDocument->currentSubPageIndex();
|
|
||||||
m_colourTable = colourTable;
|
m_colourTable = colourTable;
|
||||||
for (int i=m_colourTable*8; i<m_colourTable*8+8; i++)
|
for (int i=m_colourTable*8; i<m_colourTable*8+8; i++)
|
||||||
m_oldColourEntry[i&7] = teletextDocument->currentSubPage()->CLUT(i);
|
m_oldColourEntry[i&7] = teletextDocument->currentSubPage()->CLUT(i);
|
||||||
|
|||||||
@@ -20,11 +20,23 @@
|
|||||||
#ifndef LEVELONECOMMANDS_H
|
#ifndef LEVELONECOMMANDS_H
|
||||||
#define LEVELONECOMMANDS_H
|
#define LEVELONECOMMANDS_H
|
||||||
|
|
||||||
|
#include <QByteArrayList>
|
||||||
#include <QUndoCommand>
|
#include <QUndoCommand>
|
||||||
|
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
|
|
||||||
class TypeCharacterCommand : public QUndoCommand
|
class LevelOneCommand : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LevelOneCommand(TeletextDocument *, QUndoCommand *parent = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TeletextDocument *m_teletextDocument;
|
||||||
|
int m_subPageIndex, m_row, m_column;
|
||||||
|
bool m_firstDo;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TypeCharacterCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum { Id = 101 };
|
enum { Id = 101 };
|
||||||
@@ -37,13 +49,12 @@ public:
|
|||||||
int id() const override { return Id; }
|
int id() const override { return Id; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeletextDocument *m_teletextDocument;
|
|
||||||
unsigned char m_newCharacter, m_oldRowContents[40], m_newRowContents[40];
|
unsigned char m_newCharacter, m_oldRowContents[40], m_newRowContents[40];
|
||||||
int m_subPageIndex, m_row, m_columnStart, m_columnEnd;
|
int m_columnStart, m_columnEnd;
|
||||||
bool m_firstDo, m_insertMode;
|
bool m_insertMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ToggleMosaicBitCommand : public QUndoCommand
|
class ToggleMosaicBitCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum { Id = 102 };
|
enum { Id = 102 };
|
||||||
@@ -56,12 +67,10 @@ public:
|
|||||||
int id() const override { return Id; }
|
int id() const override { return Id; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeletextDocument *m_teletextDocument;
|
|
||||||
unsigned char m_oldCharacter, m_newCharacter;
|
unsigned char m_oldCharacter, m_newCharacter;
|
||||||
int m_subPageIndex, m_row, m_column;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BackspaceKeyCommand : public QUndoCommand
|
class BackspaceKeyCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum { Id = 103 };
|
enum { Id = 103 };
|
||||||
@@ -74,13 +83,12 @@ public:
|
|||||||
int id() const override { return Id; }
|
int id() const override { return Id; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeletextDocument *m_teletextDocument;
|
|
||||||
unsigned char m_oldRowContents[40], m_newRowContents[40];
|
unsigned char m_oldRowContents[40], m_newRowContents[40];
|
||||||
int m_subPageIndex, m_row, m_columnStart, m_columnEnd;
|
int m_columnStart, m_columnEnd;
|
||||||
bool m_firstDo, m_insertMode;
|
bool m_insertMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeleteKeyCommand : public QUndoCommand
|
class DeleteKeyCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum { Id = 104 };
|
enum { Id = 104 };
|
||||||
@@ -93,12 +101,10 @@ public:
|
|||||||
int id() const override { return Id; }
|
int id() const override { return Id; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeletextDocument *m_teletextDocument;
|
|
||||||
unsigned char m_oldRowContents[40], m_newRowContents[40];
|
unsigned char m_oldRowContents[40], m_newRowContents[40];
|
||||||
int m_subPageIndex, m_row, m_column;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class InsertSubPageCommand : public QUndoCommand
|
class InsertSubPageCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InsertSubPageCommand(TeletextDocument *, bool, bool, QUndoCommand *parent = 0);
|
InsertSubPageCommand(TeletextDocument *, bool, bool, QUndoCommand *parent = 0);
|
||||||
@@ -107,25 +113,20 @@ public:
|
|||||||
void undo() override;
|
void undo() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeletextDocument *m_teletextDocument;
|
|
||||||
int m_newSubPageIndex;
|
int m_newSubPageIndex;
|
||||||
bool m_copySubPage;
|
bool m_copySubPage;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeleteSubPageCommand : public QUndoCommand
|
class DeleteSubPageCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeleteSubPageCommand(TeletextDocument *, QUndoCommand *parent = 0);
|
DeleteSubPageCommand(TeletextDocument *, QUndoCommand *parent = 0);
|
||||||
|
|
||||||
void redo() override;
|
void redo() override;
|
||||||
void undo() override;
|
void undo() override;
|
||||||
|
|
||||||
private:
|
|
||||||
TeletextDocument *m_teletextDocument;
|
|
||||||
int m_subPageToDelete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class InsertRowCommand : public QUndoCommand
|
class InsertRowCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InsertRowCommand(TeletextDocument *, bool, QUndoCommand *parent = 0);
|
InsertRowCommand(TeletextDocument *, bool, QUndoCommand *parent = 0);
|
||||||
@@ -134,13 +135,11 @@ public:
|
|||||||
void undo() override;
|
void undo() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeletextDocument *m_teletextDocument;
|
|
||||||
int m_subPageIndex, m_row;
|
|
||||||
bool m_copyRow;
|
bool m_copyRow;
|
||||||
unsigned char m_deletedBottomRow[40];
|
unsigned char m_deletedBottomRow[40];
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeleteRowCommand : public QUndoCommand
|
class DeleteRowCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeleteRowCommand(TeletextDocument *, QUndoCommand *parent = 0);
|
DeleteRowCommand(TeletextDocument *, QUndoCommand *parent = 0);
|
||||||
@@ -149,12 +148,42 @@ public:
|
|||||||
void undo() override;
|
void undo() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeletextDocument *m_teletextDocument;
|
|
||||||
int m_subPageIndex, m_row;
|
|
||||||
unsigned char m_deletedRow[40];
|
unsigned char m_deletedRow[40];
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetColourCommand : public QUndoCommand
|
#ifndef QT_NO_CLIPBOARD
|
||||||
|
class CutCommand : public LevelOneCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CutCommand(TeletextDocument *, QUndoCommand *parent = 0);
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArrayList m_deletedCharacters;
|
||||||
|
int m_selectionTopRow, m_selectionBottomRow, m_selectionLeftColumn, m_selectionRightColumn;
|
||||||
|
int m_selectionCornerRow, m_selectionCornerColumn;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PasteCommand : public LevelOneCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PasteCommand(TeletextDocument *, int, QUndoCommand *parent = 0);
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArrayList m_deletedCharacters, m_pastingCharacters;
|
||||||
|
int m_pasteTopRow, m_pasteBottomRow, m_pasteLeftColumn, m_pasteRightColumn;
|
||||||
|
int m_clipboardDataHeight, m_clipboardDataWidth;
|
||||||
|
int m_selectionCornerRow, m_selectionCornerColumn;
|
||||||
|
bool m_selectionActive;
|
||||||
|
};
|
||||||
|
#endif // !QT_NO_CLIPBOARD
|
||||||
|
|
||||||
|
class SetColourCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetColourCommand(TeletextDocument *, int, int, QUndoCommand *parent = 0);
|
SetColourCommand(TeletextDocument *, int, int, QUndoCommand *parent = 0);
|
||||||
@@ -163,11 +192,10 @@ public:
|
|||||||
void undo() override;
|
void undo() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeletextDocument *m_teletextDocument;
|
int m_colourIndex, m_oldColour, m_newColour;
|
||||||
int m_subPageIndex, m_colourIndex, m_oldColour, m_newColour;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ResetCLUTCommand : public QUndoCommand
|
class ResetCLUTCommand : public LevelOneCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ResetCLUTCommand(TeletextDocument *, int, QUndoCommand *parent = 0);
|
ResetCLUTCommand(TeletextDocument *, int, QUndoCommand *parent = 0);
|
||||||
@@ -176,8 +204,7 @@ public:
|
|||||||
void undo() override;
|
void undo() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeletextDocument *m_teletextDocument;
|
int m_colourTable;
|
||||||
int m_subPageIndex, m_colourTable;
|
|
||||||
int m_oldColourEntry[8];
|
int m_oldColourEntry[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -27,21 +27,21 @@
|
|||||||
|
|
||||||
LevelOnePage::LevelOnePage()
|
LevelOnePage::LevelOnePage()
|
||||||
{
|
{
|
||||||
m_enhancements.reserve(208);
|
m_enhancements.reserve(maxEnhancements());
|
||||||
clearPage();
|
clearPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
LevelOnePage::LevelOnePage(const PageBase &other)
|
LevelOnePage::LevelOnePage(const PageBase &other)
|
||||||
{
|
{
|
||||||
m_enhancements.reserve(208);
|
m_enhancements.reserve(maxEnhancements());
|
||||||
clearPage();
|
clearPage();
|
||||||
|
|
||||||
for (int i=0; i<26; i++)
|
for (int i=0; i<26; i++)
|
||||||
if (other.packetNeeded(i))
|
if (other.packetExists(i))
|
||||||
setPacket(i, other.packet(i));
|
setPacket(i, other.packet(i));
|
||||||
for (int i=26; i<30; i++)
|
for (int i=26; i<30; i++)
|
||||||
for (int j=0; j<16; j++)
|
for (int j=0; j<16; j++)
|
||||||
if (other.packetNeeded(i, j))
|
if (other.packetExists(i, j))
|
||||||
setPacket(i, j, other.packet(i));
|
setPacket(i, j, other.packet(i));
|
||||||
|
|
||||||
for (int i=PageBase::C4ErasePage; i<=PageBase::C14NOS; i++)
|
for (int i=PageBase::C4ErasePage; i<=PageBase::C14NOS; i++)
|
||||||
@@ -254,7 +254,7 @@ bool LevelOnePage::setPacket(int packetNumber, int designationCode, QByteArray p
|
|||||||
return PageBase::setPacket(packetNumber, designationCode, packetContents);
|
return PageBase::setPacket(packetNumber, designationCode, packetContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LevelOnePage::packetNeeded(int packetNumber) const
|
bool LevelOnePage::packetExists(int packetNumber) const
|
||||||
{
|
{
|
||||||
if (packetNumber <= 24) {
|
if (packetNumber <= 24) {
|
||||||
for (int c=0; c<40; c++)
|
for (int c=0; c<40; c++)
|
||||||
@@ -263,10 +263,10 @@ bool LevelOnePage::packetNeeded(int packetNumber) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PageBase::packetNeeded(packetNumber);
|
return PageBase::packetExists(packetNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LevelOnePage::packetNeeded(int packetNumber, int designationCode) const
|
bool LevelOnePage::packetExists(int packetNumber, int designationCode) const
|
||||||
{
|
{
|
||||||
if (packetNumber == 26)
|
if (packetNumber == 26)
|
||||||
return packetFromEnhancementListNeeded(designationCode);
|
return packetFromEnhancementListNeeded(designationCode);
|
||||||
@@ -298,7 +298,7 @@ bool LevelOnePage::packetNeeded(int packetNumber, int designationCode) const
|
|||||||
return !isPaletteDefault(0,15);
|
return !isPaletteDefault(0,15);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PageBase::packetNeeded(packetNumber, designationCode);
|
return PageBase::packetExists(packetNumber, designationCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LevelOnePage::controlBit(int bitNumber) const
|
bool LevelOnePage::controlBit(int bitNumber) const
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ public:
|
|||||||
|
|
||||||
QByteArray packet(int) const override;
|
QByteArray packet(int) const override;
|
||||||
QByteArray packet(int, int) const override;
|
QByteArray packet(int, int) const override;
|
||||||
bool packetNeeded(int) const override;
|
bool packetExists(int) const override;
|
||||||
bool packetNeeded(int, int) const override;
|
bool packetExists(int, int) const override;
|
||||||
bool setPacket(int, QByteArray) override;
|
bool setPacket(int, QByteArray) override;
|
||||||
bool setPacket(int, int, QByteArray) override;
|
bool setPacket(int, int, QByteArray) override;
|
||||||
|
|
||||||
@@ -52,6 +52,8 @@ public:
|
|||||||
|
|
||||||
void clearPage();
|
void clearPage();
|
||||||
|
|
||||||
|
int maxEnhancements() const { return 208; };
|
||||||
|
|
||||||
/* void setSubPageNumber(int); */
|
/* void setSubPageNumber(int); */
|
||||||
int cycleValue() const { return m_cycleValue; };
|
int cycleValue() const { return m_cycleValue; };
|
||||||
void setCycleValue(int);
|
void setCycleValue(int);
|
||||||
|
|||||||
69
loadsave.cpp
69
loadsave.cpp
@@ -182,7 +182,7 @@ void saveTTI(QSaveFile &file, const TeletextDocument &document)
|
|||||||
|
|
||||||
auto write7bitPacket=[&](int packetNumber)
|
auto write7bitPacket=[&](int packetNumber)
|
||||||
{
|
{
|
||||||
if (document.subPage(p)->packetNeeded(packetNumber)) {
|
if (document.subPage(p)->packetExists(packetNumber)) {
|
||||||
QByteArray outLine = document.subPage(p)->packet(packetNumber);
|
QByteArray outLine = document.subPage(p)->packet(packetNumber);
|
||||||
|
|
||||||
outStream << QString("OL,%1,").arg(packetNumber);
|
outStream << QString("OL,%1,").arg(packetNumber);
|
||||||
@@ -193,13 +193,17 @@ void saveTTI(QSaveFile &file, const TeletextDocument &document)
|
|||||||
outLine.insert(c, 0x1b);
|
outLine.insert(c, 0x1b);
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
outStream << outLine << Qt::endl;
|
outStream << outLine << Qt::endl;
|
||||||
|
#else
|
||||||
|
outStream << outLine << endl;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto writeHammingPacket=[&](int packetNumber, int designationCode=0)
|
auto writeHammingPacket=[&](int packetNumber, int designationCode=0)
|
||||||
{
|
{
|
||||||
if (document.subPage(p)->packetNeeded(packetNumber, designationCode)) {
|
if (document.subPage(p)->packetExists(packetNumber, designationCode)) {
|
||||||
QByteArray outLine = document.subPage(p)->packet(packetNumber, designationCode);
|
QByteArray outLine = document.subPage(p)->packet(packetNumber, designationCode);
|
||||||
|
|
||||||
outStream << QString("OL,%1,").arg(packetNumber);
|
outStream << QString("OL,%1,").arg(packetNumber);
|
||||||
@@ -207,14 +211,22 @@ void saveTTI(QSaveFile &file, const TeletextDocument &document)
|
|||||||
outLine[0] = designationCode | 0x40;
|
outLine[0] = designationCode | 0x40;
|
||||||
for (int c=1; c<outLine.size(); c++)
|
for (int c=1; c<outLine.size(); c++)
|
||||||
outLine[c] = outLine.at(c) | 0x40;
|
outLine[c] = outLine.at(c) | 0x40;
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
outStream << outLine << Qt::endl;
|
outStream << outLine << Qt::endl;
|
||||||
|
#else
|
||||||
|
outStream << outLine << endl;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
outStream.setCodec("ISO-8859-1");
|
outStream.setCodec("ISO-8859-1");
|
||||||
|
|
||||||
if (!document.description().isEmpty())
|
if (!document.description().isEmpty())
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
outStream << "DE," << document.description() << Qt::endl;
|
outStream << "DE," << document.description() << Qt::endl;
|
||||||
|
#else
|
||||||
|
outStream << "DE," << document.description() << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO DS and SP commands
|
// TODO DS and SP commands
|
||||||
|
|
||||||
@@ -224,23 +236,50 @@ void saveTTI(QSaveFile &file, const TeletextDocument &document)
|
|||||||
|
|
||||||
for (p=0; p<document.numberOfSubPages(); p++) {
|
for (p=0; p<document.numberOfSubPages(); p++) {
|
||||||
|
|
||||||
outStream << QString("PN,%1%2").arg(document.pageNumber(), 3, 16, QChar('0')).arg(subPageNumber & 0xff, 2, 16, QChar('0')) << Qt::endl;
|
// Page number
|
||||||
|
outStream << QString("PN,%1%2").arg(document.pageNumber(), 3, 16, QChar('0')).arg(subPageNumber & 0xff, 2, 16, QChar('0'));
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
outStream << Qt::endl;
|
||||||
|
#else
|
||||||
|
outStream << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Subpage
|
||||||
// Magazine Organisation Table and Magazine Inventory Page don't have subpages
|
// Magazine Organisation Table and Magazine Inventory Page don't have subpages
|
||||||
if (document.pageFunction() != TeletextDocument::PFMOT && document.pageFunction() != TeletextDocument::PFMIP)
|
if (document.pageFunction() != TeletextDocument::PFMOT && document.pageFunction() != TeletextDocument::PFMIP) {
|
||||||
outStream << QString("SC,%1").arg(subPageNumber, 4, 16, QChar('0')) << Qt::endl;
|
outStream << QString("SC,%1").arg(subPageNumber, 4, 16, QChar('0'));
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
outStream << Qt::endl;
|
||||||
|
#else
|
||||||
|
outStream << endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
outStream << QString("PS,%1").arg(0x8000 | controlBitsToPS(document.subPage(p)), 4, 16, QChar('0')) << Qt::endl;
|
// Status bits
|
||||||
|
outStream << QString("PS,%1").arg(0x8000 | controlBitsToPS(document.subPage(p)), 4, 16, QChar('0'));
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
outStream << Qt::endl;
|
||||||
|
#else
|
||||||
|
outStream << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Cycle time
|
||||||
if (document.pageFunction() == TeletextDocument::PFLevelOnePage)
|
if (document.pageFunction() == TeletextDocument::PFLevelOnePage)
|
||||||
// Assume that only Level One Pages have configurable cycle times
|
// Assume that only Level One Pages have configurable cycle times
|
||||||
outStream << QString("CT,%1,%2").arg(document.subPage(p)->cycleValue()).arg(document.subPage(p)->cycleType()==LevelOnePage::CTcycles ? 'C' : 'T') << Qt::endl;
|
outStream << QString("CT,%1,%2").arg(document.subPage(p)->cycleValue()).arg(document.subPage(p)->cycleType()==LevelOnePage::CTcycles ? 'C' : 'T');
|
||||||
else
|
else
|
||||||
// X/28/0 specifies page function and coding but the PF command
|
// X/28/0 specifies page function and coding but the PF command
|
||||||
// should make it obvious to a human that this isn't a Level One Page
|
// should make it obvious to a human that this isn't a Level One Page
|
||||||
outStream << QString("PF,%1,%2").arg(document.pageFunction()).arg(document.packetCoding()) << Qt::endl;
|
outStream << QString("PF,%1,%2").arg(document.pageFunction()).arg(document.packetCoding());
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
outStream << Qt::endl;
|
||||||
|
#else
|
||||||
|
outStream << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// FastText links
|
||||||
bool writeFLCommand = false;
|
bool writeFLCommand = false;
|
||||||
if (document.pageFunction() == TeletextDocument::PFLevelOnePage && document.subPage(p)->packetNeeded(27,0)) {
|
if (document.pageFunction() == TeletextDocument::PFLevelOnePage && document.subPage(p)->packetExists(27,0)) {
|
||||||
// Subpage has FastText links - if any link to a specific subpage, we need to write X/27/0 as raw
|
// Subpage has FastText links - if any link to a specific subpage, we need to write X/27/0 as raw
|
||||||
// otherwise we write the links as a human-readable FL command later on
|
// otherwise we write the links as a human-readable FL command later on
|
||||||
writeFLCommand = true;
|
writeFLCommand = true;
|
||||||
@@ -285,7 +324,11 @@ void saveTTI(QSaveFile &file, const TeletextDocument &document)
|
|||||||
if (i<5)
|
if (i<5)
|
||||||
outStream << ',';
|
outStream << ',';
|
||||||
}
|
}
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
outStream << Qt::endl;
|
outStream << Qt::endl;
|
||||||
|
#else
|
||||||
|
outStream << endl;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
subPageNumber++;
|
subPageNumber++;
|
||||||
@@ -294,7 +337,7 @@ void saveTTI(QSaveFile &file, const TeletextDocument &document)
|
|||||||
|
|
||||||
QByteArray rowPacketAlways(PageBase *subPage, int packetNumber)
|
QByteArray rowPacketAlways(PageBase *subPage, int packetNumber)
|
||||||
{
|
{
|
||||||
if (subPage->packetNeeded(packetNumber))
|
if (subPage->packetExists(packetNumber))
|
||||||
return subPage->packet(packetNumber);
|
return subPage->packet(packetNumber);
|
||||||
else
|
else
|
||||||
return QByteArray(40, ' ');
|
return QByteArray(40, ' ');
|
||||||
@@ -345,7 +388,7 @@ QString exportHashStringPackets(LevelOnePage *subPage)
|
|||||||
const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||||
QString result;
|
QString result;
|
||||||
|
|
||||||
if (subPage->packetNeeded(28,0) || subPage->packetNeeded(28,4)) {
|
if (subPage->packetExists(28,0) || subPage->packetExists(28,4)) {
|
||||||
// X/28/0 and X/28/4 are duplicates apart from the CLUT definitions
|
// X/28/0 and X/28/4 are duplicates apart from the CLUT definitions
|
||||||
// Assemble the duplicate beginning and ending of both packets
|
// Assemble the duplicate beginning and ending of both packets
|
||||||
QString x28StringBegin, x28StringEnd;
|
QString x28StringBegin, x28StringEnd;
|
||||||
@@ -356,9 +399,9 @@ QString exportHashStringPackets(LevelOnePage *subPage)
|
|||||||
|
|
||||||
x28StringEnd = QString("%1%2%3%4").arg(subPage->defaultScreenColour(), 2, 16, QChar('0')).arg(subPage->defaultRowColour(), 2, 16, QChar('0')).arg(subPage->blackBackgroundSubst(), 1, 10).arg(subPage->colourTableRemap(), 1, 10);
|
x28StringEnd = QString("%1%2%3%4").arg(subPage->defaultScreenColour(), 2, 16, QChar('0')).arg(subPage->defaultRowColour(), 2, 16, QChar('0')).arg(subPage->blackBackgroundSubst(), 1, 10).arg(subPage->colourTableRemap(), 1, 10);
|
||||||
|
|
||||||
if (subPage->packetNeeded(28,0))
|
if (subPage->packetExists(28,0))
|
||||||
result.append(":X280=" + x28StringBegin + colourToHexString(2) + colourToHexString(3) + x28StringEnd);
|
result.append(":X280=" + x28StringBegin + colourToHexString(2) + colourToHexString(3) + x28StringEnd);
|
||||||
if (subPage->packetNeeded(28,4))
|
if (subPage->packetExists(28,4))
|
||||||
result.append(":X284=" + x28StringBegin + colourToHexString(0) + colourToHexString(1) + x28StringEnd);
|
result.append(":X284=" + x28StringBegin + colourToHexString(0) + colourToHexString(1) + x28StringEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
main.cpp
2
main.cpp
@@ -30,7 +30,7 @@ int main(int argc, char *argv[])
|
|||||||
QApplication::setApplicationDisplayName(QApplication::applicationName());
|
QApplication::setApplicationDisplayName(QApplication::applicationName());
|
||||||
QApplication::setOrganizationName("gkmac.co.uk");
|
QApplication::setOrganizationName("gkmac.co.uk");
|
||||||
QApplication::setOrganizationDomain("gkmac.co.uk");
|
QApplication::setOrganizationDomain("gkmac.co.uk");
|
||||||
QApplication::setApplicationVersion("0.1-alpha");
|
QApplication::setApplicationVersion("0.4-alpha");
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(QApplication::applicationName());
|
parser.setApplicationDescription(QApplication::applicationName());
|
||||||
parser.addHelpOption();
|
parser.addHelpOption();
|
||||||
|
|||||||
277
mainwidget.cpp
277
mainwidget.cpp
@@ -17,13 +17,18 @@
|
|||||||
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
|
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QBitmap>
|
#include <QBitmap>
|
||||||
|
#include <QClipboard>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
|
#include <QGraphicsItemGroup>
|
||||||
#include <QGraphicsProxyWidget>
|
#include <QGraphicsProxyWidget>
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
|
#include <QGraphicsSceneEvent>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QMimeData>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
#include <QUndoCommand>
|
#include <QUndoCommand>
|
||||||
@@ -50,7 +55,6 @@ TeletextWidget::TeletextWidget(QFrame *parent) : QFrame(parent)
|
|||||||
m_pageRender.setTeletextPage(m_levelOnePage);
|
m_pageRender.setTeletextPage(m_levelOnePage);
|
||||||
m_insertMode = false;
|
m_insertMode = false;
|
||||||
m_selectionInProgress = false;
|
m_selectionInProgress = false;
|
||||||
m_grid = false;
|
|
||||||
setFocusPolicy(Qt::StrongFocus);
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
m_flashTiming = m_flashPhase = 0;
|
m_flashTiming = m_flashPhase = 0;
|
||||||
connect(&m_pageRender, &TeletextPageRender::flashChanged, this, &TeletextWidget::updateFlashTimer);
|
connect(&m_pageRender, &TeletextPageRender::flashChanged, this, &TeletextWidget::updateFlashTimer);
|
||||||
@@ -58,7 +62,6 @@ TeletextWidget::TeletextWidget(QFrame *parent) : QFrame(parent)
|
|||||||
connect(m_teletextDocument, &TeletextDocument::subPageSelected, this, &TeletextWidget::subPageSelected);
|
connect(m_teletextDocument, &TeletextDocument::subPageSelected, this, &TeletextWidget::subPageSelected);
|
||||||
connect(m_teletextDocument, &TeletextDocument::contentsChange, this, &TeletextWidget::refreshRow);
|
connect(m_teletextDocument, &TeletextDocument::contentsChange, this, &TeletextWidget::refreshRow);
|
||||||
connect(m_teletextDocument, &TeletextDocument::refreshNeeded, this, &TeletextWidget::refreshPage);
|
connect(m_teletextDocument, &TeletextDocument::refreshNeeded, this, &TeletextWidget::refreshPage);
|
||||||
connect(m_teletextDocument, &TeletextDocument::selectionMoved, this, QOverload<>::of(&TeletextWidget::update));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TeletextWidget::~TeletextWidget()
|
TeletextWidget::~TeletextWidget()
|
||||||
@@ -109,13 +112,6 @@ void TeletextWidget::paintEvent(QPaintEvent *event)
|
|||||||
widgetPainter.drawPixmap(0, 0, *m_pageRender.pagePixmap(m_flashPhase), 864-m_pageRender.leftSidePanelColumns()*12, 0, m_pageRender.leftSidePanelColumns()*12, 250);
|
widgetPainter.drawPixmap(0, 0, *m_pageRender.pagePixmap(m_flashPhase), 864-m_pageRender.leftSidePanelColumns()*12, 0, m_pageRender.leftSidePanelColumns()*12, 250);
|
||||||
if (m_pageRender.rightSidePanelColumns())
|
if (m_pageRender.rightSidePanelColumns())
|
||||||
widgetPainter.drawPixmap(480+m_pageRender.leftSidePanelColumns()*12, 0, *m_pageRender.pagePixmap(m_flashPhase), 480, 0, m_pageRender.rightSidePanelColumns()*12, 250);
|
widgetPainter.drawPixmap(480+m_pageRender.leftSidePanelColumns()*12, 0, *m_pageRender.pagePixmap(m_flashPhase), 480, 0, m_pageRender.rightSidePanelColumns()*12, 250);
|
||||||
if (this->hasFocus())
|
|
||||||
widgetPainter.fillRect((m_teletextDocument->cursorColumn()+m_pageRender.leftSidePanelColumns())*12, m_teletextDocument->cursorRow()*10, 12, 10, QColor(128, 128, 128, 192));
|
|
||||||
if (m_teletextDocument->selectionActive()) {
|
|
||||||
widgetPainter.setPen(QPen(QColor(192, 192, 192, 224), 1, Qt::DashLine));
|
|
||||||
widgetPainter.setBrush(QBrush(QColor(255, 255, 255, 64)));
|
|
||||||
widgetPainter.drawRect((m_teletextDocument->selectionLeftColumn()+m_pageRender.leftSidePanelColumns())*12, m_teletextDocument->selectionTopRow()*10, m_teletextDocument->selectionWidth()*12-1, m_teletextDocument->selectionHeight()*10-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextWidget::updateFlashTimer(int newFlashTimer)
|
void TeletextWidget::updateFlashTimer(int newFlashTimer)
|
||||||
@@ -144,6 +140,16 @@ void TeletextWidget::timerEvent(QTimerEvent *event)
|
|||||||
QWidget::timerEvent(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)
|
void TeletextWidget::setInsertMode(bool insertMode)
|
||||||
{
|
{
|
||||||
m_insertMode = insertMode;
|
m_insertMode = insertMode;
|
||||||
@@ -161,14 +167,6 @@ void TeletextWidget::toggleMix(bool mixOn)
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextWidget::toggleGrid(bool gridOn)
|
|
||||||
{
|
|
||||||
m_grid = gridOn;
|
|
||||||
m_pageRender.setGrid(gridOn);
|
|
||||||
m_pageRender.renderPage();
|
|
||||||
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);
|
||||||
@@ -354,32 +352,27 @@ void TeletextWidget::keyPressEvent(QKeyEvent *event)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Qt::Key_Up:
|
case Qt::Key_Up:
|
||||||
m_teletextDocument->cursorUp();
|
m_teletextDocument->cursorUp(event->modifiers() & Qt::ShiftModifier);
|
||||||
update();
|
|
||||||
break;
|
break;
|
||||||
case Qt::Key_Down:
|
case Qt::Key_Down:
|
||||||
m_teletextDocument->cursorDown();
|
m_teletextDocument->cursorDown(event->modifiers() & Qt::ShiftModifier);
|
||||||
update();
|
|
||||||
break;
|
break;
|
||||||
case Qt::Key_Left:
|
case Qt::Key_Left:
|
||||||
m_teletextDocument->cursorLeft();
|
m_teletextDocument->cursorLeft(event->modifiers() & Qt::ShiftModifier);
|
||||||
update();
|
|
||||||
break;
|
break;
|
||||||
case Qt::Key_Right:
|
case Qt::Key_Right:
|
||||||
m_teletextDocument->cursorRight();
|
m_teletextDocument->cursorRight(event->modifiers() & Qt::ShiftModifier);
|
||||||
update();
|
|
||||||
break;
|
break;
|
||||||
case Qt::Key_Return:
|
case Qt::Key_Return:
|
||||||
case Qt::Key_Enter:
|
case Qt::Key_Enter:
|
||||||
m_teletextDocument->cursorDown();
|
m_teletextDocument->cursorDown();
|
||||||
// fall through
|
|
||||||
case Qt::Key_Home:
|
|
||||||
m_teletextDocument->moveCursor(m_teletextDocument->cursorRow(), 0);
|
m_teletextDocument->moveCursor(m_teletextDocument->cursorRow(), 0);
|
||||||
update();
|
break;
|
||||||
|
case Qt::Key_Home:
|
||||||
|
m_teletextDocument->moveCursor(m_teletextDocument->cursorRow(), 0, event->modifiers() & Qt::ShiftModifier);
|
||||||
break;
|
break;
|
||||||
case Qt::Key_End:
|
case Qt::Key_End:
|
||||||
m_teletextDocument->moveCursor(m_teletextDocument->cursorRow(), 39);
|
m_teletextDocument->moveCursor(m_teletextDocument->cursorRow(), 39, event->modifiers() & Qt::ShiftModifier);
|
||||||
update();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Qt::Key_PageUp:
|
case Qt::Key_PageUp:
|
||||||
@@ -405,8 +398,62 @@ void TeletextWidget::setCharacter(unsigned char newCharacter)
|
|||||||
|
|
||||||
void TeletextWidget::toggleCharacterBit(unsigned char bitToToggle)
|
void TeletextWidget::toggleCharacterBit(unsigned char bitToToggle)
|
||||||
{
|
{
|
||||||
QUndoCommand *toggleMosaicBitCommand = new ToggleMosaicBitCommand(m_teletextDocument, bitToToggle);
|
m_teletextDocument->undoStack()->push(new ToggleMosaicBitCommand(m_teletextDocument, bitToToggle));
|
||||||
m_teletextDocument->undoStack()->push(toggleMosaicBitCommand);
|
}
|
||||||
|
|
||||||
|
void TeletextWidget::selectionToClipboard()
|
||||||
|
{
|
||||||
|
QByteArray nativeData;
|
||||||
|
QString plainTextData;
|
||||||
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
|
||||||
|
nativeData.resize(2 + m_teletextDocument->selectionWidth() * m_teletextDocument->selectionHeight());
|
||||||
|
nativeData[0] = m_teletextDocument->selectionHeight();
|
||||||
|
nativeData[1] = m_teletextDocument->selectionWidth();
|
||||||
|
|
||||||
|
plainTextData.reserve((m_teletextDocument->selectionWidth()+1) * m_teletextDocument->selectionHeight() - 1);
|
||||||
|
|
||||||
|
int i=2;
|
||||||
|
|
||||||
|
for (int r=m_teletextDocument->selectionTopRow(); r<=m_teletextDocument->selectionBottomRow(); r++) {
|
||||||
|
for (int c=m_teletextDocument->selectionLeftColumn(); c<=m_teletextDocument->selectionRightColumn(); c++) {
|
||||||
|
nativeData[i++] = m_teletextDocument->currentSubPage()->character(r, c);
|
||||||
|
|
||||||
|
if (m_teletextDocument->currentSubPage()->character(r, c) >= 0x20)
|
||||||
|
plainTextData.append(keymapping[m_pageRender.level1CharSet(r, c)].key(m_teletextDocument->currentSubPage()->character(r, c), m_teletextDocument->currentSubPage()->character(r, c)));
|
||||||
|
else
|
||||||
|
plainTextData.append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
plainTextData.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
QMimeData *mimeData = new QMimeData();
|
||||||
|
mimeData->setData("application/x-teletext", nativeData);
|
||||||
|
mimeData->setText(plainTextData);
|
||||||
|
clipboard->setMimeData(mimeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TeletextWidget::cut()
|
||||||
|
{
|
||||||
|
if (!m_teletextDocument->selectionActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
selectionToClipboard();
|
||||||
|
m_teletextDocument->undoStack()->push(new CutCommand(m_teletextDocument));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TeletextWidget::copy()
|
||||||
|
{
|
||||||
|
if (!m_teletextDocument->selectionActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
selectionToClipboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TeletextWidget::paste()
|
||||||
|
{
|
||||||
|
m_teletextDocument->undoStack()->push(new PasteCommand(m_teletextDocument, m_pageRender.level1CharSet(m_teletextDocument->cursorRow(), m_teletextDocument->cursorColumn())));
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<int, int> TeletextWidget::mouseToRowAndColumn(const QPoint &mousePosition)
|
QPair<int, int> TeletextWidget::mouseToRowAndColumn(const QPoint &mousePosition)
|
||||||
@@ -438,25 +485,12 @@ void TeletextWidget::mouseMoveEvent(QMouseEvent *event)
|
|||||||
{
|
{
|
||||||
if (event->buttons() & Qt::LeftButton) {
|
if (event->buttons() & Qt::LeftButton) {
|
||||||
QPair<int, int> position = mouseToRowAndColumn(event->pos());
|
QPair<int, int> position = mouseToRowAndColumn(event->pos());
|
||||||
if (m_selectionInProgress || position.first != m_teletextDocument->cursorRow() || position.second != m_teletextDocument->cursorColumn()) {
|
if (position.first != m_teletextDocument->cursorRow() || position.second != m_teletextDocument->cursorColumn()) {
|
||||||
int topRow, bottomRow, leftColumn, rightColumn;
|
if (!m_selectionInProgress) {
|
||||||
|
m_selectionInProgress = true;
|
||||||
m_selectionInProgress = true;
|
m_teletextDocument->setSelectionCorner(m_teletextDocument->cursorRow(), m_teletextDocument->cursorColumn());
|
||||||
if (m_teletextDocument->cursorRow() < position.first) {
|
|
||||||
topRow = m_teletextDocument->cursorRow();
|
|
||||||
bottomRow = position.first;
|
|
||||||
} else {
|
|
||||||
topRow = position.first;
|
|
||||||
bottomRow = m_teletextDocument->cursorRow();
|
|
||||||
}
|
}
|
||||||
if (m_teletextDocument->cursorColumn() < position.second) {
|
m_teletextDocument->moveCursor(position.first, position.second, true);
|
||||||
leftColumn = m_teletextDocument->cursorColumn();
|
|
||||||
rightColumn = position.second;
|
|
||||||
} else {
|
|
||||||
leftColumn = position.second;
|
|
||||||
rightColumn = m_teletextDocument->cursorColumn();
|
|
||||||
}
|
|
||||||
m_teletextDocument->setSelection(topRow, leftColumn, bottomRow, rightColumn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -480,7 +514,12 @@ void TeletextWidget::focusOutEvent(QFocusEvent *event)
|
|||||||
|
|
||||||
LevelOneScene::LevelOneScene(QWidget *levelOneWidget, QObject *parent) : QGraphicsScene(parent)
|
LevelOneScene::LevelOneScene(QWidget *levelOneWidget, QObject *parent) : QGraphicsScene(parent)
|
||||||
{
|
{
|
||||||
|
m_grid = false;
|
||||||
|
|
||||||
|
// These dimensions are scratch, setBorderDimensions will get called straight away to adjust them
|
||||||
setSceneRect(0, 0, 600, 288);
|
setSceneRect(0, 0, 600, 288);
|
||||||
|
|
||||||
|
// Full screen colours
|
||||||
m_fullScreenTopRectItem = new QGraphicsRectItem(0, 0, 600, 19);
|
m_fullScreenTopRectItem = new QGraphicsRectItem(0, 0, 600, 19);
|
||||||
m_fullScreenTopRectItem->setPen(Qt::NoPen);
|
m_fullScreenTopRectItem->setPen(Qt::NoPen);
|
||||||
m_fullScreenTopRectItem->setBrush(QBrush(QColor(0, 0, 0)));
|
m_fullScreenTopRectItem->setBrush(QBrush(QColor(0, 0, 0)));
|
||||||
@@ -490,6 +529,7 @@ LevelOneScene::LevelOneScene(QWidget *levelOneWidget, QObject *parent) : QGraphi
|
|||||||
m_fullScreenBottomRectItem->setBrush(QBrush(QColor(0, 0, 0)));
|
m_fullScreenBottomRectItem->setBrush(QBrush(QColor(0, 0, 0)));
|
||||||
addItem(m_fullScreenBottomRectItem);
|
addItem(m_fullScreenBottomRectItem);
|
||||||
|
|
||||||
|
// Full row colours
|
||||||
for (int r=0; r<25; r++) {
|
for (int r=0; r<25; r++) {
|
||||||
m_fullRowLeftRectItem[r] = new QGraphicsRectItem(0, 19+r*10, 60, 10);
|
m_fullRowLeftRectItem[r] = new QGraphicsRectItem(0, 19+r*10, 60, 10);
|
||||||
m_fullRowLeftRectItem[r]->setPen(Qt::NoPen);
|
m_fullRowLeftRectItem[r]->setPen(Qt::NoPen);
|
||||||
@@ -501,16 +541,59 @@ LevelOneScene::LevelOneScene(QWidget *levelOneWidget, QObject *parent) : QGraphi
|
|||||||
addItem(m_fullRowRightRectItem[r]);
|
addItem(m_fullRowRightRectItem[r]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Main text widget
|
||||||
m_levelOneProxyWidget = addWidget(levelOneWidget);
|
m_levelOneProxyWidget = addWidget(levelOneWidget);
|
||||||
m_levelOneProxyWidget->setPos(60, 19);
|
m_levelOneProxyWidget->setPos(60, 19);
|
||||||
m_levelOneProxyWidget->setAutoFillBackground(false);
|
m_levelOneProxyWidget->setAutoFillBackground(false);
|
||||||
|
m_levelOneProxyWidget->setFocus();
|
||||||
|
|
||||||
|
// Selection
|
||||||
|
m_selectionRectItem = new QGraphicsRectItem(0, 0, 12, 10);
|
||||||
|
m_selectionRectItem->setVisible(false);
|
||||||
|
m_selectionRectItem->setPen(QPen(QColor(192, 192, 192), 1, Qt::DashLine));
|
||||||
|
m_selectionRectItem->setBrush(QBrush(QColor(255, 255, 255, 64)));
|
||||||
|
addItem(m_selectionRectItem);
|
||||||
|
|
||||||
|
// Cursor
|
||||||
|
m_cursorRectItem = new QGraphicsRectItem(0, 0, 12, 10);
|
||||||
|
m_cursorRectItem->setPen(Qt::NoPen);
|
||||||
|
m_cursorRectItem->setBrush(QBrush(QColor(128, 128, 128, 192)));
|
||||||
|
addItem(m_cursorRectItem);
|
||||||
|
|
||||||
|
// Optional grid overlay for text widget
|
||||||
|
m_mainGridItemGroup = new QGraphicsItemGroup;
|
||||||
|
m_mainGridItemGroup->setVisible(false);
|
||||||
|
addItem(m_mainGridItemGroup);
|
||||||
|
// Additional vertical pieces of grid for side panels
|
||||||
|
for (int i=0; i<32; i++) {
|
||||||
|
m_sidePanelGridNeeded[i] = false;
|
||||||
|
m_sidePanelGridItemGroup[i] = new QGraphicsItemGroup;
|
||||||
|
m_sidePanelGridItemGroup[i]->setVisible(false);
|
||||||
|
addItem(m_sidePanelGridItemGroup[i]);
|
||||||
|
}
|
||||||
|
for (int r=1; r<25; r++) {
|
||||||
|
for (int c=0; c<40; c++) {
|
||||||
|
QGraphicsRectItem *gridPiece = new QGraphicsRectItem(c*12, r*10, 12, 10);
|
||||||
|
gridPiece->setPen(QPen(QBrush(QColor(128, 128, 128, r<24 ? 192 : 128)), 0));
|
||||||
|
m_mainGridItemGroup->addToGroup(gridPiece);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r < 24)
|
||||||
|
for (int c=0; c<32; c++) {
|
||||||
|
QGraphicsRectItem *gridPiece = new QGraphicsRectItem(0, r*10, 12, 10);
|
||||||
|
gridPiece->setPen(QPen(QBrush(QColor(128, 128, 128, 64)), 0));
|
||||||
|
m_sidePanelGridItemGroup[c]->addToGroup(gridPiece);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelOneScene::setDimensions(int sceneWidth, int sceneHeight, int widgetWidth)
|
void LevelOneScene::setBorderDimensions(int sceneWidth, int sceneHeight, int widgetWidth, int leftSidePanelColumns, int rightSidePanelColumns)
|
||||||
{
|
{
|
||||||
setSceneRect(0, 0, sceneWidth, sceneHeight);
|
setSceneRect(0, 0, sceneWidth, sceneHeight);
|
||||||
|
|
||||||
// Assume widget height is always 250
|
// Assume text widget height is always 250
|
||||||
int topBottomBorders = (sceneHeight-250) / 2;
|
int topBottomBorders = (sceneHeight-250) / 2;
|
||||||
// Ideally we'd use m_levelOneProxyWidget->size() to discover the widget width ourselves
|
// Ideally we'd use m_levelOneProxyWidget->size() to discover the widget width ourselves
|
||||||
// but this causes a stubborn segfault, so we have to receive the widgetWidth as a parameter
|
// but this causes a stubborn segfault, so we have to receive the widgetWidth as a parameter
|
||||||
@@ -518,15 +601,103 @@ void LevelOneScene::setDimensions(int sceneWidth, int sceneHeight, int widgetWid
|
|||||||
|
|
||||||
m_levelOneProxyWidget->setPos(leftRightBorders, topBottomBorders);
|
m_levelOneProxyWidget->setPos(leftRightBorders, topBottomBorders);
|
||||||
|
|
||||||
|
// Position grid to cover central 40 columns
|
||||||
|
m_mainGridItemGroup->setPos(leftRightBorders + leftSidePanelColumns*12, topBottomBorders);
|
||||||
|
|
||||||
|
updateCursor();
|
||||||
|
updateSelection();
|
||||||
|
|
||||||
|
// Grid for right side panel
|
||||||
|
for (int c=0; c<16; c++)
|
||||||
|
if (rightSidePanelColumns > c) {
|
||||||
|
m_sidePanelGridItemGroup[c]->setPos(leftRightBorders + leftSidePanelColumns*12 + 480 + c*12, topBottomBorders);
|
||||||
|
m_sidePanelGridItemGroup[c]->setVisible(m_grid);
|
||||||
|
m_sidePanelGridNeeded[c] = true;
|
||||||
|
} else {
|
||||||
|
m_sidePanelGridItemGroup[c]->setVisible(false);
|
||||||
|
m_sidePanelGridNeeded[c] = false;
|
||||||
|
}
|
||||||
|
// Grid for left side panel
|
||||||
|
for (int c=0; c<16; c++)
|
||||||
|
if (c < leftSidePanelColumns) {
|
||||||
|
m_sidePanelGridItemGroup[31-c]->setPos(leftRightBorders + (leftSidePanelColumns-c-1)*12, topBottomBorders);
|
||||||
|
m_sidePanelGridItemGroup[31-c]->setVisible(m_grid);
|
||||||
|
m_sidePanelGridNeeded[31-c] = true;
|
||||||
|
} else {
|
||||||
|
m_sidePanelGridItemGroup[31-c]->setVisible(false);
|
||||||
|
m_sidePanelGridNeeded[31-c] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full screen colours
|
||||||
m_fullScreenTopRectItem->setRect(0, 0, sceneWidth, topBottomBorders);
|
m_fullScreenTopRectItem->setRect(0, 0, sceneWidth, topBottomBorders);
|
||||||
m_fullScreenBottomRectItem->setRect(0, 250+topBottomBorders, sceneWidth, topBottomBorders);
|
m_fullScreenBottomRectItem->setRect(0, 250+topBottomBorders, sceneWidth, topBottomBorders);
|
||||||
|
// Full row colours
|
||||||
for (int r=0; r<25; r++) {
|
for (int r=0; r<25; r++) {
|
||||||
m_fullRowLeftRectItem[r]->setRect(0, topBottomBorders+r*10, leftRightBorders+1, 10);
|
m_fullRowLeftRectItem[r]->setRect(0, topBottomBorders+r*10, leftRightBorders+1, 10);
|
||||||
m_fullRowRightRectItem[r]->setRect(sceneWidth-leftRightBorders-1, topBottomBorders+r*10, leftRightBorders+1, 10);
|
m_fullRowRightRectItem[r]->setRect(sceneWidth-leftRightBorders-1, topBottomBorders+r*10, leftRightBorders+1, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LevelOneScene::updateCursor()
|
||||||
|
{
|
||||||
|
m_cursorRectItem->setPos(m_mainGridItemGroup->pos().x() + static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->cursorColumn()*12, m_mainGridItemGroup->pos().y() + static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->cursorRow()*10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelOneScene::updateSelection()
|
||||||
|
{
|
||||||
|
if (!static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->selectionActive()) {
|
||||||
|
m_selectionRectItem->setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_selectionRectItem->setRect(m_mainGridItemGroup->pos().x() + static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->selectionLeftColumn()*12, m_mainGridItemGroup->pos().y() + static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->selectionTopRow()*10, static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->selectionWidth()*12-1, static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->selectionHeight()*10-1);
|
||||||
|
|
||||||
|
m_selectionRectItem->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelOneScene::toggleGrid(bool gridOn)
|
||||||
|
{
|
||||||
|
m_grid = gridOn;
|
||||||
|
m_mainGridItemGroup->setVisible(gridOn);
|
||||||
|
for (int i=0; i<32; i++)
|
||||||
|
if (m_sidePanelGridNeeded[i])
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (event->type() == QEvent::GraphicsSceneWheel && static_cast<QGraphicsSceneWheelEvent *>(event)->modifiers() == Qt::ControlModifier) {
|
||||||
|
if (static_cast<QGraphicsSceneWheelEvent *>(event)->delta() > 0)
|
||||||
|
emit mouseZoomIn();
|
||||||
|
else if (static_cast<QGraphicsSceneWheelEvent *>(event)->delta() < 0)
|
||||||
|
emit mouseZoomOut();
|
||||||
|
|
||||||
|
event->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void LevelOneScene::setFullScreenColour(const QColor &newColor)
|
void LevelOneScene::setFullScreenColour(const QColor &newColor)
|
||||||
{
|
{
|
||||||
m_fullScreenTopRectItem->setBrush(QBrush(newColor));
|
m_fullScreenTopRectItem->setBrush(QBrush(newColor));
|
||||||
|
|||||||
29
mainwidget.h
29
mainwidget.h
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <QBasicTimer>
|
#include <QBasicTimer>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
|
#include <QGraphicsItemGroup>
|
||||||
#include <QGraphicsProxyWidget>
|
#include <QGraphicsProxyWidget>
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
@@ -62,8 +63,8 @@ public slots:
|
|||||||
void refreshPage();
|
void refreshPage();
|
||||||
void toggleReveal(bool);
|
void toggleReveal(bool);
|
||||||
void toggleMix(bool);
|
void toggleMix(bool);
|
||||||
void toggleGrid(bool);
|
|
||||||
void updateFlashTimer(int);
|
void updateFlashTimer(int);
|
||||||
|
void pauseFlash(bool);
|
||||||
void refreshRow(int);
|
void refreshRow(int);
|
||||||
|
|
||||||
void setControlBit(int, bool);
|
void setControlBit(int, bool);
|
||||||
@@ -75,6 +76,11 @@ public slots:
|
|||||||
void setBlackBackgroundSubst(bool);
|
void setBlackBackgroundSubst(bool);
|
||||||
void setSidePanelWidths(int, int);
|
void setSidePanelWidths(int, int);
|
||||||
void setSidePanelAtL35Only(bool);
|
void setSidePanelAtL35Only(bool);
|
||||||
|
|
||||||
|
void cut();
|
||||||
|
void copy();
|
||||||
|
void paste();
|
||||||
|
|
||||||
void changeSize();
|
void changeSize();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -91,13 +97,12 @@ protected:
|
|||||||
private:
|
private:
|
||||||
TeletextDocument* m_teletextDocument;
|
TeletextDocument* m_teletextDocument;
|
||||||
LevelOnePage* m_levelOnePage;
|
LevelOnePage* m_levelOnePage;
|
||||||
bool m_insertMode, m_grid, m_selectionInProgress;
|
bool m_insertMode, m_selectionInProgress;
|
||||||
QBasicTimer m_flashTimer;
|
QBasicTimer m_flashTimer;
|
||||||
int m_flashTiming, m_flashPhase;
|
int m_flashTiming, m_flashPhase;
|
||||||
|
|
||||||
void timerEvent(QTimerEvent *event) override;
|
void timerEvent(QTimerEvent *event) override;
|
||||||
|
void selectionToClipboard();
|
||||||
void calculateDimensions();
|
|
||||||
|
|
||||||
QPair<int, int> mouseToRowAndColumn(const QPoint &);
|
QPair<int, int> mouseToRowAndColumn(const QPoint &);
|
||||||
};
|
};
|
||||||
@@ -108,16 +113,30 @@ class LevelOneScene : public QGraphicsScene
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
LevelOneScene(QWidget *, QObject *parent = nullptr);
|
LevelOneScene(QWidget *, QObject *parent = nullptr);
|
||||||
void setDimensions(int, int, int);
|
void setBorderDimensions(int, int, int, int, int);
|
||||||
|
QGraphicsRectItem *cursorRectItem() const { return m_cursorRectItem; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void updateCursor();
|
||||||
|
void updateSelection();
|
||||||
|
void toggleGrid(bool);
|
||||||
|
void hideGUIElements(bool);
|
||||||
void setFullScreenColour(const QColor &);
|
void setFullScreenColour(const QColor &);
|
||||||
void setFullRowColour(int, const QColor &);
|
void setFullRowColour(int, const QColor &);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void mouseZoomIn();
|
||||||
|
void mouseZoomOut();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool eventFilter(QObject *, QEvent *);
|
||||||
|
|
||||||
QGraphicsRectItem *m_fullScreenTopRectItem, *m_fullScreenBottomRectItem;
|
QGraphicsRectItem *m_fullScreenTopRectItem, *m_fullScreenBottomRectItem;
|
||||||
QGraphicsRectItem *m_fullRowLeftRectItem[25], *m_fullRowRightRectItem[25];
|
QGraphicsRectItem *m_fullRowLeftRectItem[25], *m_fullRowRightRectItem[25];
|
||||||
QGraphicsProxyWidget *m_levelOneProxyWidget;
|
QGraphicsProxyWidget *m_levelOneProxyWidget;
|
||||||
|
QGraphicsRectItem *m_cursorRectItem, *m_selectionRectItem;
|
||||||
|
QGraphicsItemGroup *m_mainGridItemGroup, *m_sidePanelGridItemGroup[32];
|
||||||
|
bool m_grid, m_sidePanelGridNeeded[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
137
mainwindow.cpp
137
mainwindow.cpp
@@ -20,9 +20,11 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include <QImage>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QPainter>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
@@ -120,6 +122,56 @@ bool MainWindow::saveAs()
|
|||||||
return saveFile(fileName);
|
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()
|
void MainWindow::exportZXNet()
|
||||||
{
|
{
|
||||||
QDesktopServices::openUrl(QUrl("http://zxnet.co.uk/teletext/editor/" + exportHashStringPage(m_textWidget->document()->currentSubPage()) + exportHashStringPackets(m_textWidget->document()->currentSubPage())));
|
QDesktopServices::openUrl(QUrl("http://zxnet.co.uk/teletext/editor/" + exportHashStringPage(m_textWidget->document()->currentSubPage()) + exportHashStringPackets(m_textWidget->document()->currentSubPage())));
|
||||||
@@ -132,12 +184,12 @@ void MainWindow::exportEditTF()
|
|||||||
|
|
||||||
void MainWindow::about()
|
void MainWindow::about()
|
||||||
{
|
{
|
||||||
QMessageBox::about(this, tr("About QTeletextMaker"), tr("<b>QTeletextMaker</b><br>"
|
QMessageBox::about(this, tr("About"), QString("<b>%1</b><br>"
|
||||||
"An open source Level 2.5 teletext page editor.<br>"
|
"An open source Level 2.5 teletext page editor.<br>"
|
||||||
"<i>Version 0.1-alpha</i><br><br>"
|
"<i>Version %2</i><br><br>"
|
||||||
"Copyright (C) 2020, 2021 Gavin MacGregor<br><br>"
|
"Copyright (C) 2020, 2021 Gavin MacGregor<br><br>"
|
||||||
"Released under the GNU General Public License version 3<br>"
|
"Released under the GNU General Public License version 3<br>"
|
||||||
"<a href=\"https://github.com/gkthemac/qteletextmaker\">https://github.com/gkthemac/qteletextmaker</a>"));
|
"<a href=\"https://github.com/gkthemac/qteletextmaker\">https://github.com/gkthemac/qteletextmaker</a>").arg(QApplication::applicationDisplayName()).arg(QApplication::applicationVersion()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::init()
|
void MainWindow::init()
|
||||||
@@ -157,21 +209,23 @@ void MainWindow::init()
|
|||||||
m_paletteDockWidget = new PaletteDockWidget(m_textWidget);
|
m_paletteDockWidget = new PaletteDockWidget(m_textWidget);
|
||||||
addDockWidget(Qt::RightDockWidgetArea, m_paletteDockWidget);
|
addDockWidget(Qt::RightDockWidgetArea, m_paletteDockWidget);
|
||||||
|
|
||||||
|
m_textScene = new LevelOneScene(m_textWidget, this);
|
||||||
|
|
||||||
createActions();
|
createActions();
|
||||||
createStatusBar();
|
createStatusBar();
|
||||||
|
|
||||||
readSettings();
|
readSettings();
|
||||||
|
|
||||||
m_textScene = new LevelOneScene(m_textWidget, this);
|
|
||||||
|
|
||||||
m_textView = new QGraphicsView(this);
|
m_textView = new QGraphicsView(this);
|
||||||
m_textView->setScene(m_textScene);
|
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)));
|
m_textView->setBackgroundBrush(QBrush(QColor(32, 48, 96)));
|
||||||
setSceneDimensions();
|
setSceneDimensions();
|
||||||
setCentralWidget(m_textView);
|
setCentralWidget(m_textView);
|
||||||
|
|
||||||
connect(m_textWidget->document(), &TeletextDocument::cursorMoved, this, &MainWindow::updateCursorPosition);
|
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()); } );
|
connect(m_textWidget->document()->undoStack(), &QUndoStack::cleanChanged, this, [=]() { setWindowModified(!m_textWidget->document()->undoStack()->isClean()); } );
|
||||||
connect(m_textWidget->document(), &TeletextDocument::aboutToChangeSubPage, m_x26DockWidget, &X26DockWidget::unloadX26List);
|
connect(m_textWidget->document(), &TeletextDocument::aboutToChangeSubPage, m_x26DockWidget, &X26DockWidget::unloadX26List);
|
||||||
connect(m_textWidget->document(), &TeletextDocument::subPageSelected, this, &MainWindow::updatePageWidgets);
|
connect(m_textWidget->document(), &TeletextDocument::subPageSelected, this, &MainWindow::updatePageWidgets);
|
||||||
@@ -180,12 +234,17 @@ void MainWindow::init()
|
|||||||
connect(m_textWidget->pageRender(), &TeletextPageRender::fullRowColourChanged, m_textScene, &LevelOneScene::setFullRowColour);
|
connect(m_textWidget->pageRender(), &TeletextPageRender::fullRowColourChanged, m_textScene, &LevelOneScene::setFullRowColour);
|
||||||
connect(m_textWidget, &TeletextWidget::insertKeyPressed, this, &MainWindow::toggleInsertMode);
|
connect(m_textWidget, &TeletextWidget::insertKeyPressed, this, &MainWindow::toggleInsertMode);
|
||||||
|
|
||||||
|
connect(m_textScene, &LevelOneScene::mouseZoomIn, this, &MainWindow::zoomIn);
|
||||||
|
connect(m_textScene, &LevelOneScene::mouseZoomOut, this, &MainWindow::zoomOut);
|
||||||
|
|
||||||
QShortcut *blockShortCut = new QShortcut(QKeySequence(Qt::Key_Escape, Qt::Key_J), m_textView);
|
QShortcut *blockShortCut = new QShortcut(QKeySequence(Qt::Key_Escape, Qt::Key_J), m_textView);
|
||||||
connect(blockShortCut, &QShortcut::activated, [=]() { m_textWidget->setCharacter(0x7f); });
|
connect(blockShortCut, &QShortcut::activated, [=]() { m_textWidget->setCharacter(0x7f); });
|
||||||
|
|
||||||
setUnifiedTitleAndToolBarOnMac(true);
|
setUnifiedTitleAndToolBarOnMac(true);
|
||||||
|
|
||||||
updatePageWidgets();
|
updatePageWidgets();
|
||||||
|
|
||||||
|
m_textView->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::tile(const QMainWindow *previous)
|
void MainWindow::tile(const QMainWindow *previous)
|
||||||
@@ -251,14 +310,18 @@ void MainWindow::createActions()
|
|||||||
|
|
||||||
setRecentFilesVisible(MainWindow::hasRecentFiles());
|
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"));
|
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);
|
connect(exportZXNetAct, &QAction::triggered, this, &MainWindow::exportZXNet);
|
||||||
|
|
||||||
QAction *exportEditTFAct = exportHashStringSubMenu->addAction(tr("Open in edit.tf"));
|
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);
|
connect(exportEditTFAct, &QAction::triggered, this, &MainWindow::exportEditTF);
|
||||||
|
|
||||||
fileMenu->addSeparator();
|
fileMenu->addSeparator();
|
||||||
@@ -291,36 +354,33 @@ void MainWindow::createActions()
|
|||||||
redoAction->setShortcuts(QKeySequence::Redo);
|
redoAction->setShortcuts(QKeySequence::Redo);
|
||||||
|
|
||||||
editMenu->addSeparator();
|
editMenu->addSeparator();
|
||||||
|
|
||||||
#ifndef QT_NO_CLIPBOARD
|
#ifndef QT_NO_CLIPBOARD
|
||||||
/* const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/images/cut.png"));
|
const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/images/cut.png"));
|
||||||
QAction *cutAct = new QAction(cutIcon, tr("Cu&t"), this);
|
QAction *cutAct = new QAction(cutIcon, tr("Cu&t"), this);
|
||||||
cutAct->setShortcuts(QKeySequence::Cut);
|
cutAct->setShortcuts(QKeySequence::Cut);
|
||||||
cutAct->setStatusTip(tr("Cut the current selection's contents to the "
|
cutAct->setStatusTip(tr("Cut the current selection's contents to the clipboard"));
|
||||||
"clipboard"));
|
connect(cutAct, &QAction::triggered, m_textWidget, &TeletextWidget::cut);
|
||||||
connect(cutAct, &QAction::triggered, textWidget, &QTextEdit::cut);
|
|
||||||
editMenu->addAction(cutAct);
|
editMenu->addAction(cutAct);
|
||||||
editToolBar->addAction(cutAct);
|
editToolBar->addAction(cutAct);
|
||||||
|
|
||||||
const QIcon copyIcon = QIcon::fromTheme("edit-copy", QIcon(":/images/copy.png"));
|
const QIcon copyIcon = QIcon::fromTheme("edit-copy", QIcon(":/images/copy.png"));
|
||||||
QAction *copyAct = new QAction(copyIcon, tr("&Copy"), this);
|
QAction *copyAct = new QAction(copyIcon, tr("&Copy"), this);
|
||||||
copyAct->setShortcuts(QKeySequence::Copy);
|
copyAct->setShortcuts(QKeySequence::Copy);
|
||||||
copyAct->setStatusTip(tr("Copy the current selection's contents to the "
|
copyAct->setStatusTip(tr("Copy the current selection's contents to the clipboard"));
|
||||||
"clipboard"));
|
connect(copyAct, &QAction::triggered, m_textWidget, &TeletextWidget::copy);
|
||||||
connect(copyAct, &QAction::triggered, textWidget, &QTextEdit::copy);
|
|
||||||
editMenu->addAction(copyAct);
|
editMenu->addAction(copyAct);
|
||||||
editToolBar->addAction(copyAct);
|
editToolBar->addAction(copyAct);
|
||||||
|
|
||||||
const QIcon pasteIcon = QIcon::fromTheme("edit-paste", QIcon(":/images/paste.png"));
|
const QIcon pasteIcon = QIcon::fromTheme("edit-paste", QIcon(":/images/paste.png"));
|
||||||
QAction *pasteAct = new QAction(pasteIcon, tr("&Paste"), this);
|
QAction *pasteAct = new QAction(pasteIcon, tr("&Paste"), this);
|
||||||
pasteAct->setShortcuts(QKeySequence::Paste);
|
pasteAct->setShortcuts(QKeySequence::Paste);
|
||||||
pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
|
pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current selection"));
|
||||||
"selection"));
|
connect(pasteAct, &QAction::triggered, m_textWidget, &TeletextWidget::paste);
|
||||||
connect(pasteAct, &QAction::triggered, textWidget, &QTextEdit::paste);
|
|
||||||
editMenu->addAction(pasteAct);
|
editMenu->addAction(pasteAct);
|
||||||
editToolBar->addAction(pasteAct);
|
editToolBar->addAction(pasteAct);
|
||||||
|
|
||||||
editMenu->addSeparator();
|
editMenu->addSeparator();
|
||||||
*/
|
|
||||||
#endif // !QT_NO_CLIPBOARD
|
#endif // !QT_NO_CLIPBOARD
|
||||||
|
|
||||||
QAction *insertBlankRowAct = editMenu->addAction(tr("Insert blank row"));
|
QAction *insertBlankRowAct = editMenu->addAction(tr("Insert blank row"));
|
||||||
@@ -374,7 +434,7 @@ void MainWindow::createActions()
|
|||||||
gridAct->setCheckable(true);
|
gridAct->setCheckable(true);
|
||||||
gridAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_G));
|
gridAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_G));
|
||||||
gridAct->setStatusTip(tr("Toggle the text grid"));
|
gridAct->setStatusTip(tr("Toggle the text grid"));
|
||||||
connect(gridAct, &QAction::toggled, m_textWidget, &TeletextWidget::toggleGrid);
|
connect(gridAct, &QAction::toggled, m_textScene, &LevelOneScene::toggleGrid);
|
||||||
|
|
||||||
QAction *showCodesAct = viewMenu->addAction(tr("Show codes"));
|
QAction *showCodesAct = viewMenu->addAction(tr("Show codes"));
|
||||||
showCodesAct->setCheckable(true);
|
showCodesAct->setCheckable(true);
|
||||||
@@ -415,6 +475,13 @@ void MainWindow::createActions()
|
|||||||
borderGroup->addAction(m_borderActs[i]);
|
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"));
|
QAction *zoomInAct = viewMenu->addAction(tr("Zoom In"));
|
||||||
zoomInAct->setShortcuts(QKeySequence::ZoomIn);
|
zoomInAct->setShortcuts(QKeySequence::ZoomIn);
|
||||||
zoomInAct->setStatusTip(tr("Zoom in"));
|
zoomInAct->setStatusTip(tr("Zoom in"));
|
||||||
@@ -552,7 +619,6 @@ void MainWindow::createActions()
|
|||||||
|
|
||||||
void MainWindow::setSceneDimensions()
|
void MainWindow::setSceneDimensions()
|
||||||
{
|
{
|
||||||
const float aspectRatioHorizontalScaling[4] = { 0.6, 0.6, 0.8, 0.5 };
|
|
||||||
const int topBottomBorders[3] = { 0, 10, 19 };
|
const int topBottomBorders[3] = { 0, 10, 19 };
|
||||||
const int pillarBoxSizes[3] = { 672, 720, 854 };
|
const int pillarBoxSizes[3] = { 672, 720, 854 };
|
||||||
const int leftRightBorders[3] = { 0, 24, 77 };
|
const int leftRightBorders[3] = { 0, 24, 77 };
|
||||||
@@ -568,7 +634,7 @@ void MainWindow::setSceneDimensions()
|
|||||||
else
|
else
|
||||||
newSceneWidth = m_textWidget->width() + leftRightBorders[m_viewBorder]*2;
|
newSceneWidth = m_textWidget->width() + leftRightBorders[m_viewBorder]*2;
|
||||||
|
|
||||||
m_textScene->setDimensions(newSceneWidth, 250+topBottomBorders[m_viewBorder]*2, m_textWidget->width());
|
m_textScene->setBorderDimensions(newSceneWidth, 250+topBottomBorders[m_viewBorder]*2, m_textWidget->width(), m_textWidget->pageRender()->leftSidePanelColumns(), m_textWidget->pageRender()->rightSidePanelColumns());
|
||||||
m_textView->setTransform(QTransform((1+(float)m_viewZoom/2)*aspectRatioHorizontalScaling[m_viewAspectRatio], 0, 0, 1+(float)m_viewZoom/2, 0, 0));
|
m_textView->setTransform(QTransform((1+(float)m_viewZoom/2)*aspectRatioHorizontalScaling[m_viewAspectRatio], 0, 0, 1+(float)m_viewZoom/2, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,20 +642,17 @@ void MainWindow::insertRow(bool copyRow)
|
|||||||
{
|
{
|
||||||
if (m_textWidget->document()->cursorRow() == 24)
|
if (m_textWidget->document()->cursorRow() == 24)
|
||||||
return;
|
return;
|
||||||
QUndoCommand *insertRowCommand = new InsertRowCommand(m_textWidget->document(), copyRow);
|
m_textWidget->document()->undoStack()->push(new InsertRowCommand(m_textWidget->document(), copyRow));
|
||||||
m_textWidget->document()->undoStack()->push(insertRowCommand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::deleteRow()
|
void MainWindow::deleteRow()
|
||||||
{
|
{
|
||||||
QUndoCommand *deleteRowCommand = new DeleteRowCommand(m_textWidget->document());
|
m_textWidget->document()->undoStack()->push(new DeleteRowCommand(m_textWidget->document()));
|
||||||
m_textWidget->document()->undoStack()->push(deleteRowCommand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::insertSubPage(bool afterCurrentSubPage, bool copyCurrentSubPage)
|
void MainWindow::insertSubPage(bool afterCurrentSubPage, bool copyCurrentSubPage)
|
||||||
{
|
{
|
||||||
QUndoCommand *insertSubPageCommand = new InsertSubPageCommand(m_textWidget->document(), afterCurrentSubPage, copyCurrentSubPage);
|
m_textWidget->document()->undoStack()->push(new InsertSubPageCommand(m_textWidget->document(), afterCurrentSubPage, copyCurrentSubPage));
|
||||||
m_textWidget->document()->undoStack()->push(insertSubPageCommand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::deleteSubPage()
|
void MainWindow::deleteSubPage()
|
||||||
@@ -612,6 +675,15 @@ void MainWindow::setAspectRatio(int newViewAspectRatio)
|
|||||||
setSceneDimensions();
|
setSceneDimensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::setSmoothTransform(bool smoothTransform)
|
||||||
|
{
|
||||||
|
m_viewSmoothTransform = smoothTransform;
|
||||||
|
if (smoothTransform)
|
||||||
|
m_textView->setRenderHints(QPainter::SmoothPixmapTransform);
|
||||||
|
else
|
||||||
|
m_textView->setRenderHints({ });
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::zoomIn()
|
void MainWindow::zoomIn()
|
||||||
{
|
{
|
||||||
if (m_viewZoom < 4)
|
if (m_viewZoom < 4)
|
||||||
@@ -705,6 +777,10 @@ void MainWindow::readSettings()
|
|||||||
m_viewAspectRatio = settings.value("aspectratio", 0).toInt();
|
m_viewAspectRatio = settings.value("aspectratio", 0).toInt();
|
||||||
m_viewAspectRatio = (m_viewAspectRatio < 0 || m_viewAspectRatio > 2) ? 0 : m_viewAspectRatio;
|
m_viewAspectRatio = (m_viewAspectRatio < 0 || m_viewAspectRatio > 2) ? 0 : m_viewAspectRatio;
|
||||||
m_aspectRatioActs[m_viewAspectRatio]->setChecked(true);
|
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 = settings.value("zoom", 2).toInt();
|
||||||
m_viewZoom = (m_viewZoom < 0 || m_viewZoom > 4) ? 2 : m_viewZoom;
|
m_viewZoom = (m_viewZoom < 0 || m_viewZoom > 4) ? 2 : m_viewZoom;
|
||||||
|
|
||||||
@@ -743,6 +819,7 @@ void MainWindow::writeSettings()
|
|||||||
settings.setValue("windowState", saveState());
|
settings.setValue("windowState", saveState());
|
||||||
settings.setValue("border", m_viewBorder);
|
settings.setValue("border", m_viewBorder);
|
||||||
settings.setValue("aspectratio", m_viewAspectRatio);
|
settings.setValue("aspectratio", m_viewAspectRatio);
|
||||||
|
settings.setValue("smoothTransform", m_viewSmoothTransform);
|
||||||
settings.setValue("zoom", m_viewZoom);
|
settings.setValue("zoom", m_viewZoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -926,6 +1003,8 @@ MainWindow *MainWindow::findMainWindow(const QString &fileName) const
|
|||||||
void MainWindow::updateCursorPosition()
|
void MainWindow::updateCursorPosition()
|
||||||
{
|
{
|
||||||
m_cursorPositionLabel->setText(QString("Row %1 Column %2").arg(m_textWidget->document()->cursorRow()).arg(m_textWidget->document()->cursorColumn()));
|
m_cursorPositionLabel->setText(QString("Row %1 Column %2").arg(m_textWidget->document()->cursorRow()).arg(m_textWidget->document()->cursorColumn()));
|
||||||
|
m_textScene->updateCursor();
|
||||||
|
m_textView->ensureVisible(m_textScene->cursorRectItem(), 16, 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updatePageWidgets()
|
void MainWindow::updatePageWidgets()
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ private slots:
|
|||||||
void open();
|
void open();
|
||||||
bool save();
|
bool save();
|
||||||
bool saveAs();
|
bool saveAs();
|
||||||
|
void exportPNG();
|
||||||
void exportZXNet();
|
void exportZXNet();
|
||||||
void exportEditTF();
|
void exportEditTF();
|
||||||
void updateRecentFileActions();
|
void updateRecentFileActions();
|
||||||
@@ -74,6 +75,7 @@ private slots:
|
|||||||
void setSceneDimensions();
|
void setSceneDimensions();
|
||||||
void setBorder(int);
|
void setBorder(int);
|
||||||
void setAspectRatio(int);
|
void setAspectRatio(int);
|
||||||
|
void setSmoothTransform(bool);
|
||||||
void zoomIn();
|
void zoomIn();
|
||||||
void zoomOut();
|
void zoomOut();
|
||||||
void zoomReset();
|
void zoomReset();
|
||||||
@@ -82,6 +84,7 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
enum { m_MaxRecentFiles = 10 };
|
enum { m_MaxRecentFiles = 10 };
|
||||||
|
const float aspectRatioHorizontalScaling[4] = { 0.6, 0.6, 0.8, 0.5 };
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void createActions();
|
void createActions();
|
||||||
@@ -104,6 +107,7 @@ private:
|
|||||||
QGraphicsView *m_textView;
|
QGraphicsView *m_textView;
|
||||||
|
|
||||||
int m_viewBorder, m_viewAspectRatio, m_viewZoom;
|
int m_viewBorder, m_viewAspectRatio, m_viewZoom;
|
||||||
|
bool m_viewSmoothTransform;
|
||||||
PageOptionsDockWidget *m_pageOptionsDockWidget;
|
PageOptionsDockWidget *m_pageOptionsDockWidget;
|
||||||
PageEnhancementsDockWidget *m_pageEnhancementsDockWidget;
|
PageEnhancementsDockWidget *m_pageEnhancementsDockWidget;
|
||||||
X26DockWidget *m_x26DockWidget;
|
X26DockWidget *m_x26DockWidget;
|
||||||
@@ -115,6 +119,7 @@ private:
|
|||||||
QAction *m_deleteSubPageAction;
|
QAction *m_deleteSubPageAction;
|
||||||
QAction *m_borderActs[3];
|
QAction *m_borderActs[3];
|
||||||
QAction *m_aspectRatioActs[4];
|
QAction *m_aspectRatioActs[4];
|
||||||
|
QAction *m_smoothTransformAction;
|
||||||
|
|
||||||
QLabel *m_subPageLabel, *m_cursorPositionLabel;
|
QLabel *m_subPageLabel, *m_cursorPositionLabel;
|
||||||
QToolButton *m_previousSubPageButton, *m_nextSubPageButton;
|
QToolButton *m_previousSubPageButton, *m_nextSubPageButton;
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ public:
|
|||||||
|
|
||||||
virtual QByteArray packet(int) const;
|
virtual QByteArray packet(int) const;
|
||||||
virtual QByteArray packet(int, int) const;
|
virtual QByteArray packet(int, int) const;
|
||||||
virtual bool packetNeeded(int i) const { return m_displayPackets[i] != nullptr; }
|
virtual bool packetExists(int i) const { return m_displayPackets[i] != nullptr; }
|
||||||
virtual bool packetNeeded(int i, int j) const { return m_designationPackets[i-26][j] != nullptr; }
|
virtual bool packetExists(int i, int j) const { return m_designationPackets[i-26][j] != nullptr; }
|
||||||
virtual bool setPacket(int, QByteArray);
|
virtual bool setPacket(int, QByteArray);
|
||||||
virtual bool setPacket(int, int, QByteArray);
|
virtual bool setPacket(int, int, QByteArray);
|
||||||
// bool deletePacket(int);
|
// bool deletePacket(int);
|
||||||
|
|||||||
@@ -47,12 +47,9 @@ PageEnhancementsDockWidget::PageEnhancementsDockWidget(TeletextWidget *parent):
|
|||||||
x28Layout->addWidget(new QLabel(tr("Default screen colour")), 0, 0, 1, 1);
|
x28Layout->addWidget(new QLabel(tr("Default screen colour")), 0, 0, 1, 1);
|
||||||
x28Layout->addWidget(new QLabel(tr("Default row colour")), 1, 0, 1, 1);
|
x28Layout->addWidget(new QLabel(tr("Default row colour")), 1, 0, 1, 1);
|
||||||
m_defaultScreenColourCombo = new QComboBox;
|
m_defaultScreenColourCombo = new QComboBox;
|
||||||
|
m_defaultScreenColourCombo->setModel(m_parentMainWidget->document()->clutModel());
|
||||||
m_defaultRowColourCombo = new QComboBox;
|
m_defaultRowColourCombo = new QComboBox;
|
||||||
for (int r=0; r<=3; r++)
|
m_defaultRowColourCombo->setModel(m_parentMainWidget->document()->clutModel());
|
||||||
for (int c=0; c<=7; c++) {
|
|
||||||
m_defaultScreenColourCombo->addItem(tr("CLUT %1:%2").arg(r).arg(c));
|
|
||||||
m_defaultRowColourCombo->addItem(tr("CLUT %1:%2").arg(r).arg(c));
|
|
||||||
}
|
|
||||||
x28Layout->addWidget(m_defaultScreenColourCombo, 0, 1, 1, 1, Qt::AlignTop);
|
x28Layout->addWidget(m_defaultScreenColourCombo, 0, 1, 1, 1, Qt::AlignTop);
|
||||||
connect(m_defaultScreenColourCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index){ m_parentMainWidget->setDefaultScreenColour(index); });
|
connect(m_defaultScreenColourCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index){ m_parentMainWidget->setDefaultScreenColour(index); });
|
||||||
x28Layout->addWidget(m_defaultRowColourCombo, 1, 1, 1, 1, Qt::AlignTop);
|
x28Layout->addWidget(m_defaultRowColourCombo, 1, 1, 1, 1, Qt::AlignTop);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ void PageX26Base::setEnhancementListFromPacket(int packetNumber, QByteArray pack
|
|||||||
newX26Triplet.setAddress(packetContents.at(i*3+1) & 0x3f);
|
newX26Triplet.setAddress(packetContents.at(i*3+1) & 0x3f);
|
||||||
newX26Triplet.setMode(packetContents.at(i*3+2) & 0x1f);
|
newX26Triplet.setMode(packetContents.at(i*3+2) & 0x1f);
|
||||||
newX26Triplet.setData(((packetContents.at(i*3+3) & 0x3f) << 1) | ((packetContents.at(i*3+2) & 0x20) >> 5));
|
newX26Triplet.setData(((packetContents.at(i*3+3) & 0x3f) << 1) | ((packetContents.at(i*3+2) & 0x20) >> 5));
|
||||||
m_enhancements[enhanceListPointer] = newX26Triplet;
|
m_enhancements.replace(enhanceListPointer, newX26Triplet);
|
||||||
}
|
}
|
||||||
if (newX26Triplet.mode() == 0x1f && newX26Triplet.address() == 0x3f && newX26Triplet.data() & 0x01)
|
if (newX26Triplet.mode() == 0x1f && newX26Triplet.address() == 0x3f && newX26Triplet.data() & 0x01)
|
||||||
// Last triplet was a Termination Marker (without ..follows) so clean up the repeated ones
|
// Last triplet was a Termination Marker (without ..follows) so clean up the repeated ones
|
||||||
|
|||||||
@@ -31,14 +31,15 @@ class PageX26Base : public PageBase //: public QObject
|
|||||||
//Q_OBJECT
|
//Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QList<X26Triplet> *enhancements() { return &m_enhancements; };
|
X26TripletList *enhancements() { return &m_enhancements; };
|
||||||
|
virtual int maxEnhancements() const =0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QByteArray packetFromEnhancementList(int) const;
|
QByteArray packetFromEnhancementList(int) const;
|
||||||
void setEnhancementListFromPacket(int, QByteArray);
|
void setEnhancementListFromPacket(int, QByteArray);
|
||||||
bool packetFromEnhancementListNeeded(int n) const { return ((m_enhancements.size()+12) / 13) > n; };
|
bool packetFromEnhancementListNeeded(int n) const { return ((m_enhancements.size()+12) / 13) > n; };
|
||||||
|
|
||||||
QList<X26Triplet> m_enhancements;
|
X26TripletList m_enhancements;
|
||||||
const X26Triplet m_paddingX26Triplet { 41, 0x1e, 0 };
|
const X26Triplet m_paddingX26Triplet { 41, 0x1e, 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -108,14 +108,11 @@ void PaletteDockWidget::selectColour(int colourIndex)
|
|||||||
{
|
{
|
||||||
const QColor newColour = QColorDialog::getColor(m_parentMainWidget->document()->currentSubPage()->CLUTtoQColor(colourIndex), this, "Select Colour");
|
const QColor newColour = QColorDialog::getColor(m_parentMainWidget->document()->currentSubPage()->CLUTtoQColor(colourIndex), this, "Select Colour");
|
||||||
|
|
||||||
if (newColour.isValid()) {
|
if (newColour.isValid())
|
||||||
QUndoCommand *setColourCommand = new SetColourCommand(m_parentMainWidget->document(), colourIndex, ((newColour.red() & 0xf0) << 4) | (newColour.green() & 0xf0) | ((newColour.blue() & 0xf0) >> 4));
|
m_parentMainWidget->document()->undoStack()->push(new SetColourCommand(m_parentMainWidget->document(), colourIndex, ((newColour.red() & 0xf0) << 4) | (newColour.green() & 0xf0) | ((newColour.blue() & 0xf0) >> 4)));
|
||||||
m_parentMainWidget->document()->undoStack()->push(setColourCommand);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaletteDockWidget::resetCLUT(int colourTable)
|
void PaletteDockWidget::resetCLUT(int colourTable)
|
||||||
{
|
{
|
||||||
QUndoCommand *resetCLUTCommand = new ResetCLUTCommand(m_parentMainWidget->document(), colourTable);
|
m_parentMainWidget->document()->undoStack()->push(new ResetCLUTCommand(m_parentMainWidget->document(), colourTable));
|
||||||
m_parentMainWidget->document()->undoStack()->push(resetCLUTCommand);
|
|
||||||
}
|
}
|
||||||
|
|||||||
48
render.cpp
48
render.cpp
@@ -26,15 +26,30 @@
|
|||||||
|
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
|
||||||
|
int TeletextFontBitmap::s_instances = 0;
|
||||||
|
|
||||||
|
QBitmap *TeletextFontBitmap::s_fontBitmap = nullptr;
|
||||||
|
|
||||||
|
TeletextFontBitmap::TeletextFontBitmap()
|
||||||
|
{
|
||||||
|
if (s_instances == 0)
|
||||||
|
s_fontBitmap = new QBitmap(":/images/teletextfont.png");
|
||||||
|
s_instances++;
|
||||||
|
}
|
||||||
|
|
||||||
|
TeletextFontBitmap::~TeletextFontBitmap()
|
||||||
|
{
|
||||||
|
s_instances--;
|
||||||
|
if (s_instances == 0)
|
||||||
|
delete s_fontBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
TeletextPageRender::TeletextPageRender()
|
TeletextPageRender::TeletextPageRender()
|
||||||
{
|
{
|
||||||
QPainter pixmapPainter;
|
|
||||||
|
|
||||||
m_fontBitmap = new QBitmap(":/images/teletextfont.png");
|
|
||||||
for (int i=0; i<6; i++)
|
for (int i=0; i<6; i++)
|
||||||
m_pagePixmap[i] = new QPixmap(864, 250);
|
m_pagePixmap[i] = new QPixmap(864, 250);
|
||||||
m_pagePixmap[0]->fill(Qt::transparent);
|
m_pagePixmap[0]->fill(Qt::transparent);
|
||||||
m_grid = m_mix = m_reveal = m_showCodes = false;
|
m_mix = m_reveal = m_showCodes = false;
|
||||||
m_renderLevel = 0;
|
m_renderLevel = 0;
|
||||||
m_flashRequired = 0;
|
m_flashRequired = 0;
|
||||||
m_finalFullScreenColour = 0;
|
m_finalFullScreenColour = 0;
|
||||||
@@ -58,7 +73,6 @@ TeletextPageRender::~TeletextPageRender()
|
|||||||
}
|
}
|
||||||
for (int i=0; i<6; i++)
|
for (int i=0; i<6; i++)
|
||||||
delete m_pagePixmap[i];
|
delete m_pagePixmap[i];
|
||||||
delete m_fontBitmap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextPageRender::setTeletextPage(LevelOnePage *newCurrentPage)
|
void TeletextPageRender::setTeletextPage(LevelOnePage *newCurrentPage)
|
||||||
@@ -92,7 +106,6 @@ void TeletextPageRender::setRenderLevel(int newRenderLevel)
|
|||||||
renderPage();
|
renderPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeletextPageRender::setGrid(bool newGrid) { m_grid = newGrid; }
|
|
||||||
void TeletextPageRender::setShowCodes(bool newShowCodes)
|
void TeletextPageRender::setShowCodes(bool newShowCodes)
|
||||||
{
|
{
|
||||||
m_showCodes = newShowCodes;
|
m_showCodes = newShowCodes;
|
||||||
@@ -164,7 +177,7 @@ void TeletextPageRender::buildEnhanceMap(TextLayer *enhanceLayer, int tripletNum
|
|||||||
if ((x26Triplet->address() & 0x18) == 0x08) {
|
if ((x26Triplet->address() & 0x18) == 0x08) {
|
||||||
// Local Object
|
// Local Object
|
||||||
// Check if the pointer in the Invocation triplet is valid
|
// Check if the pointer in the Invocation triplet is valid
|
||||||
// Can't point to triplets 13-15; only 12 triplets per packet
|
// Can't point to triplets 13-15; only triplets 0-12 per packet
|
||||||
if ((x26Triplet->data() & 0x0f) > 12)
|
if ((x26Triplet->data() & 0x0f) > 12)
|
||||||
break;
|
break;
|
||||||
int tripletPointer = ((x26Triplet->data() >> 4) | ((x26Triplet->address() & 1) << 3)) * 13 + (x26Triplet->data() & 0x0f);
|
int tripletPointer = ((x26Triplet->data() >> 4) | ((x26Triplet->address() & 1) << 3)) * 13 + (x26Triplet->data() & 0x0f);
|
||||||
@@ -174,12 +187,15 @@ void TeletextPageRender::buildEnhanceMap(TextLayer *enhanceLayer, int tripletNum
|
|||||||
// Check if we're pointing to an actual Object Definition of the same type
|
// Check if we're pointing to an actual Object Definition of the same type
|
||||||
if ((x26Triplet->mode() | 0x04) != m_levelOnePage->enhancements()->at(tripletPointer).mode())
|
if ((x26Triplet->mode() | 0x04) != m_levelOnePage->enhancements()->at(tripletPointer).mode())
|
||||||
break;
|
break;
|
||||||
// The Object Definition can't declare it's at triplet 13-15; only 12 triplets per packet
|
// The Object Definition can't declare it's at triplet 13-15; only triplets 0-12 per packet
|
||||||
if ((m_levelOnePage->enhancements()->at(tripletPointer).data() & 0x0f) > 12)
|
if ((m_levelOnePage->enhancements()->at(tripletPointer).data() & 0x0f) > 12)
|
||||||
break;
|
break;
|
||||||
// Check if the Object Definition triplet is where it declares it is
|
// Check if the Object Definition triplet is where it declares it is
|
||||||
if ((((m_levelOnePage->enhancements()->at(tripletPointer).data() >> 4) | ((m_levelOnePage->enhancements()->at(tripletPointer).address() & 1) << 3)) * 13 + (m_levelOnePage->enhancements()->at(tripletPointer).data() & 0x0f)) != tripletPointer)
|
if ((((m_levelOnePage->enhancements()->at(tripletPointer).data() >> 4) | ((m_levelOnePage->enhancements()->at(tripletPointer).address() & 1) << 3)) * 13 + (m_levelOnePage->enhancements()->at(tripletPointer).data() & 0x0f)) != tripletPointer)
|
||||||
break;
|
break;
|
||||||
|
// Check if (sub)Object type can be invoked by Object type we're within
|
||||||
|
if (enhanceLayer->objectType() >= (x26Triplet->mode() & 0x03))
|
||||||
|
break;
|
||||||
// Is the object required at the current presentation Level?
|
// Is the object required at the current presentation Level?
|
||||||
if (m_renderLevel == 2 && (m_levelOnePage->enhancements()->at(tripletPointer).address() & 0x08) == 0x00)
|
if (m_renderLevel == 2 && (m_levelOnePage->enhancements()->at(tripletPointer).address() & 0x08) == 0x00)
|
||||||
break;
|
break;
|
||||||
@@ -188,7 +204,7 @@ void TeletextPageRender::buildEnhanceMap(TextLayer *enhanceLayer, int tripletNum
|
|||||||
EnhanceLayer *newLayer = new EnhanceLayer;
|
EnhanceLayer *newLayer = new EnhanceLayer;
|
||||||
m_textLayer.push_back(newLayer);
|
m_textLayer.push_back(newLayer);
|
||||||
newLayer->setObjectType(x26Triplet->mode() & 0x03);
|
newLayer->setObjectType(x26Triplet->mode() & 0x03);
|
||||||
newLayer->setOrigin(activePosition.row()+originModifierR, activePosition.column()+originModifierC);
|
newLayer->setOrigin(enhanceLayer->originR() + activePosition.row() + originModifierR, enhanceLayer->originC() + activePosition.column() + originModifierC);
|
||||||
buildEnhanceMap(newLayer, tripletPointer+1);
|
buildEnhanceMap(newLayer, tripletPointer+1);
|
||||||
} else
|
} else
|
||||||
qDebug("POP or GPOP");
|
qDebug("POP or GPOP");
|
||||||
@@ -257,7 +273,7 @@ void TeletextPageRender::decodePage()
|
|||||||
setFullRowColour(r ,downwardsFullRowColour);
|
setFullRowColour(r ,downwardsFullRowColour);
|
||||||
|
|
||||||
m_textLayer[1]->enhanceMap.clear();
|
m_textLayer[1]->enhanceMap.clear();
|
||||||
if (m_renderLevel == 0 || m_levelOnePage->enhancements()->empty())
|
if (m_renderLevel == 0 || m_levelOnePage->enhancements()->isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_textLayer[1]->setFullScreenColour(-1);
|
m_textLayer[1]->setFullScreenColour(-1);
|
||||||
@@ -346,10 +362,10 @@ void TeletextPageRender::renderPage(int r)
|
|||||||
pixmapPainter.setBackground(QBrush(backQColour));
|
pixmapPainter.setBackground(QBrush(backQColour));
|
||||||
}
|
}
|
||||||
pixmapPainter.setPen(foreQColour);
|
pixmapPainter.setPen(foreQColour);
|
||||||
pixmapPainter.drawPixmap(c*12, r*10, charWidth, charHeight, *m_fontBitmap, (resultCharacter.code-32)*12, resultCharacter.set*10, 12, 10);
|
pixmapPainter.drawPixmap(c*12, r*10, charWidth, charHeight, *m_fontBitmap.rawBitmap(), (resultCharacter.code-32)*12, resultCharacter.set*10, 12, 10);
|
||||||
if (resultCharacter.diacritical) {
|
if (resultCharacter.diacritical) {
|
||||||
pixmapPainter.setBackgroundMode(Qt::TransparentMode);
|
pixmapPainter.setBackgroundMode(Qt::TransparentMode);
|
||||||
pixmapPainter.drawPixmap(c*12, r*10, charWidth, charHeight, *m_fontBitmap, 384+resultCharacter.diacritical*12, 70, 12, 10);
|
pixmapPainter.drawPixmap(c*12, r*10, charWidth, charHeight, *m_fontBitmap.rawBitmap(), 384+resultCharacter.diacritical*12, 70, 12, 10);
|
||||||
pixmapPainter.setBackgroundMode(Qt::OpaqueMode);
|
pixmapPainter.setBackgroundMode(Qt::OpaqueMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,12 +376,6 @@ void TeletextPageRender::renderPage(int r)
|
|||||||
else
|
else
|
||||||
pixmapPainter.drawRect(c*12, r*10+18, charWidth-1, 1);
|
pixmapPainter.drawRect(c*12, r*10+18, charWidth-1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_grid) {
|
|
||||||
pixmapPainter.setPen(QColor(128, 128, 128, (c <= 39) ? 192 : 64));
|
|
||||||
pixmapPainter.drawRect(c*12, r*10, 11, 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pixmapPainter.begin(m_pagePixmap[0]);
|
pixmapPainter.begin(m_pagePixmap[0]);
|
||||||
@@ -487,7 +497,7 @@ void TeletextPageRender::renderPage(int r)
|
|||||||
if (m_showCodes && c < 40 && m_levelOnePage->character(r, c)<0x20 && !m_level1Layer.isRowBottomHalf(r) && !m_cell[r][c].bottomHalf) {
|
if (m_showCodes && c < 40 && m_levelOnePage->character(r, c)<0x20 && !m_level1Layer.isRowBottomHalf(r) && !m_cell[r][c].bottomHalf) {
|
||||||
pixmapPainter.setBackground(QBrush(QColor(0, 0, 0, 128)));
|
pixmapPainter.setBackground(QBrush(QColor(0, 0, 0, 128)));
|
||||||
pixmapPainter.setPen(QColor(255, 255, 255, 224));
|
pixmapPainter.setPen(QColor(255, 255, 255, 224));
|
||||||
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, *m_fontBitmap, (m_levelOnePage->character(r, c)+32)*12, 250, 12, 10);
|
pixmapPainter.drawPixmap(c*12, r*10, 12, 10, *m_fontBitmap.rawBitmap(), (m_levelOnePage->character(r, c)+32)*12, 250, 12, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultAttributes.display.doubleHeight)
|
if (resultAttributes.display.doubleHeight)
|
||||||
|
|||||||
23
render.h
23
render.h
@@ -107,6 +107,8 @@ public:
|
|||||||
virtual int fullRowColour(int) const =0;
|
virtual int fullRowColour(int) const =0;
|
||||||
virtual bool fullRowDownwards(int) const =0;
|
virtual bool fullRowDownwards(int) const =0;
|
||||||
virtual int objectType() const =0;
|
virtual int objectType() const =0;
|
||||||
|
virtual int originR() const { return 0; };
|
||||||
|
virtual int originC() const { return 0; };
|
||||||
void setFullScreenColour(int);
|
void setFullScreenColour(int);
|
||||||
void setFullRowColour(int, int, bool);
|
void setFullRowColour(int, int, bool);
|
||||||
|
|
||||||
@@ -131,6 +133,8 @@ public:
|
|||||||
int fullRowColour(int r) const { return m_layerFullRowColour[r]; };
|
int fullRowColour(int r) const { return m_layerFullRowColour[r]; };
|
||||||
bool fullRowDownwards(int r) const { return m_layerFullRowDownwards[r]; };
|
bool fullRowDownwards(int r) const { return m_layerFullRowDownwards[r]; };
|
||||||
int objectType() const { return m_objectType; };
|
int objectType() const { return m_objectType; };
|
||||||
|
int originR() const { return m_originR; };
|
||||||
|
int originC() const { return m_originC; };
|
||||||
void setObjectType(int);
|
void setObjectType(int);
|
||||||
void setOrigin(int, int);
|
void setOrigin(int, int);
|
||||||
|
|
||||||
@@ -175,6 +179,18 @@ private:
|
|||||||
enum rowHeightEnum { RHnormal=-1, RHtophalf, RHbottomhalf } m_rowHeight[25];
|
enum rowHeightEnum { RHnormal=-1, RHtophalf, RHbottomhalf } m_rowHeight[25];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TeletextFontBitmap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TeletextFontBitmap();
|
||||||
|
~TeletextFontBitmap();
|
||||||
|
QBitmap *rawBitmap() const { return s_fontBitmap; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int s_instances;
|
||||||
|
static QBitmap* s_fontBitmap;
|
||||||
|
};
|
||||||
|
|
||||||
class TeletextPageRender : public QObject
|
class TeletextPageRender : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -185,6 +201,8 @@ public:
|
|||||||
void decodePage();
|
void decodePage();
|
||||||
void renderPage();
|
void renderPage();
|
||||||
void renderPage(int r);
|
void renderPage(int r);
|
||||||
|
bool mix() const { return m_mix; };
|
||||||
|
bool showCodes() const { return m_showCodes; };
|
||||||
void setTeletextPage(LevelOnePage *);
|
void setTeletextPage(LevelOnePage *);
|
||||||
void updateSidePanels();
|
void updateSidePanels();
|
||||||
void buildEnhanceMap(TextLayer *, int=0);
|
void buildEnhanceMap(TextLayer *, int=0);
|
||||||
@@ -193,7 +211,6 @@ public:
|
|||||||
int level1CharSet(int r, int c) const { return m_cell[r][c].level1CharSet; };
|
int level1CharSet(int r, int c) const { return m_cell[r][c].level1CharSet; };
|
||||||
int leftSidePanelColumns() const { return m_leftSidePanelColumns; };
|
int leftSidePanelColumns() const { return m_leftSidePanelColumns; };
|
||||||
int rightSidePanelColumns() const { return m_rightSidePanelColumns; };
|
int rightSidePanelColumns() const { return m_rightSidePanelColumns; };
|
||||||
void setGrid(bool);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setReveal(bool);
|
void setReveal(bool);
|
||||||
@@ -212,12 +229,12 @@ protected:
|
|||||||
inline void setFullScreenColour(int);
|
inline void setFullScreenColour(int);
|
||||||
inline void setFullRowColour(int, int);
|
inline void setFullRowColour(int, int);
|
||||||
|
|
||||||
QBitmap* m_fontBitmap;
|
TeletextFontBitmap m_fontBitmap;
|
||||||
QPixmap* m_pagePixmap[6];
|
QPixmap* m_pagePixmap[6];
|
||||||
int m_finalFullScreenColour, m_renderLevel;
|
int m_finalFullScreenColour, m_renderLevel;
|
||||||
QColor m_finalFullScreenQColor;
|
QColor m_finalFullScreenQColor;
|
||||||
int m_leftSidePanelColumns, m_rightSidePanelColumns;
|
int m_leftSidePanelColumns, m_rightSidePanelColumns;
|
||||||
bool m_reveal, m_mix, m_grid, m_showCodes;
|
bool m_reveal, m_mix, m_showCodes;
|
||||||
Level1Layer m_level1Layer;
|
Level1Layer m_level1Layer;
|
||||||
std::vector<TextLayer *> m_textLayer;
|
std::vector<TextLayer *> m_textLayer;
|
||||||
const int m_foregroundRemap[8] = { 0, 0, 0, 8, 8, 16, 16, 16 };
|
const int m_foregroundRemap[8] = { 0, 0, 0, 8, 8, 16, 16, 16 };
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ void EditTripletCommand::redo()
|
|||||||
if (m_teletextDocument->currentSubPageIndex() != m_subPageIndex)
|
if (m_teletextDocument->currentSubPageIndex() != m_subPageIndex)
|
||||||
m_teletextDocument->selectSubPageIndex(m_subPageIndex, true);
|
m_teletextDocument->selectSubPageIndex(m_subPageIndex, true);
|
||||||
|
|
||||||
m_teletextDocument->currentSubPage()->enhancements()->operator[](m_row) = m_newTriplet;
|
m_teletextDocument->currentSubPage()->enhancements()->replace(m_row, m_newTriplet);
|
||||||
m_x26Model->emit dataChanged(m_x26Model->createIndex(m_row, 0), m_x26Model->createIndex(m_row, 3), {m_role});
|
m_x26Model->emit dataChanged(m_x26Model->createIndex(m_row, 0), m_x26Model->createIndex(m_row, 3), {m_role});
|
||||||
m_teletextDocument->emit refreshNeeded();
|
m_teletextDocument->emit refreshNeeded();
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ void EditTripletCommand::undo()
|
|||||||
if (m_teletextDocument->currentSubPageIndex() != m_subPageIndex)
|
if (m_teletextDocument->currentSubPageIndex() != m_subPageIndex)
|
||||||
m_teletextDocument->selectSubPageIndex(m_subPageIndex, true);
|
m_teletextDocument->selectSubPageIndex(m_subPageIndex, true);
|
||||||
|
|
||||||
m_teletextDocument->currentSubPage()->enhancements()->operator[](m_row) = m_oldTriplet;
|
m_teletextDocument->currentSubPage()->enhancements()->replace(m_row, m_oldTriplet);
|
||||||
m_x26Model->emit dataChanged(m_x26Model->createIndex(m_row, 0), m_x26Model->createIndex(m_row, 3), {m_role});
|
m_x26Model->emit dataChanged(m_x26Model->createIndex(m_row, 0), m_x26Model->createIndex(m_row, 3), {m_role});
|
||||||
m_teletextDocument->emit refreshNeeded();
|
m_teletextDocument->emit refreshNeeded();
|
||||||
m_teletextDocument->emit tripletCommandHighlight(m_row);
|
m_teletextDocument->emit tripletCommandHighlight(m_row);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
|
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
@@ -34,8 +35,42 @@
|
|||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "render.h"
|
||||||
#include "x26dockwidget.h"
|
#include "x26dockwidget.h"
|
||||||
|
|
||||||
|
CharacterListModel::CharacterListModel(QObject *parent): QAbstractListModel(parent)
|
||||||
|
{
|
||||||
|
m_characterSet = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CharacterListModel::rowCount(const QModelIndex & /*parent*/) const
|
||||||
|
{
|
||||||
|
return 96;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant CharacterListModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
return QString("0x%1").arg(index.row()+0x20, 2, 16);
|
||||||
|
|
||||||
|
if (role == Qt::DecorationRole)
|
||||||
|
return m_fontBitmap.rawBitmap()->copy(index.row()*12, m_characterSet*10, 12, 10);
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterListModel::setCharacterSet(int characterSet)
|
||||||
|
{
|
||||||
|
if (characterSet != m_characterSet) {
|
||||||
|
m_characterSet = characterSet;
|
||||||
|
emit dataChanged(createIndex(0, 0), createIndex(95, 0), QVector<int>(Qt::DecorationRole));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent)
|
X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent)
|
||||||
{
|
{
|
||||||
QVBoxLayout *x26Layout = new QVBoxLayout;
|
QVBoxLayout *x26Layout = new QVBoxLayout;
|
||||||
@@ -161,9 +196,7 @@ X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent)
|
|||||||
QHBoxLayout *colourAndRowLayout = new QHBoxLayout;
|
QHBoxLayout *colourAndRowLayout = new QHBoxLayout;
|
||||||
|
|
||||||
m_colourComboBox = new QComboBox;
|
m_colourComboBox = new QComboBox;
|
||||||
for (int c=0; c<=3; c++)
|
m_colourComboBox->setModel(m_parentMainWidget->document()->clutModel());
|
||||||
for (int e=0; e<=7; e++)
|
|
||||||
m_colourComboBox->addItem(tr("CLUT %1:%2").arg(c).arg(e));
|
|
||||||
colourAndRowLayout->addWidget(m_colourComboBox);
|
colourAndRowLayout->addWidget(m_colourComboBox);
|
||||||
connect(m_colourComboBox, QOverload<int>::of(&QComboBox::activated), this, [=](const int value) { updateModelFromCookedWidget(value, Qt::UserRole+1); } );
|
connect(m_colourComboBox, QOverload<int>::of(&QComboBox::activated), this, [=](const int value) { updateModelFromCookedWidget(value, Qt::UserRole+1); } );
|
||||||
|
|
||||||
@@ -181,8 +214,7 @@ X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent)
|
|||||||
QHBoxLayout *characterCodeLayout = new QHBoxLayout;
|
QHBoxLayout *characterCodeLayout = new QHBoxLayout;
|
||||||
|
|
||||||
m_characterCodeComboBox = new QComboBox;
|
m_characterCodeComboBox = new QComboBox;
|
||||||
for (int i=32; i<128; i++)
|
m_characterCodeComboBox->setModel(&m_characterListModel);
|
||||||
m_characterCodeComboBox->addItem(QString("0x%1").arg(i, 2, 16), i);
|
|
||||||
characterCodeLayout->addWidget(m_characterCodeComboBox);
|
characterCodeLayout->addWidget(m_characterCodeComboBox);
|
||||||
connect(m_characterCodeComboBox, QOverload<int>::of(&QComboBox::activated), this, [=](const int value) { updateModelFromCookedWidget(value+32, Qt::UserRole+1); } );
|
connect(m_characterCodeComboBox, QOverload<int>::of(&QComboBox::activated), this, [=](const int value) { updateModelFromCookedWidget(value+32, Qt::UserRole+1); } );
|
||||||
|
|
||||||
@@ -253,13 +285,15 @@ X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent)
|
|||||||
// Invoke Local Objects
|
// Invoke Local Objects
|
||||||
QHBoxLayout *invokeLocalObjectLayout = new QHBoxLayout;
|
QHBoxLayout *invokeLocalObjectLayout = new QHBoxLayout;
|
||||||
|
|
||||||
invokeLocalObjectLayout->addWidget(new QLabel(tr("Designation")));
|
m_invokeLocalObjectDesignationCodeLabel = new QLabel(tr("Designation"));
|
||||||
|
invokeLocalObjectLayout->addWidget(m_invokeLocalObjectDesignationCodeLabel);
|
||||||
m_invokeLocalObjectDesignationCodeSpinBox = new QSpinBox;
|
m_invokeLocalObjectDesignationCodeSpinBox = new QSpinBox;
|
||||||
m_invokeLocalObjectDesignationCodeSpinBox->setMaximum(15);
|
m_invokeLocalObjectDesignationCodeSpinBox->setMaximum(15);
|
||||||
invokeLocalObjectLayout->addWidget(m_invokeLocalObjectDesignationCodeSpinBox);
|
invokeLocalObjectLayout->addWidget(m_invokeLocalObjectDesignationCodeSpinBox);
|
||||||
connect(m_invokeLocalObjectDesignationCodeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, [=](const int value) { updateModelFromCookedWidget(value, Qt::UserRole+2); } );
|
connect(m_invokeLocalObjectDesignationCodeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, [=](const int value) { updateModelFromCookedWidget(value, Qt::UserRole+2); } );
|
||||||
|
|
||||||
invokeLocalObjectLayout->addWidget(new QLabel(tr("Triplet")));
|
m_invokeLocalObjectTripletNumberLabel = new QLabel(tr("Triplet"));
|
||||||
|
invokeLocalObjectLayout->addWidget(m_invokeLocalObjectTripletNumberLabel);
|
||||||
m_invokeLocalObjectTripletNumberSpinBox = new QSpinBox;
|
m_invokeLocalObjectTripletNumberSpinBox = new QSpinBox;
|
||||||
m_invokeLocalObjectTripletNumberSpinBox->setMaximum(12);
|
m_invokeLocalObjectTripletNumberSpinBox->setMaximum(12);
|
||||||
invokeLocalObjectLayout->addWidget(m_invokeLocalObjectTripletNumberSpinBox);
|
invokeLocalObjectLayout->addWidget(m_invokeLocalObjectTripletNumberSpinBox);
|
||||||
@@ -705,7 +739,16 @@ void X26DockWidget::updateCookedTripletParameters(const QModelIndex &index)
|
|||||||
case 0x29: // G0 character
|
case 0x29: // G0 character
|
||||||
case 0x2b: // G3 character at Level 2.5
|
case 0x2b: // G3 character at Level 2.5
|
||||||
case 0x2f ... 0x3f: // G2 character, G0 character with diacritical
|
case 0x2f ... 0x3f: // G2 character, G0 character with diacritical
|
||||||
|
// TODO non-Latin G0 and G2 character sets
|
||||||
m_characterCodeComboBox->blockSignals(true);
|
m_characterCodeComboBox->blockSignals(true);
|
||||||
|
if (modeExt == 0x22 || modeExt == 0x2b)
|
||||||
|
m_characterListModel.setCharacterSet(26);
|
||||||
|
else if (modeExt == 0x2f)
|
||||||
|
m_characterListModel.setCharacterSet(7);
|
||||||
|
else if (modeExt == 0x21)
|
||||||
|
m_characterListModel.setCharacterSet(24);
|
||||||
|
else
|
||||||
|
m_characterListModel.setCharacterSet(0);
|
||||||
m_characterCodeComboBox->setCurrentIndex(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+1).toInt()-32);
|
m_characterCodeComboBox->setCurrentIndex(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+1).toInt()-32);
|
||||||
m_characterCodeComboBox->blockSignals(false);
|
m_characterCodeComboBox->blockSignals(false);
|
||||||
m_tripletParameterStackedLayout->setCurrentIndex(2);
|
m_tripletParameterStackedLayout->setCurrentIndex(2);
|
||||||
@@ -756,14 +799,22 @@ void X26DockWidget::updateCookedTripletParameters(const QModelIndex &index)
|
|||||||
// BUG we're only dealing with Local Object Definitions at the moment!
|
// BUG we're only dealing with Local Object Definitions at the moment!
|
||||||
if (index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+1).toInt() == 0 || (index.model()->data(index.model()->index(index.row(), 1), Qt::UserRole).toInt() & 0x04)) {
|
if (index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+1).toInt() == 0 || (index.model()->data(index.model()->index(index.row(), 1), Qt::UserRole).toInt() & 0x04)) {
|
||||||
// if (triplet.objectSource() == X26Triplet::LocalObjectSource) {
|
// if (triplet.objectSource() == X26Triplet::LocalObjectSource) {
|
||||||
|
const bool tripletLocationWidgetsVisible = (modeExt & 0x04) != 0x04;
|
||||||
|
|
||||||
|
m_invokeLocalObjectDesignationCodeLabel->setVisible(tripletLocationWidgetsVisible);
|
||||||
|
m_invokeLocalObjectDesignationCodeSpinBox->setVisible(tripletLocationWidgetsVisible);
|
||||||
|
m_invokeLocalObjectTripletNumberLabel->setVisible(tripletLocationWidgetsVisible);
|
||||||
|
m_invokeLocalObjectTripletNumberSpinBox->setVisible(tripletLocationWidgetsVisible);
|
||||||
m_objectSourceComboBox->setCurrentIndex(0);
|
m_objectSourceComboBox->setCurrentIndex(0);
|
||||||
m_invokeObjectSourceStackedLayout->setCurrentIndex(0);
|
m_invokeObjectSourceStackedLayout->setCurrentIndex(0);
|
||||||
m_invokeLocalObjectDesignationCodeSpinBox->blockSignals(true);
|
if (tripletLocationWidgetsVisible) {
|
||||||
m_invokeLocalObjectTripletNumberSpinBox->blockSignals(true);
|
m_invokeLocalObjectDesignationCodeSpinBox->blockSignals(true);
|
||||||
m_invokeLocalObjectDesignationCodeSpinBox->setValue(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+2).toInt());
|
m_invokeLocalObjectTripletNumberSpinBox->blockSignals(true);
|
||||||
m_invokeLocalObjectTripletNumberSpinBox->setValue(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+3).toInt());
|
m_invokeLocalObjectDesignationCodeSpinBox->setValue(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+2).toInt());
|
||||||
m_invokeLocalObjectDesignationCodeSpinBox->blockSignals(false);
|
m_invokeLocalObjectTripletNumberSpinBox->setValue(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+3).toInt());
|
||||||
m_invokeLocalObjectTripletNumberSpinBox->blockSignals(false);
|
m_invokeLocalObjectDesignationCodeSpinBox->blockSignals(false);
|
||||||
|
m_invokeLocalObjectTripletNumberSpinBox->blockSignals(false);
|
||||||
|
}
|
||||||
} else { // if (triplet.objectSource() != X26Triplet::IllegalObjectSource) {
|
} else { // if (triplet.objectSource() != X26Triplet::IllegalObjectSource) {
|
||||||
m_objectSourceComboBox->setCurrentIndex(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+1).toInt());
|
m_objectSourceComboBox->setCurrentIndex(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole+1).toInt());
|
||||||
m_invokeObjectSourceStackedLayout->setCurrentIndex(1);
|
m_invokeObjectSourceStackedLayout->setCurrentIndex(1);
|
||||||
@@ -849,28 +900,36 @@ void X26DockWidget::updateCookedTripletParameters(const QModelIndex &index)
|
|||||||
// Now deal with cooked row and column spinboxes
|
// Now deal with cooked row and column spinboxes
|
||||||
m_cookedRowSpinBox->blockSignals(true);
|
m_cookedRowSpinBox->blockSignals(true);
|
||||||
m_cookedColumnSpinBox->blockSignals(true);
|
m_cookedColumnSpinBox->blockSignals(true);
|
||||||
QVariant rowVariant = index.model()->data(index.model()->index(index.row(), 0), Qt::EditRole);
|
const QVariant rowVariant = index.model()->data(index.model()->index(index.row(), 0), Qt::EditRole);
|
||||||
if (rowVariant.isNull()) {
|
if (rowVariant.isNull()) {
|
||||||
m_cookedRowSpinBox->setEnabled(false);
|
m_cookedRowSpinBox->setEnabled(false);
|
||||||
m_cookedRowSpinBox->setValue(0);
|
m_cookedRowSpinBox->setValue(0);
|
||||||
|
m_cookedRowSpinBox->setPrefix("");
|
||||||
} else {
|
} else {
|
||||||
m_cookedRowSpinBox->setEnabled(true);
|
m_cookedRowSpinBox->setEnabled(true);
|
||||||
if (index.model()->data(index.model()->index(index.row(), 2), Qt::EditRole) == 0x10)
|
if (modeExt == 0x10) {
|
||||||
m_cookedRowSpinBox->setRange(0, 23);
|
m_cookedRowSpinBox->setRange(0, 23);
|
||||||
else
|
m_cookedRowSpinBox->setPrefix("+");
|
||||||
|
} else {
|
||||||
m_cookedRowSpinBox->setRange(1, 24);
|
m_cookedRowSpinBox->setRange(1, 24);
|
||||||
|
m_cookedRowSpinBox->setPrefix("");
|
||||||
|
}
|
||||||
m_cookedRowSpinBox->setValue(rowVariant.toInt());
|
m_cookedRowSpinBox->setValue(rowVariant.toInt());
|
||||||
}
|
}
|
||||||
QVariant columnVariant = index.model()->data(index.model()->index(index.row(), 1), Qt::EditRole);
|
const QVariant columnVariant = index.model()->data(index.model()->index(index.row(), 1), Qt::EditRole);
|
||||||
if (columnVariant.isNull()) {
|
if (columnVariant.isNull()) {
|
||||||
m_cookedColumnSpinBox->setEnabled(false);
|
m_cookedColumnSpinBox->setEnabled(false);
|
||||||
m_cookedColumnSpinBox->setValue(0);
|
m_cookedColumnSpinBox->setValue(0);
|
||||||
|
m_cookedColumnSpinBox->setPrefix("");
|
||||||
} else {
|
} else {
|
||||||
m_cookedColumnSpinBox->setEnabled(true);
|
m_cookedColumnSpinBox->setEnabled(true);
|
||||||
if (index.model()->data(index.model()->index(index.row(), 2), Qt::EditRole) == 0x10)
|
if (modeExt == 0x10) {
|
||||||
m_cookedColumnSpinBox->setMaximum(71);
|
m_cookedColumnSpinBox->setMaximum(71);
|
||||||
else
|
m_cookedColumnSpinBox->setPrefix("+");
|
||||||
|
} else {
|
||||||
m_cookedColumnSpinBox->setMaximum(39);
|
m_cookedColumnSpinBox->setMaximum(39);
|
||||||
|
m_cookedColumnSpinBox->setPrefix("");
|
||||||
|
}
|
||||||
m_cookedColumnSpinBox->setValue(columnVariant.toInt());
|
m_cookedColumnSpinBox->setValue(columnVariant.toInt());
|
||||||
}
|
}
|
||||||
m_cookedRowSpinBox->blockSignals(false);
|
m_cookedRowSpinBox->blockSignals(false);
|
||||||
|
|||||||
@@ -20,10 +20,12 @@
|
|||||||
#ifndef X26DOCKWIDGET_H
|
#ifndef X26DOCKWIDGET_H
|
||||||
#define X26DOCKWIDGET_H
|
#define X26DOCKWIDGET_H
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
@@ -31,8 +33,25 @@
|
|||||||
#include <QTableView>
|
#include <QTableView>
|
||||||
|
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
#include "render.h"
|
||||||
#include "x26model.h"
|
#include "x26model.h"
|
||||||
|
|
||||||
|
class CharacterListModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CharacterListModel(QObject *parent = 0);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
void setCharacterSet(int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TeletextFontBitmap m_fontBitmap;
|
||||||
|
int m_characterSet;
|
||||||
|
};
|
||||||
|
|
||||||
class X26DockWidget : public QDockWidget
|
class X26DockWidget : public QDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -63,6 +82,7 @@ public slots:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent(QKeyEvent *event) override;
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
CharacterListModel m_characterListModel;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTableView *m_x26View;
|
QTableView *m_x26View;
|
||||||
@@ -79,6 +99,7 @@ private:
|
|||||||
QComboBox *m_textSizeComboBox;
|
QComboBox *m_textSizeComboBox;
|
||||||
QCheckBox *m_displayAttributeBoxingCheckBox, *m_displayAttributeConcealCheckBox, *m_displayAttributeInvertCheckBox, *m_displayAttributeUnderlineCheckBox;
|
QCheckBox *m_displayAttributeBoxingCheckBox, *m_displayAttributeConcealCheckBox, *m_displayAttributeInvertCheckBox, *m_displayAttributeUnderlineCheckBox;
|
||||||
QComboBox *m_objectSourceComboBox, *m_objectRequiredAtLevelsComboBox;
|
QComboBox *m_objectSourceComboBox, *m_objectRequiredAtLevelsComboBox;
|
||||||
|
QLabel *m_invokeLocalObjectDesignationCodeLabel, *m_invokeLocalObjectTripletNumberLabel;
|
||||||
QSpinBox *m_invokeLocalObjectDesignationCodeSpinBox, *m_invokeLocalObjectTripletNumberSpinBox;
|
QSpinBox *m_invokeLocalObjectDesignationCodeSpinBox, *m_invokeLocalObjectTripletNumberSpinBox;
|
||||||
QSpinBox *m_invokePOPSubPageSpinBox, *m_invokePOPPacketNumberSpinBox;
|
QSpinBox *m_invokePOPSubPageSpinBox, *m_invokePOPPacketNumberSpinBox;
|
||||||
QComboBox *m_invokePOPTripletNumberComboBox, *m_invokePOPPointerBitsComboBox;
|
QComboBox *m_invokePOPTripletNumberComboBox, *m_invokePOPPointerBitsComboBox;
|
||||||
|
|||||||
728
x26model.cpp
728
x26model.cpp
File diff suppressed because it is too large
Load Diff
149
x26model.h
149
x26model.h
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
#include "render.h"
|
||||||
|
|
||||||
class X26Model : public QAbstractListModel
|
class X26Model : public QAbstractListModel
|
||||||
{
|
{
|
||||||
@@ -49,87 +50,99 @@ public:
|
|||||||
private:
|
private:
|
||||||
TeletextWidget *m_parentMainWidget;
|
TeletextWidget *m_parentMainWidget;
|
||||||
bool m_listLoaded;
|
bool m_listLoaded;
|
||||||
};
|
TeletextFontBitmap m_fontBitmap;
|
||||||
|
|
||||||
static const QString modeTripletName[64] {
|
const QString m_modeTripletName[64] {
|
||||||
// Row triplet modes
|
// Row triplet modes
|
||||||
"Full screen colour",
|
"Full screen colour",
|
||||||
"Full row colour",
|
"Full row colour",
|
||||||
"Reserved 0x02",
|
"Reserved 0x02",
|
||||||
"Reserved 0x03",
|
"Reserved 0x03",
|
||||||
|
|
||||||
"Set Active Position",
|
"Set Active Position",
|
||||||
"Reserved 0x05",
|
"Reserved 0x05",
|
||||||
"Reserved 0x06",
|
"Reserved 0x06",
|
||||||
"Address row 0",
|
"Address row 0",
|
||||||
|
|
||||||
"PDC origin, source",
|
"PDC origin, source",
|
||||||
"PDC month and day",
|
"PDC month and day",
|
||||||
"PDC cursor and start hour",
|
"PDC cursor and start hour",
|
||||||
"PDC cursor and end hour",
|
"PDC cursor and end hour",
|
||||||
|
|
||||||
"PDC cursor local offset",
|
"PDC cursor local offset",
|
||||||
"PDC series ID and code",
|
"PDC series ID and code",
|
||||||
"Reserved 0x0e",
|
"Reserved 0x0e",
|
||||||
"Reserved 0x0f",
|
"Reserved 0x0f",
|
||||||
|
|
||||||
"Origin modifier",
|
"Origin modifier",
|
||||||
"Invoke active object",
|
"Invoke active object",
|
||||||
"Invoke adaptive object",
|
"Invoke adaptive object",
|
||||||
"Invoke passive object",
|
"Invoke passive object",
|
||||||
|
|
||||||
"Reserved 0x14",
|
"Reserved 0x14",
|
||||||
"Define active object",
|
"Define active object",
|
||||||
"Define adaptive object",
|
"Define adaptive object",
|
||||||
"Define passive object",
|
"Define passive object",
|
||||||
|
|
||||||
"DRCS mode",
|
"DRCS mode",
|
||||||
"Reserved 0x19",
|
"Reserved 0x19",
|
||||||
"Reserved 0x1a",
|
"Reserved 0x1a",
|
||||||
"Reserved 0x1b",
|
"Reserved 0x1b",
|
||||||
|
|
||||||
"Reserved 0x1c",
|
"Reserved 0x1c",
|
||||||
"Reserved 0x1d",
|
"Reserved 0x1d",
|
||||||
"Reserved 0x1e",
|
"Reserved 0x1e",
|
||||||
"Termination marker",
|
"Termination marker",
|
||||||
|
|
||||||
// Column triplet modes
|
// Column triplet modes
|
||||||
"Foreground colour",
|
"Foreground colour",
|
||||||
"G1 character",
|
"G1 character",
|
||||||
"G3 character, level 1.5",
|
"G3 character, level 1.5",
|
||||||
"Background colour",
|
"Background colour",
|
||||||
|
|
||||||
"Reserved 0x04",
|
"Reserved 0x04",
|
||||||
"Reserved 0x05",
|
"Reserved 0x05",
|
||||||
"PDC cursor, start end min",
|
"PDC cursor, start end min",
|
||||||
"Additional flash functions",
|
"Additional flash functions",
|
||||||
|
|
||||||
"Modified G0/G2 character set",
|
"Modified G0/G2 character set",
|
||||||
"G0 character",
|
"G0 character",
|
||||||
"Reserved 0x0a",
|
"Reserved 0x0a",
|
||||||
"G3 character, level 2.5",
|
"G3 character, level 2.5",
|
||||||
|
|
||||||
"Display attributes",
|
"Display attributes",
|
||||||
"DRCS character",
|
"DRCS character",
|
||||||
"Font style",
|
"Font style",
|
||||||
"G2 character",
|
"G2 character",
|
||||||
|
|
||||||
"G0 character no diacritical",
|
"G0 character no diacritical",
|
||||||
"G0 character diacritical 1",
|
"G0 character diacritical 1",
|
||||||
"G0 character diacritical 2",
|
"G0 character diacritical 2",
|
||||||
"G0 character diacritical 3",
|
"G0 character diacritical 3",
|
||||||
"G0 character diacritical 4",
|
"G0 character diacritical 4",
|
||||||
"G0 character diacritical 5",
|
"G0 character diacritical 5",
|
||||||
"G0 character diacritical 6",
|
"G0 character diacritical 6",
|
||||||
"G0 character diacritical 7",
|
"G0 character diacritical 7",
|
||||||
"G0 character diacritical 8",
|
"G0 character diacritical 8",
|
||||||
"G0 character diacritical 9",
|
"G0 character diacritical 9",
|
||||||
"G0 character diacritical A",
|
"G0 character diacritical A",
|
||||||
"G0 character diacritical B",
|
"G0 character diacritical B",
|
||||||
"G0 character diacritical C",
|
"G0 character diacritical C",
|
||||||
"G0 character diacritical D",
|
"G0 character diacritical D",
|
||||||
"G0 character diacritical E",
|
"G0 character diacritical E",
|
||||||
"G0 character diacritical F"
|
"G0 character diacritical F"
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tripletErrorShow {
|
||||||
|
QString message;
|
||||||
|
int columnHighlight;
|
||||||
|
};
|
||||||
|
|
||||||
|
const tripletErrorShow m_tripletErrors[3] {
|
||||||
|
{ "", 0 }, // No error
|
||||||
|
{ "Active Position can't move up", 0 },
|
||||||
|
{ "Active Position can't move left within row", 1 }
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
123
x26triplets.cpp
123
x26triplets.cpp
@@ -50,3 +50,126 @@ void X26Triplet::setAddressColumn(int addressColumn)
|
|||||||
{
|
{
|
||||||
m_address = addressColumn;
|
m_address = addressColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void X26TripletList::updateInternalData(int r)
|
||||||
|
{
|
||||||
|
ActivePosition activePosition;
|
||||||
|
X26Triplet *triplet;
|
||||||
|
|
||||||
|
if (r != 0) {
|
||||||
|
activePosition.setRow(m_list[r-1].m_activePositionRow);
|
||||||
|
activePosition.setColumn(m_list[r-1].m_activePositionColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = r; i < m_list.size(); i++) {
|
||||||
|
triplet = &m_list[i];
|
||||||
|
triplet->m_error = X26Triplet::NoError;
|
||||||
|
if (triplet->isRowTriplet()) {
|
||||||
|
switch (m_list.at(i).modeExt()) {
|
||||||
|
case 0x00: // Full screen colour
|
||||||
|
if (activePosition.isDeployed())
|
||||||
|
// TODO more specific error needed
|
||||||
|
triplet->m_error = X26Triplet::ActivePositionMovedUp;
|
||||||
|
break;
|
||||||
|
case 0x01: // Full row colour
|
||||||
|
if (!activePosition.setRow(triplet->addressRow()))
|
||||||
|
triplet->m_error = X26Triplet::ActivePositionMovedUp;
|
||||||
|
break;
|
||||||
|
case 0x04: // Set Active Position;
|
||||||
|
if (!activePosition.setRow(triplet->addressRow()))
|
||||||
|
triplet->m_error = X26Triplet::ActivePositionMovedUp;
|
||||||
|
else if (triplet->data() >= 40 || !activePosition.setColumn(triplet->data()))
|
||||||
|
triplet->m_error = X26Triplet::ActivePositionMovedLeft;
|
||||||
|
break;
|
||||||
|
case 0x07: // Address row 0
|
||||||
|
if (activePosition.isDeployed())
|
||||||
|
triplet->m_error = X26Triplet::ActivePositionMovedUp;
|
||||||
|
else {
|
||||||
|
activePosition.setRow(0);
|
||||||
|
activePosition.setColumn(8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x15 ... 0x17: // Define Object
|
||||||
|
activePosition.reset();
|
||||||
|
// Make sure data field holds correct place of triplet
|
||||||
|
// otherwise the object won't appear
|
||||||
|
triplet->m_address &= 0x3c;
|
||||||
|
if (i >= 104) // Triplet 8
|
||||||
|
triplet->m_address |= 0x01;
|
||||||
|
triplet->m_data = (((i / 13) & 0x07) << 4) | (i % 13);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
// Column triplet: make sure that PDC and reserved triplets don't affect the Active Position
|
||||||
|
} else if (triplet->modeExt() != 0x24 && triplet->modeExt() != 0x25 && triplet->modeExt() != 0x26 && triplet->modeExt() != 0x2a)
|
||||||
|
if (!activePosition.setColumn(triplet->addressColumn()))
|
||||||
|
triplet->m_error = X26Triplet::ActivePositionMovedLeft;
|
||||||
|
triplet->m_activePositionRow = activePosition.row();
|
||||||
|
triplet->m_activePositionColumn = activePosition.column();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void X26TripletList::append(const X26Triplet &value)
|
||||||
|
{
|
||||||
|
m_list.append(value);
|
||||||
|
updateInternalData(m_list.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X26TripletList::insert(int i, const X26Triplet &value)
|
||||||
|
{
|
||||||
|
m_list.insert(i, value);
|
||||||
|
updateInternalData(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X26TripletList::removeAt(int i)
|
||||||
|
{
|
||||||
|
m_list.removeAt(i);
|
||||||
|
if (m_list.size() != 0 && i < m_list.size())
|
||||||
|
updateInternalData(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X26TripletList::replace(int i, const X26Triplet &value)
|
||||||
|
{
|
||||||
|
m_list.replace(i, value);
|
||||||
|
updateInternalData(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
X26TripletList::ActivePosition::ActivePosition()
|
||||||
|
{
|
||||||
|
m_row = m_column = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X26TripletList::ActivePosition::reset()
|
||||||
|
{
|
||||||
|
m_row = m_column = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X26TripletList::ActivePosition::setRow(int row)
|
||||||
|
{
|
||||||
|
if (row < m_row)
|
||||||
|
return false;
|
||||||
|
if (row > m_row) {
|
||||||
|
m_row = row;
|
||||||
|
m_column = -1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X26TripletList::ActivePosition::setColumn(int column)
|
||||||
|
{
|
||||||
|
if (column < m_column)
|
||||||
|
return false;
|
||||||
|
if (m_row == -1 and column >= 0)
|
||||||
|
m_row = 0;
|
||||||
|
m_column = column;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
bool X26TripletList::ActivePosition::setRowAndColumn(int newRow, int newColumn)
|
||||||
|
{
|
||||||
|
if (!setRow(newRow))
|
||||||
|
return false;
|
||||||
|
return setColumn(newColumn);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|||||||
@@ -20,9 +20,13 @@
|
|||||||
#ifndef X26TRIPLETS_H
|
#ifndef X26TRIPLETS_H
|
||||||
#define X26TRIPLETS_H
|
#define X26TRIPLETS_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
class X26Triplet
|
class X26Triplet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum X26TripletError { NoError, ActivePositionMovedUp, ActivePositionMovedLeft };
|
||||||
|
|
||||||
X26Triplet() {}
|
X26Triplet() {}
|
||||||
// X26Triplet(const X26Triplet &other);
|
// X26Triplet(const X26Triplet &other);
|
||||||
|
|
||||||
@@ -44,9 +48,56 @@ public:
|
|||||||
void setAddressRow(int);
|
void setAddressRow(int);
|
||||||
void setAddressColumn(int);
|
void setAddressColumn(int);
|
||||||
|
|
||||||
|
int activePositionRow() const { return m_activePositionRow; }
|
||||||
|
int activePositionColumn() const { return m_activePositionColumn; }
|
||||||
|
X26TripletError error() const { return m_error; }
|
||||||
|
|
||||||
|
friend class X26TripletList;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_address, m_mode, m_data;
|
int m_address, m_mode, m_data;
|
||||||
|
int m_activePositionRow = -1;
|
||||||
|
int m_activePositionColumn = -1;
|
||||||
|
X26TripletError m_error = NoError;
|
||||||
|
};
|
||||||
|
|
||||||
|
class X26TripletList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void append(const X26Triplet &);
|
||||||
|
void insert(int, const X26Triplet &);
|
||||||
|
void removeAt(int);
|
||||||
|
void replace(int, const X26Triplet &);
|
||||||
|
|
||||||
|
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(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateInternalData(int);
|
||||||
|
|
||||||
|
QList<X26Triplet> m_list;
|
||||||
|
|
||||||
|
class ActivePosition
|
||||||
|
{
|
||||||
|
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; }
|
||||||
|
bool setRow(int);
|
||||||
|
bool setColumn(int);
|
||||||
|
// bool setRowAndColumn(int, int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_row, m_column;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user