GB SIO: Game Boy Printer
Vicki Pfau vi@endrift.com
Sun, 30 Jul 2017 17:17:58 -0700
12 files changed,
658 insertions(+),
3 deletions(-)
jump to
M
CMakeLists.txt
→
CMakeLists.txt
@@ -57,7 +57,7 @@ file(GLOB GUI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/gui/*.c ${CMAKE_CURRENT_SOURCE_DIR}/src/feature/gui/*.c)
file(GLOB GBA_RENDERER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/renderers/*.c) file(GLOB GBA_SIO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/sio/lockstep.c) file(GLOB GBA_EXTRA_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/extra/*.c) -file(GLOB GB_SIO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/sio/lockstep.c) +file(GLOB GB_SIO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/sio/*.c) file(GLOB GB_RENDERER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/renderers/*.c) file(GLOB GB_EXTRA_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/extra/*.c) file(GLOB THIRD_PARTY_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/inih/*.c)
A
include/mgba/internal/gb/sio/printer.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_PRINTER_H +#define GB_PRINTER_H + +#include <mgba-util/common.h> + +CXX_GUARD_START + +#include <mgba/gb/interface.h> + +enum GBPrinterPacketByte { + GB_PRINTER_BYTE_MAGIC_0, + GB_PRINTER_BYTE_MAGIC_1, + GB_PRINTER_BYTE_COMMAND, + GB_PRINTER_BYTE_COMPRESSION, + GB_PRINTER_BYTE_LENGTH_0, + GB_PRINTER_BYTE_LENGTH_1, + GB_PRINTER_BYTE_DATA, + GB_PRINTER_BYTE_CHECKSUM_0, + GB_PRINTER_BYTE_CHECKSUM_1, + GB_PRINTER_BYTE_KEEPALIVE, + GB_PRINTER_BYTE_STATUS, + + GB_PRINTER_BYTE_COMPRESSED_DATUM, + GB_PRINTER_BYTE_UNCOMPRESSED_DATA +}; + +enum GBPrinterStatus { + GB_PRINTER_STATUS_CHECKSUM_ERROR = 0x01, + GB_PRINTER_STATUS_PRINTING = 0x02, + GB_PRINTER_STATUS_PRINT_REQ = 0x04, + GB_PRINTER_STATUS_READY = 0x08, + GB_PRINTER_STATUS_LOW_BATTERY = 0x10, + GB_PRINTER_STATUS_TIMEOUT = 0x20, + GB_PRINTER_STATUS_PAPER_JAM = 0x40, + GB_PRINTER_STATUS_TEMPERATURE_ISSUE = 0x80 +}; + +enum GBPrinterCommand { + GB_PRINTER_COMMAND_INIT = 0x1, + GB_PRINTER_COMMAND_PRINT = 0x2, + GB_PRINTER_COMMAND_DATA = 0x4, + GB_PRINTER_COMMAND_STATUS = 0xF, +}; + +struct GBPrinter { + struct GBSIODriver d; + + void (*print)(struct GBPrinter*, int height, const uint8_t* data); + + uint8_t* buffer; + uint16_t checksum; + enum GBPrinterCommand command; + uint16_t remainingBytes; + uint8_t remainingCmpBytes; + unsigned currentIndex; + bool compression; + + uint8_t byte; + enum GBPrinterPacketByte next; + uint8_t status; + int printWait; +}; + +void GBPrinterCreate(struct GBPrinter* printer); +void GBPrinterDonePrinting(struct GBPrinter* printer); + +CXX_GUARD_END + +#endif
A
src/gb/sio/printer.c
@@ -0,0 +1,233 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <mgba/internal/gb/sio/printer.h> + +#include <mgba/internal/gb/gb.h> +#include <mgba/internal/gb/io.h> + + +static bool GBPrinterInit(struct GBSIODriver* driver); +static void GBPrinterDeinit(struct GBSIODriver* driver); +static void GBPrinterWriteSB(struct GBSIODriver* driver, uint8_t value); +static uint8_t GBPrinterWriteSC(struct GBSIODriver* driver, uint8_t value); + +void GBPrinterCreate(struct GBPrinter* printer) { + printer->d.init = GBPrinterInit; + printer->d.deinit = GBPrinterDeinit; + printer->d.writeSB = GBPrinterWriteSB; + printer->d.writeSC = GBPrinterWriteSC; + printer->print = NULL; +} + +bool GBPrinterInit(struct GBSIODriver* driver) { + struct GBPrinter* printer = (struct GBPrinter*) driver; + + printer->checksum = 0; + printer->command = 0; + printer->remainingBytes = 0; + printer->currentIndex = 0; + printer->compression = false; + printer->byte = 0; + printer->next = GB_PRINTER_BYTE_MAGIC_0; + printer->status = 0; + printer->printWait = -1; + + printer->buffer = malloc(GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS / 2); + + return true; +} + +void GBPrinterDeinit(struct GBSIODriver* driver) { + struct GBPrinter* printer = (struct GBPrinter*) driver; + free(printer->buffer); +} + +static void GBPrinterWriteSB(struct GBSIODriver* driver, uint8_t value) { + struct GBPrinter* printer = (struct GBPrinter*) driver; + printer->byte = value; +} + +static void _processByte(struct GBPrinter* printer) { + switch (printer->command) { + case GB_PRINTER_COMMAND_DATA: + if (printer->currentIndex < GB_VIDEO_VERTICAL_PIXELS * GB_VIDEO_HORIZONTAL_PIXELS / 2) { + printer->buffer[printer->currentIndex] = printer->byte; + ++printer->currentIndex; + } + break; + case GB_PRINTER_COMMAND_PRINT: + // TODO + break; + default: + break; + } +} + +static uint8_t GBPrinterWriteSC(struct GBSIODriver* driver, uint8_t value) { + struct GBPrinter* printer = (struct GBPrinter*) driver; + if ((value & 0x81) == 0x81) { + switch (printer->next) { + driver->p->pendingSB = 0; + case GB_PRINTER_BYTE_MAGIC_0: + if (printer->byte == 0x88) { + printer->next = GB_PRINTER_BYTE_MAGIC_1; + } else { + printer->next = GB_PRINTER_BYTE_MAGIC_0; + } + break; + case GB_PRINTER_BYTE_MAGIC_1: + if (printer->byte == 0x33) { + printer->next = GB_PRINTER_BYTE_COMMAND; + } else { + printer->next = GB_PRINTER_BYTE_MAGIC_0; + } + break; + case GB_PRINTER_BYTE_COMMAND: + printer->checksum = printer->byte; + printer->command = printer->byte; + printer->next = GB_PRINTER_BYTE_COMPRESSION; + break; + case GB_PRINTER_BYTE_COMPRESSION: + printer->checksum += printer->byte; + printer->compression = printer->byte; + printer->next = GB_PRINTER_BYTE_LENGTH_0; + break; + case GB_PRINTER_BYTE_LENGTH_0: + printer->checksum += printer->byte; + printer->remainingBytes = printer->byte; + printer->next = GB_PRINTER_BYTE_LENGTH_1; + break; + case GB_PRINTER_BYTE_LENGTH_1: + printer->checksum += printer->byte; + printer->remainingBytes |= printer->byte << 8; + if (printer->remainingBytes) { + printer->next = GB_PRINTER_BYTE_DATA; + } else { + printer->next = GB_PRINTER_BYTE_CHECKSUM_0; + } + switch (printer->command) { + case GB_PRINTER_COMMAND_INIT: + printer->currentIndex = 0; + printer->status &= ~(GB_PRINTER_STATUS_PRINT_REQ | GB_PRINTER_STATUS_READY); + break; + default: + break; + } + break; + case GB_PRINTER_BYTE_DATA: + printer->checksum += printer->byte; + if (!printer->compression) { + _processByte(printer); + } else { + printer->next = printer->byte & 0x80 ? GB_PRINTER_BYTE_COMPRESSED_DATUM : GB_PRINTER_BYTE_UNCOMPRESSED_DATA; + printer->remainingCmpBytes = (printer->byte & 0x7F) + 1; + if (printer->byte & 0x80) { + ++printer->remainingCmpBytes; + } + } + --printer->remainingBytes; + if (!printer->remainingBytes) { + printer->next = GB_PRINTER_BYTE_CHECKSUM_0; + } + break; + case GB_PRINTER_BYTE_UNCOMPRESSED_DATA: + printer->checksum += printer->byte; + _processByte(printer); + --printer->remainingCmpBytes; + if (!printer->remainingCmpBytes) { + printer->next = GB_PRINTER_BYTE_DATA; + } + --printer->remainingBytes; + if (!printer->remainingBytes) { + printer->next = GB_PRINTER_BYTE_CHECKSUM_0; + } + break; + case GB_PRINTER_BYTE_COMPRESSED_DATUM: + printer->checksum += printer->byte; + while (printer->remainingCmpBytes) { + _processByte(printer); + --printer->remainingCmpBytes; + } + --printer->remainingBytes; + if (!printer->remainingBytes) { + printer->next = GB_PRINTER_BYTE_CHECKSUM_0; + } else { + printer->next = GB_PRINTER_BYTE_DATA; + } + break; + case GB_PRINTER_BYTE_CHECKSUM_0: + printer->checksum ^= printer->byte; + printer->next = GB_PRINTER_BYTE_CHECKSUM_1; + break; + case GB_PRINTER_BYTE_CHECKSUM_1: + printer->checksum ^= printer->byte << 8; + printer->next = GB_PRINTER_BYTE_KEEPALIVE; + break; + case GB_PRINTER_BYTE_KEEPALIVE: + driver->p->pendingSB = 0x81; + printer->next = GB_PRINTER_BYTE_STATUS; + break; + case GB_PRINTER_BYTE_STATUS: + switch (printer->command) { + case GB_PRINTER_COMMAND_DATA: + if (printer->currentIndex >= 0x280 && !(printer->status & GB_PRINTER_STATUS_CHECKSUM_ERROR)) { + printer->status |= GB_PRINTER_STATUS_READY; + } + break; + case GB_PRINTER_COMMAND_PRINT: + if (printer->currentIndex >= GB_VIDEO_HORIZONTAL_PIXELS * 2) { + printer->printWait = 0; + } + break; + case GB_PRINTER_COMMAND_STATUS: + if (!printer->printWait) { + printer->status &= ~GB_PRINTER_STATUS_READY; + printer->status |= GB_PRINTER_STATUS_PRINTING | GB_PRINTER_STATUS_PRINT_REQ; + if (printer->print) { + size_t y; + for (y = 0; y < printer->currentIndex / (2 * GB_VIDEO_HORIZONTAL_PIXELS); ++y) { + uint8_t lineBuffer[GB_VIDEO_HORIZONTAL_PIXELS * 2]; + uint8_t* buffer = &printer->buffer[sizeof(lineBuffer) * y]; + size_t i; + for (i = 0; i < sizeof(lineBuffer); i += 2) { + uint8_t ilo = buffer[i + 0x0]; + uint8_t ihi = buffer[i + 0x1]; + uint8_t olo = 0; + uint8_t ohi = 0; + olo |= ((ihi & 0x80) >> 0) | ((ilo & 0x80) >> 1); + olo |= ((ihi & 0x40) >> 1) | ((ilo & 0x40) >> 2); + olo |= ((ihi & 0x20) >> 2) | ((ilo & 0x20) >> 3); + olo |= ((ihi & 0x10) >> 3) | ((ilo & 0x10) >> 4); + ohi |= ((ihi & 0x08) << 4) | ((ilo & 0x08) << 3); + ohi |= ((ihi & 0x04) << 3) | ((ilo & 0x04) << 2); + ohi |= ((ihi & 0x02) << 2) | ((ilo & 0x02) << 1); + ohi |= ((ihi & 0x01) << 1) | ((ilo & 0x01) << 0); + lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) & ~1)] = olo; + lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) | 1)] = ohi; + } + memcpy(buffer, lineBuffer, sizeof(lineBuffer)); + } + printer->print(printer, printer->currentIndex * 4 / GB_VIDEO_HORIZONTAL_PIXELS, printer->buffer); + } + } + if (printer->printWait >= 0) { + --printer->printWait; + } + default: + break; + } + driver->p->pendingSB = printer->status; + printer->next = GB_PRINTER_BYTE_MAGIC_0; + break; + } + printer->byte = 0; + } + return value; +} + +void GBPrinterDonePrinting(struct GBPrinter* printer) { + printer->status &= ~GB_PRINTER_STATUS_PRINTING; +}
M
src/platform/qt/CMakeLists.txt
→
src/platform/qt/CMakeLists.txt
@@ -93,6 +93,7 @@ MultiplayerController.cpp
ObjView.cpp OverrideView.cpp PaletteView.cpp + PrinterView.cpp ROMInfo.cpp SavestateButton.cpp SensorView.cpp@@ -123,6 +124,7 @@ MemoryView.ui
ObjView.ui OverrideView.ui PaletteView.ui + PrinterView.ui ROMInfo.ui SensorView.ui SettingsView.ui
M
src/platform/qt/CoreController.cpp
→
src/platform/qt/CoreController.cpp
@@ -590,6 +590,59 @@ vf->close(vf);
#endif } +void CoreController::attachPrinter() { +#ifdef M_CORE_GB + if (platform() != PLATFORM_GB) { + return; + } + GB* gb = static_cast<GB*>(m_threadContext.core->board); + clearMultiplayerController(); + GBPrinterCreate(&m_printer.d); + m_printer.parent = this; + m_printer.d.print = [](GBPrinter* printer, int height, const uint8_t* data) { + QGBPrinter* qPrinter = reinterpret_cast<QGBPrinter*>(printer); + QImage image(GB_VIDEO_HORIZONTAL_PIXELS, height, QImage::Format_Indexed8); + QVector<QRgb> colors; + colors.append(qRgb(0xF8, 0xF8, 0xF8)); + colors.append(qRgb(0xA8, 0xA8, 0xA8)); + colors.append(qRgb(0x50, 0x50, 0x50)); + colors.append(qRgb(0x00, 0x00, 0x00)); + image.setColorTable(colors); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; x += 4) { + uint8_t byte = data[(x + y * GB_VIDEO_HORIZONTAL_PIXELS) / 4]; + image.setPixel(x + 0, y, (byte & 0xC0) >> 6); + image.setPixel(x + 1, y, (byte & 0x30) >> 4); + image.setPixel(x + 2, y, (byte & 0x0C) >> 2); + image.setPixel(x + 3, y, (byte & 0x03) >> 0); + } + } + QMetaObject::invokeMethod(qPrinter->parent, "imagePrinted", Q_ARG(const QImage&, image)); + }; + GBSIOSetDriver(&gb->sio, &m_printer.d.d); +#endif +} + +void CoreController::detachPrinter() { +#ifdef M_CORE_GB + if (platform() != PLATFORM_GB) { + return; + } + GB* gb = static_cast<GB*>(m_threadContext.core->board); + GBPrinterDonePrinting(&m_printer.d); + GBSIOSetDriver(&gb->sio, nullptr); +#endif +} + +void CoreController::endPrint() { +#ifdef M_CORE_GB + if (platform() != PLATFORM_GB) { + return; + } + GBPrinterDonePrinting(&m_printer.d); +#endif +} + void CoreController::setAVStream(mAVStream* stream) { Interrupter interrupter(this); m_threadContext.core->setAVStream(m_threadContext.core, stream);
M
src/platform/qt/CoreController.h
→
src/platform/qt/CoreController.h
@@ -22,6 +22,10 @@ #include <mgba/core/interface.h>
#include <mgba/core/thread.h> #include <mgba/core/tile-cache.h> +#ifdef M_CORE_GB +#include <mgba/internal/gb/sio/printer.h> +#endif + struct mCore; namespace QGBA {@@ -123,6 +127,10 @@
void importSharkport(const QString& path); void exportSharkport(const QString& path); + void attachPrinter(); + void detachPrinter(); + void endPrint(); + void setAVStream(mAVStream*); void clearAVStream();@@ -148,6 +156,8 @@
void unimplementedBiosCall(int); void statusPosted(const QString& message); void logPosted(int level, int category, const QString& log); + + void imagePrinted(const QImage&); private: void updateKeys();@@ -195,6 +205,13 @@ MultiplayerController* m_multiplayer = nullptr;
mVideoLogContext* m_vl = nullptr; VFile* m_vlVf = nullptr; + +#ifdef M_CORE_GB + struct QGBPrinter { + GBPrinter d; + CoreController* parent; + } m_printer; +#endif }; }
M
src/platform/qt/MultiplayerController.cpp
→
src/platform/qt/MultiplayerController.cpp
@@ -233,6 +233,9 @@ return false;
} void MultiplayerController::detachGame(CoreController* controller) { + if (m_players.empty()) { + return; + } mCoreThread* thread = controller->thread(); if (!thread) { return;
A
src/platform/qt/PrinterView.cpp
@@ -0,0 +1,73 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "PrinterView.h" + +#include "CoreController.h" +#include "GBAApp.h" + +#include <QPainter> + +using namespace QGBA; + +PrinterView::PrinterView(std::shared_ptr<CoreController> controller, QWidget* parent) + : QDialog(parent) + , m_controller(controller) +{ + m_ui.setupUi(this); + + connect(controller.get(), &CoreController::imagePrinted, this, &PrinterView::printImage); + connect(&m_timer, &QTimer::timeout, this, &PrinterView::printLine); + connect(m_ui.hurry, &QAbstractButton::clicked, this, &PrinterView::printAll); + connect(m_ui.tear, &QAbstractButton::clicked, this, &PrinterView::clear); + connect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, &PrinterView::save); + m_timer.setInterval(80); + clear(); +} + +PrinterView::~PrinterView() { + m_controller->detachPrinter(); +} + +void PrinterView::save() { + QString filename = GBAApp::app()->getSaveFileName(this, tr("Save Printout"), tr("Portable Network Graphics (*.png)")); + if (filename.isNull()) { + return; + } + m_image.save(filename); +} + +void PrinterView::clear() { + m_ui.image->setFixedHeight(0); + m_ui.image->clear(); + m_ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false); +} + +void PrinterView::printImage(const QImage& image) { + QPixmap pixmap(image.width(), image.height() + m_image.height()); + QPainter painter(&pixmap); + painter.drawPixmap(0, 0, m_image); + painter.drawImage(0, m_image.height(), image); + m_image = pixmap; + m_ui.image->setPixmap(m_image); + m_timer.start(); + m_ui.hurry->setEnabled(true); +} + +void PrinterView::printLine() { + m_ui.image->setFixedHeight(m_ui.image->height() + 1); + m_ui.scrollArea->ensureVisible(0, m_ui.image->height(), 0, 0); + if (m_ui.image->height() >= m_image.height()) { + printAll(); + } +} + +void PrinterView::printAll() { + m_timer.stop(); + m_ui.image->setFixedHeight(m_image.height()); + m_controller->endPrint(); + m_ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true); + m_ui.hurry->setEnabled(false); +}
A
src/platform/qt/PrinterView.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_PRINTER_VIEW +#define QGBA_PRINTER_VIEW + +#include <QDialog> +#include <QPixmap> +#include <QTimer> + +#include <memory> + +#include "ui_PrinterView.h" + +namespace QGBA { + +class CoreController; + +class PrinterView : public QDialog { +Q_OBJECT + +public: + PrinterView(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr); + ~PrinterView(); + +signals: + void donePrinting(); + +public slots: + void save(); + void clear(); + +private slots: + void printImage(const QImage&); + void printLine(); + void printAll(); + +private: + Ui::PrinterView m_ui; + QPixmap m_image; + QTimer m_timer; + + std::shared_ptr<CoreController> m_controller; +}; + +} + +#endif
A
src/platform/qt/PrinterView.ui
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PrinterView</class> + <widget class="QWidget" name="PrinterView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>241</width> + <height>311</height> + </rect> + </property> + <property name="windowTitle"> + <string>Game Boy Printer</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item alignment="Qt::AlignHCenter"> + <widget class="QScrollArea" name="scrollArea"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="image"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>160</width> + <height>1</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>160</width> + <height>16777215</height> + </size> + </property> + <property name="alignment"> + <set>Qt::AlignHCenter|Qt::AlignTop</set> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="hurry"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Hurry up!</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="tear"> + <property name="text"> + <string>Tear off</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Close|QDialogButtonBox::Save</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>PrinterView</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>112</x> + <y>226</y> + </hint> + <hint type="destinationlabel"> + <x>112</x> + <y>123</y> + </hint> + </hints> + </connection> + </connections> +</ui>
M
src/platform/qt/Window.cpp
→
src/platform/qt/Window.cpp
@@ -41,6 +41,7 @@ #include "MemoryView.h"
#include "OverrideView.h" #include "ObjView.h" #include "PaletteView.h" +#include "PrinterView.h" #include "ROMInfo.h" #include "SensorView.h" #include "SettingsView.h"@@ -1358,9 +1359,7 @@ fpsTargetOption->addValue(tr("120"), 120, target);
fpsTargetOption->addValue(tr("240"), 240, target); m_config->updateOption("fpsTarget"); -#if defined(USE_PNG) || defined(USE_FFMPEG) || defined(USE_MAGICK) avMenu->addSeparator(); -#endif #ifdef USE_PNG QAction* screenshot = new QAction(tr("Take &screenshot"), avMenu);@@ -1396,6 +1395,18 @@ m_controller->endVideoLog();
}); addControlledAction(avMenu, stopVL, "stopVL"); m_gameActions.append(stopVL); + +#ifdef M_CORE_GB + QAction* gbPrint = new QAction(tr("Game Boy Printer..."), avMenu); + connect(gbPrint, &QAction::triggered, [this]() { + PrinterView* view = new PrinterView(m_controller); + openView(view); + m_controller->attachPrinter(); + + }); + addControlledAction(avMenu, gbPrint, "gbPrint"); + m_gameActions.append(gbPrint); +#endif avMenu->addSeparator(); m_videoLayers = avMenu->addMenu(tr("Video layers"));@@ -1807,6 +1818,7 @@ m_pendingPatch = QString();
} m_controller->start(); + m_controller->loadConfig(m_config); } WindowBackground::WindowBackground(QWidget* parent)