mirror of
https://github.com/markdavidlong/AppleSAWS.git
synced 2024-11-22 00:31:04 +00:00
Created HiresScreenWidget and optimized display code
This commit is contained in:
parent
5ba9a0155e
commit
581ac6fa5e
@ -55,7 +55,9 @@ SOURCES += \
|
||||
src/ui/widgets/characterwidget.cpp \
|
||||
src/ui/viewers/applesoftfiledetailviewer.cpp \
|
||||
src/ui/widgets/hexconverter.cpp \
|
||||
src/ui/viewers/viewerbase.cpp
|
||||
src/ui/viewers/viewerbase.cpp \
|
||||
src/ui/widgets/CharacterSetExplorer.cpp \
|
||||
src/ui/widgets/HiresScreenWidget.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
@ -93,7 +95,9 @@ HEADERS += \
|
||||
src/ui/widgets/hexconverter.h \
|
||||
src/ui/widgets/hrcgcontrolsinfo.h \
|
||||
src/ui/viewers/viewerbase.h \
|
||||
src/ui/viewers/fileviewerinterface.h
|
||||
src/ui/viewers/fileviewerinterface.h \
|
||||
src/ui/widgets/CharacterSetExplorer.h \
|
||||
src/ui/widgets/HiresScreenWidget.h
|
||||
|
||||
FORMS += \
|
||||
src/ui/catalogwidget.ui \
|
||||
@ -105,4 +109,5 @@ FORMS += \
|
||||
src/ui/viewers/applesoftfiledetailviewer.ui \
|
||||
src/ui/widgets/hexconverter.ui \
|
||||
src/ui/widgets/hrcgcontrolsinfo.ui \
|
||||
src/ui/viewers/viewerbase.ui
|
||||
src/ui/viewers/viewerbase.ui \
|
||||
src/ui/widgets/CharacterSetExplorer.ui
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>107</width>
|
||||
<height>117</height>
|
||||
<width>538</width>
|
||||
<height>483</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <QDebug>
|
||||
#include <QResizeEvent>
|
||||
#include <QSettings>
|
||||
#include <QGridLayout>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@ -13,285 +14,14 @@
|
||||
HiresViewWidget::HiresViewWidget(QWidget *parent) :
|
||||
FileViewerInterface(parent)
|
||||
{
|
||||
QGridLayout *gv = new QGridLayout(this);
|
||||
setLayout(gv);
|
||||
hrsw = new HiresScreenWidget(this);
|
||||
gv->addWidget(hrsw);
|
||||
|
||||
resize(561,384);
|
||||
QSettings settings;
|
||||
m_viewMode = static_cast<ViewMode>(settings.value("HiresViewWidget.ViewMode",Color2).toInt());
|
||||
m_showScanLines = settings.value("HiresViewWidget.ShowScanLines",true).toBool();
|
||||
|
||||
if (m_rowTable == 0) { makeOffsetTable(); }
|
||||
|
||||
m_pixmap = QPixmap(561,384);
|
||||
QPainter painter(&m_pixmap);
|
||||
painter.setBrush(Qt::black);
|
||||
painter.drawRect(0,0,this->width(),this->height());
|
||||
|
||||
formatGroup = new QActionGroup(this);
|
||||
|
||||
monochromeAction = new QAction("Monochrome Display",this);
|
||||
monochromeAction->setCheckable(true);
|
||||
monochromeAction->setChecked(false);
|
||||
formatGroup->addAction(monochromeAction);
|
||||
|
||||
ntscAction = new QAction("NTSC Display",this);
|
||||
ntscAction->setCheckable(true);
|
||||
ntscAction->setChecked(true);
|
||||
formatGroup->addAction(ntscAction);
|
||||
|
||||
perPixelColorAction= new QAction("Per Pixel Color Display",this);
|
||||
perPixelColorAction->setCheckable(true);
|
||||
perPixelColorAction->setChecked(false);
|
||||
formatGroup->addAction(perPixelColorAction);
|
||||
|
||||
|
||||
|
||||
showScanLinesAction = new QAction("Show Scan Lines",this);
|
||||
showScanLinesAction->setCheckable(true);
|
||||
showScanLinesAction->setChecked(m_showScanLines);
|
||||
|
||||
|
||||
connect(ntscAction, SIGNAL(toggled(bool)), this, SLOT(handleNtscAction(bool)));
|
||||
connect(monochromeAction, SIGNAL(toggled(bool)), this, SLOT(handleMonochromeAction(bool)));
|
||||
connect(perPixelColorAction, SIGNAL(toggled(bool)), this, SLOT(handlePerPixelColorAction(bool)));
|
||||
|
||||
connect(showScanLinesAction, SIGNAL(toggled(bool)), this, SLOT(handleShowScanLinesAction(bool)));
|
||||
|
||||
}
|
||||
|
||||
void HiresViewWidget::handleNtscAction(bool toggled) {
|
||||
if (toggled) {
|
||||
m_viewMode = Color2;
|
||||
update();
|
||||
}
|
||||
QSettings settings;
|
||||
settings.setValue("HiresViewWidget.ViewMode",m_viewMode);
|
||||
}
|
||||
|
||||
void HiresViewWidget::handleMonochromeAction(bool toggled) {
|
||||
if (toggled) {
|
||||
m_viewMode = Monochrome;
|
||||
update();
|
||||
}
|
||||
QSettings settings;
|
||||
settings.setValue("HiresViewWidget.ViewMode",m_viewMode);
|
||||
}
|
||||
|
||||
void HiresViewWidget::handlePerPixelColorAction(bool toggled) {
|
||||
if (toggled) {
|
||||
m_viewMode = Color1;
|
||||
update();
|
||||
}
|
||||
QSettings settings;
|
||||
settings.setValue("HiresViewWidget.ViewMode",m_viewMode);
|
||||
}
|
||||
|
||||
void HiresViewWidget::handleShowScanLinesAction(bool toggled) {
|
||||
m_showScanLines = toggled;
|
||||
update();
|
||||
QSettings settings;
|
||||
settings.setValue("HiresViewWidget.ShowScanLines",toggled);
|
||||
}
|
||||
|
||||
void HiresViewWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
// if (m_pixmap.size() != this->size()) {
|
||||
// m_pixmap = m_pixmap.scaled(this->size(),Qt::KeepAspectRatio);
|
||||
// }
|
||||
|
||||
drawPixmap();
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
QPixmap tmppixmap = m_pixmap;
|
||||
// tmppixmap = tmppixmap.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
painter.drawPixmap(0,0,tmppixmap);
|
||||
}
|
||||
|
||||
void HiresViewWidget::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void HiresViewWidget::drawPixmap() {
|
||||
|
||||
QPainter pmpainter(&m_pixmap);
|
||||
|
||||
pmpainter.setBrush(Qt::black);
|
||||
pmpainter.setPen(Qt::black);
|
||||
pmpainter.drawRect(0,0,m_pixmap.width(),m_pixmap.height());
|
||||
|
||||
if (m_viewMode == Monochrome)
|
||||
{
|
||||
pmpainter.setPen(Qt::white);
|
||||
pmpainter.setBrush(Qt::white);
|
||||
|
||||
quint8 chunkCount = 0;
|
||||
// for (int idx = 0; idx < m_data.size() ; idx+=40) {
|
||||
int idx = 0;
|
||||
while (idx < m_data.size()) {
|
||||
int rowcol = findRowCol(idx);
|
||||
// int xoff = (rowcol / 10000) * 7;
|
||||
int yoff = (rowcol % 10000);
|
||||
|
||||
QBitArray bits(561,false);
|
||||
int bitoffset = 0;
|
||||
bool lastbit = false;
|
||||
|
||||
for (int jdx = 0; jdx < 40; jdx++)
|
||||
{
|
||||
quint8 byte = m_data[idx++];
|
||||
QBitArray dataBits = byteToBits(byte);
|
||||
|
||||
bool highBit = dataBits.at(0);
|
||||
|
||||
if (highBit) {
|
||||
bits[bitoffset++] = lastbit;
|
||||
}
|
||||
|
||||
for (int xdx = 1; xdx < 7; xdx++) {
|
||||
bits[bitoffset++] = dataBits.at(xdx);
|
||||
bits[bitoffset++] = dataBits.at(xdx);
|
||||
}
|
||||
lastbit = dataBits.at(7);
|
||||
bits[bitoffset++] = dataBits.at(7);
|
||||
if (!highBit) {
|
||||
bits[bitoffset++] = dataBits.at(7);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drawMonoLine(pmpainter, yoff*2, bits);
|
||||
if (!m_showScanLines) drawMonoLine(pmpainter, yoff*2+1, bits);
|
||||
|
||||
|
||||
chunkCount++;
|
||||
if (chunkCount == 3) {
|
||||
chunkCount = 0;
|
||||
idx+=8;
|
||||
}
|
||||
|
||||
}
|
||||
} else if (m_viewMode == Color1) {
|
||||
|
||||
pmpainter.setPen(Qt::white);
|
||||
pmpainter.setBrush(Qt::white);
|
||||
|
||||
for (int idx = 0; idx < m_data.size() ; idx++) {
|
||||
int rowcol = findRowCol(idx);
|
||||
|
||||
quint8 byte = m_data[idx];
|
||||
|
||||
bool highBit = byte & 0x80;
|
||||
|
||||
QColor oddColor = highBit? QColor(orangeColor) : QColor(greenColor);
|
||||
QColor evenColor = highBit? QColor(blueColor) : QColor(purpleColor);
|
||||
|
||||
int xoff = (rowcol / 10000) * 7;
|
||||
int yoff = (rowcol % 10000)*2;
|
||||
|
||||
quint8 cOffset = 0;// highBit?1:0;
|
||||
|
||||
quint8 doubleScan = 0;
|
||||
if (!m_showScanLines)
|
||||
{
|
||||
doubleScan = 1;
|
||||
}
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?oddColor:evenColor);
|
||||
pmpainter.setBrush(xoff & 0x01?oddColor:evenColor);
|
||||
|
||||
if (byte & 0x01) { pmpainter.drawRect((cOffset+xoff*2)+0,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?evenColor:oddColor);
|
||||
pmpainter.setBrush(xoff & 0x01?evenColor:oddColor);
|
||||
|
||||
if (byte & 0x02) { pmpainter.drawRect((cOffset+xoff*2)+2,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?oddColor:evenColor);
|
||||
pmpainter.setBrush(xoff & 0x01?oddColor:evenColor);
|
||||
|
||||
if (byte & 0x04) { pmpainter.drawRect((cOffset+xoff*2)+4,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?evenColor:oddColor);
|
||||
pmpainter.setBrush(xoff & 0x01?evenColor:oddColor);
|
||||
|
||||
if (byte & 0x08) { pmpainter.drawRect((cOffset+xoff*2)+6,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?oddColor:evenColor);
|
||||
pmpainter.setBrush(xoff & 0x01?oddColor:evenColor);
|
||||
|
||||
|
||||
if (byte & 0x10) { pmpainter.drawRect((cOffset+xoff*2)+8,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?evenColor:oddColor);
|
||||
pmpainter.setBrush(xoff & 0x01?evenColor:oddColor);
|
||||
|
||||
if (byte & 0x20) { pmpainter.drawRect((cOffset+xoff*2)+10,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?oddColor:evenColor);
|
||||
pmpainter.setBrush(xoff & 0x01?oddColor:evenColor);
|
||||
|
||||
|
||||
if (byte & 0x40) { pmpainter.drawRect((cOffset+xoff*2)+12,yoff,cOffset?0:1,doubleScan); }
|
||||
|
||||
|
||||
|
||||
if (idx >= (280*192)) break;
|
||||
}
|
||||
} else if (m_viewMode == Color2) {
|
||||
|
||||
pmpainter.setPen(Qt::white);
|
||||
pmpainter.setBrush(Qt::white);
|
||||
|
||||
quint8 chunkCount = 0;
|
||||
// for (int idx = 0; idx < m_data.size() ; idx+=40) {
|
||||
int idx = 0;
|
||||
while (idx < m_data.size()) {
|
||||
int rowcol = findRowCol(idx);
|
||||
// int xoff = (rowcol / 10000) * 7;
|
||||
int yoff = (rowcol % 10000);
|
||||
|
||||
QBitArray bits(561,false);
|
||||
int bitoffset = 0;
|
||||
bool lastbit = false;
|
||||
|
||||
for (int jdx = 0; jdx < 40; jdx++)
|
||||
{
|
||||
quint8 byte = m_data[idx++];
|
||||
QBitArray dataBits = byteToBits(byte);
|
||||
|
||||
bool highBit = dataBits.at(0);
|
||||
|
||||
if (highBit) {
|
||||
bits[bitoffset++] = lastbit;
|
||||
}
|
||||
|
||||
for (int xdx = 1; xdx < 7; xdx++) {
|
||||
bits[bitoffset++] = dataBits.at(xdx);
|
||||
bits[bitoffset++] = dataBits.at(xdx);
|
||||
}
|
||||
lastbit = dataBits.at(7);
|
||||
bits[bitoffset++] = dataBits.at(7);
|
||||
if (!highBit) {
|
||||
bits[bitoffset++] = dataBits.at(7);
|
||||
}
|
||||
}
|
||||
|
||||
drawNtscLine(pmpainter, yoff*2, bits);
|
||||
if (!m_showScanLines) {
|
||||
drawNtscLine(pmpainter, yoff*2+1, bits);
|
||||
}
|
||||
|
||||
chunkCount++;
|
||||
if (chunkCount == 3) {
|
||||
chunkCount = 0;
|
||||
idx+=8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HiresViewWidget::setFile(BinaryFile *file) {
|
||||
m_file = file;
|
||||
@ -299,238 +29,17 @@ void HiresViewWidget::setFile(BinaryFile *file) {
|
||||
QString title = QString("Image: %1").arg(m_file->filename());
|
||||
setWindowTitle(title);
|
||||
|
||||
setData(file->data());
|
||||
|
||||
hrsw->setData(file->data());
|
||||
}
|
||||
|
||||
void HiresViewWidget::setData(QByteArray data) {
|
||||
m_data = data;
|
||||
|
||||
drawPixmap();
|
||||
}
|
||||
|
||||
void HiresViewWidget::drawMonoLine(QPainter &painter, int lineNum, QBitArray data) {
|
||||
for (int idx = 0; idx < data.count(); idx++) {
|
||||
|
||||
if (data.at(idx))
|
||||
{
|
||||
painter.setPen(Qt::white);
|
||||
} else {
|
||||
painter.setPen(Qt::black);
|
||||
}
|
||||
|
||||
|
||||
painter.drawPoint(idx,lineNum);
|
||||
}
|
||||
}
|
||||
|
||||
QColor HiresViewWidget::getColorFromBits(QBitArray bits, quint8 phase)
|
||||
{
|
||||
quint8 bitval = (bits[0] * 0x08) +
|
||||
(bits[1] * 0x04) +
|
||||
(bits[2] * 0x02) +
|
||||
(bits[3] * 0x01);
|
||||
|
||||
phase %= 4;
|
||||
|
||||
//qDebug() << bits << phase;
|
||||
|
||||
|
||||
if (bitval == 0) { return blackColor; }
|
||||
|
||||
if (bitval == 1 && phase == 0) return brownColor;
|
||||
if (bitval == 2 && phase == 1) return brownColor;
|
||||
if (bitval == 4 && phase == 2) return brownColor;
|
||||
if (bitval == 8 && phase == 3) return brownColor;
|
||||
|
||||
if (bitval == 2 && phase == 0) return darkGreenColor;
|
||||
if (bitval == 4 && phase == 1) return darkGreenColor;
|
||||
if (bitval == 8 && phase == 2) return darkGreenColor;
|
||||
if (bitval == 1 && phase == 3) return darkGreenColor;
|
||||
|
||||
if (bitval == 3 && phase == 0) return greenColor;
|
||||
if (bitval == 6 && phase == 1) return greenColor;
|
||||
if (bitval == 12 && phase == 2) return greenColor;
|
||||
if (bitval == 9 && phase == 3) return greenColor;
|
||||
|
||||
if (bitval == 4 && phase == 0) return darkBlueColor;
|
||||
if (bitval == 8 && phase == 1) return darkBlueColor;
|
||||
if (bitval == 1 && phase == 2) return darkBlueColor;
|
||||
if (bitval == 2 && phase == 3) return darkBlueColor;
|
||||
|
||||
if (bitval == 5 && phase == 0) return grayColor;
|
||||
if (bitval == 10 && phase == 1) return grayColor;
|
||||
if (bitval == 5 && phase == 2) return grayColor;
|
||||
if (bitval == 10 && phase == 3) return grayColor;
|
||||
|
||||
if (bitval == 6 && phase == 0) return blueColor;
|
||||
if (bitval == 12 && phase == 1) return blueColor;
|
||||
if (bitval == 9 && phase == 2) return blueColor;
|
||||
if (bitval == 3 && phase == 3) return blueColor;
|
||||
|
||||
if (bitval == 7 && phase == 0) return aquaColor;
|
||||
if (bitval == 14 && phase == 1) return aquaColor;
|
||||
if (bitval == 13 && phase == 2) return aquaColor;
|
||||
if (bitval == 11 && phase == 3) return aquaColor;
|
||||
|
||||
if (bitval == 8 && phase == 0) return redColor;
|
||||
if (bitval == 1 && phase == 1) return redColor;
|
||||
if (bitval == 2 && phase == 2) return redColor;
|
||||
if (bitval == 4 && phase == 3) return redColor;
|
||||
|
||||
if (bitval == 9 && phase == 0) return orangeColor;
|
||||
if (bitval == 3 && phase == 1) return orangeColor;
|
||||
if (bitval == 6 && phase == 2) return orangeColor;
|
||||
if (bitval == 12 && phase == 3) return orangeColor;
|
||||
|
||||
if (bitval == 10 && phase == 0) return gray2Color;
|
||||
if (bitval == 5 && phase == 1) return gray2Color;
|
||||
if (bitval == 10 && phase == 2) return gray2Color;
|
||||
if (bitval == 5 && phase == 3) return gray2Color;
|
||||
|
||||
if (bitval == 11 && phase == 0) return yellowColor;
|
||||
if (bitval == 7 && phase == 1) return yellowColor;
|
||||
if (bitval == 14 && phase == 2) return yellowColor;
|
||||
if (bitval == 13 && phase == 3) return yellowColor;
|
||||
|
||||
if (bitval == 12 && phase == 0) return purpleColor;
|
||||
if (bitval == 9 && phase == 1) return purpleColor;
|
||||
if (bitval == 3 && phase == 2) return purpleColor;
|
||||
if (bitval == 6 && phase == 3) return purpleColor;
|
||||
|
||||
if (bitval == 13 && phase == 0) return pinkColor;
|
||||
if (bitval == 11 && phase == 1) return pinkColor;
|
||||
if (bitval == 7 && phase == 2) return pinkColor;
|
||||
if (bitval == 14 && phase == 3) return pinkColor;
|
||||
|
||||
if (bitval == 14 && phase == 0) return lightBlueColor;
|
||||
if (bitval == 13 && phase == 1) return lightBlueColor;
|
||||
if (bitval == 11 && phase == 2) return lightBlueColor;
|
||||
if (bitval == 7 && phase == 3) return lightBlueColor;
|
||||
|
||||
return whiteColor;
|
||||
|
||||
}
|
||||
|
||||
void HiresViewWidget::drawNtscLine(QPainter &painter, int lineNum, QBitArray data) {
|
||||
QVector<QColor> colors;
|
||||
colors.resize(data.count()+3);
|
||||
|
||||
for (int idx = 0; idx < data.count(); idx++) {
|
||||
QBitArray tmp(4);
|
||||
tmp[0]=data.at(idx+0);
|
||||
if (idx < data.count()-1) tmp[1]=data.at(idx+1); else tmp[1] = false;
|
||||
if (idx < data.count()-2) tmp[2]=data.at(idx+2); else tmp[2] = false;
|
||||
if (idx < data.count()-3) tmp[3]=data.at(idx+3); else tmp[3] = false;
|
||||
colors[idx] = getColorFromBits(tmp,idx %4);
|
||||
colors[idx+1] = getColorFromBits(tmp,idx %4);
|
||||
colors[idx+2] = getColorFromBits(tmp,idx %4);
|
||||
colors[idx+3] = getColorFromBits(tmp,idx %4);
|
||||
}
|
||||
|
||||
|
||||
for (int idx = 0; idx < colors.count(); idx++)
|
||||
{
|
||||
painter.setPen(colors.at(idx));
|
||||
painter.setBrush(colors.at(idx));
|
||||
painter.drawPoint(idx,lineNum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QBitArray HiresViewWidget::byteToBits(quint8 byte) {
|
||||
QBitArray bits(8);
|
||||
bits.setBit(0,byte & 0x80);
|
||||
bits.setBit(7,byte & 0x40);
|
||||
bits.setBit(6,byte & 0x20);
|
||||
bits.setBit(5,byte & 0x10);
|
||||
bits.setBit(4,byte & 0x08);
|
||||
bits.setBit(3,byte & 0x04);
|
||||
bits.setBit(2,byte & 0x02);
|
||||
bits.setBit(1,byte & 0x01);
|
||||
return bits;
|
||||
}
|
||||
|
||||
void HiresViewWidget::setMode(HiresViewWidget::ViewMode viewmode)
|
||||
{
|
||||
m_viewMode = viewmode;
|
||||
update();
|
||||
}
|
||||
|
||||
int HiresViewWidget::findRowCol(int offset) {
|
||||
int retval = 0;
|
||||
retval = (*m_rowTable)[offset];
|
||||
return retval;
|
||||
}
|
||||
|
||||
void HiresViewWidget::makeOffsetTable() {
|
||||
m_rowTable = new QMap<int,int>();
|
||||
|
||||
for (int idx = 0; idx < 8192; idx++)
|
||||
{
|
||||
(*m_rowTable)[idx] = -1; // Fill the memory holes. Brute force, but it works.
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
||||
int outer = 0x0000;
|
||||
for (int idx = 0; idx < 8; idx++) {
|
||||
int inner = 0x0000;
|
||||
for (int jdx = 0; jdx < 8; jdx++) {
|
||||
for (int kdx = 0; kdx<40;kdx++) {
|
||||
(*m_rowTable)[outer+inner+kdx] = count + (kdx*10000);
|
||||
}
|
||||
count++;
|
||||
inner += 0x0400;
|
||||
}
|
||||
outer += 0x0080;
|
||||
}
|
||||
|
||||
|
||||
outer = 0x0028;
|
||||
for (int idx = 0; idx < 8; idx++) {
|
||||
int inner = 0x0000;
|
||||
for (int jdx = 0; jdx < 8; jdx++) {
|
||||
for (int kdx = 0; kdx<40;kdx++) {
|
||||
(*m_rowTable)[outer+inner+kdx] = count + (kdx*10000);
|
||||
}
|
||||
count++;
|
||||
inner += 0x0400;
|
||||
}
|
||||
outer += 0x0080;
|
||||
}
|
||||
|
||||
outer = 0x0050;
|
||||
for (int idx = 0; idx < 8; idx++) {
|
||||
int inner = 0x0000;
|
||||
for (int jdx = 0; jdx < 8; jdx++) {
|
||||
for (int kdx = 0; kdx<40;kdx++) {
|
||||
(*m_rowTable)[outer+inner+kdx] = count + (kdx*10000);
|
||||
}
|
||||
count++;
|
||||
inner += 0x0400;
|
||||
}
|
||||
outer += 0x0080;
|
||||
}
|
||||
}
|
||||
|
||||
void HiresViewWidget::contextMenuEvent(QContextMenuEvent *event) {
|
||||
QMenu menu(this);
|
||||
menu.addAction(monochromeAction);
|
||||
menu.addAction(ntscAction);
|
||||
menu.addAction(perPixelColorAction);
|
||||
menu.addSeparator();
|
||||
menu.addAction(showScanLinesAction);
|
||||
menu.exec(event->globalPos());
|
||||
}
|
||||
|
||||
bool HiresViewWidget::optionsMenuItems(QMenu *menu)
|
||||
{
|
||||
menu->addAction(monochromeAction);
|
||||
menu->addAction(ntscAction);
|
||||
menu->addAction(perPixelColorAction);
|
||||
menu->addAction(hrsw->monochromeAction());
|
||||
menu->addAction(hrsw->ntscAction());
|
||||
menu->addAction(hrsw->perPixelColorAction());
|
||||
menu->addSeparator();
|
||||
menu->addAction(showScanLinesAction);
|
||||
menu->addAction(hrsw->showScanLinesAction());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -543,5 +52,3 @@ void HiresViewWidget::setFile(GenericFile *file)
|
||||
}
|
||||
}
|
||||
|
||||
QMap<int,int> *HiresViewWidget::m_rowTable = 0;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "binaryfile.h"
|
||||
#include "fileviewerinterface.h"
|
||||
#include "HiresScreenWidget.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPixmap>
|
||||
@ -13,22 +14,6 @@
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
|
||||
static const QColor blackColor = QColor(0,0,0);
|
||||
static const QColor brownColor = QColor();
|
||||
static const QColor darkGreenColor = QColor(96,114,3);
|
||||
static const QColor greenColor = QColor(20,245,60);
|
||||
static const QColor darkBlueColor = QColor(96,78,189);
|
||||
static const QColor grayColor = QColor(156,156,156);
|
||||
static const QColor blueColor = QColor(20,207,253);
|
||||
static const QColor aquaColor = QColor(114,255,208);
|
||||
static const QColor redColor = QColor(227,30,96);
|
||||
static const QColor orangeColor = QColor(255,106,60);
|
||||
static const QColor gray2Color = QColor(156,156,156);
|
||||
static const QColor yellowColor = QColor(208,221,141);
|
||||
static const QColor purpleColor = QColor(255,68,253);
|
||||
static const QColor pinkColor = QColor(255,160,208);
|
||||
static const QColor lightBlueColor = QColor(208,195,255);
|
||||
static const QColor whiteColor = QColor(255,255,255);
|
||||
|
||||
|
||||
class HiresViewWidget : public FileViewerInterface
|
||||
@ -36,64 +21,15 @@ class HiresViewWidget : public FileViewerInterface
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
|
||||
enum ViewMode {
|
||||
Monochrome,
|
||||
Color1,
|
||||
Color2
|
||||
};
|
||||
|
||||
explicit HiresViewWidget(QWidget *parent = 0);
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
static QBitArray byteToBits(quint8 byte);
|
||||
void contextMenuEvent(QContextMenuEvent *);
|
||||
|
||||
virtual bool optionsMenuItems(QMenu *);
|
||||
|
||||
signals:
|
||||
explicit HiresViewWidget(QWidget *parent = 0);
|
||||
virtual bool optionsMenuItems(QMenu *);
|
||||
|
||||
public slots:
|
||||
void setFile(GenericFile *file);
|
||||
void setFile(BinaryFile *file);
|
||||
|
||||
void setData(QByteArray data);
|
||||
void setMode(ViewMode);
|
||||
|
||||
protected slots:
|
||||
void handleNtscAction(bool toggled);
|
||||
void handleMonochromeAction(bool toggled);
|
||||
void handlePerPixelColorAction(bool toggled);
|
||||
void handleShowScanLinesAction(bool toggled);
|
||||
|
||||
private:
|
||||
QPixmap m_pixmap;
|
||||
QByteArray m_data;
|
||||
|
||||
|
||||
int findRowCol(int offset);
|
||||
static QMap<int,int> *m_rowTable;
|
||||
|
||||
void makeOffsetTable();
|
||||
|
||||
ViewMode m_viewMode;
|
||||
|
||||
void drawNtscLine(QPainter &painter,int linenum, QBitArray data);
|
||||
void drawMonoLine(QPainter &painter, int lineNum, QBitArray data);
|
||||
|
||||
QColor getColorFromBits(QBitArray bits, quint8 phase);
|
||||
|
||||
QAction *monochromeAction;
|
||||
QAction *ntscAction;
|
||||
QAction *perPixelColorAction;
|
||||
QAction *showScanLinesAction;
|
||||
QActionGroup *formatGroup;
|
||||
|
||||
bool m_showScanLines;
|
||||
|
||||
void drawPixmap();
|
||||
HiresScreenWidget *hrsw;
|
||||
|
||||
BinaryFile *m_file;
|
||||
};
|
||||
|
14
src/ui/widgets/CharacterSetExplorer.cpp
Normal file
14
src/ui/widgets/CharacterSetExplorer.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "CharacterSetExplorer.h"
|
||||
#include "ui_CharacterSetExplorer.h"
|
||||
|
||||
CharacterSetExplorer::CharacterSetExplorer(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::CharacterSetExplorer)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
CharacterSetExplorer::~CharacterSetExplorer()
|
||||
{
|
||||
delete ui;
|
||||
}
|
22
src/ui/widgets/CharacterSetExplorer.h
Normal file
22
src/ui/widgets/CharacterSetExplorer.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef CHARACTERSETEXPLORER_H
|
||||
#define CHARACTERSETEXPLORER_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class CharacterSetExplorer;
|
||||
}
|
||||
|
||||
class CharacterSetExplorer : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CharacterSetExplorer(QWidget *parent = 0);
|
||||
~CharacterSetExplorer();
|
||||
|
||||
private:
|
||||
Ui::CharacterSetExplorer *ui;
|
||||
};
|
||||
|
||||
#endif // CHARACTERSETEXPLORER_H
|
45
src/ui/widgets/CharacterSetExplorer.ui
Normal file
45
src/ui/widgets/CharacterSetExplorer.ui
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CharacterSetExplorer</class>
|
||||
<widget class="QDialog" name="CharacterSetExplorer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>423</width>
|
||||
<height>352</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="1,999999">
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="drawWidget" native="true"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Text:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="inputText"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="drawButton">
|
||||
<property name="text">
|
||||
<string>Draw</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
518
src/ui/widgets/HiresScreenWidget.cpp
Normal file
518
src/ui/widgets/HiresScreenWidget.cpp
Normal file
@ -0,0 +1,518 @@
|
||||
#include "HiresScreenWidget.h"
|
||||
|
||||
#include "binaryfile.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QMap>
|
||||
#include <QDebug>
|
||||
#include <QResizeEvent>
|
||||
#include <QSettings>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
HiresScreenWidget::HiresScreenWidget(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
if (m_rawAddressToColRowList.size() == 0 ||
|
||||
m_appleAddressToColRowList.size() == 0)
|
||||
{
|
||||
makeAddressTables();
|
||||
}
|
||||
|
||||
resize(561,384);
|
||||
QSettings settings;
|
||||
m_viewMode = static_cast<ViewMode>(settings.value("HiresScreenWidget.ViewMode",NTSCColor).toInt());
|
||||
m_showScanLines = settings.value("HiresScreenWidget.ShowScanLines",true).toBool();
|
||||
|
||||
m_pixmap = QPixmap(561,384);
|
||||
QPainter painter(&m_pixmap);
|
||||
painter.setBrush(Qt::black);
|
||||
painter.drawRect(0,0,this->width(),this->height());
|
||||
|
||||
formatGroup = new QActionGroup(this);
|
||||
|
||||
m_monochromeAction = new QAction("Monochrome Display",this);
|
||||
m_monochromeAction->setCheckable(true);
|
||||
m_monochromeAction->setChecked((m_viewMode == Monochrome));
|
||||
formatGroup->addAction(m_monochromeAction);
|
||||
|
||||
m_ntscAction = new QAction("NTSC Display",this);
|
||||
m_ntscAction->setCheckable(true);
|
||||
m_ntscAction->setChecked((m_viewMode == NTSCColor));
|
||||
formatGroup->addAction(m_ntscAction);
|
||||
|
||||
m_perPixelColorAction= new QAction("Per-Pixel Color Display",this);
|
||||
m_perPixelColorAction->setCheckable(true);
|
||||
m_perPixelColorAction->setChecked((m_viewMode == PerPixelColor));
|
||||
formatGroup->addAction(m_perPixelColorAction);
|
||||
|
||||
m_showScanLinesAction = new QAction("Show Scan Lines",this);
|
||||
m_showScanLinesAction->setCheckable(true);
|
||||
m_showScanLinesAction->setChecked(m_showScanLines);
|
||||
|
||||
|
||||
connect(m_ntscAction, SIGNAL(toggled(bool)), this, SLOT(handleNtscAction(bool)));
|
||||
connect(m_monochromeAction, SIGNAL(toggled(bool)), this, SLOT(handleMonochromeAction(bool)));
|
||||
connect(m_perPixelColorAction, SIGNAL(toggled(bool)), this, SLOT(handlePerPixelColorAction(bool)));
|
||||
|
||||
connect(m_showScanLinesAction, SIGNAL(toggled(bool)), this, SLOT(handleShowScanLinesAction(bool)));
|
||||
|
||||
}
|
||||
|
||||
void HiresScreenWidget::handleNtscAction(bool toggled) {
|
||||
if (toggled) {
|
||||
m_viewMode = NTSCColor;
|
||||
update();
|
||||
}
|
||||
QSettings settings;
|
||||
settings.setValue("HiresScreenWidget.ViewMode",m_viewMode);
|
||||
}
|
||||
|
||||
void HiresScreenWidget::handleMonochromeAction(bool toggled) {
|
||||
if (toggled) {
|
||||
m_viewMode = Monochrome;
|
||||
update();
|
||||
}
|
||||
QSettings settings;
|
||||
settings.setValue("HiresScreenWidget.ViewMode",m_viewMode);
|
||||
}
|
||||
|
||||
void HiresScreenWidget::handlePerPixelColorAction(bool toggled) {
|
||||
if (toggled) {
|
||||
m_viewMode = PerPixelColor;
|
||||
update();
|
||||
}
|
||||
QSettings settings;
|
||||
settings.setValue("HiresScreenWidget.ViewMode",m_viewMode);
|
||||
}
|
||||
|
||||
void HiresScreenWidget::handleShowScanLinesAction(bool toggled) {
|
||||
m_showScanLines = toggled;
|
||||
update();
|
||||
QSettings settings;
|
||||
settings.setValue("HiresScreenWidget.ShowScanLines",toggled);
|
||||
}
|
||||
|
||||
|
||||
void HiresScreenWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
// if (m_pixmap.size() != this->size()) {
|
||||
// m_pixmap = m_pixmap.scaled(this->size(),Qt::KeepAspectRatio);
|
||||
// }
|
||||
|
||||
drawPixmap();
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
QPixmap tmppixmap = m_pixmap;
|
||||
// tmppixmap = tmppixmap.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
painter.drawPixmap(0,0,tmppixmap);
|
||||
}
|
||||
|
||||
void HiresScreenWidget::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void HiresScreenWidget::drawPixmap() {
|
||||
|
||||
QPainter pmpainter(&m_pixmap);
|
||||
|
||||
pmpainter.setBrush(Qt::black);
|
||||
pmpainter.setPen(Qt::black);
|
||||
pmpainter.drawRect(0,0,m_pixmap.width(),m_pixmap.height());
|
||||
|
||||
if (m_viewMode == Monochrome || m_viewMode == NTSCColor)
|
||||
{
|
||||
pmpainter.setPen(Qt::white);
|
||||
pmpainter.setBrush(Qt::white);
|
||||
|
||||
quint8 chunkCount = 0;
|
||||
|
||||
int idx = 0;
|
||||
while (idx < qMin(m_data.size(),8192)) {
|
||||
ColRow cr = getColRowFromAppleAddress(idx);
|
||||
|
||||
int yoff = cr.row();
|
||||
|
||||
QBitArray bits(561,false);
|
||||
int bitoffset = 0;
|
||||
bool lastbit = false;
|
||||
|
||||
for (int jdx = 0; jdx < 40; jdx++)
|
||||
{
|
||||
|
||||
quint8 byte = m_data[idx++];
|
||||
QBitArray dataBits = byteToBits(byte);
|
||||
|
||||
bool highBit = dataBits.at(0);
|
||||
|
||||
if (highBit) {
|
||||
bits[bitoffset++] = lastbit;
|
||||
}
|
||||
|
||||
for (int xdx = 1; xdx < 7; xdx++) {
|
||||
bits[bitoffset++] = dataBits.at(xdx);
|
||||
bits[bitoffset++] = dataBits.at(xdx);
|
||||
}
|
||||
lastbit = dataBits.at(7);
|
||||
bits[bitoffset++] = dataBits.at(7);
|
||||
if (!highBit) {
|
||||
bits[bitoffset++] = dataBits.at(7);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (m_viewMode == Monochrome)
|
||||
{
|
||||
drawMonoLine(pmpainter, yoff*2, bits);
|
||||
if (!m_showScanLines) drawMonoLine(pmpainter, yoff*2+1, bits);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawNtscLine(pmpainter, yoff*2, bits);
|
||||
if (!m_showScanLines) drawNtscLine(pmpainter, yoff*2+1, bits);
|
||||
}
|
||||
|
||||
chunkCount++;
|
||||
if (chunkCount == 3) {
|
||||
chunkCount = 0;
|
||||
idx+=8; // Skip screen hole
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (m_viewMode == PerPixelColor)
|
||||
{
|
||||
pmpainter.setPen(Qt::white);
|
||||
pmpainter.setBrush(Qt::white);
|
||||
|
||||
for (int idx = 0; idx < qMin(m_data.size(),8192) ; idx++) {
|
||||
ColRow cr = getColRowFromAppleAddress(idx);
|
||||
|
||||
quint8 byte = m_data[idx];
|
||||
|
||||
bool highBit = byte & 0x80;
|
||||
|
||||
QColor oddColor = highBit? QColor(orangeColor) : QColor(greenColor);
|
||||
QColor evenColor = highBit? QColor(blueColor) : QColor(purpleColor);
|
||||
|
||||
int xoff = cr.col() * 7;
|
||||
int yoff = cr.row() * 2;
|
||||
|
||||
quint8 cOffset = 0;// highBit?1:0;
|
||||
|
||||
quint8 doubleScan = 0;
|
||||
if (!m_showScanLines)
|
||||
{
|
||||
doubleScan = 1;
|
||||
}
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?oddColor:evenColor);
|
||||
pmpainter.setBrush(xoff & 0x01?oddColor:evenColor);
|
||||
|
||||
if (byte & 0x01) { pmpainter.drawRect((cOffset+xoff*2)+0,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?evenColor:oddColor);
|
||||
pmpainter.setBrush(xoff & 0x01?evenColor:oddColor);
|
||||
|
||||
if (byte & 0x02) { pmpainter.drawRect((cOffset+xoff*2)+2,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?oddColor:evenColor);
|
||||
pmpainter.setBrush(xoff & 0x01?oddColor:evenColor);
|
||||
|
||||
if (byte & 0x04) { pmpainter.drawRect((cOffset+xoff*2)+4,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?evenColor:oddColor);
|
||||
pmpainter.setBrush(xoff & 0x01?evenColor:oddColor);
|
||||
|
||||
if (byte & 0x08) { pmpainter.drawRect((cOffset+xoff*2)+6,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?oddColor:evenColor);
|
||||
pmpainter.setBrush(xoff & 0x01?oddColor:evenColor);
|
||||
|
||||
|
||||
if (byte & 0x10) { pmpainter.drawRect((cOffset+xoff*2)+8,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?evenColor:oddColor);
|
||||
pmpainter.setBrush(xoff & 0x01?evenColor:oddColor);
|
||||
|
||||
if (byte & 0x20) { pmpainter.drawRect((cOffset+xoff*2)+10,yoff,1,doubleScan); }
|
||||
|
||||
pmpainter.setPen(xoff & 0x01?oddColor:evenColor);
|
||||
pmpainter.setBrush(xoff & 0x01?oddColor:evenColor);
|
||||
|
||||
|
||||
if (byte & 0x40) { pmpainter.drawRect((cOffset+xoff*2)+12,yoff,cOffset?0:1,doubleScan); }
|
||||
|
||||
|
||||
|
||||
if (idx >= (280*192)) break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HiresScreenWidget::setUnpackedData(QByteArray unpackedData)
|
||||
{
|
||||
QByteArray packedData = packData(unpackedData);
|
||||
setData(packedData);
|
||||
}
|
||||
|
||||
QByteArray HiresScreenWidget::packData(QByteArray unpackedData)
|
||||
{
|
||||
QByteArray packedData;
|
||||
packedData.resize(8192);
|
||||
packedData.fill(0x00);
|
||||
|
||||
for (int idx = 0; idx < qMin(unpackedData.count(),8192); idx++)
|
||||
{
|
||||
ColRow cr = getColRowFromRawAddress(idx);
|
||||
packedData[cr.appleAddress()] = unpackedData[idx];
|
||||
}
|
||||
|
||||
return packedData;
|
||||
}
|
||||
|
||||
int HiresScreenWidget::getLineAddressOffset(int line)
|
||||
{
|
||||
static QList<quint16> blockOffset {
|
||||
0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380,
|
||||
0x0028, 0x00A0, 0x0128, 0x01A8, 0x0228, 0x02A8, 0x0328, 0x03A8,
|
||||
0x0040, 0x00D0, 0x0150, 0x00D0, 0x0250, 0x02D0, 0x0350, 0x03D0
|
||||
};
|
||||
|
||||
static QList<quint16> boxSub {
|
||||
0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00
|
||||
};
|
||||
|
||||
int block = line / 8;
|
||||
int sub = line % 8;
|
||||
|
||||
return blockOffset[block] + boxSub[sub];
|
||||
}
|
||||
|
||||
void HiresScreenWidget::setData(QByteArray data) {
|
||||
m_data = data;
|
||||
|
||||
drawPixmap();
|
||||
}
|
||||
|
||||
void HiresScreenWidget::drawMonoLine(QPainter &painter, int lineNum, QBitArray data) {
|
||||
for (int idx = 0; idx < data.count(); idx++) {
|
||||
|
||||
if (data.at(idx))
|
||||
{
|
||||
painter.setPen(Qt::white);
|
||||
} else {
|
||||
painter.setPen(Qt::black);
|
||||
}
|
||||
|
||||
painter.drawPoint(idx,lineNum);
|
||||
}
|
||||
}
|
||||
|
||||
QColor HiresScreenWidget::getColorFromBits(QBitArray bits, quint8 phase)
|
||||
{
|
||||
quint8 bitval = (bits[0] * 0x08) +
|
||||
(bits[1] * 0x04) +
|
||||
(bits[2] * 0x02) +
|
||||
(bits[3] * 0x01);
|
||||
|
||||
phase %= 4;
|
||||
|
||||
if (bitval == 0) { return blackColor; }
|
||||
|
||||
if (bitval == 1 && phase == 0) return brownColor;
|
||||
if (bitval == 2 && phase == 1) return brownColor;
|
||||
if (bitval == 4 && phase == 2) return brownColor;
|
||||
if (bitval == 8 && phase == 3) return brownColor;
|
||||
|
||||
if (bitval == 2 && phase == 0) return darkGreenColor;
|
||||
if (bitval == 4 && phase == 1) return darkGreenColor;
|
||||
if (bitval == 8 && phase == 2) return darkGreenColor;
|
||||
if (bitval == 1 && phase == 3) return darkGreenColor;
|
||||
|
||||
if (bitval == 3 && phase == 0) return greenColor;
|
||||
if (bitval == 6 && phase == 1) return greenColor;
|
||||
if (bitval == 12 && phase == 2) return greenColor;
|
||||
if (bitval == 9 && phase == 3) return greenColor;
|
||||
|
||||
if (bitval == 4 && phase == 0) return darkBlueColor;
|
||||
if (bitval == 8 && phase == 1) return darkBlueColor;
|
||||
if (bitval == 1 && phase == 2) return darkBlueColor;
|
||||
if (bitval == 2 && phase == 3) return darkBlueColor;
|
||||
|
||||
if (bitval == 5 && phase == 0) return grayColor;
|
||||
if (bitval == 10 && phase == 1) return grayColor;
|
||||
if (bitval == 5 && phase == 2) return grayColor;
|
||||
if (bitval == 10 && phase == 3) return grayColor;
|
||||
|
||||
if (bitval == 6 && phase == 0) return blueColor;
|
||||
if (bitval == 12 && phase == 1) return blueColor;
|
||||
if (bitval == 9 && phase == 2) return blueColor;
|
||||
if (bitval == 3 && phase == 3) return blueColor;
|
||||
|
||||
if (bitval == 7 && phase == 0) return aquaColor;
|
||||
if (bitval == 14 && phase == 1) return aquaColor;
|
||||
if (bitval == 13 && phase == 2) return aquaColor;
|
||||
if (bitval == 11 && phase == 3) return aquaColor;
|
||||
|
||||
if (bitval == 8 && phase == 0) return redColor;
|
||||
if (bitval == 1 && phase == 1) return redColor;
|
||||
if (bitval == 2 && phase == 2) return redColor;
|
||||
if (bitval == 4 && phase == 3) return redColor;
|
||||
|
||||
if (bitval == 9 && phase == 0) return orangeColor;
|
||||
if (bitval == 3 && phase == 1) return orangeColor;
|
||||
if (bitval == 6 && phase == 2) return orangeColor;
|
||||
if (bitval == 12 && phase == 3) return orangeColor;
|
||||
|
||||
if (bitval == 10 && phase == 0) return gray2Color;
|
||||
if (bitval == 5 && phase == 1) return gray2Color;
|
||||
if (bitval == 10 && phase == 2) return gray2Color;
|
||||
if (bitval == 5 && phase == 3) return gray2Color;
|
||||
|
||||
if (bitval == 11 && phase == 0) return yellowColor;
|
||||
if (bitval == 7 && phase == 1) return yellowColor;
|
||||
if (bitval == 14 && phase == 2) return yellowColor;
|
||||
if (bitval == 13 && phase == 3) return yellowColor;
|
||||
|
||||
if (bitval == 12 && phase == 0) return purpleColor;
|
||||
if (bitval == 9 && phase == 1) return purpleColor;
|
||||
if (bitval == 3 && phase == 2) return purpleColor;
|
||||
if (bitval == 6 && phase == 3) return purpleColor;
|
||||
|
||||
if (bitval == 13 && phase == 0) return pinkColor;
|
||||
if (bitval == 11 && phase == 1) return pinkColor;
|
||||
if (bitval == 7 && phase == 2) return pinkColor;
|
||||
if (bitval == 14 && phase == 3) return pinkColor;
|
||||
|
||||
if (bitval == 14 && phase == 0) return lightBlueColor;
|
||||
if (bitval == 13 && phase == 1) return lightBlueColor;
|
||||
if (bitval == 11 && phase == 2) return lightBlueColor;
|
||||
if (bitval == 7 && phase == 3) return lightBlueColor;
|
||||
|
||||
return whiteColor;
|
||||
|
||||
}
|
||||
|
||||
void HiresScreenWidget::drawNtscLine(QPainter &painter, int lineNum, QBitArray data) {
|
||||
QVector<QColor> colors;
|
||||
colors.resize(data.count()+3);
|
||||
|
||||
for (int idx = 0; idx < data.count(); idx++) {
|
||||
QBitArray tmp(4);
|
||||
tmp[0]=data.at(idx+0);
|
||||
if (idx < data.count()-1) tmp[1]=data.at(idx+1); else tmp[1] = false;
|
||||
if (idx < data.count()-2) tmp[2]=data.at(idx+2); else tmp[2] = false;
|
||||
if (idx < data.count()-3) tmp[3]=data.at(idx+3); else tmp[3] = false;
|
||||
colors[idx] = getColorFromBits(tmp,idx %4);
|
||||
colors[idx+1] = getColorFromBits(tmp,idx %4);
|
||||
colors[idx+2] = getColorFromBits(tmp,idx %4);
|
||||
colors[idx+3] = getColorFromBits(tmp,idx %4);
|
||||
}
|
||||
|
||||
for (int idx = 0; idx < colors.count(); idx++)
|
||||
{
|
||||
painter.setPen(colors.at(idx));
|
||||
painter.setBrush(colors.at(idx));
|
||||
painter.drawPoint(idx,lineNum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QBitArray HiresScreenWidget::byteToBits(quint8 byte) {
|
||||
QBitArray bits(8);
|
||||
bits.setBit(0,byte & 0x80);
|
||||
bits.setBit(7,byte & 0x40);
|
||||
bits.setBit(6,byte & 0x20);
|
||||
bits.setBit(5,byte & 0x10);
|
||||
bits.setBit(4,byte & 0x08);
|
||||
bits.setBit(3,byte & 0x04);
|
||||
bits.setBit(2,byte & 0x02);
|
||||
bits.setBit(1,byte & 0x01);
|
||||
return bits;
|
||||
}
|
||||
|
||||
void HiresScreenWidget::setMode(HiresScreenWidget::ViewMode viewmode)
|
||||
{
|
||||
m_viewMode = viewmode;
|
||||
update();
|
||||
}
|
||||
|
||||
void HiresScreenWidget::contextMenuEvent(QContextMenuEvent *event) {
|
||||
QMenu menu(this);
|
||||
menu.addAction(m_monochromeAction);
|
||||
menu.addAction(m_ntscAction);
|
||||
menu.addAction(m_perPixelColorAction);
|
||||
menu.addSeparator();
|
||||
menu.addAction(m_showScanLinesAction);
|
||||
menu.exec(event->globalPos());
|
||||
}
|
||||
|
||||
HiresScreenWidget::ColRow HiresScreenWidget::getColRowFromAppleAddress(quint16 address)
|
||||
{
|
||||
if (address > 8191) {
|
||||
qDebug() << "Invalid apple address " << address;
|
||||
address = 8191;
|
||||
}
|
||||
return m_appleAddressToColRowList[address];
|
||||
}
|
||||
|
||||
HiresScreenWidget::ColRow HiresScreenWidget::getColRowFromRawAddress(quint16 address)
|
||||
{
|
||||
if (address > 8191) {
|
||||
qDebug() << "Invalid raw address " << address;
|
||||
address = 8191;
|
||||
}
|
||||
return m_rawAddressToColRowList[address];
|
||||
}
|
||||
|
||||
void HiresScreenWidget::makeAddressTables()
|
||||
{
|
||||
qDebug() << " ****** makeAddressTables()";
|
||||
m_rawAddressToColRowList.resize(8192);
|
||||
m_appleAddressToColRowList.resize(8192);
|
||||
|
||||
for (int row = 0; row < 192; row++)
|
||||
{
|
||||
for (int col = 0; col < 40; col++)
|
||||
{
|
||||
ColRow cr(col,row);
|
||||
// qDebug() << "Col: " << col << "Row: " << row << "Raw: " << cr.rawAddress() << " Apple: " << cr.appleAddress();
|
||||
|
||||
m_rawAddressToColRowList[cr.rawAddress()] = cr;
|
||||
m_appleAddressToColRowList[cr.appleAddress()] = cr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGHOLES
|
||||
int num = 0;
|
||||
quint16 lasthole = 0;
|
||||
for (int idx = 0; idx < 8192; idx++)
|
||||
{
|
||||
if (!m_appleAddressToColRowList[idx].isDefined())
|
||||
{
|
||||
if (lasthole != 0 && lasthole != (idx-1)) { qDebug() << "\n"; }
|
||||
qDebug() << "Hole" << num << "at" << idx+0x2000 << uint16ToHex(idx+0x2000); ;
|
||||
num++;
|
||||
lasthole = idx;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
QVector<HiresScreenWidget::ColRow> HiresScreenWidget::m_rawAddressToColRowList
|
||||
= QVector<HiresScreenWidget::ColRow>();
|
||||
QVector<HiresScreenWidget::ColRow> HiresScreenWidget::m_appleAddressToColRowList
|
||||
= QVector<HiresScreenWidget::ColRow>();
|
149
src/ui/widgets/HiresScreenWidget.h
Normal file
149
src/ui/widgets/HiresScreenWidget.h
Normal file
@ -0,0 +1,149 @@
|
||||
#ifndef HIRESSCREENWIDGET_H
|
||||
#define HIRESSCREENWIDGET_H
|
||||
|
||||
#include "binaryfile.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPixmap>
|
||||
#include <QByteArray>
|
||||
#include <QPair>
|
||||
#include <QMap>
|
||||
#include <QBitArray>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QVector>
|
||||
#include <QDebug>
|
||||
|
||||
static const QColor blackColor = QColor(0,0,0);
|
||||
static const QColor grayColor = QColor(156,156,156);
|
||||
static const QColor gray2Color = QColor(156,156,156);
|
||||
static const QColor whiteColor = QColor(255,255,255);
|
||||
static const QColor darkBlueColor = QColor(96,78,189);
|
||||
static const QColor lightBlueColor = QColor(208,195,255);
|
||||
static const QColor purpleColor = QColor(255,68,253);
|
||||
static const QColor redColor = QColor(227,30,96);
|
||||
static const QColor pinkColor = QColor(255,160,208);
|
||||
static const QColor orangeColor = QColor(255,106,60);
|
||||
static const QColor brownColor = QColor(96,114,3);
|
||||
static const QColor yellowColor = QColor(208,221,141);
|
||||
static const QColor greenColor = QColor(20,245,60);
|
||||
static const QColor darkGreenColor = QColor(0,163,96);
|
||||
static const QColor aquaColor = QColor(114,255,208);
|
||||
static const QColor blueColor = QColor(20,207,253);
|
||||
|
||||
class HiresScreenWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
class ColRow {
|
||||
public:
|
||||
ColRow() { m_col = 0; m_row = 0; m_undefined = true; }
|
||||
ColRow(quint8 col, quint8 row) { setColRow(col,row); }
|
||||
void setColRow(quint8 col, quint8 row) { m_col = col; m_row = row; calc(); }
|
||||
|
||||
quint8 col() const { return m_col; }
|
||||
quint8 row() const { return m_row; }
|
||||
|
||||
bool isDefined() const { return !m_undefined; }
|
||||
bool isUndefined() const { return m_undefined; }
|
||||
|
||||
quint16 appleAddress() { return m_appleAddress; }
|
||||
quint16 rawAddress() { return m_rawAddress; }
|
||||
|
||||
private:
|
||||
quint8 m_col;
|
||||
quint8 m_row;
|
||||
|
||||
quint16 m_appleAddress;
|
||||
quint16 m_rawAddress;
|
||||
bool m_undefined;
|
||||
|
||||
void calc() {
|
||||
if (m_col > 39) { qDebug() << "Col out of range: " << m_col; m_col = 39; }
|
||||
if (m_row > 191) { qDebug() << "Row out of range: " << m_row; m_row = 191; }
|
||||
|
||||
m_rawAddress = (m_row*40) + m_col;
|
||||
|
||||
unsigned short blockOffset[] = {
|
||||
0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380,
|
||||
0x0028, 0x00A8, 0x0128, 0x01A8, 0x0228, 0x02A8, 0x0328, 0x03A8,
|
||||
0x0050, 0x00D0, 0x0150, 0x01D0, 0x0250, 0x02D0, 0x0350, 0x03D0
|
||||
};
|
||||
|
||||
unsigned short boxSub[] = {
|
||||
0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00
|
||||
};
|
||||
|
||||
m_appleAddress = blockOffset[m_row/8]+boxSub[m_row%8] + m_col;
|
||||
m_undefined = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
enum ViewMode {
|
||||
Monochrome,
|
||||
PerPixelColor,
|
||||
NTSCColor
|
||||
};
|
||||
|
||||
explicit HiresScreenWidget(QWidget *parent = 0);
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
static QBitArray byteToBits(quint8 byte);
|
||||
void contextMenuEvent(QContextMenuEvent *);
|
||||
|
||||
QAction *monochromeAction() { return m_monochromeAction; }
|
||||
QAction *ntscAction() { return m_ntscAction; }
|
||||
QAction *perPixelColorAction() { return m_perPixelColorAction; }
|
||||
QAction *showScanLinesAction() { return m_showScanLinesAction; }
|
||||
|
||||
ColRow getColRowFromAppleAddress(quint16 address);
|
||||
ColRow getColRowFromRawAddress(quint16 address);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void setData(QByteArray data);
|
||||
void setMode(ViewMode);
|
||||
void setUnpackedData(QByteArray unpackedData);
|
||||
|
||||
protected:
|
||||
int getLineAddressOffset(int line);
|
||||
QByteArray packData(QByteArray unpackedData);
|
||||
|
||||
protected slots:
|
||||
void handleNtscAction(bool toggled);
|
||||
void handleMonochromeAction(bool toggled);
|
||||
void handlePerPixelColorAction(bool toggled);
|
||||
void handleShowScanLinesAction(bool toggled);
|
||||
|
||||
private:
|
||||
void makeOffsetTable();
|
||||
void makeAddressTables();
|
||||
QColor getColorFromBits(QBitArray bits, quint8 phase);
|
||||
void drawNtscLine(QPainter &painter,int linenum, QBitArray data);
|
||||
void drawMonoLine(QPainter &painter, int lineNum, QBitArray data);
|
||||
void drawPixmap();
|
||||
|
||||
|
||||
QPixmap m_pixmap;
|
||||
QByteArray m_data;
|
||||
|
||||
ViewMode m_viewMode;
|
||||
|
||||
QAction *m_monochromeAction;
|
||||
QAction *m_ntscAction;
|
||||
QAction *m_perPixelColorAction;
|
||||
QAction *m_showScanLinesAction;
|
||||
QActionGroup *formatGroup;
|
||||
|
||||
bool m_showScanLines;
|
||||
|
||||
static QVector<ColRow> m_rawAddressToColRowList;
|
||||
static QVector<ColRow> m_appleAddressToColRowList;
|
||||
};
|
||||
|
||||
#endif // HIRESSCREENWIDGET_H
|
Loading…
Reference in New Issue
Block a user