Files
QTeletextMaker/x26model.cpp
G.K.MacGregor f36143e10f Really show correct G0 and G2 character set in widgets
Amendment to 7b59c78. This should prevent spurious NOS character sets from
appearing in the widgets, and should also prevent the G0 and G2 character
sets from getting mixed up in the widgets when those triplets are within
object definitions.

The G0 and G2 character set in the widgets may still be incorrect in corner
cases of objects invoked within areas of the page where the character set
has been changed either with the ESC/Switch spacing attribute or with the
"modified G0/G2 character set designation" triplet.
2023-08-15 18:11:40 +01:00

883 lines
36 KiB
C++

/*
* Copyright (C) 2020-2023 Gavin MacGregor
*
* This file is part of QTeletextMaker.
*
* QTeletextMaker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QTeletextMaker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
*/
#include "x26model.h"
#include <QList>
#include "render.h"
#include "x26commands.h"
X26Model::X26Model(TeletextWidget *parent): QAbstractListModel(parent)
{
m_parentMainWidget = parent;
m_listLoaded = true;
}
void X26Model::setX26ListLoaded(bool newListLoaded)
{
beginResetModel();
m_listLoaded = newListLoaded;
endResetModel();
}
int X26Model::rowCount(const QModelIndex & /*parent*/) const
{
return m_listLoaded ? m_parentMainWidget->document()->currentSubPage()->enhancements()->size() : 0;
}
int X26Model::columnCount(const QModelIndex & /*parent*/) const
{
return 4;
}
QVariant X26Model::data(const QModelIndex &index, int role) const
{
const X26Triplet triplet = m_parentMainWidget->document()->currentSubPage()->enhancements()->at(index.row());
// Qt::UserRole will always return the raw values
if (role == Qt::UserRole)
switch (index.column()) {
case 0:
return triplet.address();
case 1:
return triplet.mode();
case 2:
return triplet.data();
default:
return QVariant();
}
// Error colours from KDE Plasma Breeze (light) theme
if (role == Qt::ForegroundRole) {
if (triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight)
return QColor(252, 252, 252);
else if ((index.column() == 2 && triplet.reservedMode()) || (index.column() == 3 && triplet.reservedData()))
return QColor(35, 38, 39);
}
if (role == Qt::BackgroundRole) {
if (triplet.error() != X26Triplet::NoError && index.column() == m_tripletErrors[triplet.error()].columnHighlight)
return QColor(218, 68, 63);
else if ((index.column() == 2 && triplet.reservedMode()) || (index.column() == 3 && triplet.reservedData()))
return QColor(246, 116, 0);
}
if (role == Qt::ToolTipRole && triplet.error() != X26Triplet::NoError)
return m_tripletErrors[triplet.error()].message;
if (role == Qt::DisplayRole || role == Qt::EditRole)
switch (index.column()) {
case 0:
// Show row number only if address part of triplet actually represents a row:
// Full row colour, Set Active Position and Origin Modifier
// For Origin Modifier address of 40 refers to same row, so show it as 0
if (triplet.modeExt() == 0x10) {
if (triplet.address() == 40)
return "+0";
else
return QString("+%1").arg(triplet.addressRow());
}
if (triplet.modeExt() == 0x01 || triplet.modeExt() == 0x04)
return triplet.addressRow();
else
return QVariant();
case 1:
if (!triplet.isRowTriplet())
return triplet.addressColumn();
// For Set Active Position and Origin Modifier, data is the column
else if (triplet.modeExt() == 0x04)
return triplet.data();
else if (triplet.modeExt() == 0x10)
return QString("+%1").arg(triplet.data());
else
return QVariant();
}
QString result;
if (role == Qt::DisplayRole) {
if (index.column() == 2)
return (m_modeTripletName[triplet.modeExt()]);
// Column 3 - describe effects of data/address triplet parameters in plain English
switch (triplet.modeExt()) {
case 0x01: // Full row colour
case 0x07: // Address row 0
if ((triplet.data() & 0x60) == 0x60)
result = ", down to bottom";
else if ((triplet.data() & 0x60) == 0x00)
result = ", this row only";
// fall-through
case 0x00: // Full screen colour
if (!(result.isEmpty()) || (triplet.data() & 0x60) == 0x00) {
result.prepend(QString("CLUT %1:%2").arg((triplet.data() & 0x18) >> 3).arg(triplet.data() & 0x07));
return result;
}
break;
case 0x04: // Set Active Position
case 0x10: // Origin Modifier
// For Set Active Position and Origin Modifier, data is the column, so return blank
return QVariant();
case 0x11 ... 0x13: // Invoke object
switch (triplet.address() & 0x18) {
case 0x08:
return QString("Local: d%1 t%2").arg((triplet.data() >> 4) | ((triplet.address() & 0x01) << 3)).arg(triplet.data() & 0x0f);
case 0x10:
result = "POP";
break;
case 0x18:
result = "GPOP";
break;
// case 0x00: shouldn't happen since that would make a column triplet, not a row triplet
}
result.append(QString(": subpage %1 pkt %2 trplt %3 bits ").arg(triplet.data() & 0x0f).arg((triplet.address() & 0x03) + 1).arg(((triplet.data() & 0x60) >> 5) * 3 + (triplet.modeExt() & 0x03)));
if (triplet.data() & 0x10)
result.append("10-18");
else
result.append("1-9");
return result;
case 0x15 ... 0x17: // Define object
switch (triplet.address() & 0x18) {
case 0x08:
return "Local: L2.5 only";
break;
case 0x10:
return "Local: L3.5 only";
break;
case 0x18:
return "Local: L2.5 and 3.5";
break;
// case 0x00: shouldn't happen since that would make a column triplet, not a row triplet
}
break;
case 0x18: // DRCS mode
result = (triplet.data() & 0x40) == 0x40 ? "Normal" : "Global";
result.append(QString(": subpage %1, ").arg(triplet.data() & 0x0f));
switch (triplet.data() & 0x30) {
case 0x10:
result.append("L2.5 only");
break;
case 0x20:
result.append("L3.5 only");
break;
case 0x30:
result.append("L2.5 and 3.5");
break;
case 0x00:
result.append("Reserved");
break;
}
return result;
case 0x1f: // Termination
switch (triplet.data() & 0x07) {
case 0x00:
return "Intermed (G)POP subpage. End of object, more follows";
break;
case 0x01:
return "Intermed (G)POP subpage. End of last object on page";
break;
case 0x02:
return "Last (G)POP subpage. End of object, more follows";
break;
case 0x03:
return "Last (G)POP subpage. End of last object on page";
break;
case 0x04:
return "Local object definitions. End of object, more follows";
break;
case 0x05:
return "Local object definitions. End of last object on page";
break;
case 0x06:
return "End of local enhance data. Local objects follow";
break;
case 0x07:
return "End of local enhance data. No local objects";
break;
}
break;
case 0x08 ... 0x0d: // PDC
return QString("0x%1").arg(triplet.data(), 2, 16, QChar('0'));
case 0x20: // Foreground colour
case 0x23: // Background colour
if (!(triplet.data() & 0x60))
return QString("CLUT %1:%2").arg((triplet.data() & 0x18) >> 3).arg(triplet.data() & 0x07);
break;
case 0x21: // G1 mosaic character
case 0x22: // G3 mosaic character at level 1.5
case 0x29: // G0 character
case 0x2b: // G3 mosaic character at level >=2.5
case 0x2f ... 0x3f: // G2 character or G0 diacritical mark
if (triplet.data() >= 0x20)
return QString("0x%1").arg(triplet.data(), 2, 16);
break;
case 0x27: // Flash functions
if (triplet.data() < 0x18) {
switch (triplet.data() & 0x03) {
case 0x00:
result = "Steady";
break;
case 0x01:
result = "Normal";
break;
case 0x02:
result = "Invert";
break;
case 0x03:
result = "Adj CLUT";
break;
}
switch (triplet.data() & 0x1c) {
case 0x00:
result.append(", 1Hz");
break;
case 0x04:
result.append(", 2Hz ph 1");
break;
case 0x08:
result.append(", 2Hz ph 2");
break;
case 0x0c:
result.append(", 2Hz ph 3");
break;
case 0x10:
result.append(", 2Hz inc");
break;
case 0x14:
result.append(", 2Hz dec");
break;
}
return result;
}
break;
case 0x28: // Modified G0 and G2 character set
switch (triplet.data()) {
case 0x20:
return QString("0x20 Cyrillic 1 Serbian/Croatian");
case 0x24:
return QString("0x24 Cyrillic 2 Russian/Bulgarian");
case 0x25:
return QString("0x25 Cyrillic 3 Ukranian");
case 0x36:
return QString("0x36 Latin");
case 0x37:
return QString("0x37 Greek");
case 0x40:
case 0x44:
return QString("0x%1 G0 Latin, G2 Arabic").arg(triplet.data(), 2, 16);
case 0x47:
case 0x57:
return QString("0x%1 Arabic").arg(triplet.data(), 2, 16);
case 0x55:
return QString("0x55 G0 Hebrew, G2 Arabic");
}
if (triplet.data() < 0x27)
return QString("0x%1 Latin").arg(triplet.data(), 2, 16, QChar('0'));
break;
case 0x2c: // Display attributes
if (triplet.data() & 0x02)
result.append("Boxing ");
if (triplet.data() & 0x04)
result.append("Conceal ");
if (triplet.data() & 0x10)
result.append("Invert ");
if (triplet.data() & 0x20)
result.append("Underline ");
if (result.isEmpty())
result = "None";
else
// Chop off the last space
result.chop(1);
switch (triplet.data() & 0x41) {
case 0x00:
result.append(", normal size");
break;
case 0x01:
result.append(", double height");
break;
case 0x40:
result.append(", double width");
break;
case 0x41:
result.append(", double size");
break;
}
return result;
case 0x2d: // DRCS character
result = (triplet.data() & 0x40) == 0x40 ? "Normal" : "Global";
result.append(QString(": %1").arg(triplet.data() & 0x3f));
return result;
case 0x2e: // Font style
if (triplet.data() & 0x01)
result.append("Proportional ");
if (triplet.data() & 0x02)
result.append("Bold ");
if (triplet.data() & 0x04)
result.append("Italic ");
if (result.isEmpty())
result = "None";
else
// Chop off the last space
result.chop(1);
result.append(QString(", %1 row(s)").arg(triplet.data() >> 4));
return result;
case 0x26: // PDC
return QString("0x%1").arg(triplet.data(), 2, 16, QChar('0'));
default: // Reserved
return QString("Reserved 0x%1").arg(triplet.data(), 2, 16, QChar('0'));
}
// Reserved mode or data
return QString("Reserved 0x%1").arg(triplet.data(), 2, 16, QChar('0'));
}
if (role == Qt::DecorationRole && index.column() == 3)
switch (triplet.modeExt()) {
case 0x00: // Full screen colour
case 0x20: // Foreground colour
case 0x23: // Background colour
if (!(triplet.data() & 0x60))
return m_parentMainWidget->document()->currentSubPage()->CLUTtoQColor(triplet.data());
break;
case 0x01: // Full row colour
case 0x07: // Address row 0
if (((triplet.data() & 0x60) == 0x00) || ((triplet.data() & 0x60) == 0x60))
return m_parentMainWidget->document()->currentSubPage()->CLUTtoQColor(triplet.data() & 0x1f);
break;
case 0x21: // G1 mosaic character
if (triplet.data() & 0x20)
return m_fontBitmap.rawBitmap()->copy((triplet.data()-32)*12, 24*10, 12, 10);
break;
case 0x22: // G3 mosaic character at level 1.5
case 0x2b: // G3 mosaic character at level >=2.5
if (triplet.data() >= 0x20)
return m_fontBitmap.rawBitmap()->copy((triplet.data()-32)*12, 26*10, 12, 10);
break;
case 0x2f: // G2 character
if (triplet.data() >= 0x20)
return m_fontBitmap.rawBitmap()->copy((triplet.data()-32)*12, m_parentMainWidget->pageDecode()->cellG2CharacterSet(triplet.activePositionRow(), triplet.activePositionColumn())*10, 12, 10);
break;
case 0x29: // G0 character
case 0x30 ... 0x3f: // G0 diacritical mark
if (triplet.data() >= 0x20)
return m_fontBitmap.rawBitmap()->copy((triplet.data()-32)*12, m_parentMainWidget->pageDecode()->cellG0CharacterSet(triplet.activePositionRow(), triplet.activePositionColumn())*10, 12, 10);
break;
}
if (role == Qt::EditRole && index.column() == 2)
return triplet.modeExt();
if (role < Qt::UserRole)
return QVariant();
switch (triplet.modeExt()) {
case 0x01: // Full row colour
case 0x07: // Address row 0
if (role == Qt::UserRole+2) // "this row only" or "down to bottom"
return (triplet.data() & 0x60) == 0x60;
// fall-through
case 0x00: // Full screen colour
case 0x20: // Foreground colour
case 0x23: // Background colour
if (role == Qt::UserRole+1) // Colour index
return triplet.data() & 0x1f;
break;
case 0x11 ... 0x13: // Invoke object
switch (role) {
case Qt::UserRole+1: // Object source: Local, POP or GPOP
return ((triplet.address() & 0x18) >> 3) - 1;
case Qt::UserRole+2:
if ((triplet.address() & 0x18) == 0x08)
// Local object: Designation code
return ((triplet.address() & 0x01) << 3) | ((triplet.data() & 0x70) >> 4);
else
// (G)POP object: Subpage
return triplet.data() & 0x0f;
case Qt::UserRole+3:
if ((triplet.address() & 0x08) == 0x08)
// Local object: Triplet number
return triplet.data() & 0x0f;
else
// (G)POP object: Pointer location
return (triplet.address() & 0x03) + 1;
case Qt::UserRole+4: // (G)POP object: Triplet number
return triplet.data() >> 5;
case Qt::UserRole+5: // (G)POP object: Pointer position
return (triplet.data() & 0x10) >> 4;
}
break;
case 0x15 ... 0x17: // Define object
switch (role) {
case Qt::UserRole+1: // Required at which levels
return ((triplet.address() & 0x18) >> 3) - 1;
case Qt::UserRole+2: // Local object: Designation code
return ((triplet.address() & 0x01) << 3) | ((triplet.data() & 0x70) >> 4);
case Qt::UserRole+3: // Local object: Triplet number
return triplet.data() & 0x0f;
}
break;
case 0x18: // DRCS mode
switch (role) {
case Qt::UserRole+1: // Required at which levels
return ((triplet.data() & 0x30) >> 4) - 1;
case Qt::UserRole+3: // Normal or Global
return (triplet.data() & 0x40) == 0x40;
case Qt::UserRole+4: // Subpage
return triplet.data() & 0x0f;
}
break;
case 0x1f: // Termination
switch (role) {
case Qt::UserRole+1: // Intermed POP subpage|Last POP subpage|Local Object|Local enhance
return ((triplet.data() & 0x06) >> 1);
case Qt::UserRole+2: // More follows/Last
return (triplet.data() & 0x01) == 0x01;
}
break;
case 0x27: // Flash functions
switch (role) {
case Qt::UserRole+1: // Flash mode
return triplet.data() & 0x03;
case Qt::UserRole+2: // Flash rate and phase
return triplet.data() >> 2;
}
break;
case 0x2c: // Display attributes
switch (role) {
case Qt::UserRole+1: // Text size
return (triplet.data() & 0x01) | ((triplet.data() & 0x40) >> 5);
case Qt::UserRole+2: // Boxing/window
return (triplet.data() & 0x02) == 0x02;
case Qt::UserRole+3: // Conceal
return (triplet.data() & 0x04) == 0x04;
case Qt::UserRole+4: // Invert
return (triplet.data() & 0x10) == 0x10;
case Qt::UserRole+5: // Underline/Separated
return (triplet.data() & 0x20) == 0x20;
}
break;
case 0x2d: // DRCS character
switch (role) {
case Qt::UserRole+1: // Normal or Global
return (triplet.data() & 0x40) == 0x40;
case Qt::UserRole+2: // Character number
return triplet.data() & 0x3f;
}
break;
case 0x2e: // Font style
switch (role) {
case Qt::UserRole+1: // Proportional
return (triplet.data() & 0x01) == 0x01;
case Qt::UserRole+2: // Bold
return (triplet.data() & 0x02) == 0x02;
case Qt::UserRole+3: // Italic
return (triplet.data() & 0x04) == 0x04;
case Qt::UserRole+4: // Number of rows
return triplet.data() >> 4;
}
break;
case 0x2f: // G2 character
// Qt::UserRole+1 is character number, returned by default below
if (role == Qt::UserRole+2) // Character set
return m_parentMainWidget->pageDecode()->cellG2CharacterSet(triplet.activePositionRow(), triplet.activePositionColumn());
break;
case 0x29: // G0 character
case 0x30 ... 0x3f: // G0 diacritical mark
// Qt::UserRole+1 is character number, returned by default below
if (role == Qt::UserRole+2) // Character set
return m_parentMainWidget->pageDecode()->cellG0CharacterSet(triplet.activePositionRow(), triplet.activePositionColumn());
break;
};
// For characters and other triplet modes, return the complete data value
if (role == Qt::UserRole+1)
return triplet.data();
return QVariant();
}
bool X26Model::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
if (!value.canConvert<int>())
return false;
const int intValue = value.toInt();
if (intValue < 0)
return false;
// Raw address, mode and data values
if (role == Qt::UserRole && index.column() <= 2) {
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), index.column(), 0x00, intValue, role));
return true;
}
const X26Triplet triplet = m_parentMainWidget->document()->currentSubPage()->enhancements()->at(index.row());
// Cooked row, column and triplet mode
if (role == Qt::EditRole) {
switch (index.column()) {
case 0: // Cooked row
// Maximum row is 24
if (intValue > 24)
return false;
// Set Active Position and Full Row Colour can't select row 0
if (((triplet.modeExt() == 0x04) || (triplet.modeExt() == 0x01)) && intValue == 0)
return false;
// For Origin Modifier address of 40 refers to same row
if (triplet.modeExt() == 0x10 && intValue == 24) {
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 40, role));
return true;
}
// Others use address 40 for row 24
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, (intValue == 24) ? 40 : intValue+40, role));
return true;
case 1: // Cooked column
// Origin modifier allows columns up to 71
if (intValue > (triplet.modeExt() == 0x10 ? 71 : 39))
return false;
// For Set Active Position and Origin Modifier, data is the column
if (triplet.modeExt() == 0x04 || triplet.modeExt() == 0x10)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, intValue, role));
else
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, intValue, role));
return true;
case 2: // Cooked triplet mode
if (intValue < 0x20 && !triplet.isRowTriplet()) {
// Changing mode from column triplet to row triplet
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 41, role));
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0, role));
}
if (intValue >= 0x20 && triplet.isRowTriplet()) {
// Changing mode from row triplet to column triplet
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 0, role));
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0, role));
}
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETmode, 0x00, intValue & 0x1f, role));
// Now set data values to avoid reserved bits if we need to
// FIXME this can rather messily push multiple EditTripletCommands
// that rely on mergeWith to tidy them up afterwards
// Also this just flips bits, where we could use default values
switch (intValue) {
case 0x00: // Full screen colour
case 0x20: // Foreground colour
case 0x23: // Background colour
// Both S1 and S0 reserved bits must be clear
if (triplet.data() & 0x60)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x1f, 0x00, role));
break;
case 0x07: // Address row 0
// Address locked to 63
if (triplet.address() != 63)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 63, role));
// fall-through
case 0x01: // Full row colour
// S1 and S0 bits need to be the same
if ((triplet.data() & 0x60) != 0x00 && (triplet.data() & 0x60) != 0x60)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x1f, 0x00, role));
break;
case 0x04: // Set Active Position
// Data range 0-39
if (triplet.data() >= 40)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0, role));
break;
case 0x10: // Origin modifier
// Data range 0-71
if (triplet.data() >= 72)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0, role));
break;
case 0x11: // Invoke Active Object
case 0x12: // Invoke Adaptive Object
case 0x13: // Invoke Passive Object
case 0x15: // Define Active Object
case 0x16: // Define Adaptive Object
case 0x17: // Define Passive Object
// Bit 3 of Address is reserved
if ((triplet.address() & 0x04) == 0x04)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x7b, 0x00, role));
// BUG we're only dealing with Local Object Definitions at the moment!
// If source is Local, triplet number must be in range 0-12
if (((triplet.address() & 0x18) == 0x08) && ((triplet.data() & 0x0f) >= 12))
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x70, 0x00, role));
break;
case 0x18: // DRCS mode
// At least one of the L1 and L0 bits must be set
if ((triplet.data() & 0x30) == 0x00)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x4f, 0x30, role));
break;
case 0x1f: // Termination marker
// Address locked to 63
if (triplet.address() != 63)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 63, role));
// Clear reserved bits D6-D3
if (triplet.data() & 0x78)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x07, 0x00, role));
break;
case 0x21: // G1 mosaic character
case 0x22: // G3 mosaic character at level 1.5
case 0x29: // G0 character
case 0x2b: // G3 mosaic character at level >=2.5
case 0x2f ... 0x3f: // G2 character or G0 diacritical mark
// Data range 0x20-0x7f
if (triplet.data() < 0x20)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0x20, role));
break;
case 0x27: // Additional flash functions
// D6 and D5 must be clear, D4 and D3 set is reserved phase
if (triplet.data() >= 0x18)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0, role));
break;
case 0x2c: // Display attributes
case 0x2e: // Font style
// Clear reserved bit D3
if (triplet.data() & 0x08)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x77, 0x00, role));
break;
case 0x2d: // DRCS character
// D5-D0 range 0-47
if ((triplet.data() & 0x3f) >= 48)
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x40, 0x77, role));
break;
}
return true;
}
return false;
}
if (role < Qt::UserRole)
return false;
switch (triplet.modeExt()) {
case 0x01: // Full row colour
case 0x07: // Address row 0
switch (role) {
case Qt::UserRole+1: // Colour index
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x60, intValue, role));
return true;
case Qt::UserRole+2: // "this row only" or "down to bottom"
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x1f, intValue * 0x60, role));
break;
}
break;
case 0x11 ... 0x13: // Invoke object
switch (role) {
case Qt::UserRole+1: // Object source: Local, POP or GPOP
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x27, (intValue+1) << 3, role));
return true;
case Qt::UserRole+2:
if ((triplet.address() & 0x18) == 0x08) {
// Local object: Designation code
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x0f, (intValue & 0x07) << 4, role));
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x38, intValue >> 3, role));
} else
// (G)POP object: Subpage
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x30, intValue, role));
return true;
case Qt::UserRole+3: // Invoke object
if ((triplet.address() & 0x18) == 0x08)
// Local object: triplet number
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x70, intValue, role));
else
// (G)POP object: Pointer location
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x7c, intValue - 1, role));
return true;
case Qt::UserRole+4: // (G)POP object: Triplet number
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x1f, intValue << 5, role));
return true;
case Qt::UserRole+5: // (G)POP object: Pointer position
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x6f, intValue << 4, role));
return true;
}
break;
case 0x15 ... 0x17: // Define object
switch (role) {
case Qt::UserRole+1: // Required at which levels
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x27, (intValue+1) << 3, role));
return true;
case Qt::UserRole+2: // Local object: Designation code
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x0f, (intValue & 0x07) << 4, role));
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x38, intValue >> 3, role));
return true;
case Qt::UserRole+3: // Local object: triplet number
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x70, intValue, role));
break;
}
break;
case 0x18: // DRCS Mode
switch (role) {
case Qt::UserRole+1: // Required at which levels
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x4f, (intValue+1) << 4, role));
return true;
case Qt::UserRole+3: // Normal or Global
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x3f, intValue << 6, role));
return true;
case Qt::UserRole+4: // Subpage
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x70, intValue, role));
return true;
}
break;
case 0x1f: // Termination
switch (role) {
case Qt::UserRole+1: // Intermed POP subpage|Last POP subpage|Local Object|Local enhance
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x01, intValue << 1, role));
return true;
case Qt::UserRole+2: // More follows/Last
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x06, intValue, role));
return true;
}
break;
case 0x27: // Flash functions
switch (role) {
case Qt::UserRole+1: // Flash mode
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x1c, intValue, role));
return true;
case Qt::UserRole+2: // Flash rate and phase
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x03, intValue << 2, role));
break;
}
break;
case 0x2c: // Display attributes
switch (role) {
case Qt::UserRole+1: // Text size
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x36, ((intValue & 0x02) << 5) | (intValue & 0x01), role));
return true;
case Qt::UserRole+2: // Boxing/window
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7d, intValue << 1, role));
return true;
case Qt::UserRole+3: // Conceal
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7b, intValue << 2, role));
return true;
case Qt::UserRole+4: // Invert
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x6f, intValue << 4, role));
return true;
case Qt::UserRole+5: // Underline/Separated
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x5f, intValue << 5, role));
return true;
}
break;
case 0x2d: // DRCS character
switch (role) {
case Qt::UserRole+1: // Normal or Global
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x3f, intValue << 6, role));
return true;
case Qt::UserRole+2: // Character number
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x40, intValue, role));
break;
}
break;
case 0x2e: // Font style
switch (role) {
case Qt::UserRole+1: // Proportional
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7e, intValue, role));
return true;
case Qt::UserRole+2: // Bold
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7d, intValue << 1, role));
return true;
case Qt::UserRole+3: // Italic
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7b, intValue << 2, role));
return true;
case Qt::UserRole+4: // Number of rows
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x07, intValue << 4, role));
return true;
}
break;
}
// Fpr other triplet modes, set the complete data value
if (role == Qt::UserRole+1) {
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, intValue, role));
return true;
}
return false;
}
QVariant X26Model::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole) {
if (orientation == Qt::Horizontal) {
switch (section) {
case 0:
return tr("Row");
case 1:
return tr("Col");
case 2:
return tr("Mode");
case 3:
return tr("Data");
default:
return QVariant();
}
} else if (orientation == Qt::Vertical)
return QString("d%1 t%2").arg(section / 13).arg(section % 13);
}
return QVariant();
}
bool X26Model::insertRows(int row, int count, const QModelIndex &parent)
{
Q_UNUSED(parent);
if (m_parentMainWidget->document()->currentSubPage()->enhancements()->size() + count > m_parentMainWidget->document()->currentSubPage()->maxEnhancements())
return false;
m_parentMainWidget->document()->undoStack()->push(new InsertTripletCommand(m_parentMainWidget->document(), this, row, count, m_parentMainWidget->document()->currentSubPage()->enhancements()->at(row)));
return true;
}
bool X26Model::insertRows(int row, int count, const QModelIndex &parent, X26Triplet triplet)
{
Q_UNUSED(parent);
if (m_parentMainWidget->document()->currentSubPage()->enhancements()->size() + count > m_parentMainWidget->document()->currentSubPage()->maxEnhancements())
return false;
m_parentMainWidget->document()->undoStack()->push(new InsertTripletCommand(m_parentMainWidget->document(), this, row, count, triplet));
return true;
}
bool X26Model::removeRows(int row, int count, const QModelIndex &index)
{
Q_UNUSED(index);
m_parentMainWidget->document()->undoStack()->push(new DeleteTripletCommand(m_parentMainWidget->document(), this, row, count));
return true;
}
/*
Qt::ItemFlags X26Model::flags(const QModelIndex &index) const
{
if (!index.isValid())
return QAbstractItemModel::flags(index);
if (index.column() <= 1)
return QAbstractItemModel::flags(index);
if (index.column() >= 2)
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
return QAbstractItemModel::flags(index);
}
*/