diff --git a/AppleSAWS.pro b/AppleSAWS.pro index c5454a6..5ebe0ab 100644 --- a/AppleSAWS.pro +++ b/AppleSAWS.pro @@ -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 diff --git a/src/ui/viewers/hexdumpviewer.ui b/src/ui/viewers/hexdumpviewer.ui index 93de795..ec8dc2c 100644 --- a/src/ui/viewers/hexdumpviewer.ui +++ b/src/ui/viewers/hexdumpviewer.ui @@ -6,8 +6,8 @@ 0 0 - 107 - 117 + 538 + 483 diff --git a/src/ui/viewers/hiresviewwidget.cxx b/src/ui/viewers/hiresviewwidget.cxx index 5083b49..546a246 100644 --- a/src/ui/viewers/hiresviewwidget.cxx +++ b/src/ui/viewers/hiresviewwidget.cxx @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -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(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 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(); - - 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 *HiresViewWidget::m_rowTable = 0; - diff --git a/src/ui/viewers/hiresviewwidget.h b/src/ui/viewers/hiresviewwidget.h index 4f0ce20..72eec19 100644 --- a/src/ui/viewers/hiresviewwidget.h +++ b/src/ui/viewers/hiresviewwidget.h @@ -3,6 +3,7 @@ #include "binaryfile.h" #include "fileviewerinterface.h" +#include "HiresScreenWidget.h" #include #include @@ -13,22 +14,6 @@ #include #include -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 *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; }; diff --git a/src/ui/widgets/CharacterSetExplorer.cpp b/src/ui/widgets/CharacterSetExplorer.cpp new file mode 100644 index 0000000..52fcffe --- /dev/null +++ b/src/ui/widgets/CharacterSetExplorer.cpp @@ -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; +} diff --git a/src/ui/widgets/CharacterSetExplorer.h b/src/ui/widgets/CharacterSetExplorer.h new file mode 100644 index 0000000..4b52663 --- /dev/null +++ b/src/ui/widgets/CharacterSetExplorer.h @@ -0,0 +1,22 @@ +#ifndef CHARACTERSETEXPLORER_H +#define CHARACTERSETEXPLORER_H + +#include + +namespace Ui { +class CharacterSetExplorer; +} + +class CharacterSetExplorer : public QDialog +{ + Q_OBJECT + +public: + explicit CharacterSetExplorer(QWidget *parent = 0); + ~CharacterSetExplorer(); + +private: + Ui::CharacterSetExplorer *ui; +}; + +#endif // CHARACTERSETEXPLORER_H diff --git a/src/ui/widgets/CharacterSetExplorer.ui b/src/ui/widgets/CharacterSetExplorer.ui new file mode 100644 index 0000000..527f891 --- /dev/null +++ b/src/ui/widgets/CharacterSetExplorer.ui @@ -0,0 +1,45 @@ + + + CharacterSetExplorer + + + + 0 + 0 + 423 + 352 + + + + Dialog + + + + + + + + + + + Text: + + + + + + + + + + Draw + + + + + + + + + + diff --git a/src/ui/widgets/HiresScreenWidget.cpp b/src/ui/widgets/HiresScreenWidget.cpp new file mode 100644 index 0000000..d3cd799 --- /dev/null +++ b/src/ui/widgets/HiresScreenWidget.cpp @@ -0,0 +1,518 @@ +#include "HiresScreenWidget.h" + +#include "binaryfile.h" + +#include +#include +#include +#include +#include + +#include "util.h" + +#include + + +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(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 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 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 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::m_rawAddressToColRowList += QVector(); +QVector HiresScreenWidget::m_appleAddressToColRowList += QVector(); diff --git a/src/ui/widgets/HiresScreenWidget.h b/src/ui/widgets/HiresScreenWidget.h new file mode 100644 index 0000000..c6d9940 --- /dev/null +++ b/src/ui/widgets/HiresScreenWidget.h @@ -0,0 +1,149 @@ +#ifndef HIRESSCREENWIDGET_H +#define HIRESSCREENWIDGET_H + +#include "binaryfile.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 m_rawAddressToColRowList; + static QVector m_appleAddressToColRowList; +}; + +#endif // HIRESSCREENWIDGET_H