Initial Qt Commit

This commit is contained in:
Joakim L. Gilje 2021-11-25 10:20:56 +01:00
parent 81a49c8c5c
commit c587a02b1a
66 changed files with 8434 additions and 1 deletions

View File

@ -60,6 +60,7 @@ option(MUNT "MUNT" ON)
option(VRAMDUMP "Video RAM dumping" OFF)
option(DINPUT "DirectInput" OFF)
option(DISCORD "Discord integration" ON)
option(QT "QT GUI" ON)
option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF)

View File

@ -221,7 +221,10 @@ add_subdirectory(sio)
add_subdirectory(scsi)
add_subdirectory(sound)
add_subdirectory(video)
if(APPLE)
if (QT)
add_subdirectory(qt)
elseif(APPLE)
add_subdirectory(mac)
add_subdirectory(unix)
elseif(WIN32)

86
src/qt/CMakeLists.txt Normal file
View File

@ -0,0 +1,86 @@
find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
add_library(plat STATIC qt.c qt_main.cpp qt_platform.cpp qt_midi.cpp cpp11_thread.cpp)
add_library(ui STATIC
qt_ui.cpp
qt_cdrom.c
qt_sdl.c
qt_mainwindow.cpp
qt_mainwindow.hpp
qt_mainwindow.ui
qt_settings.cpp
qt_settings.hpp
qt_settings.ui
qt_settingsmachine.cpp
qt_settingsmachine.hpp
qt_settingsmachine.ui
qt_settingsdisplay.cpp
qt_settingsdisplay.hpp
qt_settingsdisplay.ui
qt_settingsinput.cpp
qt_settingsinput.hpp
qt_settingsinput.ui
qt_settingssound.cpp
qt_settingssound.hpp
qt_settingssound.ui
qt_settingsnetwork.cpp
qt_settingsnetwork.hpp
qt_settingsnetwork.ui
qt_settingsports.cpp
qt_settingsports.hpp
qt_settingsports.ui
qt_settingsstoragecontrollers.cpp
qt_settingsstoragecontrollers.hpp
qt_settingsstoragecontrollers.ui
qt_settingsharddisks.cpp
qt_settingsharddisks.hpp
qt_settingsharddisks.ui
qt_settingsfloppycdrom.cpp
qt_settingsfloppycdrom.hpp
qt_settingsfloppycdrom.ui
qt_settingsotherremovable.cpp
qt_settingsotherremovable.hpp
qt_settingsotherremovable.ui
qt_settingsotherperipherals.cpp
qt_settingsotherperipherals.hpp
qt_settingsotherperipherals.ui
qt_deviceconfig.cpp
qt_deviceconfig.hpp
qt_deviceconfig.ui
qt_filefield.cpp
qt_filefield.hpp
qt_filefield.ui
qt_harddiskdialog.cpp
qt_harddiskdialog.hpp
qt_harddiskdialog.ui
qt_harddrive_common.cpp
qt_harddrive_common.hpp
qt_models_common.cpp
qt_models_common.hpp
../qt_resources.qrc
)
target_link_libraries(
plat
PRIVATE
Qt5::Widgets
)
target_link_libraries(
ui
PRIVATE
Qt5::Widgets
)

1
src/qt/TODO Normal file
View File

@ -0,0 +1 @@
* Joystick support

130
src/qt/cpp11_thread.cpp Normal file
View File

@ -0,0 +1,130 @@
#include <mutex>
#include <atomic>
#include <thread>
#include <condition_variable>
#include <86box/plat.h>
struct event_cpp11_t
{
std::condition_variable cond;
std::mutex mutex;
std::atomic_bool state = false;
};
extern "C" {
thread_t *
thread_create(void (*thread_rout)(void *param), void *param)
{
auto thread = new std::thread([thread_rout, param] {
thread_rout(param);
});
return thread;
}
mutex_t *
thread_create_mutex_with_spin_count(unsigned int spin_count)
{
/* Setting spin count of a mutex is not possible with pthreads. */
return thread_create_mutex();
}
int
thread_wait(thread_t *arg, int timeout)
{
(void) timeout;
auto thread = reinterpret_cast<std::thread*>(arg);
thread->join();
return 0;
}
mutex_t *
thread_create_mutex(void)
{
auto mutex = new std::mutex;
return mutex;
}
int
thread_wait_mutex(mutex_t *_mutex)
{
if (_mutex == nullptr)
return(0);
auto mutex = reinterpret_cast<std::mutex*>(_mutex);
mutex->lock();
return 1;
}
int
thread_release_mutex(mutex_t *_mutex)
{
if (_mutex == nullptr)
return(0);
auto mutex = reinterpret_cast<std::mutex*>(_mutex);
mutex->unlock();
return 1;
}
void
thread_close_mutex(mutex_t *_mutex)
{
auto mutex = reinterpret_cast<std::mutex*>(_mutex);
delete mutex;
}
event_t *
thread_create_event()
{
auto ev = new event_cpp11_t;
return ev;
}
int
thread_wait_event(event_t *handle, int timeout)
{
auto event = reinterpret_cast<event_cpp11_t*>(handle);
auto lock = std::unique_lock<std::mutex>(event->mutex);
if (timeout < 0) {
event->cond.wait(lock, [=] { return event->state.load(); });
} else {
auto to = std::chrono::system_clock::now() + std::chrono::milliseconds(timeout);
std::cv_status status;
do {
status = event->cond.wait_until(lock, to);
} while ((status != std::cv_status::timeout) && !event->state);
if (status == std::cv_status::timeout) {
return 1;
}
}
return 0;
}
void
thread_set_event(event_t *handle)
{
auto event = reinterpret_cast<event_cpp11_t*>(handle);
event->state = true;
event->cond.notify_all();
}
void
thread_reset_event(event_t *handle)
{
auto event = reinterpret_cast<event_cpp11_t*>(handle);
event->state = false;
}
void
thread_destroy_event(event_t *handle)
{
auto event = reinterpret_cast<event_cpp11_t*>(handle);
delete event;
}
}

70
src/qt/qt.c Normal file
View File

@ -0,0 +1,70 @@
/*
* C functionality for Qt platform, where the C equivalent is not easily
* implemented in Qt
*/
#include <stdint.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/plat.h>
#include <86box/timer.h>
#include <86box/nvr.h>
#include "qt_sdl.h"
int qt_nvr_save(void) {
return nvr_save();
}
char icon_set[256] = ""; /* name of the iconset to be used */
wchar_t* plat_get_string(int i)
{
switch (i)
{
case IDS_2077:
return L"Click to capture mouse.";
case IDS_2078:
return L"Press CTRL-END to release mouse";
case IDS_2079:
return L"Press CTRL-END or middle button to release mouse";
case IDS_2080:
return L"Failed to initialize FluidSynth";
case IDS_4099:
return L"MFM/RLL or ESDI CD-ROM drives never existed";
case IDS_2093:
return L"Failed to set up PCap";
case IDS_2094:
return L"No PCap devices found";
case IDS_2110:
return L"Unable to initialize FreeType";
case IDS_2111:
return L"Unable to initialize SDL, libsdl2 is required";
case IDS_2131:
return L"libfreetype is required for ESC/P printer emulation.";
case IDS_2132:
return L"libgs is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files.";
case IDS_2129:
return L"Make sure libpcap is installed and that you are on a libpcap-compatible network connection.";
case IDS_2114:
return L"Unable to initialize Ghostscript";
case IDS_2063:
return L"Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine.";
case IDS_2064:
return L"Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card.";
case IDS_2128:
return L"Hardware not available";
}
return L"";
}
int
plat_vidapi(char* api) {
return 0;
}
char* plat_vidapi_name(int api) {
return "default";
}

264
src/qt/qt_cdrom.c Normal file
View File

@ -0,0 +1,264 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Handle the platform-side of CDROM/ZIP/MO drives.
*
*
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2016-2018 Miran Grca.
* Copyright 2017,2018 Fred N. van Kempen.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/config.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/cassette.h>
#include <86box/cartridge.h>
#include <86box/fdd.h>
#include <86box/hdd.h>
#include <86box/scsi_device.h>
#include <86box/cdrom.h>
#include <86box/mo.h>
#include <86box/zip.h>
#include <86box/scsi_disk.h>
#include <86box/plat.h>
#include <86box/ui.h>
void
cassette_mount(char *fn, uint8_t wp)
{
pc_cas_set_fname(cassette, NULL);
memset(cassette_fname, 0, sizeof(cassette_fname));
cassette_ui_writeprot = wp;
pc_cas_set_fname(cassette, fn);
if (fn != NULL)
memcpy(cassette_fname, fn, MIN(511, strlen(fn)));
ui_sb_update_icon_state(SB_CASSETTE, (fn == NULL) ? 1 : 0);
//media_menu_update_cassette();
ui_sb_update_tip(SB_CASSETTE);
config_save();
}
void
cassette_eject(void)
{
pc_cas_set_fname(cassette, NULL);
memset(cassette_fname, 0x00, sizeof(cassette_fname));
ui_sb_update_icon_state(SB_CASSETTE, 1);
//media_menu_update_cassette();
ui_sb_update_tip(SB_CASSETTE);
config_save();
}
void
cartridge_mount(uint8_t id, char *fn, uint8_t wp)
{
cart_close(id);
cart_load(id, fn);
ui_sb_update_icon_state(SB_CARTRIDGE | id, strlen(cart_fns[id]) ? 0 : 1);
//media_menu_update_cartridge(id);
ui_sb_update_tip(SB_CARTRIDGE | id);
config_save();
}
void
cartridge_eject(uint8_t id)
{
cart_close(id);
ui_sb_update_icon_state(SB_CARTRIDGE | id, 1);
//media_menu_update_cartridge(id);
ui_sb_update_tip(SB_CARTRIDGE | id);
config_save();
}
void
floppy_mount(uint8_t id, char *fn, uint8_t wp)
{
fdd_close(id);
ui_writeprot[id] = wp;
fdd_load(id, fn);
ui_sb_update_icon_state(SB_FLOPPY | id, strlen(floppyfns[id]) ? 0 : 1);
//media_menu_update_floppy(id);
ui_sb_update_tip(SB_FLOPPY | id);
config_save();
}
void
floppy_eject(uint8_t id)
{
fdd_close(id);
ui_sb_update_icon_state(SB_FLOPPY | id, 1);
//media_menu_update_floppy(id);
ui_sb_update_tip(SB_FLOPPY | id);
config_save();
}
void
plat_cdrom_ui_update(uint8_t id, uint8_t reload)
{
cdrom_t *drv = &cdrom[id];
if (drv->host_drive == 0) {
ui_sb_update_icon_state(SB_CDROM|id, 1);
} else {
ui_sb_update_icon_state(SB_CDROM|id, 0);
}
//media_menu_update_cdrom(id);
ui_sb_update_tip(SB_CDROM|id);
}
void
cdrom_mount(uint8_t id, char *fn)
{
cdrom[id].prev_host_drive = cdrom[id].host_drive;
strcpy(cdrom[id].prev_image_path, cdrom[id].image_path);
if (cdrom[id].ops && cdrom[id].ops->exit)
cdrom[id].ops->exit(&(cdrom[id]));
cdrom[id].ops = NULL;
memset(cdrom[id].image_path, 0, sizeof(cdrom[id].image_path));
cdrom_image_open(&(cdrom[id]), fn);
/* Signal media change to the emulated machine. */
if (cdrom[id].insert)
cdrom[id].insert(cdrom[id].priv);
cdrom[id].host_drive = (strlen(cdrom[id].image_path) == 0) ? 0 : 200;
if (cdrom[id].host_drive == 200) {
ui_sb_update_icon_state(SB_CDROM | id, 0);
} else {
ui_sb_update_icon_state(SB_CDROM | id, 1);
}
//media_menu_update_cdrom(id);
ui_sb_update_tip(SB_CDROM | id);
config_save();
}
void
mo_eject(uint8_t id)
{
mo_t *dev = (mo_t *) mo_drives[id].priv;
mo_disk_close(dev);
if (mo_drives[id].bus_type) {
/* Signal disk change to the emulated machine. */
mo_insert(dev);
}
ui_sb_update_icon_state(SB_MO | id, 1);
//media_menu_update_mo(id);
ui_sb_update_tip(SB_MO | id);
config_save();
}
void
mo_mount(uint8_t id, char *fn, uint8_t wp)
{
mo_t *dev = (mo_t *) mo_drives[id].priv;
mo_disk_close(dev);
mo_drives[id].read_only = wp;
mo_load(dev, fn);
mo_insert(dev);
ui_sb_update_icon_state(SB_MO | id, strlen(mo_drives[id].image_path) ? 0 : 1);
//media_menu_update_mo(id);
ui_sb_update_tip(SB_MO | id);
config_save();
}
void
mo_reload(uint8_t id)
{
mo_t *dev = (mo_t *) mo_drives[id].priv;
mo_disk_reload(dev);
if (strlen(mo_drives[id].image_path) == 0) {
ui_sb_update_icon_state(SB_MO|id, 1);
} else {
ui_sb_update_icon_state(SB_MO|id, 0);
}
//media_menu_update_mo(id);
ui_sb_update_tip(SB_MO|id);
config_save();
}
void
zip_eject(uint8_t id)
{
zip_t *dev = (zip_t *) zip_drives[id].priv;
zip_disk_close(dev);
if (zip_drives[id].bus_type) {
/* Signal disk change to the emulated machine. */
zip_insert(dev);
}
ui_sb_update_icon_state(SB_ZIP | id, 1);
//media_menu_update_zip(id);
ui_sb_update_tip(SB_ZIP | id);
config_save();
}
void
zip_mount(uint8_t id, char *fn, uint8_t wp)
{
zip_t *dev = (zip_t *) zip_drives[id].priv;
zip_disk_close(dev);
zip_drives[id].read_only = wp;
zip_load(dev, fn);
zip_insert(dev);
ui_sb_update_icon_state(SB_ZIP | id, strlen(zip_drives[id].image_path) ? 0 : 1);
//media_menu_update_zip(id);
ui_sb_update_tip(SB_ZIP | id);
config_save();
}
void
zip_reload(uint8_t id)
{
zip_t *dev = (zip_t *) zip_drives[id].priv;
zip_disk_reload(dev);
if (strlen(zip_drives[id].image_path) == 0) {
ui_sb_update_icon_state(SB_ZIP|id, 1);
} else {
ui_sb_update_icon_state(SB_ZIP|id, 0);
}
//media_menu_update_zip(id);
ui_sb_update_tip(SB_ZIP|id);
config_save();
}

157
src/qt/qt_deviceconfig.cpp Normal file
View File

@ -0,0 +1,157 @@
#include "qt_deviceconfig.hpp"
#include "ui_qt_deviceconfig.h"
#include <QDebug>
#include <QComboBox>
#include <QFormLayout>
#include <QSpinBox>
#include <QCheckBox>
extern "C" {
#include <86box/86box.h>
#include <86box/config.h>
#include <86box/device.h>
}
#include "qt_filefield.hpp"
DeviceConfig::DeviceConfig(QWidget *parent) :
QDialog(parent),
ui(new Ui::DeviceConfig)
{
ui->setupUi(this);
}
DeviceConfig::~DeviceConfig()
{
delete ui;
}
void DeviceConfig::ConfigureDevice(const _device_* device) {
DeviceConfig dc;
dc.setWindowTitle(QString("%1 Device Configuration").arg(device->name));
device_context_t device_context;
device_set_context(&device_context, device, 0);
const auto* config = device->config;
while (config->type != -1) {
switch (config->type) {
case CONFIG_BINARY:
{
auto value = config_get_int(device_context.name, const_cast<char*>(config->name), config->default_int);
auto* cbox = new QCheckBox();
cbox->setObjectName(config->name);
cbox->setChecked(value > 0);
dc.ui->formLayout->addRow(config->description, cbox);
break;
}
case CONFIG_SELECTION:
case CONFIG_MIDI:
case CONFIG_MIDI_IN:
case CONFIG_HEX16:
case CONFIG_HEX20:
{
auto* cbox = new QComboBox();
cbox->setObjectName(config->name);
auto* model = cbox->model();
int currentIndex = -1;
int selected = config_get_int(device_context.name, const_cast<char*>(config->name), config->default_int);
for (auto* sel = config->selection; (sel->description != nullptr) && (strlen(sel->description) > 0); ++sel) {
int rows = model->rowCount();
model->insertRow(rows);
auto idx = model->index(rows, 0);
model->setData(idx, sel->description, Qt::DisplayRole);
model->setData(idx, sel->value, Qt::UserRole);
if (selected == sel->value) {
currentIndex = idx.row();
}
}
dc.ui->formLayout->addRow(config->description, cbox);
cbox->setCurrentIndex(currentIndex);
break;
}
case CONFIG_SPINNER:
{
int value = config_get_int(device_context.name, const_cast<char*>(config->name), config->default_int);
auto* spinBox = new QSpinBox();
spinBox->setObjectName(config->name);
spinBox->setMaximum(config->spinner.max);
spinBox->setMinimum(config->spinner.min);
if (config->spinner.step > 0) {
spinBox->setSingleStep(config->spinner.step);
}
spinBox->setValue(value);
dc.ui->formLayout->addRow(config->description, spinBox);
break;
}
case CONFIG_FNAME:
{
auto* fileName = config_get_string(device_context.name, const_cast<char*>(config->name), const_cast<char*>(config->default_string));
auto* fileField = new FileField();
fileField->setObjectName(config->name);
fileField->setFileName(fileName);
dc.ui->formLayout->addRow(config->description, fileField);
break;
}
}
++config;
}
int res = dc.exec();
if (res == QDialog::Accepted) {
config = device->config;
while (config->type != -1) {
switch (config->type) {
case CONFIG_BINARY:
{
auto* cbox = dc.findChild<QCheckBox*>(config->name);
config_set_int(device_context.name, const_cast<char*>(config->name), cbox->isChecked() ? 1 : 0);
break;
}
case CONFIG_SELECTION:
case CONFIG_MIDI:
case CONFIG_MIDI_IN:
case CONFIG_HEX16:
case CONFIG_HEX20:
{
auto* cbox = dc.findChild<QComboBox*>(config->name);
config_set_int(device_context.name, const_cast<char*>(config->name), cbox->currentData().toInt());
break;
}
case CONFIG_FNAME:
{
auto* fbox = dc.findChild<FileField*>(config->name);
auto fileName = fbox->fileName().toUtf8();
config_set_string(device_context.name, const_cast<char*>(config->name), fileName.data());
break;
}
case CONFIG_SPINNER:
{
auto* spinBox = dc.findChild<QSpinBox*>(config->name);
config_set_int(device_context.name, const_cast<char*>(config->name), spinBox->value());
break;
}
}
config++;
}
}
}
QString DeviceConfig::DeviceName(const _device_* device, const char *internalName, int bus) {
if (QStringLiteral("none") == internalName) {
return "None";
} else if (QStringLiteral("internal") == internalName) {
return "Internal";
} else if (device == nullptr) {
return QString();
} else {
char temp[512];
device_get_name(device, bus, temp);
return temp;
}
}

View File

@ -0,0 +1,28 @@
#ifndef QT_DEVICECONFIG_HPP
#define QT_DEVICECONFIG_HPP
#include <QDialog>
extern "C" {
struct _device_;
}
namespace Ui {
class DeviceConfig;
}
class DeviceConfig : public QDialog
{
Q_OBJECT
public:
explicit DeviceConfig(QWidget *parent = nullptr);
~DeviceConfig();
static void ConfigureDevice(const _device_* device);
static QString DeviceName(const _device_* device, const char* internalName, int bus);
private:
Ui::DeviceConfig *ui;
};
#endif // QT_DEVICECONFIG_HPP

74
src/qt/qt_deviceconfig.ui Normal file
View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DeviceConfig</class>
<widget class="QDialog" name="DeviceConfig">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout"/>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DeviceConfig</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DeviceConfig</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

34
src/qt/qt_filefield.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "qt_filefield.hpp"
#include "ui_qt_filefield.h"
#include <QFileDialog>
FileField::FileField(QWidget *parent) :
QWidget(parent),
ui(new Ui::FileField)
{
ui->setupUi(this);
}
FileField::~FileField()
{
delete ui;
}
void FileField::setFileName(const QString &fileName) {
fileName_ = fileName;
ui->label->setText(fileName);
}
void FileField::on_pushButton_clicked() {
QString fileName;
if (createFile_) {
fileName = QFileDialog::getSaveFileName(this, "Create...");
} else {
fileName = QFileDialog::getOpenFileName(this, "Open...");
}
fileName_ = fileName;
ui->label->setText(fileName);
emit fileSelected(fileName);
}

35
src/qt/qt_filefield.hpp Normal file
View File

@ -0,0 +1,35 @@
#ifndef QT_FILEFIELD_HPP
#define QT_FILEFIELD_HPP
#include <QWidget>
namespace Ui {
class FileField;
}
class FileField : public QWidget
{
Q_OBJECT
public:
explicit FileField(QWidget *parent = nullptr);
~FileField();
QString fileName() const { return fileName_; }
void setFileName(const QString& fileName);
void setCreateFile(bool createFile) { createFile_ = createFile; }
signals:
void fileSelected(const QString& fileName);
private slots:
void on_pushButton_clicked();
private:
Ui::FileField *ui;
QString fileName_;
bool createFile_ = false;
};
#endif // QT_FILEFIELD_HPP

47
src/qt/qt_filefield.ui Normal file
View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FileField</class>
<widget class="QWidget" name="FileField">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,1">
<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>
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,706 @@
#include "qt_harddiskdialog.hpp"
#include "ui_qt_harddiskdialog.h"
extern "C" {
#include <86box/86box.h>
#include <86box/hdd.h>
#include "../disk/minivhd/minivhd.h"
#include "../disk/minivhd/minivhd_util.h"
}
#include <thread>
#include <QMessageBox>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QFileDialog>
#include <QProgressDialog>
#include <QPushButton>
#include "qt_harddrive_common.hpp"
#include "qt_models_common.hpp"
HarddiskDialog::HarddiskDialog(bool existing, QWidget *parent) :
QDialog(parent),
ui(new Ui::HarddiskDialog)
{
ui->setupUi(this);
if (existing) {
setWindowTitle("Add Existing Hard Disk");
ui->lineEditCylinders->setEnabled(false);
ui->lineEditHeads->setEnabled(false);
ui->lineEditSectors->setEnabled(false);
ui->lineEditSize->setEnabled(false);
ui->comboBoxType->setEnabled(false);
ui->comboBoxFormat->hide();
ui->labelFormat->hide();
connect(ui->fileField, &FileField::fileSelected, this, &HarddiskDialog::onExistingFileSelected);
} else {
setWindowTitle("Add New Hard Disk");
ui->fileField->setCreateFile(true);
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &HarddiskDialog::onCreateNewFile);
}
auto* model = ui->comboBoxFormat->model();
model->insertRows(0, 6);
model->setData(model->index(0, 0), "Raw image (.img)");
model->setData(model->index(1, 0), "HDI image (.hdi)");
model->setData(model->index(2, 0), "HDX image (.hdx)");
model->setData(model->index(3, 0), "Fixed-size VHD (.vhd)");
model->setData(model->index(4, 0), "Dynamic-size VHD (.vhd)");
model->setData(model->index(5, 0), "Differencing VHD (.vhd)");
model = ui->comboBoxBlockSize->model();
model->insertRows(0, 2);
model->setData(model->index(0, 0), "Large blocks (2 MiB)");
model->setData(model->index(1, 0), "Small blocks (512 KiB)");
ui->comboBoxBlockSize->hide();
ui->labelBlockSize->hide();
Harddrives::populateBuses(ui->comboBoxBus->model());
ui->comboBoxBus->setCurrentIndex(3);
model = ui->comboBoxType->model();
for (int i = 0; i < 127; i++) {
uint64_t size = ((uint64_t) hdd_table[i][0]) * hdd_table[i][1] * hdd_table[i][2];
uint64_t size_mb = size >> 11LL;
QString text = QString("%1 MiB (CHS: %2, %3, %4)").arg(size_mb).arg(hdd_table[i][0]).arg(hdd_table[i][1]).arg(hdd_table[i][2]);
Models::AddEntry(model, text, i);
}
Models::AddEntry(model, "Custom...", 127);
Models::AddEntry(model, "Custom (large)...", 128);
ui->lineEditSize->setValidator(new QIntValidator());
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
connect(ui->fileField, &FileField::fileSelected, this, [this] {
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
});
}
HarddiskDialog::~HarddiskDialog()
{
delete ui;
}
uint8_t HarddiskDialog::bus() const {
return static_cast<uint8_t>(ui->comboBoxBus->currentData().toUInt());
}
uint8_t HarddiskDialog::channel() const {
return static_cast<uint8_t>(ui->comboBoxChannel->currentData().toUInt());
}
QString HarddiskDialog::fileName() const {
return ui->fileField->fileName();
}
void HarddiskDialog::on_comboBoxFormat_currentIndexChanged(int index) {
bool enabled;
if (index == 5) { /* They switched to a diff VHD; disable the geometry fields. */
enabled = false;
ui->lineEditCylinders->setText(QStringLiteral("(N/A)"));
ui->lineEditHeads->setText(QStringLiteral("(N/A)"));
ui->lineEditSectors->setText(QStringLiteral("(N/A)"));
ui->lineEditSize->setText(QStringLiteral("(N/A)"));
} else {
enabled = true;
ui->lineEditCylinders->setText(QString::number(cylinders_));
ui->lineEditHeads->setText(QString::number(heads_));
ui->lineEditSectors->setText(QString::number(sectors_));
recalcSize();
}
ui->lineEditCylinders->setEnabled(enabled);
ui->lineEditHeads->setEnabled(enabled);
ui->lineEditSectors->setEnabled(enabled);
ui->lineEditSize->setEnabled(enabled);
ui->comboBoxType->setEnabled(enabled);
if (index < 4) {
ui->comboBoxBlockSize->hide();
ui->labelBlockSize->hide();
} else {
ui->comboBoxBlockSize->show();
ui->labelBlockSize->show();
}
}
/* If the disk geometry requested in the 86Box GUI is not compatible with the internal VHD geometry,
* we adjust it to the next-largest size that is compatible. On average, this will be a difference
* of about 21 MB, and should only be necessary for VHDs larger than 31.5 GB, so should never be more
* than a tenth of a percent change in size.
*/
static void adjust_86box_geometry_for_vhd(MVHDGeom *_86box_geometry, MVHDGeom *vhd_geometry)
{
if (_86box_geometry->cyl <= 65535) {
vhd_geometry->cyl = _86box_geometry->cyl;
vhd_geometry->heads = _86box_geometry->heads;
vhd_geometry->spt = _86box_geometry->spt;
return;
}
int desired_sectors = _86box_geometry->cyl * _86box_geometry->heads * _86box_geometry->spt;
if (desired_sectors > 267321600)
desired_sectors = 267321600;
int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */
if (remainder > 0)
desired_sectors += (85680 - remainder);
_86box_geometry->cyl = desired_sectors / (16 * 63);
_86box_geometry->heads = 16;
_86box_geometry->spt = 63;
vhd_geometry->cyl = desired_sectors / (16 * 255);
vhd_geometry->heads = 16;
vhd_geometry->spt = 255;
}
static HarddiskDialog* callbackPtr = nullptr;
static MVHDGeom create_drive_vhd_fixed(const QString& fileName, HarddiskDialog* p, uint16_t cyl, uint8_t heads, uint8_t spt) {
MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt };
MVHDGeom vhd_geometry;
adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry);
int vhd_error = 0;
QByteArray filenameBytes = fileName.toUtf8();
callbackPtr = p;
MVHDMeta *vhd = mvhd_create_fixed(filenameBytes.data(), vhd_geometry, &vhd_error, [](uint32_t current_sector, uint32_t total_sectors) {
callbackPtr->fileProgress((current_sector * 100) / total_sectors);
});
callbackPtr = nullptr;
if (vhd == NULL) {
_86box_geometry.cyl = 0;
_86box_geometry.heads = 0;
_86box_geometry.spt = 0;
} else {
mvhd_close(vhd);
}
return _86box_geometry;
}
static MVHDGeom create_drive_vhd_dynamic(const QString& fileName, uint16_t cyl, uint8_t heads, uint8_t spt, int blocksize) {
MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt };
MVHDGeom vhd_geometry;
adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry);
int vhd_error = 0;
QByteArray filenameBytes = fileName.toUtf8();
MVHDCreationOptions options;
options.block_size_in_sectors = blocksize;
options.path = filenameBytes.data();
options.size_in_bytes = 0;
options.geometry = vhd_geometry;
options.type = MVHD_TYPE_DYNAMIC;
MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error);
if (vhd == NULL) {
_86box_geometry.cyl = 0;
_86box_geometry.heads = 0;
_86box_geometry.spt = 0;
} else {
mvhd_close(vhd);
}
return _86box_geometry;
}
static MVHDGeom create_drive_vhd_diff(const QString& fileName, const QString& parentFileName, int blocksize) {
int vhd_error = 0;
QByteArray filenameBytes = fileName.toUtf8();
QByteArray parentFilenameBytes = fileName.toUtf8();
MVHDCreationOptions options;
options.block_size_in_sectors = blocksize;
options.path = filenameBytes.data();
options.parent_path = parentFilenameBytes.data();
options.type = MVHD_TYPE_DIFF;
MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error);
MVHDGeom vhd_geometry;
if (vhd == NULL) {
vhd_geometry.cyl = 0;
vhd_geometry.heads = 0;
vhd_geometry.spt = 0;
} else {
vhd_geometry = mvhd_get_geometry(vhd);
if (vhd_geometry.spt > 63) {
vhd_geometry.cyl = mvhd_calc_size_sectors(&vhd_geometry) / (16 * 63);
vhd_geometry.heads = 16;
vhd_geometry.spt = 63;
}
mvhd_close(vhd);
}
return vhd_geometry;
}
void HarddiskDialog::onCreateNewFile() {
qint64 size = ui->lineEditSize->text().toUInt() << 20U;
if (size > 0x1FFFFFFE00ll) {
QMessageBox::critical(this, "Disk image too large", "Disk images cannot be larger than 127 GiB");
return;
}
int img_format = ui->comboBoxFormat->currentIndex();
uint32_t zero = 0;
uint32_t base = 0x1000;
uint32_t sector_size = 512;
auto fileName = ui->fileField->fileName();
QString expectedSuffix;
switch (img_format) {
case 1:
expectedSuffix = "hdi";
break;
case 2:
expectedSuffix = "hdx";
break;
case 3:
case 4:
case 5:
expectedSuffix = "vhd";
break;
}
if (! expectedSuffix.isEmpty()) {
QFileInfo fileInfo(fileName);
if (fileInfo.suffix().compare(expectedSuffix, Qt::CaseInsensitive) != 0) {
fileName = QString("%1.%2").arg(fileName, expectedSuffix);
ui->fileField->setFileName(fileName);
}
}
QFile file(fileName);
if (! file.open(QIODevice::WriteOnly)) {
QMessageBox::critical(this, "Unable to write file", "Make sure the file is being saved to a writable directory");
return;
}
if (img_format == 1) { /* HDI file */
QDataStream stream(&file);
stream.setByteOrder(QDataStream::LittleEndian);
if (size >= 0x100000000ll) {
QMessageBox::critical(this, "Disk image too large", "HDI disk images cannot be larger than 4 GiB");
return;
}
uint32_t s = static_cast<uint32_t>(size);
stream << zero; /* 00000000: Zero/unknown */
stream << zero; /* 00000004: Zero/unknown */
stream << base; /* 00000008: Offset at which data starts */
stream << s; /* 0000000C: Full size of the data (32-bit) */
stream << sector_size; /* 00000010: Sector size in bytes */
stream << sectors_; /* 00000014: Sectors per cylinder */
stream << heads_; /* 00000018: Heads per cylinder */
stream << cylinders_; /* 0000001C: Cylinders */
for (int i = 0; i < 0x3f8; i++) {
stream << zero;
}
} else if (img_format == 2) { /* HDX file */
QDataStream stream(&file);
stream.setByteOrder(QDataStream::LittleEndian);
quint64 signature = 0xD778A82044445459;
stream << signature; /* 00000000: Signature */
stream << size; /* 00000008: Full size of the data (64-bit) */
stream << sector_size; /* 00000010: Sector size in bytes */
stream << sectors_; /* 00000014: Sectors per cylinder */
stream << heads_; /* 00000018: Heads per cylinder */
stream << cylinders_; /* 0000001C: Cylinders */
stream << zero; /* 00000020: [Translation] Sectors per cylinder */
stream << zero; /* 00000004: [Translation] Heads per cylinder */
} else if (img_format >= 3) { /* VHD file */
file.close();
MVHDGeom _86box_geometry;
int block_size = ui->comboBoxBlockSize->currentIndex() == 0 ? MVHD_BLOCK_LARGE : MVHD_BLOCK_SMALL;
switch (img_format) {
case 3:
{
QProgressDialog progress("Creating disk image", QString(), 0, 100, this);
connect(this, &HarddiskDialog::fileProgress, &progress, &QProgressDialog::setValue);
std::thread writer([&_86box_geometry, fileName, this] {
_86box_geometry = create_drive_vhd_fixed(fileName, this, cylinders_, heads_, sectors_);
});
progress.exec();
writer.join();
}
break;
case 4:
_86box_geometry = create_drive_vhd_dynamic(fileName, cylinders_, heads_, sectors_, block_size);
break;
case 5:
QString vhdParent = QFileDialog::getOpenFileName(this, "Select the parent VHD", QString(), "VHD files (*.vhd);;All files (*.*)");
if (vhdParent.isEmpty()) {
return;
}
_86box_geometry = create_drive_vhd_diff(fileName, vhdParent, block_size);
break;
}
if (img_format != 5) {
QMessageBox::information(this, "Disk image created", "Remember to partition and format the newly-created drive");
}
ui->lineEditCylinders->setText(QString::number(_86box_geometry.cyl));
ui->lineEditHeads->setText(QString::number(_86box_geometry.heads));
ui->lineEditSectors->setText(QString::number(_86box_geometry.spt));
cylinders_ = _86box_geometry.cyl;
heads_ = _86box_geometry.heads;
sectors_ = _86box_geometry.spt;
return;
}
// formats 0, 1 and 2
QProgressDialog progress("Creating disk image", QString(), 0, 100, this);
connect(this, &HarddiskDialog::fileProgress, &progress, &QProgressDialog::setValue);
std::thread writer([size, &file, this] {
QDataStream stream(&file);
stream.setByteOrder(QDataStream::LittleEndian);
QByteArray buf(1048576, 0);
uint64_t mibBlocks = size >> 20;
uint64_t restBlock = size & 0xfffff;
if (restBlock) {
stream << QByteArray::fromRawData(buf.data(), restBlock);
}
if (mibBlocks) {
for (uint64_t i = 0; i < mibBlocks; ++i) {
stream << buf;
emit fileProgress(static_cast<int>((i * 100) / mibBlocks));
}
}
emit fileProgress(100);
});
progress.exec();
writer.join();
QMessageBox::information(this, "Disk image created", "Remember to partition and format the newly-created drive");
}
static void adjust_vhd_geometry_for_86box(MVHDGeom *vhd_geometry) {
if (vhd_geometry->spt <= 63)
return;
int desired_sectors = vhd_geometry->cyl * vhd_geometry->heads * vhd_geometry->spt;
if (desired_sectors > 267321600)
desired_sectors = 267321600;
int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */
if (remainder > 0)
desired_sectors -= remainder;
vhd_geometry->cyl = desired_sectors / (16 * 63);
vhd_geometry->heads = 16;
vhd_geometry->spt = 63;
}
void HarddiskDialog::recalcSelection() {
int selection = 127;
for (int i = 0; i < 127; i++) {
if ((cylinders_ == hdd_table[i][0]) &&
(heads_ == hdd_table[i][1]) &&
(sectors_ == hdd_table[i][2]))
selection = i;
}
if ((selection == 127) && (heads_ == 16) && (sectors_ == 63)) {
selection = 128;
}
ui->comboBoxType->setCurrentIndex(selection);
}
void HarddiskDialog::onExistingFileSelected(const QString &fileName) {
// TODO : Over to non-existing file selected
/*
if (!(existing & 1)) {
f = _wfopen(wopenfilestring, L"rb");
if (f != NULL) {
fclose(f);
if (settings_msgbox_ex(MBX_QUESTION_YN, (wchar_t *) IDS_4111, (wchar_t *) IDS_4118, (wchar_t *) IDS_4120, (wchar_t *) IDS_4121, NULL) != 0) / * yes * /
return FALSE;
}
}
f = _wfopen(wopenfilestring, (existing & 1) ? L"rb" : L"wb");
if (f == NULL) {
hdd_add_file_open_error:
fclose(f);
settings_msgbox_header(MBX_ERROR, (existing & 1) ? (wchar_t *) IDS_4114 : (wchar_t *) IDS_4115, (existing & 1) ? (wchar_t *) IDS_4107 : (wchar_t *) IDS_4108);
return TRUE;
}
*/
uint64_t size = 0;
uint32_t sector_size = 0;
uint32_t sectors = 0;
uint32_t heads = 0;
uint32_t cylinders = 0;
int vhd_error = 0;
QFile file(fileName);
if (! file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this, "Unable to read file", "Make sure the file exists and is readable");
return;
}
QByteArray fileNameUtf8 = fileName.toUtf8();
QFileInfo fi(file);
if (image_is_hdi(fileNameUtf8.data()) || image_is_hdx(fileNameUtf8.data(), 1)) {
file.seek(0x10);
QDataStream stream(&file);
stream.setByteOrder(QDataStream::LittleEndian);
stream >> sector_size;
if (sector_size != 512) {
QMessageBox::critical(this, "Unsupported disk image", "HDI or HDX images with a sector size other than 512 are not supported");
return;
}
sectors = heads = cylinders = 0;
stream >> sectors;
stream >> heads;
stream >> cylinders;
} else if (image_is_vhd(fileNameUtf8.data(), 1)) {
MVHDMeta* vhd = mvhd_open(fileNameUtf8.data(), 0, &vhd_error);
if (vhd == nullptr) {
QMessageBox::critical(this, "Unable to read file", "Make sure the file exists and is readable");
return;
} else if (vhd_error == MVHD_ERR_TIMESTAMP) {
QMessageBox::StandardButton btn = QMessageBox::warning(this, "Parent and child disk timestamps do not match", "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?", QMessageBox::Yes | QMessageBox::No);
if (btn == QMessageBox::Yes) {
int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhd_error);
if (ts_res != 0) {
QMessageBox::critical(this, "Error", "Could not fix VHD timestamp");
mvhd_close(vhd);
return;
}
} else {
mvhd_close(vhd);
return;
}
}
MVHDGeom vhd_geom = mvhd_get_geometry(vhd);
adjust_vhd_geometry_for_86box(&vhd_geom);
cylinders = vhd_geom.cyl;
heads = vhd_geom.heads;
sectors = vhd_geom.spt;
size = static_cast<uint64_t>(cylinders * heads * sectors * 512);
mvhd_close(vhd);
} else {
size = file.size();
if (((size % 17) == 0) && (size <= 142606336)) {
sectors = 17;
if (size <= 26738688)
heads = 4;
else if (((size % 3072) == 0) && (size <= 53477376))
heads = 6;
else {
int i;
for (i = 5; i < 16; i++) {
if (((size % (i << 9)) == 0) && (size <= ((i * 17) << 19)))
break;
if (i == 5)
i++;
}
heads = i;
}
} else {
sectors = 63;
heads = 16;
}
cylinders = ((size >> 9) / heads) / sectors;
}
if ((sectors > max_sectors) || (heads > max_heads) || (cylinders > max_cylinders)) {
QMessageBox::critical(this, "Unable to read file", "Make sure the file exists and is readable");
return;
}
heads_ = heads;
sectors_ = sectors;
cylinders_ = cylinders;
ui->lineEditCylinders->setText(QString::number(cylinders));
ui->lineEditHeads->setText(QString::number(heads));
ui->lineEditSectors->setText(QString::number(sectors));
recalcSize();
recalcSelection();
ui->lineEditCylinders->setEnabled(true);
ui->lineEditHeads->setEnabled(true);
ui->lineEditSectors->setEnabled(true);
ui->lineEditSize->setEnabled(true);
ui->comboBoxType->setEnabled(true);
}
void HarddiskDialog::recalcSize() {
uint64_t size = (static_cast<uint64_t>(cylinders_) * static_cast<uint64_t>(heads_) * static_cast<uint64_t>(sectors_)) << 9;
ui->lineEditSize->setText(QString::number(size >> 20));
}
bool HarddiskDialog::checkAndAdjustSectors() {
if (sectors_ > max_sectors) {
sectors_ = max_sectors;
ui->lineEditSectors->setText(QString::number(max_sectors));
recalcSize();
recalcSelection();
return false;
}
return true;
}
bool HarddiskDialog::checkAndAdjustHeads() {
if (heads_ > max_heads) {
heads_ = max_heads;
ui->lineEditHeads->setText(QString::number(max_heads));
recalcSize();
recalcSelection();
return false;
}
return true;
}
bool HarddiskDialog::checkAndAdjustCylinders() {
if (cylinders_ > max_cylinders) {
cylinders_ = max_cylinders;
ui->lineEditCylinders->setText(QString::number(max_cylinders));
recalcSize();
recalcSelection();
return false;
}
return true;
}
void HarddiskDialog::on_comboBoxBus_currentIndexChanged(int index) {
if (index < 0) {
return;
}
switch (ui->comboBoxBus->currentData().toInt()) {
case HDD_BUS_DISABLED:
default:
max_sectors = max_heads = max_cylinders = 0;
break;
case HDD_BUS_MFM:
max_sectors = 26; /* 17 for MFM, 26 for RLL. */
max_heads = 15;
max_cylinders = 2047;
break;
case HDD_BUS_XTA:
max_sectors = 63;
max_heads = 16;
max_cylinders = 1023;
break;
case HDD_BUS_ESDI:
max_sectors = 99; /* ESDI drives usually had 32 to 43 sectors per track. */
max_heads = 16;
max_cylinders = 266305;
break;
case HDD_BUS_IDE:
max_sectors = 63;
max_heads = 255;
max_cylinders = 266305;
break;
case HDD_BUS_ATAPI:
case HDD_BUS_SCSI:
max_sectors = 99;
max_heads = 255;
max_cylinders = 266305;
break;
}
checkAndAdjustCylinders();
checkAndAdjustHeads();
checkAndAdjustSectors();
if (ui->lineEditCylinders->validator() != nullptr) {
delete ui->lineEditCylinders->validator();
}
if (ui->lineEditHeads->validator() != nullptr) {
delete ui->lineEditHeads->validator();
}
if (ui->lineEditSectors->validator() != nullptr) {
delete ui->lineEditSectors->validator();
}
ui->lineEditCylinders->setValidator(new QIntValidator(1, max_cylinders, this));
ui->lineEditHeads->setValidator(new QIntValidator(1, max_heads, this));
ui->lineEditSectors->setValidator(new QIntValidator(1, max_sectors, this));
Harddrives::populateBusChannels(ui->comboBoxChannel->model(), ui->comboBoxBus->currentData().toInt());
}
void HarddiskDialog::on_lineEditSize_textEdited(const QString &text) {
uint32_t size = text.toUInt();
/* This is needed to ensure VHD standard compliance. */
hdd_image_calc_chs(&cylinders_, &heads_, &sectors_, size);
ui->lineEditCylinders->setText(QString::number(cylinders_));
ui->lineEditHeads->setText(QString::number(heads_));
ui->lineEditSectors->setText(QString::number(sectors_));
recalcSelection();
checkAndAdjustCylinders();
checkAndAdjustHeads();
checkAndAdjustSectors();
}
void HarddiskDialog::on_lineEditCylinders_textEdited(const QString &text) {
cylinders_ = text.toUInt();
if (checkAndAdjustCylinders()) {
recalcSize();
recalcSelection();
}
}
void HarddiskDialog::on_lineEditHeads_textEdited(const QString &text) {
heads_ = text.toUInt();
if (checkAndAdjustHeads()) {
recalcSize();
recalcSelection();
}
}
void HarddiskDialog::on_lineEditSectors_textEdited(const QString &text) {
sectors_ = text.toUInt();
if (checkAndAdjustSectors()) {
recalcSize();
recalcSelection();
}
}
void HarddiskDialog::on_comboBoxType_currentIndexChanged(int index) {
if (index < 0) {
return;
}
if ((index != 127) && (index != 128)) {
cylinders_ = hdd_table[index][0];
heads_ = hdd_table[index][1];
sectors_ = hdd_table[index][2];
ui->lineEditCylinders->setText(QString::number(cylinders_));
ui->lineEditHeads->setText(QString::number(heads_));
ui->lineEditSectors->setText(QString::number(sectors_));
recalcSize();
} else if (index == 128) {
heads_ = 16;
sectors_ = 63;
ui->lineEditHeads->setText(QString::number(heads_));
ui->lineEditSectors->setText(QString::number(sectors_));
recalcSize();
}
checkAndAdjustCylinders();
checkAndAdjustHeads();
checkAndAdjustSectors();
}

View File

@ -0,0 +1,57 @@
#ifndef QT_HARDDISKDIALOG_HPP
#define QT_HARDDISKDIALOG_HPP
#include <QDialog>
namespace Ui {
class HarddiskDialog;
}
class HarddiskDialog : public QDialog
{
Q_OBJECT
public:
explicit HarddiskDialog(bool existing, QWidget *parent = nullptr);
~HarddiskDialog();
uint8_t bus() const;
uint8_t channel() const;
QString fileName() const;
uint32_t cylinders() const { return cylinders_; }
uint32_t heads() const { return heads_; }
uint32_t sectors() const { return sectors_; }
signals:
void fileProgress(int i);
private slots:
void on_comboBoxType_currentIndexChanged(int index);
void on_lineEditSectors_textEdited(const QString &arg1);
void on_lineEditHeads_textEdited(const QString &arg1);
void on_lineEditCylinders_textEdited(const QString &arg1);
void on_lineEditSize_textEdited(const QString &arg1);
void on_comboBoxBus_currentIndexChanged(int index);
void on_comboBoxFormat_currentIndexChanged(int index);
void onCreateNewFile();
void onExistingFileSelected(const QString& fileName);
private:
Ui::HarddiskDialog *ui;
uint32_t cylinders_;
uint32_t heads_;
uint32_t sectors_;
uint32_t max_sectors = 0;
uint32_t max_heads = 0;
uint32_t max_cylinders = 0;
bool checkAndAdjustCylinders();
bool checkAndAdjustHeads();
bool checkAndAdjustSectors();
void recalcSize();
void recalcSelection();
};
#endif // QT_HARDDISKDIALOG_HPP

230
src/qt/qt_harddiskdialog.ui Normal file
View File

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HarddiskDialog</class>
<widget class="QDialog" name="HarddiskDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>File name</string>
</property>
</widget>
</item>
<item>
<widget class="FileField" name="fileField" native="true"/>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Cylinders</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Sectors</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditCylinders"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditSize"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Size (MiB)</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Heads</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="lineEditHeads">
<property name="maxLength">
<number>32767</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLineEdit" name="lineEditSectors">
<property name="maxLength">
<number>32767</number>
</property>
</widget>
</item>
<item row="1" column="3" colspan="3">
<widget class="QComboBox" name="comboBoxType"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Bus</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxBus"/>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Channel</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxChannel"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayoutFormat">
<item>
<widget class="QLabel" name="labelFormat">
<property name="text">
<string>Format</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxFormat"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>5</number>
</property>
<item>
<widget class="QLabel" name="labelBlockSize">
<property name="text">
<string>Block Size</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxBlockSize"/>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>FileField</class>
<extends>QWidget</extends>
<header>qt_filefield.hpp</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>lineEditCylinders</tabstop>
<tabstop>lineEditHeads</tabstop>
<tabstop>lineEditSectors</tabstop>
<tabstop>lineEditSize</tabstop>
<tabstop>comboBoxType</tabstop>
<tabstop>comboBoxBus</tabstop>
<tabstop>comboBoxChannel</tabstop>
<tabstop>comboBoxFormat</tabstop>
<tabstop>comboBoxBlockSize</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>HarddiskDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>HarddiskDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,101 @@
#include "qt_harddrive_common.hpp"
#include <cstdint>
extern "C" {
#include <86box/hdd.h>
}
#include <QAbstractItemModel>
void Harddrives::populateBuses(QAbstractItemModel *model) {
model->removeRows(0, model->rowCount());
model->insertRows(0, 6);
model->setData(model->index(0, 0), "MFM/RLL");
model->setData(model->index(1, 0), "XT IDE");
model->setData(model->index(2, 0), "ESDI");
model->setData(model->index(3, 0), "IDE");
model->setData(model->index(4, 0), "ATAPI");
model->setData(model->index(5, 0), "SCSI");
model->setData(model->index(0, 0), HDD_BUS_MFM, Qt::UserRole);
model->setData(model->index(1, 0), HDD_BUS_XTA, Qt::UserRole);
model->setData(model->index(2, 0), HDD_BUS_ESDI, Qt::UserRole);
model->setData(model->index(3, 0), HDD_BUS_IDE, Qt::UserRole);
model->setData(model->index(4, 0), HDD_BUS_ATAPI, Qt::UserRole);
model->setData(model->index(5, 0), HDD_BUS_SCSI, Qt::UserRole);
}
void Harddrives::populateRemovableBuses(QAbstractItemModel *model) {
model->removeRows(0, model->rowCount());
model->insertRows(0, 3);
model->setData(model->index(0, 0), "Disabled");
model->setData(model->index(1, 0), "ATAPI");
model->setData(model->index(2, 0), "SCSI");
model->setData(model->index(0, 0), HDD_BUS_DISABLED, Qt::UserRole);
model->setData(model->index(1, 0), HDD_BUS_ATAPI, Qt::UserRole);
model->setData(model->index(2, 0), HDD_BUS_SCSI, Qt::UserRole);
}
void Harddrives::populateBusChannels(QAbstractItemModel *model, int bus) {
model->removeRows(0, model->rowCount());
int busRows = 0;
int shifter = 1;
int orer = 1;
int subChannelWidth = 1;
switch (bus) {
case HDD_BUS_MFM:
case HDD_BUS_XTA:
case HDD_BUS_ESDI:
busRows = 2;
break;
case HDD_BUS_IDE:
case HDD_BUS_ATAPI:
busRows = 8;
break;
case HDD_BUS_SCSI:
shifter = 4;
orer = 15;
busRows = 64;
subChannelWidth = 2;
break;
}
model->insertRows(0, busRows);
for (int i = 0; i < busRows; ++i) {
auto idx = model->index(i, 0);
model->setData(idx, QString("%1:%2").arg(i >> shifter).arg(i & orer, subChannelWidth, 10, QChar('0')));
model->setData(idx, ((i >> shifter) << shifter) | (i & orer), Qt::UserRole);
}
}
QString Harddrives::BusChannelName(uint8_t bus, uint8_t channel) {
QString busName;
switch(bus) {
case HDD_BUS_DISABLED:
busName = QString("Disabled");
break;
case HDD_BUS_MFM:
busName = QString("MFM/RLL (%1:%2)").arg(channel >> 1).arg(channel & 1);
break;
case HDD_BUS_XTA:
busName = QString("XT IDE (%1:%2)").arg(channel >> 1).arg(channel & 1);
break;
case HDD_BUS_ESDI:
busName = QString("ESDI (%1:%2)").arg(channel >> 1).arg(channel & 1);
break;
case HDD_BUS_IDE:
busName = QString("IDE (%1:%2)").arg(channel >> 1).arg(channel & 1);
break;
case HDD_BUS_ATAPI:
busName = QString("ATAPI (%1:%2)").arg(channel >> 1).arg(channel & 1);
break;
case HDD_BUS_SCSI:
busName = QString("SCSI (%1:%2)").arg(channel >> 4).arg(channel & 15, 2, 10, QChar('0'));
break;
}
return busName;
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <cstdint>
class QString;
class QAbstractItemModel;
namespace Harddrives {
void populateBuses(QAbstractItemModel* model);
void populateRemovableBuses(QAbstractItemModel* model);
void populateBusChannels(QAbstractItemModel* model, int bus);
QString BusChannelName(uint8_t bus, uint8_t channel);
};

104
src/qt/qt_main.cpp Normal file
View File

@ -0,0 +1,104 @@
#include <QApplication>
#include <QDebug>
#include <QElapsedTimer>
#include <QThread>
#include <QTimer>
#include <86box/86box.h>
#include <86box/plat.h>
#include <86box/ui.h>
#include <86box/video.h>
#include <thread>
#include "qt_mainwindow.hpp"
#include "qt_sdl.h"
// Void Cast
#define VC(x) const_cast<wchar_t*>(x)
extern QElapsedTimer elapsed_timer;
extern int nvr_dosave;
extern MainWindow* main_window;
extern "C" {
extern int qt_nvr_save(void);
}
void
main_thread_fn()
{
uint64_t old_time, new_time;
int drawits, frames;
QThread::currentThread()->setPriority(QThread::HighestPriority);
framecountx = 0;
//title_update = 1;
old_time = elapsed_timer.elapsed();
drawits = frames = 0;
while (!is_quit && cpu_thread_run) {
/* See if it is time to run a frame of code. */
new_time = elapsed_timer.elapsed();
drawits += (new_time - old_time);
old_time = new_time;
if (drawits > 0 && !dopause) {
/* Yes, so do one frame now. */
drawits -= 10;
if (drawits > 50)
drawits = 0;
/* Run a block of code. */
pc_run();
/* Every 200 frames we save the machine status. */
if (++frames >= 200 && nvr_dosave) {
qt_nvr_save();
nvr_dosave = 0;
frames = 0;
}
} else /* Just so we dont overload the host OS. */
std::this_thread::sleep_for(std::chrono::milliseconds(1));
/* If needed, handle a screen resize. */
if (doresize && !video_fullscreen && !is_quit) {
if (vid_resize & 2)
plat_resize(fixed_size_x, fixed_size_y);
else
plat_resize(scrnsz_x, scrnsz_y);
doresize = 0;
}
}
is_quit = 1;
}
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
elapsed_timer.start();
pc_init(argc, argv);
if (! pc_init_modules()) {
ui_msgbox_header(MBX_FATAL, VC(L"No ROMs found."), VC(L"86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory."));
return 6;
}
main_window = new MainWindow();
main_window->show();
pc_reset_hard_init();
/* Set the PAUSE mode depending on the renderer. */
// plat_pause(0);
/* Initialize the rendering window, or fullscreen. */
auto main_thread = std::thread([] {
main_thread_fn();
});
auto ret = app.exec();
cpu_thread_run = 0;
main_thread.join();
return ret;
}

299
src/qt/qt_mainwindow.cpp Normal file
View File

@ -0,0 +1,299 @@
#include "qt_mainwindow.hpp"
#include "ui_qt_mainwindow.h"
extern "C" {
#include <86box/86box.h>
#include <86box/keyboard.h>
#include <86box/mouse.h>
#include <86box/config.h>
#include <86box/plat.h>
#include "qt_sdl.h"
};
#include <QWindow>
#include <QDebug>
#include <QTimer>
#include <QKeyEvent>
#include "qt_settings.hpp"
CentralWidget::CentralWidget(QWidget *parent) : QWidget(parent) {}
CentralWidget::~CentralWidget() = default;
MainWindowLabel::MainWindowLabel(QWidget *parent) : QLabel(parent) {
setMouseTracking(true);
}
MainWindowLabel::~MainWindowLabel() = default;
void MainWindowLabel::mouseMoveEvent(QMouseEvent *event) {
pos_ = event->pos();
}
void MainWindowLabel::mousePressEvent(QMouseEvent *event) {
buttons_ = event->buttons();
}
void MainWindowLabel::mouseReleaseEvent(QMouseEvent *event) {
buttons_ = event->buttons();
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
Q_INIT_RESOURCE(qt_resources);
ui->setupUi(this);
connect(this, &MainWindow::pollMouse, this, [] {
sdl_mouse_poll();
});
connect(this, &MainWindow::setMouseCapture, this, [](bool state) {
mouse_capture = state ? 1 : 0;
sdl_mouse_capture(mouse_capture);
});
connect(this, &MainWindow::setFullscreen, this, [](bool state) {
video_fullscreen = state ? 1 : 0;
sdl_set_fs(video_fullscreen);
});
connect(this, &MainWindow::resizeContents, this, [this](int w, int h) {
sdl_resize(w, h);
});
connect(ui->menubar, &QMenuBar::triggered, this, [] {
config_save();
});
ui->actionKeyboard_requires_capture->setChecked(kbd_req_capture);
ui->actionRight_CTRL_is_left_ALT->setChecked(rctrl_is_lalt);
sdl_inits();
sdl_timer = new QTimer(this);
connect(sdl_timer, &QTimer::timeout, this, [] {
auto status = sdl_main();
if (status == SdlMainQuit) {
QApplication::quit();
}
});
sdl_timer->start(5);
}
MainWindow::~MainWindow() {
sdl_close();
delete ui;
}
void MainWindow::on_actionKeyboard_requires_capture_triggered() {
kbd_req_capture ^= 1;
}
void MainWindow::on_actionRight_CTRL_is_left_ALT_triggered() {
rctrl_is_lalt ^= 1;
}
void MainWindow::on_actionHard_Reset_triggered() {
pc_reset_hard();
}
void MainWindow::on_actionCtrl_Alt_Del_triggered() {
pc_send_cad();
}
void MainWindow::on_actionCtrl_Alt_Esc_triggered() {
pc_send_cae();
}
void MainWindow::on_actionPause_triggered() {
plat_pause(dopause ^ 1);
}
void MainWindow::on_actionExit_triggered() {
close();
}
void MainWindow::on_actionSettings_triggered() {
Settings settings;
settings.exec();
switch (settings.result()) {
case QDialog::Accepted:
/*
pc_reset_hard_close();
settings.save();
config_changed = 2;
pc_reset_hard_init();
*/
settings.save();
config_changed = 2;
pc_reset_hard();
break;
case QDialog::Rejected:
break;
}
}
static const int keycode_entries = 136;
// xmodmap -pk
static const uint16_t xfree86_keycode_table[keycode_entries] = {
/* 0 */ 0,
/* 1 */ 0,
/* 2 */ 0,
/* 3 */ 0,
/* 4 */ 0,
/* 5 */ 0,
/* 6 */ 0,
/* 7 */ 0,
/* 8 */ 0,
/* 9 */ 0x01, // Esc
/* 10 */ 0x02, // 1
/* 11 */ 0x03, // 2
/* 12 */ 0x04, // 3
/* 13 */ 0x05, // 4
/* 14 */ 0x06, // 5
/* 15 */ 0x07, // 6
/* 16 */ 0x08, // 7
/* 17 */ 0x09, // 8
/* 18 */ 0x0a, // 9
/* 19 */ 0x0b, // 0
/* 20 */ 0x0c, // -
/* 21 */ 0x0d, // =
/* 22 */ 0x0e, // BackSpace
/* 23 */ 0x0f, // Tab
/* 24 */ 0x10, // Q
/* 25 */ 0x11, // W
/* 26 */ 0x12, // E
/* 27 */ 0x13, // R
/* 28 */ 0x14, // T
/* 29 */ 0x15, // Y
/* 30 */ 0x16, // U
/* 31 */ 0x17, // I
/* 32 */ 0x18, // O
/* 33 */ 0x19, // P
/* 34 */ 0x1a, // [
/* 35 */ 0x1b, // ]
/* 36 */ 0x1c, // Return
/* 37 */ 0x1d, // LeftControl
/* 38 */ 0x1e, // A
/* 39 */ 0x1f, // S
/* 40 */ 0x20, // D
/* 41 */ 0x21, // F
/* 42 */ 0x22, // G
/* 43 */ 0x23, // H
/* 44 */ 0x24, // J
/* 45 */ 0x25, // K
/* 46 */ 0x26, // L
/* 47 */ 0x27, // ;
/* 48 */ 0x28, // '
/* 49 */ 0x29, // ` (???)
/* 50 */ 0x2a, // LeftShift
/* 51 */ 0x2b, // BackSlash
/* 52 */ 0x2c, // Z
/* 53 */ 0x2d, // X
/* 54 */ 0x2e, // C
/* 55 */ 0x2f, // V
/* 56 */ 0x30, // B
/* 57 */ 0x31, // N
/* 58 */ 0x32, // M
/* 59 */ 0x33, // ,
/* 60 */ 0x34, // .
/* 61 */ 0x35, // -
/* 62 */ 0x36, // RightShift
/* 63 */ 0x37, // KeyPad Multiply
/* 64 */ 0x38, // LeftAlt
/* 65 */ 0x39, // Space
/* 66 */ 0x3a, // CapsLock
/* 67 */ 0x3b, // F01
/* 68 */ 0x3c, // F02
/* 69 */ 0x3d, // F03
/* 70 */ 0x3e, // F04
/* 71 */ 0x3f, // F05
/* 72 */ 0x40, // F06
/* 73 */ 0x41, // F07
/* 74 */ 0x42, // F08
/* 75 */ 0x43, // F09
/* 76 */ 0x44, // F10
/* 77 */ 0x45, // NumLock
/* 78 */ 0x46, // ScrollLock
/* 79 */ 0x47, // KeyPad7
/* 80 */ 0x48, // KeyPad8
/* 81 */ 0x49, // KeyPad9
/* 82 */ 0x4a, // KeyPad Minus
/* 83 */ 0x4b, // KeyPad4
/* 84 */ 0x4c, // KeyPad5
/* 85 */ 0x4d, // KeyPad6
/* 86 */ 0x4e, // KeyPad Plus
/* 87 */ 0x4f, // KeyPad1
/* 88 */ 0x50, // KeyPad2
/* 89 */ 0x51, // KeyPad3
/* 90 */ 0x52, // KeyPad0
/* 91 */ 0x53, // KeyPad .
/* 92 */ 0,
/* 93 */ 0,
/* 94 */ 0x56, // Less/Great
/* 95 */ 0x57, // F11
/* 96 */ 0x58, // F12
/* 97 */ 0,
/* 98 */ 0,
/* 99 */ 0,
/* 100 */ 0,
/* 101 */ 0,
/* 102 */ 0,
/* 103 */ 0,
/* 104 */ 0x11c, // KeyPad Enter
/* 105 */ 0x11d, // RightControl
/* 106 */ 0x135, // KeyPad Divide
/* 107 */ 0x137, // PrintScreen / SysReq
/* 108 */ 0x138, // RightAlt
/* 109 */ 0,
/* 110 */ 0x147, // Home
/* 111 */ 0x148, // Up
/* 112 */ 0x149, // PageUp
/* 113 */ 0x14b, // Left
/* 114 */ 0x14d, // Right
/* 115 */ 0x14f, // End
/* 116 */ 0x150, // Down
/* 117 */ 0x151, // PageDown
/* 118 */ 0x152, // Insert
/* 119 */ 0x153, // Delete
/* 120 */ 0,
/* 121 */ 0,
/* 122 */ 0,
/* 123 */ 0,
/* 124 */ 0,
/* 125 */ 0,
/* 126 */ 0,
/* 127 */ 0,
/* 128 */ 0,
/* 129 */ 0,
/* 130 */ 0,
/* 131 */ 0,
/* 132 */ 0,
/* 133 */ 0x15b, // SuperLeft
/* 134 */ 0x15c, // SuperRight
/* 135 */ 0x15d, // Application
};
static void handle_keypress_event(int state, quint32 native_scancode) {
if (native_scancode > keycode_entries) {
return;
}
uint16_t translated_code = xfree86_keycode_table[native_scancode];
if (translated_code == 0) {
return;
}
keyboard_input(state, translated_code);
if (keyboard_isfsexit() > 0) {
plat_setfullscreen(0);
}
if (keyboard_ismsexit() > 0) {
plat_mouse_capture(0);
}
}
void MainWindow::on_actionFullscreen_triggered() {
setFullscreen(true);
}

83
src/qt/qt_mainwindow.hpp Normal file
View File

@ -0,0 +1,83 @@
#ifndef QT_MAINWINDOW_HPP
#define QT_MAINWINDOW_HPP
#include <QMainWindow>
#include <QLabel>
namespace Ui {
class MainWindow;
}
class MainWindowLabel : public QLabel
{
Q_OBJECT
public:
explicit MainWindowLabel(QWidget *parent = nullptr);
~MainWindowLabel();
const QPoint& pos() { return pos_; }
Qt::MouseButtons buttons() { return buttons_; }
protected:
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
private:
QPoint pos_;
Qt::MouseButtons buttons_;
};
class CentralWidget : public QWidget
{
Q_OBJECT
public:
explicit CentralWidget(QWidget *parent = nullptr);
~CentralWidget();
void setSizeHint(QSize size) { size_ = size; }
QSize sizeHint() const override { return size_; }
private:
QSize size_;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void paint(const QImage& image);
void resizeContents(int w, int h);
void pollMouse();
void setFullscreen(bool state);
void setMouseCapture(bool state);
private slots:
void on_actionFullscreen_triggered();
private slots:
void on_actionSettings_triggered();
void on_actionExit_triggered();
void on_actionPause_triggered();
void on_actionCtrl_Alt_Del_triggered();
void on_actionCtrl_Alt_Esc_triggered();
void on_actionHard_Reset_triggered();
void on_actionRight_CTRL_is_left_ALT_triggered();
void on_actionKeyboard_requires_capture_triggered();
private:
struct DeltaPos {
int x = 0;
int y = 0;
int z = 0;
};
Ui::MainWindow *ui;
DeltaPos mouseDelta;
QWindow* sdl_wrapped_window;
QWidget* sdl_wrapped_widget;
QTimer* sdl_timer;
};
#endif // QT_MAINWINDOW_HPP

143
src/qt/qt_mainwindow.ui Normal file
View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>724</width>
<height>274</height>
</rect>
</property>
<property name="windowTitle">
<string>86Box</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>724</width>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="menuAction">
<property name="title">
<string>Action</string>
</property>
<addaction name="actionKeyboard_requires_capture"/>
<addaction name="actionRight_CTRL_is_left_ALT"/>
<addaction name="separator"/>
<addaction name="actionHard_Reset"/>
<addaction name="actionCtrl_Alt_Del"/>
<addaction name="separator"/>
<addaction name="actionCtrl_Alt_Esc"/>
<addaction name="separator"/>
<addaction name="actionPause"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuTools">
<property name="title">
<string>Tools</string>
</property>
<addaction name="actionSettings"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>View</string>
</property>
<addaction name="actionFullscreen"/>
</widget>
<addaction name="menuAction"/>
<addaction name="menuView"/>
<addaction name="menuTools"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionKeyboard_requires_capture">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Keyboard requires capture</string>
</property>
</action>
<action name="actionRight_CTRL_is_left_ALT">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Right CTRL is left ALT</string>
</property>
</action>
<action name="actionHard_Reset">
<property name="text">
<string>Hard Reset</string>
</property>
</action>
<action name="actionCtrl_Alt_Del">
<property name="text">
<string>Ctrl+Alt+Del</string>
</property>
</action>
<action name="actionCtrl_Alt_Esc">
<property name="text">
<string>Ctrl+Alt+Esc</string>
</property>
</action>
<action name="actionPause">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Pause</string>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>Exit</string>
</property>
</action>
<action name="actionSettings">
<property name="text">
<string>Settings</string>
</property>
</action>
<action name="actionFullscreen">
<property name="text">
<string>Fullscreen</string>
</property>
<property name="shortcut">
<string>Ctrl+Alt+PgUp</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

32
src/qt/qt_midi.cpp Normal file
View File

@ -0,0 +1,32 @@
#include <cstdint>
extern "C" {
void plat_midi_play_msg(uint8_t *msg)
{}
void plat_midi_play_sysex(uint8_t *sysex, unsigned int len)
{}
void plat_midi_input_init(void)
{}
void plat_midi_input_close(void)
{}
int plat_midi_write(uint8_t val)
{ return 0; }
void plat_midi_init()
{}
void plat_midi_close()
{}
int plat_midi_get_num_devs()
{ return 0; }
int plat_midi_in_get_num_devs(void)
{ return 0; }
}

View File

@ -0,0 +1,15 @@
#include "qt_models_common.hpp"
#include <QAbstractItemModel>
int Models::AddEntry(QAbstractItemModel *model, const QString& displayRole, int userRole)
{
int row = model->rowCount();
model->insertRow(row);
auto idx = model->index(row, 0);
model->setData(idx, displayRole, Qt::DisplayRole);
model->setData(idx, userRole, Qt::UserRole);
return row;
}

View File

@ -0,0 +1,8 @@
#pragma once
class QString;
class QAbstractItemModel;
namespace Models
{
int AddEntry(QAbstractItemModel* model, const QString& displayRole, int userRole);
};

382
src/qt/qt_platform.cpp Normal file
View File

@ -0,0 +1,382 @@
#include <cstdio>
#include <mutex>
#include <memory>
#include <algorithm>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QTemporaryFile>
#include <QCoreApplication>
#include <QLibrary>
#include <QElapsedTimer>
#ifdef Q_OS_UNIX
#include <sys/mman.h>
#endif
// static QByteArray buf;
extern QElapsedTimer elapsed_timer;
QElapsedTimer elapsed_timer;
static std::mutex blitmx;
class CharPointer {
public:
CharPointer(char* buf, int size) : b(buf), s(size) {}
CharPointer& operator=(const QByteArray &ba) {
if (s > 0) {
strncpy(b, ba.data(), s-1);
b[s] = 0;
} else {
// if we haven't been told the length of b, just assume enough
// because we didn't get it from emulator code
strcpy(b, ba.data());
b[ba.size()] = 0;
}
return *this;
}
private:
char* b;
int s;
};
extern "C" {
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/gameport.h>
#include <86box/plat_dynld.h>
#include <86box/config.h>
#include <86box/ui.h>
#include "../cpu/cpu.h"
#include <86box/plat.h>
volatile int cpu_thread_run = 1;
int mouse_capture = 0;
int fixed_size_x = 640;
int fixed_size_y = 480;
int rctrl_is_lalt = 0;
int update_icons = 0;
int kbd_req_capture = 0;
int hide_status_bar = 0;
uint32_t lang_id = 0x0409, lang_sys = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US
plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS];
joystick_t joystick_state[MAX_JOYSTICKS];
int stricmp(const char* s1, const char* s2)
{
return QByteArray(s1).compare(s2, Qt::CaseInsensitive);
}
int strnicmp(const char *s1, const char *s2, size_t n)
{
QByteArray b1(s1, std::min(strlen(s1), n));
QByteArray b2(s2, std::min(strlen(s2), n));
return b1.compare(b2, Qt::CaseInsensitive);
}
void
do_stop(void)
{
QCoreApplication::quit();
}
void plat_get_exe_name(char *s, int size)
{
CharPointer(s, size) = QCoreApplication::applicationFilePath().toUtf8();
}
uint32_t
plat_get_ticks(void)
{
return elapsed_timer.elapsed();
}
uint64_t
plat_timer_read(void)
{
return elapsed_timer.elapsed();
}
FILE *
plat_fopen(const char *path, const char *mode)
{
/*
QString filepath(path);
if (filepath.isEmpty()) {
return nullptr;
}
qWarning() << "plat_fopen" << filepath;
bool ok = false;
QFile file(filepath);
auto mode_len = strlen(mode);
for (size_t i = 0; i < mode_len; ++i) {
switch (mode[i]) {
case 'r':
ok = file.open(QIODevice::ReadOnly);
break;
case 'w':
ok = file.open(QIODevice::ReadWrite);
break;
case 'b':
case 't':
break;
default:
qWarning() << "Unhandled open mode" << mode[i];
}
}
if (ok) {
qDebug() << "filehandle" << file.handle();
QFile returned;
qDebug() << "\t" << returned.open(file.handle(), file.openMode(), QFileDevice::FileHandleFlag::DontCloseHandle);
return fdopen(returned.handle(), mode);
} else {
return nullptr;
}
*/
#ifdef Q_OS_WINDOWS
wchar_t *pathw, *modew;
int len;
FILE *fp;
if (acp_utf8)
return fopen(path, mode);
else {
len = mbstoc16s(NULL, path, 0) + 1;
pathw = malloc(sizeof(wchar_t) * len);
mbstoc16s(pathw, path, len);
len = mbstoc16s(NULL, mode, 0) + 1;
modew = malloc(sizeof(wchar_t) * len);
mbstoc16s(modew, mode, len);
fp = _wfopen(pathw, modew);
free(pathw);
free(modew);
return fp;
}
#endif
#ifdef Q_OS_UNIX
return fopen(path, mode);
#endif
}
FILE *
plat_fopen64(const char *path, const char *mode)
{
return fopen(path, mode);
}
int
plat_dir_create(char *path)
{
return QDir().mkdir(path) ? 0 : -1;
}
int
plat_dir_check(char *path)
{
QFileInfo fi(path);
return fi.isDir() ? 1 : 0;
}
int
plat_getcwd(char *bufp, int max)
{
CharPointer(bufp, max) = QDir::currentPath().toUtf8();
return 0;
}
void
plat_get_dirname(char *dest, const char *path)
{
QFileInfo fi(path);
CharPointer(dest, -1) = fi.dir().path().toUtf8();
}
char *
plat_get_extension(char *s)
{
auto len = strlen(s);
auto idx = QByteArray::fromRawData(s, len).lastIndexOf('.');
if (idx >= 0) {
return s+idx+1;
}
return s+len;
}
char *
plat_get_filename(char *s)
{
auto idx = QByteArray::fromRawData(s, strlen(s)).lastIndexOf(QDir::separator().toLatin1());
if (idx >= 0) {
return s+idx+1;
}
return s;
}
int
plat_path_abs(char *path)
{
QFileInfo fi(path);
return fi.isAbsolute() ? 1 : 0;
}
void
plat_path_slash(char *path)
{
auto len = strlen(path);
auto separator = QDir::separator().toLatin1();
if (path[len-1] != separator) {
path[len] = separator;
path[len+1] = 0;
}
}
void
plat_append_filename(char *dest, const char *s1, const char *s2)
{
strcpy(dest, s1);
plat_path_slash(dest);
strcat(dest, s2);
}
void
plat_tempfile(char *bufp, char *prefix, char *suffix)
{
QString name;
if (prefix != nullptr) {
name.append(QString("%1-").arg(prefix));
}
name.append("XXXXXX");
if (suffix != nullptr) {
name.append(suffix);
}
QTemporaryFile temp(name);
QByteArray buf(bufp);
buf = temp.fileName().toUtf8();
}
void plat_remove(char* path)
{
QFile(path).remove();
}
void *
plat_mmap(size_t size, uint8_t executable)
{
#if defined Q_OS_WINDOWS
return VirtualAlloc(NULL, size, MEM_COMMIT, executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
#elif defined Q_OS_UNIX
#if defined Q_OS_DARWIN && defined MAP_JIT
void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE | (executable ? MAP_JIT : 0), 0, 0);
#else
void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE, 0, 0);
auto retval = *reinterpret_cast<int*>(ret);
return (retval < 0) ? nullptr : ret;
#endif
#endif
}
void
plat_munmap(void *ptr, size_t size)
{
munmap(ptr, size);
}
void
plat_pause(int p)
{
static wchar_t oldtitle[512];
wchar_t title[512];
dopause = p;
if (p) {
wcsncpy(oldtitle, ui_window_title(NULL), sizeof_w(oldtitle) - 1);
wcscpy(title, oldtitle);
wcscat(title, L" - PAUSED -");
ui_window_title(title);
} else {
ui_window_title(oldtitle);
}
}
// because we can't include nvr.h because it's got fields named new
extern int nvr_save(void);
void
plat_power_off(void)
{
confirm_exit = 0;
nvr_save();
config_save();
/* Deduct a sufficiently large number of cycles that no instructions will
run before the main thread is terminated */
cycles -= 99999999;
cpu_thread_run = 0;
}
void set_language(uint32_t id) {
lang_id = id;
}
/* Sets up the program language before initialization. */
uint32_t plat_language_code(char* langcode) {
/* or maybe not */
return 0;
}
/* Converts back the language code to LCID */
void plat_language_code_r(uint32_t lcid, char* outbuf, int len) {
/* or maybe not */
return;
}
void* dynld_module(const char *name, dllimp_t *table)
{
auto lib = std::unique_ptr<QLibrary>(new QLibrary(name));
if (lib->load()) {
for (auto imp = table; imp->name != nullptr; imp++)
{
if ((imp->func = reinterpret_cast<void*>(lib->resolve(imp->name))) != nullptr)
{
return nullptr;
}
}
}
return lib.release();
}
void dynld_close(void *handle)
{
delete reinterpret_cast<QLibrary*>(handle);
}
void joystick_init(void) {}
void joystick_close(void) {}
void joystick_process(void) {}
void startblit()
{
blitmx.lock();
}
void endblit()
{
blitmx.unlock();
}
}

743
src/qt/qt_sdl.c Normal file
View File

@ -0,0 +1,743 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Rendering module for libSDL2
*
* NOTE: Given all the problems reported with FULLSCREEN use of SDL,
* we will not use that, but, instead, use a new window which
* coverrs the entire desktop.
*
*
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Michael Dr<EFBFBD>ing, <michael@drueing.de>
*
* Copyright 2018-2020 Fred N. van Kempen.
* Copyright 2018-2020 Michael Dr<EFBFBD>ing.
*
* Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the entire
* above notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <SDL2/SDL.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
/* This #undef is needed because a SDL include header redefines HAVE_STDARG_H. */
#undef HAVE_STDARG_H
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/mouse.h>
#include <86box/keyboard.h>
#include <86box/device.h>
#include <86box/plat.h>
#include <86box/plat_dynld.h>
#include <86box/video.h>
#include <86box/ui.h>
#include <86box/version.h>
#include "qt_sdl.h"
#define RENDERER_FULL_SCREEN 1
#define RENDERER_HARDWARE 2
#define RENDERER_OPENGL 4
static SDL_Window *sdl_win = NULL;
static SDL_Renderer *sdl_render = NULL;
static SDL_Texture *sdl_tex = NULL;
static int sdl_w, sdl_h;
static int sdl_fs, sdl_flags = -1;
static int cur_w, cur_h;
static int cur_ww = 0, cur_wh = 0;
static volatile int sdl_enabled = 0;
static SDL_mutex* sdl_mutex = NULL;
static int blit_w = 0, blit_h = 0, blit_tex_updated = 0;
static const uint16_t sdl_to_xt[0x200] =
{
[SDL_SCANCODE_ESCAPE] = 0x01,
[SDL_SCANCODE_1] = 0x02,
[SDL_SCANCODE_2] = 0x03,
[SDL_SCANCODE_3] = 0x04,
[SDL_SCANCODE_4] = 0x05,
[SDL_SCANCODE_5] = 0x06,
[SDL_SCANCODE_6] = 0x07,
[SDL_SCANCODE_7] = 0x08,
[SDL_SCANCODE_8] = 0x09,
[SDL_SCANCODE_9] = 0x0A,
[SDL_SCANCODE_0] = 0x0B,
[SDL_SCANCODE_MINUS] = 0x0C,
[SDL_SCANCODE_EQUALS] = 0x0D,
[SDL_SCANCODE_BACKSPACE] = 0x0E,
[SDL_SCANCODE_TAB] = 0x0F,
[SDL_SCANCODE_Q] = 0x10,
[SDL_SCANCODE_W] = 0x11,
[SDL_SCANCODE_E] = 0x12,
[SDL_SCANCODE_R] = 0x13,
[SDL_SCANCODE_T] = 0x14,
[SDL_SCANCODE_Y] = 0x15,
[SDL_SCANCODE_U] = 0x16,
[SDL_SCANCODE_I] = 0x17,
[SDL_SCANCODE_O] = 0x18,
[SDL_SCANCODE_P] = 0x19,
[SDL_SCANCODE_LEFTBRACKET] = 0x1A,
[SDL_SCANCODE_RIGHTBRACKET] = 0x1B,
[SDL_SCANCODE_RETURN] = 0x1C,
[SDL_SCANCODE_LCTRL] = 0x1D,
[SDL_SCANCODE_A] = 0x1E,
[SDL_SCANCODE_S] = 0x1F,
[SDL_SCANCODE_D] = 0x20,
[SDL_SCANCODE_F] = 0x21,
[SDL_SCANCODE_G] = 0x22,
[SDL_SCANCODE_H] = 0x23,
[SDL_SCANCODE_J] = 0x24,
[SDL_SCANCODE_K] = 0x25,
[SDL_SCANCODE_L] = 0x26,
[SDL_SCANCODE_SEMICOLON] = 0x27,
[SDL_SCANCODE_APOSTROPHE] = 0x28,
[SDL_SCANCODE_GRAVE] = 0x29,
[SDL_SCANCODE_LSHIFT] = 0x2A,
[SDL_SCANCODE_BACKSLASH] = 0x2B,
[SDL_SCANCODE_Z] = 0x2C,
[SDL_SCANCODE_X] = 0x2D,
[SDL_SCANCODE_C] = 0x2E,
[SDL_SCANCODE_V] = 0x2F,
[SDL_SCANCODE_B] = 0x30,
[SDL_SCANCODE_N] = 0x31,
[SDL_SCANCODE_M] = 0x32,
[SDL_SCANCODE_COMMA] = 0x33,
[SDL_SCANCODE_PERIOD] = 0x34,
[SDL_SCANCODE_SLASH] = 0x35,
[SDL_SCANCODE_RSHIFT] = 0x36,
[SDL_SCANCODE_KP_MULTIPLY] = 0x37,
[SDL_SCANCODE_LALT] = 0x38,
[SDL_SCANCODE_SPACE] = 0x39,
[SDL_SCANCODE_CAPSLOCK] = 0x3A,
[SDL_SCANCODE_F1] = 0x3B,
[SDL_SCANCODE_F2] = 0x3C,
[SDL_SCANCODE_F3] = 0x3D,
[SDL_SCANCODE_F4] = 0x3E,
[SDL_SCANCODE_F5] = 0x3F,
[SDL_SCANCODE_F6] = 0x40,
[SDL_SCANCODE_F7] = 0x41,
[SDL_SCANCODE_F8] = 0x42,
[SDL_SCANCODE_F9] = 0x43,
[SDL_SCANCODE_F10] = 0x44,
[SDL_SCANCODE_NUMLOCKCLEAR] = 0x45,
[SDL_SCANCODE_SCROLLLOCK] = 0x46,
[SDL_SCANCODE_HOME] = 0x147,
[SDL_SCANCODE_UP] = 0x148,
[SDL_SCANCODE_PAGEUP] = 0x149,
[SDL_SCANCODE_KP_MINUS] = 0x4A,
[SDL_SCANCODE_LEFT] = 0x14B,
[SDL_SCANCODE_KP_5] = 0x4C,
[SDL_SCANCODE_RIGHT] = 0x14D,
[SDL_SCANCODE_KP_PLUS] = 0x4E,
[SDL_SCANCODE_END] = 0x14F,
[SDL_SCANCODE_DOWN] = 0x150,
[SDL_SCANCODE_PAGEDOWN] = 0x151,
[SDL_SCANCODE_INSERT] = 0x152,
[SDL_SCANCODE_DELETE] = 0x153,
[SDL_SCANCODE_F11] = 0x57,
[SDL_SCANCODE_F12] = 0x58,
[SDL_SCANCODE_KP_ENTER] = 0x11c,
[SDL_SCANCODE_RCTRL] = 0x11d,
[SDL_SCANCODE_KP_DIVIDE] = 0x135,
[SDL_SCANCODE_RALT] = 0x138,
[SDL_SCANCODE_KP_9] = 0x49,
[SDL_SCANCODE_KP_8] = 0x48,
[SDL_SCANCODE_KP_7] = 0x47,
[SDL_SCANCODE_KP_6] = 0x4D,
[SDL_SCANCODE_KP_4] = 0x4B,
[SDL_SCANCODE_KP_3] = 0x51,
[SDL_SCANCODE_KP_2] = 0x50,
[SDL_SCANCODE_KP_1] = 0x4F,
[SDL_SCANCODE_KP_0] = 0x52,
[SDL_SCANCODE_KP_PERIOD] = 0x53,
[SDL_SCANCODE_LGUI] = 0x15B,
[SDL_SCANCODE_RGUI] = 0x15C,
[SDL_SCANCODE_APPLICATION] = 0x15D,
[SDL_SCANCODE_PRINTSCREEN] = 0x137,
[SDL_SCANCODE_NONUSBACKSLASH] = 0x56,
};
typedef struct mouseinputdata
{
int deltax, deltay, deltaz;
int mousebuttons;
} mouseinputdata;
static mouseinputdata mousedata;
// #define ENABLE_SDL_LOG 3
#ifdef ENABLE_SDL_LOG
int sdl_do_log = ENABLE_SDL_LOG;
static void
sdl_log(const char *fmt, ...)
{
va_list ap;
if (sdl_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define sdl_log(fmt, ...)
#endif
static void
sdl_integer_scale(double *d, double *g)
{
double ratio;
if (*d > *g) {
ratio = floor(*d / *g);
*d = *g * ratio;
} else {
ratio = ceil(*d / *g);
*d = *g / ratio;
}
}
static void
sdl_stretch(int *w, int *h, int *x, int *y)
{
double hw, gw, hh, gh, dx, dy, dw, dh, gsr, hsr;
hw = (double) sdl_w;
hh = (double) sdl_h;
gw = (double) *w;
gh = (double) *h;
hsr = hw / hh;
switch (video_fullscreen_scale) {
case FULLSCR_SCALE_FULL:
default:
*w = sdl_w;
*h = sdl_h;
*x = 0;
*y = 0;
break;
case FULLSCR_SCALE_43:
case FULLSCR_SCALE_KEEPRATIO:
if (video_fullscreen_scale == FULLSCR_SCALE_43)
gsr = 4.0 / 3.0;
else
gsr = gw / gh;
if (gsr <= hsr) {
dw = hh * gsr;
dh = hh;
} else {
dw = hw;
dh = hw / gsr;
}
dx = (hw - dw) / 2.0;
dy = (hh - dh) / 2.0;
*w = (int) dw;
*h = (int) dh;
*x = (int) dx;
*y = (int) dy;
break;
case FULLSCR_SCALE_INT:
gsr = gw / gh;
if (gsr <= hsr) {
dw = hh * gsr;
dh = hh;
} else {
dw = hw;
dh = hw / gsr;
}
sdl_integer_scale(&dw, &gw);
sdl_integer_scale(&dh, &gh);
dx = (hw - dw) / 2.0;
dy = (hh - dh) / 2.0;
*w = (int) dw;
*h = (int) dh;
*x = (int) dx;
*y = (int) dy;
break;
}
}
static void
sdl_blit(int x, int y, int w, int h)
{
void *pixeldata;
int pitch;
if (!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL)) {
video_blit_complete();
return;
}
SDL_LockMutex(sdl_mutex);
SDL_LockTexture(sdl_tex, 0, &pixeldata, &pitch);
video_copy(pixeldata, &(buffer32->line[y][x]), h * (2048 + 64) * sizeof(uint32_t));
if (screenshots)
video_screenshot((uint32_t *) pixeldata, 0, 0, (2048 + 64));
blit_w = w;
blit_h = h;
blit_tex_updated = 1;
SDL_UnlockTexture(sdl_tex);
SDL_UnlockMutex(sdl_mutex);
video_blit_complete();
}
static void
sdl_destroy_window(void)
{
if (sdl_win != NULL) {
SDL_DestroyWindow(sdl_win);
sdl_win = NULL;
}
}
static void
sdl_destroy_texture(void)
{
if (sdl_tex != NULL) {
SDL_DestroyTexture(sdl_tex);
sdl_tex = NULL;
}
/* SDL_DestroyRenderer also automatically destroys all associated textures. */
if (sdl_render != NULL) {
SDL_DestroyRenderer(sdl_render);
sdl_render = NULL;
}
}
void
sdl_close(void)
{
if (sdl_mutex != NULL)
SDL_LockMutex(sdl_mutex);
/* Unregister our renderer! */
video_setblit(NULL);
if (sdl_enabled)
sdl_enabled = 0;
if (sdl_mutex != NULL) {
SDL_DestroyMutex(sdl_mutex);
sdl_mutex = NULL;
}
sdl_destroy_texture();
sdl_destroy_window();
/* Quit. */
SDL_Quit();
sdl_flags = -1;
}
static void sdl_select_best_hw_driver(void) {
int i;
SDL_RendererInfo renderInfo;
for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
SDL_GetRenderDriverInfo(i, &renderInfo);
if (renderInfo.flags & SDL_RENDERER_ACCELERATED) {
SDL_SetHint(SDL_HINT_RENDER_DRIVER, renderInfo.name);
return;
}
}
}
static void
sdl_init_texture(void)
{
if (sdl_flags & RENDERER_HARDWARE) {
sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0");
} else {
sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE);
}
sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, (2048 + 64), (2048 + 64));
if (sdl_render == NULL) {
sdl_log("SDL: unable to SDL_CreateRenderer (%s)\n", SDL_GetError());
}
if (sdl_tex == NULL) {
sdl_log("SDL: unable to SDL_CreateTexture (%s)\n", SDL_GetError());
}
}
static void
sdl_reinit_texture(void)
{
if (sdl_flags == -1)
return;
sdl_destroy_texture();
sdl_init_texture();
}
void sdl_set_fs(int fs) {
SDL_SetWindowFullscreen(sdl_win, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
SDL_SetRelativeMouseMode((SDL_bool)mouse_capture);
sdl_fs = fs;
if (fs) {
sdl_flags |= RENDERER_FULL_SCREEN;
} else {
sdl_flags &= ~RENDERER_FULL_SCREEN;
}
sdl_reinit_texture();
}
static int
sdl_init_common(void* win, int flags)
{
wchar_t temp[128];
SDL_version ver;
sdl_log("SDL: init (fs=%d)\n", 0);
/* Get and log the version of the DLL we are using. */
SDL_GetVersion(&ver);
sdl_log("SDL: version %d.%d.%d\n", ver.major, ver.minor, ver.patch);
/* Initialize the SDL system. */
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
sdl_log("SDL: initialization failed (%s)\n", SDL_GetError());
return(0);
}
if (flags & RENDERER_HARDWARE) {
if (flags & RENDERER_OPENGL)
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "OpenGL");
else
sdl_select_best_hw_driver();
}
/* Get the size of the (current) desktop. */
SDL_DisplayMode dm;
if (SDL_GetDesktopDisplayMode(0, &dm) != 0) {
sdl_log("SDL: SDL_GetDesktopDisplayMode failed (%s)\n", SDL_GetError());
return(0);
}
sdl_w = dm.w;
sdl_h = dm.h;
sdl_flags = flags;
sdl_win = SDL_CreateWindow("86Box renderer", 640, 480, 100, 100, sdl_flags);
if (sdl_win == NULL) {
sdl_log("SDL: unable to CreateWindowFrom (%s)\n", SDL_GetError());
}
sdl_init_texture();
sdl_set_fs(video_fullscreen & 1);
/* Make sure we get a clean exit. */
atexit(sdl_close);
/* Register our renderer! */
video_setblit(sdl_blit);
sdl_enabled = 1;
sdl_mutex = SDL_CreateMutex();
return(1);
}
int
sdl_inits(void* win)
{
return sdl_init_common(win, 0);
}
int
sdl_inith(void* win)
{
return sdl_init_common(win, RENDERER_HARDWARE);
}
int
sdl_initho(void* win)
{
return sdl_init_common(win, RENDERER_HARDWARE | RENDERER_OPENGL);
}
int
sdl_pause(void)
{
return(0);
}
void
sdl_resize(int w, int h)
{
int ww = 0, wh = 0;
if (video_fullscreen & 2)
return;
if ((w == cur_w) && (h == cur_h))
return;
SDL_LockMutex(sdl_mutex);
ww = w;
wh = h;
if (sdl_fs) {
// sdl_stretch(&ww, &wh, &wx, &wy);
// MoveWindow(hwndRender, wx, wy, ww, wh, TRUE);
}
cur_w = w;
cur_h = h;
cur_ww = ww;
cur_wh = wh;
SDL_SetWindowSize(sdl_win, cur_ww, cur_wh);
sdl_reinit_texture();
SDL_UnlockMutex(sdl_mutex);
}
void
sdl_enable(int enable)
{
if (sdl_flags == -1)
return;
SDL_LockMutex(sdl_mutex);
sdl_enabled = !!enable;
if (enable == 1) {
SDL_SetWindowSize(sdl_win, cur_ww, cur_wh);
sdl_reinit_texture();
}
SDL_UnlockMutex(sdl_mutex);
}
void
sdl_reload(void)
{
if (sdl_flags & RENDERER_HARDWARE) {
SDL_LockMutex(sdl_mutex);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0");
sdl_reinit_texture();
SDL_UnlockMutex(sdl_mutex);
}
}
static int mouse_inside = 0;
enum sdl_main_status sdl_main() {
int ret = SdlMainOk;
SDL_Rect r_src;
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
ret = SdlMainQuit;
break;
case SDL_MOUSEWHEEL:
{
if (mouse_capture || video_fullscreen)
{
if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED)
{
event.wheel.x *= -1;
event.wheel.y *= -1;
}
mousedata.deltaz = event.wheel.y;
}
break;
}
case SDL_MOUSEMOTION:
{
if (mouse_capture || video_fullscreen)
{
mousedata.deltax += event.motion.xrel;
mousedata.deltay += event.motion.yrel;
}
break;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
if ((event.button.button == SDL_BUTTON_LEFT)
&& !(mouse_capture || video_fullscreen)
&& event.button.state == SDL_RELEASED
&& mouse_inside)
{
plat_mouse_capture(1);
break;
}
if (mouse_get_buttons() < 3 && event.button.button == SDL_BUTTON_MIDDLE && !video_fullscreen)
{
plat_mouse_capture(0);
break;
}
if (mouse_capture || video_fullscreen)
{
int buttonmask = 0;
switch(event.button.button)
{
case SDL_BUTTON_LEFT:
buttonmask = 1;
break;
case SDL_BUTTON_RIGHT:
buttonmask = 2;
break;
case SDL_BUTTON_MIDDLE:
buttonmask = 4;
break;
}
if (event.button.state == SDL_PRESSED)
{
mousedata.mousebuttons |= buttonmask;
}
else mousedata.mousebuttons &= ~buttonmask;
}
break;
}
case SDL_RENDER_DEVICE_RESET:
case SDL_RENDER_TARGETS_RESET:
{
sdl_reinit_texture();
break;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
{
uint16_t xtkey = 0;
switch(event.key.keysym.scancode)
{
default:
xtkey = sdl_to_xt[event.key.keysym.scancode];
break;
}
keyboard_input(event.key.state == SDL_PRESSED, xtkey);
}
break;
case SDL_WINDOWEVENT:
{
switch (event.window.event)
{
case SDL_WINDOWEVENT_ENTER:
mouse_inside = 1;
break;
case SDL_WINDOWEVENT_LEAVE:
mouse_inside = 0;
break;
}
}
}
}
if (blit_tex_updated > 0) {
SDL_LockMutex(sdl_mutex);
int status = SDL_RenderClear(sdl_render);
if (status) {
sdl_log("SDL: unable to SDL_RenderClear (%s)\n", SDL_GetError());
}
r_src.x = 0;
r_src.y = 0;
r_src.w = blit_w;
r_src.h = blit_h;
status = SDL_RenderCopy(sdl_render, sdl_tex, &r_src, 0);
if (status) {
sdl_log("SDL: unable to copy texture to renderer (%s)\n", SDL_GetError());
}
SDL_RenderPresent(sdl_render);
blit_tex_updated = 0;
SDL_UnlockMutex(sdl_mutex);
}
if (mouse_capture && keyboard_ismsexit()) {
plat_mouse_capture(0);
}
if (video_fullscreen && keyboard_isfsexit()) {
plat_setfullscreen(0);
}
return ret;
}
void sdl_mouse_capture(int on) {
SDL_SetRelativeMouseMode((SDL_bool)on);
}
void sdl_mouse_poll() {
mouse_x = mousedata.deltax;
mouse_y = mousedata.deltay;
mouse_z = mousedata.deltaz;
mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0;
mouse_buttons = mousedata.mousebuttons;
}

73
src/qt/qt_sdl.h Normal file
View File

@ -0,0 +1,73 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Definitions for the libSDL2 rendering module.
*
*
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Michael Drüing, <michael@drueing.de>
*
* Copyright 2018,2019 Fred N. van Kempen.
* Copyright 2018,2019 Michael Drüing.
*
* Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the entire
* above notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WIN_SDL_H
# define WIN_SDL_H
extern void* sdl_win_handle;
extern void sdl_close(void);
extern int sdl_inits();
extern int sdl_inith();
extern int sdl_initho();
extern int sdl_pause(void);
extern void sdl_resize(int w, int h);
extern void sdl_enable(int enable);
extern void sdl_set_fs(int fs);
extern void sdl_reload(void);
enum sdl_main_status {
SdlMainOk,
SdlMainQuit,
};
extern enum sdl_main_status sdl_main();
extern void sdl_mouse_capture(int on);
extern void sdl_mouse_poll();
#endif /*WIN_SDL_H*/

131
src/qt/qt_settings.cpp Normal file
View File

@ -0,0 +1,131 @@
#include "qt_settings.hpp"
#include "ui_qt_settings.h"
#include "qt_settingsmachine.hpp"
#include "qt_settingsdisplay.hpp"
#include "qt_settingsinput.hpp"
#include "qt_settingssound.hpp"
#include "qt_settingsnetwork.hpp"
#include "qt_settingsports.hpp"
#include "qt_settingsstoragecontrollers.hpp"
#include "qt_settingsharddisks.hpp"
#include "qt_settingsfloppycdrom.hpp"
#include "qt_settingsotherremovable.hpp"
#include "qt_settingsotherperipherals.hpp"
#include <QDebug>
class SettingsModel : public QAbstractListModel {
public:
SettingsModel(QObject* parent) : QAbstractListModel(parent) {}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
private:
QStringList pages = {
"Machine",
"Display",
"Input Devices",
"Sound",
"Network",
"Ports (COM & LPT)",
"Storage Controllers",
"Hard Disks",
"Floppy & CD-ROM Drives",
"Other Removable Devices",
"Other Peripherals",
};
QStringList page_icons = {
"machine",
"display",
"input_devices",
"sound",
"network",
"ports",
"storage_controllers",
"hard_disk",
"floppy_and_cdrom_drives",
"other_removable_devices",
"other_peripherals",
};
};
QVariant SettingsModel::data(const QModelIndex &index, int role) const {
Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::ParentIsInvalid));
switch (role) {
case Qt::DisplayRole:
return pages.at(index.row());
case Qt::DecorationRole:
return QIcon(QString(":/settings/win/icons/%1.ico").arg(page_icons[index.row()]));
default:
return {};
}
}
int SettingsModel::rowCount(const QModelIndex &parent) const {
(void) parent;
return pages.size();
}
Settings::Settings(QWidget *parent) :
QDialog(parent),
ui(new Ui::Settings)
{
ui->setupUi(this);
ui->listView->setModel(new SettingsModel(this));
machine = new SettingsMachine(this);
display = new SettingsDisplay(this);
input = new SettingsInput(this);
sound = new SettingsSound(this);
network = new SettingsNetwork(this);
ports = new SettingsPorts(this);
storageControllers = new SettingsStorageControllers(this);
harddisks = new SettingsHarddisks(this);
floppyCdrom = new SettingsFloppyCDROM(this);
otherRemovable = new SettingsOtherRemovable(this);
otherPeripherals = new SettingsOtherPeripherals(this);
ui->stackedWidget->addWidget(machine);
ui->stackedWidget->addWidget(display);
ui->stackedWidget->addWidget(input);
ui->stackedWidget->addWidget(sound);
ui->stackedWidget->addWidget(network);
ui->stackedWidget->addWidget(ports);
ui->stackedWidget->addWidget(storageControllers);
ui->stackedWidget->addWidget(harddisks);
ui->stackedWidget->addWidget(floppyCdrom);
ui->stackedWidget->addWidget(otherRemovable);
ui->stackedWidget->addWidget(otherPeripherals);
connect(machine, &SettingsMachine::currentMachineChanged, display, &SettingsDisplay::onCurrentMachineChanged);
connect(machine, &SettingsMachine::currentMachineChanged, input, &SettingsInput::onCurrentMachineChanged);
connect(machine, &SettingsMachine::currentMachineChanged, sound, &SettingsSound::onCurrentMachineChanged);
connect(machine, &SettingsMachine::currentMachineChanged, network, &SettingsNetwork::onCurrentMachineChanged);
connect(machine, &SettingsMachine::currentMachineChanged, storageControllers, &SettingsStorageControllers::onCurrentMachineChanged);
connect(ui->listView->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex &current, const QModelIndex &previous) {
ui->stackedWidget->setCurrentIndex(current.row());
});
}
Settings::~Settings()
{
delete ui;
}
void Settings::save() {
machine->save();
display->save();
input->save();
sound->save();
network->save();
ports->save();
storageControllers->save();
harddisks->save();
floppyCdrom->save();
otherRemovable->save();
otherPeripherals->save();
}

46
src/qt/qt_settings.hpp Normal file
View File

@ -0,0 +1,46 @@
#ifndef QT_SETTINGS_HPP
#define QT_SETTINGS_HPP
#include <QDialog>
namespace Ui {
class Settings;
}
class SettingsMachine;
class SettingsDisplay;
class SettingsInput;
class SettingsSound;
class SettingsNetwork;
class SettingsPorts;
class SettingsStorageControllers;
class SettingsHarddisks;
class SettingsFloppyCDROM;
class SettingsOtherRemovable;
class SettingsOtherPeripherals;
class Settings : public QDialog
{
Q_OBJECT
public:
explicit Settings(QWidget *parent = nullptr);
~Settings();
void save();
private:
Ui::Settings *ui;
SettingsMachine* machine;
SettingsDisplay* display;
SettingsInput* input;
SettingsSound* sound;
SettingsNetwork* network;
SettingsPorts* ports;
SettingsStorageControllers* storageControllers;
SettingsHarddisks* harddisks;
SettingsFloppyCDROM* floppyCdrom;
SettingsOtherRemovable* otherRemovable;
SettingsOtherPeripherals* otherPeripherals;
};
#endif // QT_SETTINGS_HPP

87
src/qt/qt_settings.ui Normal file
View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Settings</class>
<widget class="QDialog" name="Settings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>595</height>
</rect>
</property>
<property name="windowTitle">
<string>86Box Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,3">
<item>
<widget class="QListView" name="listView"/>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Settings</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Settings</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,105 @@
#include "qt_settingsdisplay.hpp"
#include "ui_qt_settingsdisplay.h"
#include <QDebug>
extern "C" {
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/video.h>
}
#include "qt_deviceconfig.hpp"
#include "qt_models_common.hpp"
SettingsDisplay::SettingsDisplay(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsDisplay)
{
ui->setupUi(this);
onCurrentMachineChanged(machine);
}
SettingsDisplay::~SettingsDisplay()
{
delete ui;
}
void SettingsDisplay::save() {
gfxcard = ui->comboBoxVideo->currentData().toInt();
voodoo_enabled = ui->checkBoxVoodoo->isChecked() ? 1 : 0;
}
void SettingsDisplay::onCurrentMachineChanged(int machineId) {
// win_settings_video_proc, WM_INITDIALOG
this->machineId = machineId;
auto* machine = &machines[machineId];
auto* model = ui->comboBoxVideo->model();
auto removeRows = model->rowCount();
int c = 0;
int selectedRow = 0;
while (true) {
/* Skip "internal" if machine doesn't have it. */
if ((c == 1) && !(machine->flags & MACHINE_VIDEO)) {
c++;
continue;
}
const device_t* video_dev = video_card_getdevice(c);
QString name = DeviceConfig::DeviceName(video_dev, video_get_internal_name(c), 1);
if (name.isEmpty()) {
break;
}
if (video_card_available(c) &&
device_is_valid(video_dev, machine->flags)) {
int row = Models::AddEntry(model, name, c);
if (c == gfxcard) {
selectedRow = row - removeRows;
}
}
c++;
}
model->removeRows(0, removeRows);
if (machine->flags & MACHINE_VIDEO_ONLY) {
ui->comboBoxVideo->setEnabled(false);
selectedRow = 1;
} else {
ui->comboBoxVideo->setEnabled(true);
}
ui->comboBoxVideo->setCurrentIndex(selectedRow);
}
void SettingsDisplay::on_pushButtonConfigure_clicked() {
auto* device = video_card_getdevice(ui->comboBoxVideo->currentData().toInt());
DeviceConfig::ConfigureDevice(device);
}
void SettingsDisplay::on_pushButtonConfigureVoodoo_clicked() {
DeviceConfig::ConfigureDevice(&voodoo_device);
}
void SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) {
if (index < 0) {
return;
}
int videoCard = ui->comboBoxVideo->currentData().toInt();
ui->pushButtonConfigure->setEnabled(video_card_has_config(videoCard) > 0);
bool machineHasPci = machines[machineId].flags & MACHINE_BUS_PCI;
ui->checkBoxVoodoo->setEnabled(machineHasPci);
if (machineHasPci) {
ui->checkBoxVoodoo->setChecked(voodoo_enabled);
}
ui->pushButtonConfigureVoodoo->setEnabled(machineHasPci && ui->checkBoxVoodoo->isChecked());
}
void SettingsDisplay::on_checkBoxVoodoo_stateChanged(int state) {
ui->pushButtonConfigureVoodoo->setEnabled(state == Qt::Checked);
}

View File

@ -0,0 +1,34 @@
#ifndef QT_SETTINGSDISPLAY_HPP
#define QT_SETTINGSDISPLAY_HPP
#include <QWidget>
namespace Ui {
class SettingsDisplay;
}
class SettingsDisplay : public QWidget
{
Q_OBJECT
public:
explicit SettingsDisplay(QWidget *parent = nullptr);
~SettingsDisplay();
void save();
public slots:
void onCurrentMachineChanged(int machineId);
private slots:
void on_checkBoxVoodoo_stateChanged(int state);
void on_comboBoxVideo_currentIndexChanged(int index);
void on_pushButtonConfigureVoodoo_clicked();
void on_pushButtonConfigure_clicked();
private:
Ui::SettingsDisplay *ui;
int machineId = 0;
};
#endif // QT_SETTINGSDISPLAY_HPP

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsDisplay</class>
<widget class="QWidget" name="SettingsDisplay">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<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 row="0" column="1">
<widget class="QComboBox" name="comboBoxVideo"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Video</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="pushButtonConfigure">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonConfigureVoodoo">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="checkBoxVoodoo">
<property name="text">
<string>Voodoo Graphics</string>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,217 @@
#include "qt_settingsfloppycdrom.hpp"
#include "ui_qt_settingsfloppycdrom.h"
extern "C" {
#include <86box/timer.h>
#include <86box/fdd.h>
#include <86box/cdrom.h>
}
#include <QStandardItemModel>
#include "qt_models_common.hpp"
#include "qt_harddrive_common.hpp"
static void setFloppyType(QAbstractItemModel* model, const QModelIndex& idx, int type) {
QIcon icon;
if (type == 0) {
icon = QIcon(":/settings/win/icons/floppy_disabled.ico");
} else if (type >= 1 && type <= 6) {
icon = QIcon(":/settings/win/icons/floppy_525.ico");
} else {
icon = QIcon(":/settings/win/icons/floppy_35.ico");
}
model->setData(idx, fdd_getname(type));
model->setData(idx, type, Qt::UserRole);
model->setData(idx, icon, Qt::DecorationRole);
}
static void setCDROMBus(QAbstractItemModel* model, const QModelIndex& idx, uint8_t bus, uint8_t channel) {
QIcon icon;
switch (bus) {
case CDROM_BUS_DISABLED:
icon = QIcon(":/settings/win/icons/cdrom_disabled.ico");
break;
case CDROM_BUS_ATAPI:
case CDROM_BUS_SCSI:
icon = QIcon(":/settings/win/icons/cdrom.ico");
break;
}
auto i = idx.siblingAtColumn(0);
model->setData(i, Harddrives::BusChannelName(bus, channel));
model->setData(i, bus, Qt::UserRole);
model->setData(i, channel, Qt::UserRole + 1);
model->setData(i, icon, Qt::DecorationRole);
}
static void setCDROMSpeed(QAbstractItemModel* model, const QModelIndex& idx, uint8_t speed) {
auto i = idx.siblingAtColumn(1);
model->setData(i, QString("%1x").arg(speed));
model->setData(i, speed, Qt::UserRole);
}
SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsFloppyCDROM)
{
ui->setupUi(this);
auto* model = ui->comboBoxFloppyType->model();
int i = 0;
while (true) {
QString name = fdd_getname(i);
if (name.isEmpty()) {
break;
}
Models::AddEntry(model, name, i);
++i;
}
model = new QStandardItemModel(0, 3, this);
ui->tableViewFloppy->setModel(model);
model->setHeaderData(0, Qt::Horizontal, "Type");
model->setHeaderData(1, Qt::Horizontal, "Turbo");
model->setHeaderData(2, Qt::Horizontal, "Check BPB");
model->insertRows(0, FDD_NUM);
/* Floppy drives category */
for (int i = 0; i < FDD_NUM; i++) {
auto idx = model->index(i, 0);
int type = fdd_get_type(i);
setFloppyType(model, idx, type);
model->setData(idx.siblingAtColumn(1), fdd_get_turbo(i) > 0 ? "On" : "Off");
model->setData(idx.siblingAtColumn(2), fdd_get_check_bpb(i) > 0 ? "On" : "Off");
}
ui->tableViewFloppy->resizeColumnsToContents();
ui->tableViewFloppy->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
connect(ui->tableViewFloppy->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SettingsFloppyCDROM::onFloppyRowChanged);
ui->tableViewFloppy->setCurrentIndex(model->index(0, 0));
Harddrives::populateRemovableBuses(ui->comboBoxBus->model());
model = ui->comboBoxSpeed->model();
for (int i = 0; i <= 72; i++) {
Models::AddEntry(model, QString("%1x").arg(i), i);
}
model = new QStandardItemModel(0, 2, this);
ui->tableViewCDROM->setModel(model);
model->setHeaderData(0, Qt::Horizontal, "Bus");
model->setHeaderData(1, Qt::Horizontal, "Speed");
model->insertRows(0, CDROM_NUM);
for (int i = 0; i < CDROM_NUM; i++) {
auto idx = model->index(i, 0);
setCDROMBus(model, idx, cdrom[i].bus_type, cdrom[i].res);
setCDROMSpeed(model, idx.siblingAtColumn(1), cdrom[i].speed);
}
ui->tableViewCDROM->resizeColumnsToContents();
ui->tableViewCDROM->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
connect(ui->tableViewCDROM->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SettingsFloppyCDROM::onCDROMRowChanged);
ui->tableViewCDROM->setCurrentIndex(model->index(0, 0));
}
SettingsFloppyCDROM::~SettingsFloppyCDROM()
{
delete ui;
}
void SettingsFloppyCDROM::save() {
auto* model = ui->tableViewFloppy->model();
for (int i = 0; i < FDD_NUM; i++) {
fdd_set_type(i, model->index(i, 0).data(Qt::UserRole).toInt());
fdd_set_turbo(i, model->index(i, 1).data() == "On" ? 1 : 0);
fdd_set_check_bpb(i, model->index(i, 2).data() == "On" ? 1 : 0);
}
/* Removable devices category */
model = ui->tableViewCDROM->model();
memset(cdrom, 0, sizeof(cdrom));
for (int i = 0; i < CDROM_NUM; i++) {
cdrom[i].bus_type = model->index(i, 0).data(Qt::UserRole).toUInt();
cdrom[i].res = model->index(i, 0).data(Qt::UserRole + 1).toUInt();
cdrom[i].speed = model->index(i, 1).data(Qt::UserRole).toUInt();
}
}
void SettingsFloppyCDROM::onFloppyRowChanged(const QModelIndex &current) {
int type = current.siblingAtColumn(0).data(Qt::UserRole).toInt();
ui->comboBoxFloppyType->setCurrentIndex(type);
ui->checkBoxTurboTimings->setChecked(current.siblingAtColumn(1).data() == "On");
ui->checkBoxCheckBPB->setChecked(current.siblingAtColumn(2).data() == "On");
}
void SettingsFloppyCDROM::onCDROMRowChanged(const QModelIndex &current) {
uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt();
uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt();
uint8_t speed = current.siblingAtColumn(1).data(Qt::UserRole).toUInt();
ui->comboBoxBus->setCurrentIndex(-1);
auto* model = ui->comboBoxBus->model();
auto match = model->match(model->index(0, 0), Qt::UserRole, bus);
if (! match.isEmpty()) {
ui->comboBoxBus->setCurrentIndex(match.first().row());
}
model = ui->comboBoxChannel->model();
match = model->match(model->index(0, 0), Qt::UserRole, channel);
if (! match.isEmpty()) {
ui->comboBoxChannel->setCurrentIndex(match.first().row());
}
ui->comboBoxSpeed->setCurrentIndex(speed);
}
void SettingsFloppyCDROM::on_checkBoxTurboTimings_stateChanged(int arg1) {
auto idx = ui->tableViewFloppy->selectionModel()->currentIndex();
ui->tableViewFloppy->model()->setData(idx.siblingAtColumn(1), arg1 == Qt::Checked ? "On" : "Off");
}
void SettingsFloppyCDROM::on_checkBoxCheckBPB_stateChanged(int arg1) {
auto idx = ui->tableViewFloppy->selectionModel()->currentIndex();
ui->tableViewFloppy->model()->setData(idx.siblingAtColumn(2), arg1 == Qt::Checked ? "On" : "Off");
}
void SettingsFloppyCDROM::on_comboBoxFloppyType_activated(int index) {
setFloppyType(ui->tableViewFloppy->model(), ui->tableViewFloppy->selectionModel()->currentIndex(), index);
}
void SettingsFloppyCDROM::on_comboBoxBus_currentIndexChanged(int index) {
if (index < 0) {
return;
}
int bus = ui->comboBoxBus->currentData().toInt();
bool enabled = (bus != CDROM_BUS_DISABLED);
ui->comboBoxChannel->setEnabled(enabled);
ui->comboBoxSpeed->setEnabled(enabled);
Harddrives::populateBusChannels(ui->comboBoxChannel->model(), bus);
}
void SettingsFloppyCDROM::on_comboBoxSpeed_activated(int index) {
auto idx = ui->tableViewCDROM->selectionModel()->currentIndex();
setCDROMSpeed(ui->tableViewCDROM->model(), idx.siblingAtColumn(1), index);
}
void SettingsFloppyCDROM::on_comboBoxBus_activated(int) {
setCDROMBus(
ui->tableViewCDROM->model(),
ui->tableViewCDROM->selectionModel()->currentIndex(),
ui->comboBoxBus->currentData().toUInt(),
ui->comboBoxChannel->currentData().toUInt());
}
void SettingsFloppyCDROM::on_comboBoxChannel_activated(int) {
setCDROMBus(
ui->tableViewCDROM->model(),
ui->tableViewCDROM->selectionModel()->currentIndex(),
ui->comboBoxBus->currentData().toUInt(),
ui->comboBoxChannel->currentData().toUInt());
}

View File

@ -0,0 +1,35 @@
#ifndef QT_SETTINGSFLOPPYCDROM_HPP
#define QT_SETTINGSFLOPPYCDROM_HPP
#include <QWidget>
namespace Ui {
class SettingsFloppyCDROM;
}
class SettingsFloppyCDROM : public QWidget
{
Q_OBJECT
public:
explicit SettingsFloppyCDROM(QWidget *parent = nullptr);
~SettingsFloppyCDROM();
void save();
private slots:
void on_comboBoxChannel_activated(int index);
void on_comboBoxBus_activated(int index);
void on_comboBoxSpeed_activated(int index);
void on_comboBoxBus_currentIndexChanged(int index);
void on_comboBoxFloppyType_activated(int index);
void on_checkBoxCheckBPB_stateChanged(int arg1);
void on_checkBoxTurboTimings_stateChanged(int arg1);
void onFloppyRowChanged(const QModelIndex &current);
void onCDROMRowChanged(const QModelIndex &current);
private:
Ui::SettingsFloppyCDROM *ui;
};
#endif // QT_SETTINGSFLOPPYCDROM_HPP

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsFloppyCDROM</class>
<widget class="QWidget" name="SettingsFloppyCDROM">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>544</width>
<height>617</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<widget class="QLabel" name="label">
<property name="text">
<string>Floppy Drives</string>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="tableViewFloppy">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxFloppyType"/>
</item>
<item>
<widget class="QCheckBox" name="checkBoxTurboTimings">
<property name="text">
<string>Turbo Timings</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCheckBPB">
<property name="text">
<string>Check BPB</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>CD-ROM Drives</string>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="tableViewCDROM">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Channel</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxBus"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Speed</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Bus</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QComboBox" name="comboBoxChannel"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxSpeed"/>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,225 @@
#include "qt_settingsharddisks.hpp"
#include "ui_qt_settingsharddisks.h"
extern "C" {
#include <86box/86box.h>
#include <86box/hdd.h>
}
#include <QStandardItemModel>
#include "qt_harddiskdialog.hpp"
#include "qt_harddrive_common.hpp"
const int ColumnBus = 0;
const int ColumnFilename = 1;
const int ColumnCylinders = 2;
const int ColumnHeads = 3;
const int ColumnSectors = 4;
const int ColumnSize = 5;
const int DataBus = Qt::UserRole;
const int DataBusChannel = Qt::UserRole + 1;
/*
static void
normalize_hd_list()
{
hard_disk_t ihdd[HDD_NUM];
int i, j;
j = 0;
memset(ihdd, 0x00, HDD_NUM * sizeof(hard_disk_t));
for (i = 0; i < HDD_NUM; i++) {
if (temp_hdd[i].bus != HDD_BUS_DISABLED) {
memcpy(&(ihdd[j]), &(temp_hdd[i]), sizeof(hard_disk_t));
j++;
}
}
memcpy(temp_hdd, ihdd, HDD_NUM * sizeof(hard_disk_t));
}
*/
static QString busChannelName(const QModelIndex& idx) {
return Harddrives::BusChannelName(idx.data(DataBus).toUInt(), idx.data(DataBusChannel).toUInt());
}
static void addRow(QAbstractItemModel* model, hard_disk_t* hd) {
const QString userPath = usr_path;
int row = model->rowCount();
model->insertRow(row);
QString busName = Harddrives::BusChannelName(hd->bus, hd->channel);
model->setData(model->index(row, ColumnBus), busName);
model->setData(model->index(row, ColumnBus), QIcon(":/settings/win/icons/hard_disk.ico"), Qt::DecorationRole);
model->setData(model->index(row, ColumnBus), hd->bus, DataBus);
model->setData(model->index(row, ColumnBus), hd->channel, DataBusChannel);
QString fileName = hd->fn;
if (fileName.startsWith(userPath, Qt::CaseInsensitive)) {
model->setData(model->index(row, ColumnFilename), fileName.mid(userPath.size()));
} else {
model->setData(model->index(row, ColumnFilename), fileName);
}
model->setData(model->index(row, ColumnFilename), fileName, Qt::UserRole);
model->setData(model->index(row, ColumnCylinders), hd->tracks);
model->setData(model->index(row, ColumnHeads), hd->hpc);
model->setData(model->index(row, ColumnSectors), hd->spt);
model->setData(model->index(row, ColumnSize), (hd->tracks * hd->hpc * hd->spt) >> 11);
}
SettingsHarddisks::SettingsHarddisks(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsHarddisks)
{
ui->setupUi(this);
QAbstractItemModel* model = new QStandardItemModel(0, 6, this);
model->setHeaderData(ColumnBus, Qt::Horizontal, "Bus");
model->setHeaderData(ColumnFilename, Qt::Horizontal, "File");
model->setHeaderData(ColumnCylinders, Qt::Horizontal, "C");
model->setHeaderData(ColumnHeads, Qt::Horizontal, "H");
model->setHeaderData(ColumnSectors, Qt::Horizontal, "S");
model->setHeaderData(ColumnSize, Qt::Horizontal, "MiB");
ui->tableView->setModel(model);
for (int i = 0; i < HDD_NUM; i++) {
if (hdd[i].bus > 0) {
addRow(model, &hdd[i]);
}
}
ui->tableView->resizeColumnsToContents();
ui->tableView->horizontalHeader()->setSectionResizeMode(ColumnFilename, QHeaderView::Stretch);
auto* tableSelectionModel = ui->tableView->selectionModel();
connect(tableSelectionModel, &QItemSelectionModel::currentRowChanged, this, &SettingsHarddisks::onTableRowChanged);
onTableRowChanged(QModelIndex());
Harddrives::populateBuses(ui->comboBoxBus->model());
on_comboBoxBus_currentIndexChanged(0);
}
SettingsHarddisks::~SettingsHarddisks()
{
delete ui;
}
void SettingsHarddisks::save() {
memset(hdd, 0, sizeof(hdd));
auto* model = ui->tableView->model();
int rows = model->rowCount();
for (int i = 0; i < rows; ++i) {
auto idx = model->index(i, ColumnBus);
hdd[i].bus = idx.data(DataBus).toUInt();
hdd[i].channel = idx.data(DataBusChannel).toUInt();
hdd[i].tracks = idx.siblingAtColumn(ColumnCylinders).data().toUInt();
hdd[i].hpc = idx.siblingAtColumn(ColumnHeads).data().toUInt();
hdd[i].spt = idx.siblingAtColumn(ColumnSectors).data().toUInt();
QByteArray fileName = idx.siblingAtColumn(ColumnFilename).data(Qt::UserRole).toString().toUtf8();
strncpy(hdd[i].fn, fileName.data(), sizeof(hdd[i].fn));
hdd[i].priv = nullptr;
}
}
void SettingsHarddisks::on_comboBoxBus_currentIndexChanged(int index) {
if (index < 0) {
return;
}
auto idx = ui->tableView->selectionModel()->currentIndex();
if (idx.isValid()) {
auto* model = ui->tableView->model();
auto col = idx.siblingAtColumn(ColumnBus);
model->setData(col, ui->comboBoxBus->currentData(Qt::UserRole), DataBus);
model->setData(col, busChannelName(col), Qt::DisplayRole);
}
Harddrives::populateBusChannels(ui->comboBoxChannel->model(), ui->comboBoxBus->currentData().toInt());
}
void SettingsHarddisks::on_comboBoxChannel_currentIndexChanged(int index) {
if (index < 0) {
return;
}
auto idx = ui->tableView->selectionModel()->currentIndex();
if (idx.isValid()) {
auto* model = ui->tableView->model();
auto col = idx.siblingAtColumn(ColumnBus);
model->setData(col, ui->comboBoxChannel->currentData(Qt::UserRole), DataBusChannel);
model->setData(col, busChannelName(col), Qt::DisplayRole);
}
}
void SettingsHarddisks::onTableRowChanged(const QModelIndex &current) {
bool hidden = !current.isValid();
ui->labelBus->setHidden(hidden);
ui->labelChannel->setHidden(hidden);
ui->comboBoxBus->setHidden(hidden);
ui->comboBoxChannel->setHidden(hidden);
uint32_t bus = current.siblingAtColumn(ColumnBus).data(DataBus).toUInt();
uint32_t busChannel = current.siblingAtColumn(ColumnBus).data(DataBusChannel).toUInt();
auto* model = ui->comboBoxBus->model();
auto match = model->match(model->index(0, 0), Qt::UserRole, bus);
if (! match.isEmpty()) {
ui->comboBoxBus->setCurrentIndex(match.first().row());
}
model = ui->comboBoxChannel->model();
match = model->match(model->index(0, 0), Qt::UserRole, busChannel);
if (! match.isEmpty()) {
ui->comboBoxChannel->setCurrentIndex(match.first().row());
}
}
static void addDriveFromDialog(Ui::SettingsHarddisks* ui, const HarddiskDialog& dlg) {
QByteArray fn = dlg.fileName().toUtf8();
hard_disk_t hd;
hd.bus = dlg.bus();
hd.channel = dlg.channel();
hd.tracks = dlg.cylinders();
hd.hpc = dlg.heads();
hd.spt = dlg.sectors();
strncpy(hd.fn, fn.data(), sizeof(hd.fn));
addRow(ui->tableView->model(), &hd);
ui->tableView->resizeColumnsToContents();
ui->tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
}
void SettingsHarddisks::on_pushButtonNew_clicked() {
HarddiskDialog dialog(false, this);
switch (dialog.exec()) {
case QDialog::Accepted:
addDriveFromDialog(ui, dialog);
break;
}
}
void SettingsHarddisks::on_pushButtonExisting_clicked() {
HarddiskDialog dialog(true, this);
switch (dialog.exec()) {
case QDialog::Accepted:
addDriveFromDialog(ui, dialog);
break;
}
}
void SettingsHarddisks::on_pushButtonRemove_clicked() {
auto idx = ui->tableView->selectionModel()->currentIndex();
if (! idx.isValid()) {
return;
}
auto* model = ui->tableView->model();
model->removeRow(idx.row());
}

View File

@ -0,0 +1,35 @@
#ifndef QT_SETTINGSHARDDISKS_HPP
#define QT_SETTINGSHARDDISKS_HPP
#include <QWidget>
namespace Ui {
class SettingsHarddisks;
}
class SettingsHarddisks : public QWidget
{
Q_OBJECT
public:
explicit SettingsHarddisks(QWidget *parent = nullptr);
~SettingsHarddisks();
void save();
private slots:
void on_comboBoxChannel_currentIndexChanged(int index);
private slots:
void on_pushButtonRemove_clicked();
void on_pushButtonExisting_clicked();
void on_pushButtonNew_clicked();
void on_comboBoxBus_currentIndexChanged(int index);
void onTableRowChanged(const QModelIndex& current);
private:
Ui::SettingsHarddisks *ui;
};
#endif // QT_SETTINGSHARDDISKS_HPP

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsHarddisks</class>
<widget class="QWidget" name="SettingsHarddisks">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<widget class="QTableView" name="tableView">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="labelBus">
<property name="text">
<string>Bus</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxBus"/>
</item>
<item>
<widget class="QLabel" name="labelChannel">
<property name="text">
<string>ID</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxChannel"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButtonNew">
<property name="text">
<string>New</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonExisting">
<property name="text">
<string>Existing</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

114
src/qt/qt_settingsinput.cpp Normal file
View File

@ -0,0 +1,114 @@
#include "qt_settingsinput.hpp"
#include "ui_qt_settingsinput.h"
#include <QDebug>
extern "C" {
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/mouse.h>
#include <86box/gameport.h>
}
#include "qt_deviceconfig.hpp"
SettingsInput::SettingsInput(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsInput)
{
ui->setupUi(this);
onCurrentMachineChanged(machine);
}
SettingsInput::~SettingsInput()
{
delete ui;
}
void SettingsInput::save() {
mouse_type = ui->comboBoxMouse->currentData().toInt();
joystick_type = ui->comboBoxJoystick->currentData().toInt();
}
void SettingsInput::onCurrentMachineChanged(int machineId) {
// win_settings_video_proc, WM_INITDIALOG
this->machineId = machineId;
const auto* machine = &machines[machineId];
auto* mouseModel = ui->comboBoxMouse->model();
auto removeRows = mouseModel->rowCount();
int selectedRow = 0;
for (int i = 0; i < mouse_get_ndev(); ++i) {
const auto* dev = mouse_get_device(i);
if ((i == MOUSE_TYPE_INTERNAL) && !(machines[machineId].flags & MACHINE_MOUSE)) {
continue;
}
if (device_is_valid(dev, machine->flags) == 0) {
continue;
}
QString name = DeviceConfig::DeviceName(dev, mouse_get_internal_name(i), 0);
int row = mouseModel->rowCount();
mouseModel->insertRow(row);
auto idx = mouseModel->index(row, 0);
mouseModel->setData(idx, name, Qt::DisplayRole);
mouseModel->setData(idx, i, Qt::UserRole);
if (i == mouse_type) {
selectedRow = row - removeRows;
}
}
mouseModel->removeRows(0, removeRows);
ui->comboBoxMouse->setCurrentIndex(selectedRow);
int i = 0;
char* joyName = joystick_get_name(i);
auto* joystickModel = ui->comboBoxJoystick->model();
removeRows = joystickModel->rowCount();
selectedRow = 0;
while (joyName) {
int row = joystickModel->rowCount();
joystickModel->insertRow(row);
auto idx = joystickModel->index(row, 0);
joystickModel->setData(idx, joyName, Qt::DisplayRole);
joystickModel->setData(idx, i, Qt::UserRole);
if (i == joystick_type) {
selectedRow = row - removeRows;
}
++i;
joyName = joystick_get_name(i);
}
joystickModel->removeRows(0, removeRows);
ui->comboBoxJoystick->setCurrentIndex(selectedRow);
}
void SettingsInput::on_comboBoxMouse_currentIndexChanged(int index) {
int mouseId = ui->comboBoxMouse->currentData().toInt();
ui->pushButtonConfigureMouse->setEnabled(mouse_has_config(mouseId) > 0);
}
void SettingsInput::on_comboBoxJoystick_currentIndexChanged(int index) {
int joystickId = ui->comboBoxJoystick->currentData().toInt();
for (int i = 0; i < 4; ++i) {
auto* btn = findChild<QPushButton*>(QString("pushButtonJoystick%1").arg(i+1));
if (btn == nullptr) {
continue;
}
btn->setEnabled(joystick_get_max_joysticks(joystickId) > i);
}
}
void SettingsInput::on_pushButtonConfigureMouse_clicked() {
int mouseId = ui->comboBoxMouse->currentData().toInt();
DeviceConfig::ConfigureDevice(mouse_get_device(mouseId));
}

View File

@ -0,0 +1,33 @@
#ifndef QT_SETTINGSINPUT_HPP
#define QT_SETTINGSINPUT_HPP
#include <QWidget>
namespace Ui {
class SettingsInput;
}
class SettingsInput : public QWidget
{
Q_OBJECT
public:
explicit SettingsInput(QWidget *parent = nullptr);
~SettingsInput();
void save();
public slots:
void onCurrentMachineChanged(int machineId);
private slots:
void on_pushButtonConfigureMouse_clicked();
void on_comboBoxJoystick_currentIndexChanged(int index);
void on_comboBoxMouse_currentIndexChanged(int index);
private:
Ui::SettingsInput *ui;
int machineId = 0;
};
#endif // QT_SETTINGSINPUT_HPP

134
src/qt/qt_settingsinput.ui Normal file
View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsInput</class>
<widget class="QWidget" name="SettingsInput">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout">
<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 row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Mouse</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxMouse"/>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="pushButtonConfigureMouse">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Joystick</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxJoystick"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<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>
<widget class="QPushButton" name="pushButtonJoystick1">
<property name="text">
<string>Joystick 1...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonJoystick2">
<property name="text">
<string>Joystick 2...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonJoystick3">
<property name="text">
<string>Joystick 3...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonJoystick4">
<property name="text">
<string>Joystick 4...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,348 @@
#include "qt_settingsmachine.hpp"
#include "ui_qt_settingsmachine.h"
#include <QDebug>
#include <QDialog>
#include <QFrame>
#include <QVBoxLayout>
#include <QDialogButtonBox>
extern "C" {
#include "../cpu/cpu.h"
#include <86box/86box.h>
#include <86box/config.h>
#include <86box/device.h>
#include <86box/machine.h>
}
// from nvr.h, which we can't import into CPP code
#define TIME_SYNC_DISABLED 0
#define TIME_SYNC_ENABLED 1
#define TIME_SYNC_UTC 2
#include "qt_deviceconfig.hpp"
#include "qt_models_common.hpp"
/*
class MachineModel : public QAbstractListModel {
public:
MachineModel(QObject* parent) : QAbstractListModel(parent) {}
bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
private:
struct Entry {
QString name;
int id;
};
QList<Entry> entries;
};
bool MachineModel::insertRows(int row, int count, const QModelIndex &parent) {
beginInsertRows(parent, row, row + count - 1);
for (int i = 0; i < count; ++i) {
entries.insert(row, Entry{});
}
endInsertRows();
return true;
}
bool MachineModel::removeRows(int row, int count, const QModelIndex &parent) {
beginRemoveRows(parent, row, row + count - 1);
for (int i = 0; i < count; ++i) {
entries.removeAt(row);
}
endRemoveRows();
return true;
}
QVariant MachineModel::data(const QModelIndex &index, int role) const {
Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::ParentIsInvalid));
switch (role) {
case Qt::DisplayRole:
return entries.at(index.row()).name;
case Qt::UserRole:
return entries.at(index.row()).id;
default:
return {};
}
}
int MachineModel::rowCount(const QModelIndex &parent) const {
(void) parent;
return entries.size();
}
bool MachineModel::setData(const QModelIndex &index, const QVariant &value, int role) {
Entry* entry = nullptr;
if (index.row() < entries.size()) {
entry = &entries[index.row()];
} else if (index.row() == entries.size()) {
entries.append(Entry{});
entry = &entries.back();
}
bool ret = true;
if (entry != nullptr) {
switch (role) {
case Qt::DisplayRole:
entry->name = value.toString();
case Qt::UserRole:
entry->id = value.toInt();
default:
ret = false;
break;
}
}
return ret;
}
*/
SettingsMachine::SettingsMachine(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsMachine)
{
ui->setupUi(this);
switch (time_sync) {
case TIME_SYNC_ENABLED:
ui->radioButtonLocalTime->setChecked(true);
break;
case TIME_SYNC_ENABLED | TIME_SYNC_UTC:
ui->radioButtonUTC->setChecked(true);
break;
case TIME_SYNC_DISABLED:
default:
ui->radioButtonDisabled->setChecked(true);
break;
}
auto* waitStatesModel = ui->comboBoxWaitStates->model();
waitStatesModel->insertRows(0, 9);
auto idx = waitStatesModel->index(0, 0);
waitStatesModel->setData(idx, "Default", Qt::DisplayRole);
waitStatesModel->setData(idx, 0, Qt::UserRole);
for (int i = 0; i < 8; ++i) {
idx = waitStatesModel->index(i+1, 0);
waitStatesModel->setData(idx, QString("%1 Wait State(s)").arg(i), Qt::DisplayRole);
waitStatesModel->setData(idx, i+1, Qt::UserRole);
}
int selectedMachineType = 0;
auto* machineTypesModel = ui->comboBoxMachineType->model();
for (int i = 0; i < MACHINE_TYPE_MAX; ++i) {
Models::AddEntry(machineTypesModel, machine_types[i].name, machine_types[i].id);
if (machine_types[i].id == machines[machine].type) {
selectedMachineType = i;
}
}
ui->comboBoxMachineType->setCurrentIndex(selectedMachineType);
}
SettingsMachine::~SettingsMachine() {
delete ui;
}
void SettingsMachine::save() {
machine = ui->comboBoxMachine->currentData().toInt();
cpu_f = const_cast<cpu_family_t*>(&cpu_families[ui->comboBoxCPU->currentData().toInt()]);
cpu = ui->comboBoxSpeed->currentData().toInt();
fpu_type = ui->comboBoxFPU->currentData().toInt();
cpu_use_dynarec = ui->checkBoxDynamicRecompiler->isChecked() ? 1 : 0;
if (machines[machine].ram_granularity < 1024) {
mem_size = ui->spinBoxRAM->value();
} else {
mem_size = ui->spinBoxRAM->value() * 1024;
}
if (ui->comboBoxWaitStates->isEnabled()) {
cpu_waitstates = ui->comboBoxWaitStates->currentData().toInt();
} else {
cpu_waitstates = 0;
}
time_sync = 0;
if (ui->radioButtonLocalTime->isChecked()) {
time_sync = TIME_SYNC_ENABLED;
}
if (ui->radioButtonUTC->isChecked()) {
time_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC;
}
}
void SettingsMachine::on_comboBoxMachineType_currentIndexChanged(int index) {
auto* model = ui->comboBoxMachine->model();
int removeRows = model->rowCount();
int selectedMachineRow = 0;
for (int i = 0; i < machine_count(); ++i) {
if ((machines[i].type == index) && machine_available(i)) {
int row = Models::AddEntry(model, machines[i].name, i);
if (i == machine) {
selectedMachineRow = row - removeRows;
}
}
}
model->removeRows(0, removeRows);
ui->comboBoxMachine->setCurrentIndex(-1);
ui->comboBoxMachine->setCurrentIndex(selectedMachineRow);
}
void SettingsMachine::on_comboBoxMachine_currentIndexChanged(int index) {
// win_settings_machine_recalc_machine
if (index < 0) {
return;
}
int machineId = ui->comboBoxMachine->currentData().toInt();
const auto* device = machine_getdevice(machineId);
ui->pushButtonConfigure->setEnabled((device != nullptr) && (device->config != nullptr));
auto* modelCpu = ui->comboBoxCPU->model();
int removeRows = modelCpu->rowCount();
int i = 0;
int eligibleRows = 0;
int selectedCpuFamilyRow = 0;
while (cpu_families[i].package != 0) {
if (cpu_family_is_eligible(&cpu_families[i], machineId)) {
Models::AddEntry(modelCpu, QString("%1 %2").arg(cpu_families[i].manufacturer, cpu_families[i].name), i);
if (&cpu_families[i] == cpu_f) {
selectedCpuFamilyRow = eligibleRows;
}
++eligibleRows;
}
++i;
}
modelCpu->removeRows(0, removeRows);
ui->comboBoxCPU->setEnabled(eligibleRows > 1);
ui->comboBoxCPU->setCurrentIndex(-1);
ui->comboBoxCPU->setCurrentIndex(selectedCpuFamilyRow);
auto* machine = &machines[machineId];
if ((machine->ram_granularity < 1024)) {
ui->spinBoxRAM->setMinimum(machine->min_ram);
ui->spinBoxRAM->setMaximum(machine->max_ram);
ui->spinBoxRAM->setSingleStep(machine->ram_granularity);
ui->spinBoxRAM->setSuffix(" KiB");
ui->spinBoxRAM->setValue(mem_size);
} else {
uint maxram;
#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
maxram = std::min(machine->max_ram, 2097152U);
#else
maxram = std::min(machine->max_ram, 3145728U);
#endif
ui->spinBoxRAM->setMinimum(machine->min_ram / 1024);
ui->spinBoxRAM->setMaximum(maxram / 1024);
ui->spinBoxRAM->setSingleStep(machine->ram_granularity / 1024);
ui->spinBoxRAM->setSuffix(" MiB");
ui->spinBoxRAM->setValue(mem_size / 1024);
}
ui->spinBoxRAM->setEnabled(machine->min_ram != machine->max_ram);
ui->spinBoxRAM->setEnabled(machine->min_ram != machine->max_ram);
emit currentMachineChanged(machineId);
}
void SettingsMachine::on_comboBoxCPU_currentIndexChanged(int index) {
if (index < 0) {
return;
}
int machineId = ui->comboBoxMachine->currentData().toInt();
int cpuFamilyId = ui->comboBoxCPU->currentData().toInt();
const auto* cpuFamily = &cpu_families[cpuFamilyId];
auto* modelSpeed = ui->comboBoxSpeed->model();
int removeRows = modelSpeed->rowCount();
// win_settings_machine_recalc_cpu_m
int i = 0;
int eligibleRows = 0;
int selectedSpeedRow = 0;
while (cpuFamily->cpus[i].cpu_type != 0) {
if (cpu_is_eligible(cpuFamily, i, machineId)) {
Models::AddEntry(modelSpeed, QString("%1").arg(cpuFamily->cpus[i].name), i);
if (cpu == i) {
selectedSpeedRow = eligibleRows;
}
++eligibleRows;
}
++i;
}
modelSpeed->removeRows(0, removeRows);
ui->comboBoxSpeed->setEnabled(eligibleRows > 1);
ui->comboBoxSpeed->setCurrentIndex(-1);
ui->comboBoxSpeed->setCurrentIndex(selectedSpeedRow);
}
void SettingsMachine::on_comboBoxSpeed_currentIndexChanged(int index) {
if (index < 0) {
return;
}
// win_settings_machine_recalc_cpu
int cpuFamilyId = ui->comboBoxCPU->currentData().toInt();
const auto* cpuFamily = &cpu_families[cpuFamilyId];
int cpuId = ui->comboBoxSpeed->currentData().toInt();
uint cpuType = cpuFamily->cpus[cpuId].cpu_type;
if ((cpuType >= CPU_286) && (cpuType <= CPU_386DX)) {
ui->comboBoxWaitStates->setEnabled(true);
ui->comboBoxWaitStates->setCurrentIndex(cpu_waitstates);
} else {
ui->comboBoxWaitStates->setCurrentIndex(0);
ui->comboBoxWaitStates->setEnabled(false);
}
#ifdef USE_DYNAREC
uint8_t flags = cpuFamily->cpus[cpuId].cpu_flags;
if (! (flags & CPU_SUPPORTS_DYNAREC)) {
ui->checkBoxDynamicRecompiler->setChecked(false);
ui->checkBoxDynamicRecompiler->setEnabled(false);
} else if (flags & CPU_REQUIRES_DYNAREC) {
ui->checkBoxDynamicRecompiler->setChecked(true);
ui->checkBoxDynamicRecompiler->setEnabled(false);
} else {
ui->checkBoxDynamicRecompiler->setChecked(cpu_use_dynarec);
ui->checkBoxDynamicRecompiler->setEnabled(true);
}
#endif
// win_settings_machine_recalc_fpu
auto* modelFpu = ui->comboBoxFPU->model();
int removeRows = modelFpu->rowCount();
int i = 0;
int selectedFpuRow = 0;
for (const char* fpuName = fpu_get_name_from_index(cpuFamily, cpuId, i); fpuName != nullptr; fpuName = fpu_get_name_from_index(cpuFamily, cpuId, ++i)) {
auto fpuType = fpu_get_type_from_index(cpuFamily, cpuId, i);
Models::AddEntry(modelFpu, QString("%1").arg(fpuName), fpuType);
if (fpu_type == fpuType) {
selectedFpuRow = i;
}
}
modelFpu->removeRows(0, removeRows);
ui->comboBoxFPU->setEnabled(modelFpu->rowCount() > 1);
ui->comboBoxFPU->setCurrentIndex(-1);
ui->comboBoxFPU->setCurrentIndex(selectedFpuRow);
}
void SettingsMachine::on_pushButtonConfigure_clicked() {
// deviceconfig_inst_open
int machineId = ui->comboBoxMachine->currentData().toInt();
const auto* device = machine_getdevice(machineId);
DeviceConfig::ConfigureDevice(device);
}

View File

@ -0,0 +1,41 @@
#ifndef QT_SETTINGSMACHINE_HPP
#define QT_SETTINGSMACHINE_HPP
#include <QWidget>
namespace Ui {
class SettingsMachine;
}
class SettingsMachine : public QWidget
{
Q_OBJECT
public:
explicit SettingsMachine(QWidget *parent = nullptr);
~SettingsMachine();
void save();
signals:
void currentMachineChanged(int machineId);
private slots:
void on_pushButtonConfigure_clicked();
private slots:
void on_comboBoxSpeed_currentIndexChanged(int index);
private slots:
void on_comboBoxCPU_currentIndexChanged(int index);
private slots:
void on_comboBoxMachine_currentIndexChanged(int index);
private slots:
void on_comboBoxMachineType_currentIndexChanged(int index);
private:
Ui::SettingsMachine *ui;
};
#endif // QT_SETTINGSMACHINE_HPP

View File

@ -0,0 +1,229 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsMachine</class>
<widget class="QWidget" name="SettingsMachine">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>458</width>
<height>390</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout">
<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>
<widget class="QWidget" name="widget" native="true">
<layout class="QFormLayout" name="formLayout">
<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 row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Machine Type</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxMachineType"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Machine</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>CPU</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>FPU</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Wait States</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Memory</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="comboBoxFPU"/>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="comboBoxWaitStates"/>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="spinBoxRAM"/>
</item>
<item row="3" column="1">
<widget class="QWidget" name="widget_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<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>
<widget class="QComboBox" name="comboBoxCPU"/>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Speed</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSpeed"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="widget_3" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<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>
<widget class="QComboBox" name="comboBoxMachine"/>
</item>
<item>
<widget class="QPushButton" name="pushButtonConfigure">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxDynamicRecompiler">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>2</horstretch>
<verstretch>2</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Dynamic Recompiler</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Time Synchronization</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="radioButtonDisabled">
<property name="text">
<string>Disabled</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonLocalTime">
<property name="text">
<string>Enabled (Local Time)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonUTC">
<property name="text">
<string>Enabled (UTC)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,113 @@
#include "qt_settingsnetwork.hpp"
#include "ui_qt_settingsnetwork.h"
extern "C" {
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/network.h>
}
#include "qt_models_common.hpp"
#include "qt_deviceconfig.hpp"
static void enableElements(Ui::SettingsNetwork *ui) {
int netType = ui->comboBoxNetwork->currentData().toInt();
ui->comboBoxPcap->setEnabled(netType == NET_TYPE_PCAP);
bool adaptersEnabled = netType == NET_TYPE_SLIRP ||
(netType == NET_TYPE_PCAP && ui->comboBoxPcap->currentData().toInt() > 0);
ui->comboBoxAdapter->setEnabled(adaptersEnabled);
ui->pushButtonConfigure->setEnabled(adaptersEnabled && ui->comboBoxAdapter->currentIndex() > 0);
}
SettingsNetwork::SettingsNetwork(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsNetwork)
{
ui->setupUi(this);
auto* model = ui->comboBoxNetwork->model();
Models::AddEntry(model, "None", NET_TYPE_NONE);
Models::AddEntry(model, "PCap", NET_TYPE_PCAP);
Models::AddEntry(model, "SLiRP", NET_TYPE_SLIRP);
ui->comboBoxNetwork->setCurrentIndex(network_type);
int selectedRow = 0;
model = ui->comboBoxPcap->model();
QString currentPcapDevice = network_host;
for (int c = 0; c < network_ndev; c++) {
Models::AddEntry(model, network_devs[c].description, c);
if (QString(network_devs[c].device) == currentPcapDevice) {
selectedRow = c;
}
}
ui->comboBoxPcap->setCurrentIndex(-1);
ui->comboBoxPcap->setCurrentIndex(selectedRow);
onCurrentMachineChanged(machine);
enableElements(ui);
}
SettingsNetwork::~SettingsNetwork()
{
delete ui;
}
void SettingsNetwork::save() {
network_type = ui->comboBoxNetwork->currentData().toInt();
memset(network_host, '\0', sizeof(network_host));
strcpy(network_host, network_devs[ui->comboBoxPcap->currentData().toInt()].device);
network_card = ui->comboBoxAdapter->currentData().toInt();
}
void SettingsNetwork::onCurrentMachineChanged(int machineId) {
this->machineId = machineId;
auto* machine = &machines[machineId];
auto* model = ui->comboBoxAdapter->model();
auto removeRows = model->rowCount();
int c = 0;
int selectedRow = 0;
while (true) {
auto name = DeviceConfig::DeviceName(network_card_getdevice(c), network_card_get_internal_name(c), 1);
if (name.isEmpty()) {
break;
}
if (network_card_available(c) && device_is_valid(network_card_getdevice(c), machine->flags)) {
int row = Models::AddEntry(model, name, c);
if (c == network_card) {
selectedRow = row - removeRows;
}
}
c++;
}
model->removeRows(0, removeRows);
ui->comboBoxAdapter->setEnabled(model->rowCount() > 0);
ui->comboBoxAdapter->setCurrentIndex(-1);
ui->comboBoxAdapter->setCurrentIndex(selectedRow);
}
void SettingsNetwork::on_comboBoxNetwork_currentIndexChanged(int index) {
if (index < 0) {
return;
}
enableElements(ui);
}
void SettingsNetwork::on_comboBoxAdapter_currentIndexChanged(int index) {
if (index < 0) {
return;
}
enableElements(ui);
}
void SettingsNetwork::on_pushButtonConfigure_clicked() {
DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxAdapter->currentData().toInt()));
}

View File

@ -0,0 +1,33 @@
#ifndef QT_SETTINGSNETWORK_HPP
#define QT_SETTINGSNETWORK_HPP
#include <QWidget>
namespace Ui {
class SettingsNetwork;
}
class SettingsNetwork : public QWidget
{
Q_OBJECT
public:
explicit SettingsNetwork(QWidget *parent = nullptr);
~SettingsNetwork();
void save();
public slots:
void onCurrentMachineChanged(int machineId);
private slots:
void on_pushButtonConfigure_clicked();
void on_comboBoxAdapter_currentIndexChanged(int index);
void on_comboBoxNetwork_currentIndexChanged(int index);
private:
Ui::SettingsNetwork *ui;
int machineId = 0;
};
#endif // QT_SETTINGSNETWORK_HPP

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsNetwork</class>
<widget class="QWidget" name="SettingsNetwork">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<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 row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>PCap Device</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Network Adapter</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxPcap"/>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxNetwork"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Network Type</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<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>
<widget class="QComboBox" name="comboBoxAdapter"/>
</item>
<item>
<widget class="QPushButton" name="pushButtonConfigure">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,133 @@
#include "qt_settingsotherperipherals.hpp"
#include "ui_qt_settingsotherperipherals.h"
extern "C" {
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/isamem.h>
#include <86box/isartc.h>
}
#include "qt_deviceconfig.hpp"
#include "qt_models_common.hpp"
SettingsOtherPeripherals::SettingsOtherPeripherals(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsOtherPeripherals)
{
ui->setupUi(this);
ui->checkBoxISABugger->setChecked(bugger_enabled > 0 ? true : false);
ui->checkBoxPOSTCard->setChecked(postcard_enabled > 0 ? true : false);
auto* model = ui->comboBoxRTC->model();
int d = 0;
int selectedRow = 0;
while (true) {
QString name = DeviceConfig::DeviceName(isartc_get_device(d), isartc_get_internal_name(d), 0);
if (name.isEmpty()) {
break;
}
int row = Models::AddEntry(model, name, d);
if (d == isartc_type) {
selectedRow = row;
}
++d;
}
ui->comboBoxRTC->setCurrentIndex(selectedRow);
for (int c = 0; c < ISAMEM_MAX; c++) {
auto* cbox = findChild<QComboBox*>(QString("comboBoxCard%1").arg(c + 1));
model = cbox->model();
d = 0;
selectedRow = 0;
while (true) {
QString name = DeviceConfig::DeviceName(isamem_get_device(d), isamem_get_internal_name(d), 0);
if (name.isEmpty()) {
break;
}
int row = Models::AddEntry(model, name, d);
if (d == isartc_type) {
selectedRow = row;
}
++d;
}
cbox->setCurrentIndex(-1);
cbox->setCurrentIndex(selectedRow);
}
}
SettingsOtherPeripherals::~SettingsOtherPeripherals()
{
delete ui;
}
void SettingsOtherPeripherals::save() {
/* Other peripherals category */
bugger_enabled = ui->checkBoxISABugger->isChecked() ? 1 : 0;
postcard_enabled = ui->checkBoxPOSTCard->isChecked() ? 1 : 0;
isartc_type = ui->comboBoxRTC->currentData().toInt();
/* ISA memory boards. */
for (int i = 0; i < ISAMEM_MAX; i++) {
auto* cbox = findChild<QComboBox*>(QString("comboBoxCard%1").arg(i + 1));
isamem_type[i] = cbox->currentData().toInt();
}
}
void SettingsOtherPeripherals::on_comboBoxRTC_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonConfigureRTC->setEnabled(index != 0);
}
void SettingsOtherPeripherals::on_pushButtonConfigureRTC_clicked() {
DeviceConfig::ConfigureDevice(isartc_get_device(ui->comboBoxRTC->currentData().toInt()));
}
void SettingsOtherPeripherals::on_comboBoxCard1_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonConfigureCard1->setEnabled(index != 0);
}
void SettingsOtherPeripherals::on_pushButtonConfigureCard1_clicked() {
DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard1->currentData().toInt()));
}
void SettingsOtherPeripherals::on_comboBoxCard2_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonConfigureCard2->setEnabled(index != 0);
}
void SettingsOtherPeripherals::on_pushButtonConfigureCard2_clicked() {
DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard2->currentData().toInt()));
}
void SettingsOtherPeripherals::on_comboBoxCard3_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonConfigureCard3->setEnabled(index != 0);
}
void SettingsOtherPeripherals::on_pushButtonConfigureCard3_clicked() {
DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard3->currentData().toInt()));
}
void SettingsOtherPeripherals::on_comboBoxCard4_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonConfigureCard4->setEnabled(index != 0);
}
void SettingsOtherPeripherals::on_pushButtonConfigureCard4_clicked() {
DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard4->currentData().toInt()));
}

View File

@ -0,0 +1,53 @@
#ifndef QT_SETTINGSOTHERPERIPHERALS_HPP
#define QT_SETTINGSOTHERPERIPHERALS_HPP
#include <QWidget>
namespace Ui {
class SettingsOtherPeripherals;
}
class SettingsOtherPeripherals : public QWidget
{
Q_OBJECT
public:
explicit SettingsOtherPeripherals(QWidget *parent = nullptr);
~SettingsOtherPeripherals();
void save();
private slots:
void on_pushButtonConfigureCard4_clicked();
private slots:
void on_comboBoxCard4_currentIndexChanged(int index);
private slots:
void on_pushButtonConfigureCard3_clicked();
private slots:
void on_comboBoxCard3_currentIndexChanged(int index);
private slots:
void on_pushButtonConfigureCard2_clicked();
private slots:
void on_comboBoxCard2_currentIndexChanged(int index);
private slots:
void on_pushButtonConfigureCard1_clicked();
private slots:
void on_comboBoxCard1_currentIndexChanged(int index);
private slots:
void on_pushButtonConfigureRTC_clicked();
private slots:
void on_comboBoxRTC_currentIndexChanged(int index);
private:
Ui::SettingsOtherPeripherals *ui;
};
#endif // QT_SETTINGSOTHERPERIPHERALS_HPP

View File

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsOtherPeripherals</class>
<widget class="QWidget" name="SettingsOtherPeripherals">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>421</width>
<height>458</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>ISA RTC</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxRTC"/>
</item>
<item>
<widget class="QPushButton" name="pushButtonConfigureRTC">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>ISA Memory Expansion</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonConfigureCard2">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxCard2"/>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButtonConfigureCard3">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Card 2</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Card 3</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="pushButtonConfigureCard1">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxCard1"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Card 1</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxCard3"/>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxCard4"/>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="pushButtonConfigureCard4">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Card 4</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="checkBoxISABugger">
<property name="text">
<string>ISABugger Device</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxPOSTCard">
<property name="text">
<string>POST card</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,267 @@
#include "qt_settingsotherremovable.hpp"
#include "ui_qt_settingsotherremovable.h"
extern "C" {
#include <86box/timer.h>
#include <86box/scsi_device.h>
#include <86box/mo.h>
#include <86box/zip.h>
}
#include <QStandardItemModel>
#include "qt_models_common.hpp"
#include "qt_harddrive_common.hpp"
static QString moDriveTypeName(int i) {
return QString("%1 %2 %3").arg(mo_drive_types[i].vendor, mo_drive_types[i].model, mo_drive_types[i].revision);
}
static void setMOBus(QAbstractItemModel* model, const QModelIndex& idx, uint8_t bus, uint8_t channel) {
QIcon icon;
switch (bus) {
case MO_BUS_DISABLED:
icon = QIcon(":/settings/win/icons/mo_disabled.ico");
break;
case MO_BUS_ATAPI:
case MO_BUS_SCSI:
icon = QIcon(":/settings/win/icons/mo.ico");
break;
}
auto i = idx.siblingAtColumn(0);
model->setData(i, Harddrives::BusChannelName(bus, channel));
model->setData(i, bus, Qt::UserRole);
model->setData(i, channel, Qt::UserRole + 1);
model->setData(i, icon, Qt::DecorationRole);
}
static void setMOType(QAbstractItemModel* model, const QModelIndex& idx, uint32_t type) {
auto i = idx.siblingAtColumn(1);
if (idx.siblingAtColumn(0).data(Qt::UserRole).toUInt() == MO_BUS_DISABLED) {
model->setData(i, "None");
} else {
model->setData(i, moDriveTypeName(type));
}
model->setData(i, type, Qt::UserRole);
}
static void setZIPBus(QAbstractItemModel* model, const QModelIndex& idx, uint8_t bus, uint8_t channel) {
QIcon icon;
switch (bus) {
case ZIP_BUS_DISABLED:
icon = QIcon(":/settings/win/icons/zip_disabled.ico");
break;
case ZIP_BUS_ATAPI:
case ZIP_BUS_SCSI:
icon = QIcon(":/settings/win/icons/zip.ico");
break;
}
auto i = idx.siblingAtColumn(0);
model->setData(i, Harddrives::BusChannelName(bus, channel));
model->setData(i, bus, Qt::UserRole);
model->setData(i, channel, Qt::UserRole + 1);
model->setData(i, icon, Qt::DecorationRole);
}
static void setZIPType(QAbstractItemModel* model, const QModelIndex& idx, bool is250) {
auto i = idx.siblingAtColumn(1);
model->setData(i, is250 ? "ZIP 250" : "ZIP 100");
model->setData(i, is250, Qt::UserRole);
}
SettingsOtherRemovable::SettingsOtherRemovable(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsOtherRemovable)
{
ui->setupUi(this);
Harddrives::populateRemovableBuses(ui->comboBoxMOBus->model());
auto* model = ui->comboBoxMOType->model();
for (uint32_t i = 0; i < KNOWN_MO_DRIVE_TYPES; i++) {
Models::AddEntry(model, moDriveTypeName(i), i);
}
model = new QStandardItemModel(0, 2, this);
ui->tableViewMO->setModel(model);
model->setHeaderData(0, Qt::Horizontal, "Bus");
model->setHeaderData(1, Qt::Horizontal, "Type");
model->insertRows(0, MO_NUM);
for (int i = 0; i < MO_NUM; i++) {
auto idx = model->index(i, 0);
setMOBus(model, idx, mo_drives[i].bus_type, mo_drives[i].res);
setMOType(model, idx.siblingAtColumn(1), mo_drives[i].type);
}
ui->tableViewMO->resizeColumnsToContents();
ui->tableViewMO->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
connect(ui->tableViewMO->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SettingsOtherRemovable::onMORowChanged);
ui->tableViewMO->setCurrentIndex(model->index(0, 0));
Harddrives::populateRemovableBuses(ui->comboBoxZIPBus->model());
model = new QStandardItemModel(0, 2, this);
ui->tableViewZIP->setModel(model);
model->setHeaderData(0, Qt::Horizontal, "Bus");
model->setHeaderData(1, Qt::Horizontal, "Type");
model->insertRows(0, ZIP_NUM);
for (int i = 0; i < ZIP_NUM; i++) {
auto idx = model->index(i, 0);
setZIPBus(model, idx, zip_drives[i].bus_type, zip_drives[i].res);
setZIPType(model, idx, zip_drives[i].is_250 > 0);
}
ui->tableViewZIP->resizeColumnsToContents();
ui->tableViewZIP->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
connect(ui->tableViewZIP->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SettingsOtherRemovable::onZIPRowChanged);
ui->tableViewZIP->setCurrentIndex(model->index(0, 0));
}
SettingsOtherRemovable::~SettingsOtherRemovable()
{
delete ui;
}
void SettingsOtherRemovable::save() {
auto* model = ui->tableViewMO->model();
memset(mo_drives, 0, sizeof(mo_drives));
for (int i = 0; i < MO_NUM; i++) {
mo_drives[i].f = NULL;
mo_drives[i].priv = NULL;
mo_drives[i].bus_type = model->index(i, 0).data(Qt::UserRole).toUInt();
mo_drives[i].res = model->index(i, 0).data(Qt::UserRole + 1).toUInt();
mo_drives[i].type = model->index(i, 1).data(Qt::UserRole).toUInt();
}
model = ui->tableViewZIP->model();
memset(zip_drives, 0, sizeof(zip_drives));
for (int i = 0; i < ZIP_NUM; i++) {
zip_drives[i].f = NULL;
zip_drives[i].priv = NULL;
zip_drives[i].bus_type = model->index(i, 0).data(Qt::UserRole).toUInt();
zip_drives[i].res = model->index(i, 0).data(Qt::UserRole + 1).toUInt();
zip_drives[i].is_250 = model->index(i, 1).data(Qt::UserRole).toBool() ? 1 : 0;
}
}
void SettingsOtherRemovable::onMORowChanged(const QModelIndex &current) {
uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt();
uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt();
uint8_t type = current.siblingAtColumn(1).data(Qt::UserRole).toUInt();
ui->comboBoxMOBus->setCurrentIndex(-1);
auto* model = ui->comboBoxMOBus->model();
auto match = model->match(model->index(0, 0), Qt::UserRole, bus);
if (! match.isEmpty()) {
ui->comboBoxMOBus->setCurrentIndex(match.first().row());
}
model = ui->comboBoxMOChannel->model();
match = model->match(model->index(0, 0), Qt::UserRole, channel);
if (! match.isEmpty()) {
ui->comboBoxMOChannel->setCurrentIndex(match.first().row());
}
ui->comboBoxMOType->setCurrentIndex(type);
}
void SettingsOtherRemovable::onZIPRowChanged(const QModelIndex &current) {
uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt();
uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt();
bool is250 = current.siblingAtColumn(1).data(Qt::UserRole).toBool();
ui->comboBoxZIPBus->setCurrentIndex(-1);
auto* model = ui->comboBoxZIPBus->model();
auto match = model->match(model->index(0, 0), Qt::UserRole, bus);
if (! match.isEmpty()) {
ui->comboBoxZIPBus->setCurrentIndex(match.first().row());
}
model = ui->comboBoxZIPChannel->model();
match = model->match(model->index(0, 0), Qt::UserRole, channel);
if (! match.isEmpty()) {
ui->comboBoxZIPChannel->setCurrentIndex(match.first().row());
}
ui->checkBoxZIP250->setChecked(is250);
}
void SettingsOtherRemovable::on_comboBoxMOBus_currentIndexChanged(int index) {
if (index < 0) {
return;
}
int bus = ui->comboBoxMOBus->currentData().toInt();
bool enabled = (bus != MO_BUS_DISABLED);
ui->comboBoxMOChannel->setEnabled(enabled);
ui->comboBoxMOType->setEnabled(enabled);
Harddrives::populateBusChannels(ui->comboBoxMOChannel->model(), bus);
}
void SettingsOtherRemovable::on_comboBoxMOBus_activated(int) {
setMOBus(
ui->tableViewMO->model(),
ui->tableViewMO->selectionModel()->currentIndex(),
ui->comboBoxMOBus->currentData().toUInt(),
ui->comboBoxMOChannel->currentData().toUInt());
setMOType(
ui->tableViewMO->model(),
ui->tableViewMO->selectionModel()->currentIndex(),
ui->comboBoxMOType->currentData().toUInt());
ui->tableViewMO->resizeColumnsToContents();
ui->tableViewMO->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
}
void SettingsOtherRemovable::on_comboBoxMOChannel_activated(int) {
setMOBus(
ui->tableViewMO->model(),
ui->tableViewMO->selectionModel()->currentIndex(),
ui->comboBoxMOBus->currentData().toUInt(),
ui->comboBoxMOChannel->currentData().toUInt());
}
void SettingsOtherRemovable::on_comboBoxMOType_activated(int) {
setMOType(
ui->tableViewMO->model(),
ui->tableViewMO->selectionModel()->currentIndex(),
ui->comboBoxMOType->currentData().toUInt());
ui->tableViewMO->resizeColumnsToContents();
ui->tableViewMO->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
}
void SettingsOtherRemovable::on_comboBoxZIPBus_currentIndexChanged(int index) {
if (index < 0) {
return;
}
int bus = ui->comboBoxZIPBus->currentData().toInt();
bool enabled = (bus != ZIP_BUS_DISABLED);
ui->comboBoxZIPChannel->setEnabled(enabled);
ui->checkBoxZIP250->setEnabled(enabled);
Harddrives::populateBusChannels(ui->comboBoxZIPChannel->model(), bus);
}
void SettingsOtherRemovable::on_comboBoxZIPBus_activated(int) {
setZIPBus(
ui->tableViewZIP->model(),
ui->tableViewZIP->selectionModel()->currentIndex(),
ui->comboBoxZIPBus->currentData().toUInt(),
ui->comboBoxZIPChannel->currentData().toUInt());
}
void SettingsOtherRemovable::on_comboBoxZIPChannel_activated(int) {
setZIPBus(
ui->tableViewZIP->model(),
ui->tableViewZIP->selectionModel()->currentIndex(),
ui->comboBoxZIPBus->currentData().toUInt(),
ui->comboBoxZIPChannel->currentData().toUInt());
}
void SettingsOtherRemovable::on_checkBoxZIP250_stateChanged(int state) {
setZIPType(
ui->tableViewZIP->model(),
ui->tableViewZIP->selectionModel()->currentIndex(),
state == Qt::Checked);
}

View File

@ -0,0 +1,52 @@
#ifndef QT_SETTINGSOTHERREMOVABLE_HPP
#define QT_SETTINGSOTHERREMOVABLE_HPP
#include <QWidget>
namespace Ui {
class SettingsOtherRemovable;
}
class SettingsOtherRemovable : public QWidget
{
Q_OBJECT
public:
explicit SettingsOtherRemovable(QWidget *parent = nullptr);
~SettingsOtherRemovable();
void save();
private slots:
void on_checkBoxZIP250_stateChanged(int arg1);
private slots:
void on_comboBoxZIPChannel_activated(int index);
private slots:
void on_comboBoxZIPBus_activated(int index);
private slots:
void on_comboBoxZIPBus_currentIndexChanged(int index);
private slots:
void on_comboBoxMOType_activated(int index);
private slots:
void on_comboBoxMOChannel_activated(int index);
private slots:
void on_comboBoxMOBus_activated(int index);
private slots:
void on_comboBoxMOBus_currentIndexChanged(int index);
private slots:
void onMORowChanged(const QModelIndex &current);
void onZIPRowChanged(const QModelIndex &current);
private:
Ui::SettingsOtherRemovable *ui;
};
#endif // QT_SETTINGSOTHERREMOVABLE_HPP

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsOtherRemovable</class>
<widget class="QWidget" name="SettingsOtherRemovable">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>418</width>
<height>433</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<widget class="QLabel" name="label">
<property name="text">
<string>MO Drives</string>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="tableViewMO">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Bus</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Channel</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxMOBus"/>
</item>
<item row="0" column="3">
<widget class="QComboBox" name="comboBoxMOChannel"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QComboBox" name="comboBoxMOType"/>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>ZIP Drives</string>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="tableViewZIP">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Bus</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxZIPBus"/>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Channel</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxZIPChannel"/>
</item>
<item>
<widget class="QCheckBox" name="checkBoxZIP250">
<property name="text">
<string>ZIP 250</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,81 @@
#include "qt_settingsports.hpp"
#include "ui_qt_settingsports.h"
extern "C" {
#include <86box/86box.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/lpt.h>
}
#include "qt_deviceconfig.hpp"
#include "qt_models_common.hpp"
SettingsPorts::SettingsPorts(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsPorts)
{
ui->setupUi(this);
for (int i = 0; i < 3; i++) {
auto* cbox = findChild<QComboBox*>(QString("comboBoxLpt%1").arg(i+1));
auto* model = cbox->model();
int c = 0;
int selectedRow = 0;
while (true) {
const char* lptName = lpt_device_get_name(c);
if (lptName == nullptr) {
break;
}
Models::AddEntry(model, lptName, c);
if (c == lpt_ports[i].device) {
selectedRow = c;
}
c++;
}
cbox->setCurrentIndex(selectedRow);
auto* checkBox = findChild<QCheckBox*>(QString("checkBoxParallel%1").arg(i+1));
checkBox->setChecked(lpt_ports[i].enabled > 0);
cbox->setEnabled(lpt_ports[i].enabled > 0);
}
for (int i = 0; i < 4; i++) {
auto* checkBox = findChild<QCheckBox*>(QString("checkBoxSerial%1").arg(i+1));
checkBox->setChecked(serial_enabled[i] > 0);
}
}
SettingsPorts::~SettingsPorts()
{
delete ui;
}
void SettingsPorts::save() {
for (int i = 0; i < 3; i++) {
auto* cbox = findChild<QComboBox*>(QString("comboBoxLpt%1").arg(i+1));
auto* checkBox = findChild<QCheckBox*>(QString("checkBoxParallel%1").arg(i+1));
lpt_ports[i].device = cbox->currentData().toInt();
lpt_ports[i].enabled = checkBox->isChecked() ? 1 : 0;
}
for (int i = 0; i < 4; i++) {
auto* checkBox = findChild<QCheckBox*>(QString("checkBoxSerial%1").arg(i+1));
serial_enabled[i] = checkBox->isChecked() ? 1 : 0;
}
}
void SettingsPorts::on_checkBoxParallel1_stateChanged(int state) {
ui->comboBoxLpt1->setEnabled(state == Qt::Checked);
}
void SettingsPorts::on_checkBoxParallel2_stateChanged(int state) {
ui->comboBoxLpt2->setEnabled(state == Qt::Checked);
}
void SettingsPorts::on_checkBoxParallel3_stateChanged(int state) {
ui->comboBoxLpt3->setEnabled(state == Qt::Checked);
}

View File

@ -0,0 +1,28 @@
#ifndef QT_SETTINGSPORTS_HPP
#define QT_SETTINGSPORTS_HPP
#include <QWidget>
namespace Ui {
class SettingsPorts;
}
class SettingsPorts : public QWidget
{
Q_OBJECT
public:
explicit SettingsPorts(QWidget *parent = nullptr);
~SettingsPorts();
void save();
private slots:
void on_checkBoxParallel3_stateChanged(int arg1);
void on_checkBoxParallel2_stateChanged(int arg1);
void on_checkBoxParallel1_stateChanged(int arg1);
private:
Ui::SettingsPorts *ui;
};
#endif // QT_SETTINGSPORTS_HPP

133
src/qt/qt_settingsports.ui Normal file
View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsPorts</class>
<widget class="QWidget" name="SettingsPorts">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>398</width>
<height>341</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>LPT1 Device</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxLpt1"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>LPT2 Device</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxLpt2"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>LPT3 Device</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxLpt3"/>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="checkBoxSerial1">
<property name="text">
<string>Serial Port 1</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkBoxParallel1">
<property name="text">
<string>Parallel Port 1</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBoxSerial2">
<property name="text">
<string>Serial Port 2</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBoxParallel2">
<property name="text">
<string>Parallel Port 2</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBoxSerial3">
<property name="text">
<string>Serial Port 3</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkBoxParallel3">
<property name="text">
<string>Parallel Port 3</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxSerial4">
<property name="text">
<string>Serial Port 4</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

223
src/qt/qt_settingssound.cpp Normal file
View File

@ -0,0 +1,223 @@
#include "qt_settingssound.hpp"
#include "ui_qt_settingssound.h"
extern "C" {
#include <86box/86box.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/sound.h>
#include <86box/midi.h>
#include <86box/snd_mpu401.h>
}
#include "qt_deviceconfig.hpp"
#include "qt_models_common.hpp"
SettingsSound::SettingsSound(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsSound)
{
ui->setupUi(this);
onCurrentMachineChanged(machine);
}
SettingsSound::~SettingsSound()
{
delete ui;
}
void SettingsSound::save() {
sound_card_current = ui->comboBoxSoundCard->currentData().toInt();
midi_device_current = ui->comboBoxMidiOut->currentData().toInt();
midi_input_device_current = ui->comboBoxMidiIn->currentData().toInt();
mpu401_standalone_enable = ui->checkBoxMPU401->isChecked() ? 1 : 0;
SSI2001 = ui->checkBoxSSI2001->isChecked() ? 1 : 0;;
GAMEBLASTER = ui->checkBoxCMS->isChecked() ? 1 : 0;
GUS = ui->checkBoxGUS->isChecked() ? 1 : 0;;
sound_is_float = ui->checkBoxFloat32->isChecked() ? 1 : 0;;
}
void SettingsSound::onCurrentMachineChanged(int machineId) {
this->machineId = machineId;
auto* machine = &machines[machineId];
auto* model = ui->comboBoxSoundCard->model();
auto removeRows = model->rowCount();
int c = 0;
int selectedRow = 0;
while (true) {
/* Skip "internal" if machine doesn't have it. */
if ((c == 1) && !(machine->flags & MACHINE_SOUND)) {
c++;
continue;
}
auto* sound_dev = sound_card_getdevice(c);
QString name = DeviceConfig::DeviceName(sound_dev, sound_card_get_internal_name(c), 1);
if (name.isEmpty()) {
break;
}
if (sound_card_available(c)) {
if (device_is_valid(sound_dev, machine->flags)) {
int row = Models::AddEntry(model, name, c);
if (c == sound_card_current) {
selectedRow = row - removeRows;
}
}
}
c++;
}
model->removeRows(0, removeRows);
ui->comboBoxSoundCard->setEnabled(model->rowCount() > 0);
ui->comboBoxSoundCard->setCurrentIndex(-1);
ui->comboBoxSoundCard->setCurrentIndex(selectedRow);
model = ui->comboBoxMidiOut->model();
removeRows = model->rowCount();
c = 0;
selectedRow = 0;
while (true) {
QString name = DeviceConfig::DeviceName(midi_device_getdevice(c), midi_device_get_internal_name(c), 0);
if (name.isEmpty()) {
break;
}
if (midi_device_available(c)) {
int row = Models::AddEntry(model, name, c);
if (c == midi_input_device_current) {
selectedRow = row - removeRows;
}
}
c++;
}
model->removeRows(0, removeRows);
ui->comboBoxMidiOut->setEnabled(model->rowCount() > 0);
ui->comboBoxMidiOut->setCurrentIndex(-1);
ui->comboBoxMidiOut->setCurrentIndex(selectedRow);
model = ui->comboBoxMidiIn->model();
removeRows = model->rowCount();
c = 0;
selectedRow = 0;
while (true) {
QString name = DeviceConfig::DeviceName(midi_in_device_getdevice(c), midi_device_get_internal_name(c), 0);
if (name.isEmpty()) {
break;
}
if (midi_in_device_available(c)) {
int row = Models::AddEntry(model, name, c);
if (c == midi_device_current) {
selectedRow = row - removeRows;
}
}
c++;
}
model->removeRows(0, removeRows);
ui->comboBoxMidiIn->setEnabled(model->rowCount() > 0);
ui->comboBoxMidiIn->setCurrentIndex(-1);
ui->comboBoxMidiIn->setCurrentIndex(selectedRow);
ui->checkBoxMPU401->setChecked(mpu401_standalone_enable > 0);
ui->checkBoxSSI2001->setChecked(SSI2001 > 0);
ui->checkBoxCMS->setChecked(GAMEBLASTER > 0);
ui->checkBoxGUS->setChecked(GUS > 0);
ui->checkBoxFloat32->setChecked(sound_is_float > 0);
ui->pushButtonConfigureSSI2001->setEnabled((SSI2001 > 0) && (machine->flags & MACHINE_BUS_ISA));
ui->pushButtonConfigureCMS->setEnabled((GAMEBLASTER > 0) && (machine->flags & MACHINE_BUS_ISA));
ui->pushButtonConfigureGUS->setEnabled((GUS > 0) && (machine->flags & MACHINE_BUS_ISA16));
}
static bool allowMpu401(Ui::SettingsSound *ui) {
QString midiOut = midi_device_get_internal_name(ui->comboBoxMidiOut->currentData().toInt());
QString midiIn = midi_in_device_get_internal_name(ui->comboBoxMidiIn->currentData().toInt());
if (midiOut.isEmpty()) {
return false;
}
if (midiOut == QStringLiteral("none") && midiIn == QStringLiteral("none")) {
return false;
}
return true;
}
void SettingsSound::on_comboBoxSoundCard_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonConfigureSoundCard->setEnabled(sound_card_has_config(ui->comboBoxSoundCard->currentData().toInt()));
}
void SettingsSound::on_pushButtonConfigureSoundCard_clicked() {
DeviceConfig::ConfigureDevice(sound_card_getdevice(ui->comboBoxSoundCard->currentData().toInt()));
}
void SettingsSound::on_comboBoxMidiOut_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonConfigureMidiOut->setEnabled(midi_device_has_config(ui->comboBoxMidiOut->currentData().toInt()));
ui->checkBoxMPU401->setEnabled(allowMpu401(ui));
ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked());
}
void SettingsSound::on_pushButtonConfigureMidiOut_clicked() {
DeviceConfig::ConfigureDevice(midi_device_getdevice(ui->comboBoxMidiOut->currentData().toInt()));
}
void SettingsSound::on_comboBoxMidiIn_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonConfigureMidiIn->setEnabled(midi_in_device_has_config(ui->comboBoxMidiIn->currentData().toInt()));
ui->checkBoxMPU401->setEnabled(allowMpu401(ui));
ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked());
}
void SettingsSound::on_pushButtonConfigureMidiIn_clicked() {
DeviceConfig::ConfigureDevice(midi_in_device_getdevice(ui->comboBoxMidiIn->currentData().toInt()));
}
void SettingsSound::on_checkBoxMPU401_stateChanged(int state) {
ui->pushButtonConfigureMPU401->setEnabled(state == Qt::Checked);
}
void SettingsSound::on_checkBoxSSI2001_stateChanged(int state) {
ui->pushButtonConfigureSSI2001->setEnabled(state == Qt::Checked);
}
void SettingsSound::on_checkBoxCMS_stateChanged(int state) {
ui->pushButtonConfigureCMS->setEnabled(state == Qt::Checked);
}
void SettingsSound::on_checkBoxGUS_stateChanged(int state) {
ui->pushButtonConfigureGUS->setEnabled(state == Qt::Checked);
}
void SettingsSound::on_pushButtonConfigureMPU401_clicked() {
if (machines[machineId].flags & MACHINE_MCA) {
DeviceConfig::ConfigureDevice(&mpu401_mca_device);
} else {
DeviceConfig::ConfigureDevice(&mpu401_device);
}
}
void SettingsSound::on_pushButtonConfigureSSI2001_clicked() {
DeviceConfig::ConfigureDevice(&ssi2001_device);
}
void SettingsSound::on_pushButtonConfigureCMS_clicked() {
DeviceConfig::ConfigureDevice(&cms_device);
}
void SettingsSound::on_pushButtonConfigureGUS_clicked() {
DeviceConfig::ConfigureDevice(&gus_device);
}

View File

@ -0,0 +1,44 @@
#ifndef QT_SETTINGSSOUND_HPP
#define QT_SETTINGSSOUND_HPP
#include <QWidget>
namespace Ui {
class SettingsSound;
}
class SettingsSound : public QWidget
{
Q_OBJECT
public:
explicit SettingsSound(QWidget *parent = nullptr);
~SettingsSound();
void save();
public slots:
void onCurrentMachineChanged(int machineId);
private slots:
void on_pushButtonConfigureGUS_clicked();
void on_pushButtonConfigureCMS_clicked();
void on_pushButtonConfigureSSI2001_clicked();
void on_pushButtonConfigureMPU401_clicked();
void on_checkBoxGUS_stateChanged(int arg1);
void on_checkBoxCMS_stateChanged(int arg1);
void on_checkBoxSSI2001_stateChanged(int arg1);
void on_checkBoxMPU401_stateChanged(int arg1);
void on_pushButtonConfigureMidiIn_clicked();
void on_pushButtonConfigureMidiOut_clicked();
void on_comboBoxMidiIn_currentIndexChanged(int index);
void on_comboBoxMidiOut_currentIndexChanged(int index);
void on_pushButtonConfigureSoundCard_clicked();
void on_comboBoxSoundCard_currentIndexChanged(int index);
private:
Ui::SettingsSound *ui;
int machineId = 0;
};
#endif // QT_SETTINGSSOUND_HPP

160
src/qt/qt_settingssound.ui Normal file
View File

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsSound</class>
<widget class="QWidget" name="SettingsSound">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>387</width>
<height>332</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<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 row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>MIDI In</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="checkBoxSSI2001">
<property name="text">
<string>Innovation SSI-2001</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="checkBoxGUS">
<property name="text">
<string>Gravis Ultrasound</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Sound Card</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="pushButtonConfigureSoundCard">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxMidiIn"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>MIDI Out</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxMPU401">
<property name="text">
<string>Standalone MPU-401</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="pushButtonConfigureMPU401">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="pushButtonConfigureMidiIn">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QPushButton" name="pushButtonConfigureSSI2001">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="checkBoxCMS">
<property name="text">
<string>CMS / Game Blaster</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxSoundCard"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxMidiOut"/>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="pushButtonConfigureMidiOut">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="checkBoxFloat32">
<property name="text">
<string>Use FLOAT32 sound</string>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="QPushButton" name="pushButtonConfigureCMS">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="6" column="3">
<widget class="QPushButton" name="pushButtonConfigureGUS">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,233 @@
#include "qt_settingsstoragecontrollers.hpp"
#include "ui_qt_settingsstoragecontrollers.h"
extern "C" {
#include <86box/86box.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/fdc_ext.h>
#include <86box/scsi.h>
#include <86box/scsi_device.h>
#include <86box/cassette.h>
}
#include "qt_deviceconfig.hpp"
#include "qt_models_common.hpp"
SettingsStorageControllers::SettingsStorageControllers(QWidget *parent) :
QWidget(parent),
ui(new Ui::SettingsStorageControllers)
{
ui->setupUi(this);
ui->checkBoxCassette->setChecked(cassette_enable > 0);
onCurrentMachineChanged(machine);
}
SettingsStorageControllers::~SettingsStorageControllers()
{
delete ui;
}
void SettingsStorageControllers::save() {
/* Storage devices category */
for (int i = 0; i < SCSI_BUS_MAX; ++i) {
auto* cbox = findChild<QComboBox*>(QString("comboBoxSCSI%1").arg(i+1));
scsi_card_current[i] = cbox->currentData().toInt();
}
hdc_current = ui->comboBoxHD->currentData().toInt();
fdc_type = ui->comboBoxFD->currentData().toInt();
ide_ter_enabled = ui->checkBoxTertiaryIDE->isChecked() ? 1 : 0;
ide_qua_enabled = ui->checkBoxQuaternaryIDE->isChecked() ? 1 : 0;
cassette_enable = ui->checkBoxCassette->isChecked() ? 1 : 0;
}
void SettingsStorageControllers::onCurrentMachineChanged(int machineId) {
this->machineId = machineId;
auto* machine = &machines[machineId];
/*HD controller config*/
auto* model = ui->comboBoxHD->model();
auto removeRows = model->rowCount();
int c = 0;
int selectedRow = 0;
while (true) {
/* Skip "internal" if machine doesn't have it. */
if ((c == 1) && !(machine->flags & MACHINE_HDC)) {
c++;
continue;
}
QString name = DeviceConfig::DeviceName(hdc_get_device(c), hdc_get_internal_name(c), 1);
if (name.isEmpty()) {
break;
}
if (hdc_available(c)) {
auto* hdc_dev = hdc_get_device(c);
if (device_is_valid(hdc_dev, machine->flags)) {
int row = Models::AddEntry(model, name, c);
if (c == hdc_current) {
selectedRow = row - removeRows;
}
}
}
c++;
}
model->removeRows(0, removeRows);
ui->comboBoxHD->setEnabled(model->rowCount() > 0);
ui->comboBoxHD->setCurrentIndex(-1);
ui->comboBoxHD->setCurrentIndex(selectedRow);
/*FD controller config*/
model = ui->comboBoxFD->model();
removeRows = model->rowCount();
c = 0;
selectedRow = 0;
while (true) {
QString name = DeviceConfig::DeviceName(fdc_card_getdevice(c), fdc_card_get_internal_name(c), 1);
if (name.isEmpty()) {
break;
}
if (fdc_card_available(c)) {
auto* fdc_dev = fdc_card_getdevice(c);
if (device_is_valid(fdc_dev, machine->flags)) {
int row = Models::AddEntry(model, name, c);
if (c == fdc_type) {
selectedRow = row - removeRows;
}
}
}
c++;
}
model->removeRows(0, removeRows);
ui->comboBoxFD->setEnabled(model->rowCount() > 0);
ui->comboBoxFD->setCurrentIndex(-1);
ui->comboBoxFD->setCurrentIndex(selectedRow);
for (int i = 0; i < SCSI_BUS_MAX; ++i) {
auto* cbox = findChild<QComboBox*>(QString("comboBoxSCSI%1").arg(i+1));
model = cbox->model();
removeRows = model->rowCount();
c = 0;
selectedRow = 0;
while (true) {
auto name = DeviceConfig::DeviceName(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1);
if (name.isEmpty()) {
break;
}
if (scsi_card_available(c)) {
auto* scsi_dev = scsi_card_getdevice(c);
if (device_is_valid(scsi_dev, machine->flags)) {
int row = Models::AddEntry(model, name, c);
if (c == scsi_card_current[i]) {
selectedRow = row - removeRows;
}
}
}
c++;
}
model->removeRows(0, removeRows);
cbox->setEnabled(model->rowCount() > 0);
cbox->setCurrentIndex(-1);
cbox->setCurrentIndex(selectedRow);
}
int is_at = IS_AT(machineId);
ui->checkBoxTertiaryIDE->setEnabled(is_at > 0);
ui->checkBoxQuaternaryIDE->setEnabled(is_at > 0);
}
void SettingsStorageControllers::on_comboBoxHD_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonHD->setEnabled(hdc_has_config(ui->comboBoxHD->currentData().toInt()) > 0);
}
void SettingsStorageControllers::on_comboBoxFD_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonFD->setEnabled(hdc_has_config(ui->comboBoxFD->currentData().toInt()) > 0);
}
void SettingsStorageControllers::on_checkBoxTertiaryIDE_stateChanged(int arg1) {
ui->pushButtonTertiaryIDE->setEnabled(arg1 == Qt::Checked);
}
void SettingsStorageControllers::on_checkBoxQuaternaryIDE_stateChanged(int arg1) {
ui->pushButtonQuaternaryIDE->setEnabled(arg1 == Qt::Checked);
}
void SettingsStorageControllers::on_pushButtonHD_clicked() {
DeviceConfig::ConfigureDevice(hdc_get_device(ui->comboBoxHD->currentData().toInt()));
}
void SettingsStorageControllers::on_pushButtonFD_clicked() {
DeviceConfig::ConfigureDevice(fdc_card_getdevice(ui->comboBoxFD->currentData().toInt()));
}
void SettingsStorageControllers::on_pushButtonTertiaryIDE_clicked() {
DeviceConfig::ConfigureDevice(&ide_ter_device);
}
void SettingsStorageControllers::on_pushButtonQuaternaryIDE_clicked() {
DeviceConfig::ConfigureDevice(&ide_qua_device);
}
void SettingsStorageControllers::on_comboBoxSCSI1_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonSCSI1->setEnabled(scsi_card_has_config(ui->comboBoxSCSI1->currentData().toInt()) > 0);
}
void SettingsStorageControllers::on_comboBoxSCSI2_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonSCSI2->setEnabled(scsi_card_has_config(ui->comboBoxSCSI2->currentData().toInt()) > 0);
}
void SettingsStorageControllers::on_comboBoxSCSI3_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonSCSI3->setEnabled(scsi_card_has_config(ui->comboBoxSCSI3->currentData().toInt()) > 0);
}
void SettingsStorageControllers::on_comboBoxSCSI4_currentIndexChanged(int index) {
if (index < 0) {
return;
}
ui->pushButtonSCSI4->setEnabled(scsi_card_has_config(ui->comboBoxSCSI4->currentData().toInt()) > 0);
}
void SettingsStorageControllers::on_pushButtonSCSI1_clicked() {
DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI1->currentData().toInt()));
}
void SettingsStorageControllers::on_pushButtonSCSI2_clicked() {
DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI2->currentData().toInt()));
}
void SettingsStorageControllers::on_pushButtonSCSI3_clicked() {
DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI3->currentData().toInt()));
}
void SettingsStorageControllers::on_pushButtonSCSI4_clicked() {
DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI4->currentData().toInt()));
}

View File

@ -0,0 +1,76 @@
#ifndef QT_SETTINGSSTORAGECONTROLLERS_HPP
#define QT_SETTINGSSTORAGECONTROLLERS_HPP
#include <QWidget>
namespace Ui {
class SettingsStorageControllers;
}
class SettingsStorageControllers : public QWidget
{
Q_OBJECT
public:
explicit SettingsStorageControllers(QWidget *parent = nullptr);
~SettingsStorageControllers();
void save();
public slots:
void onCurrentMachineChanged(int machineId);
private slots:
void on_pushButtonSCSI4_clicked();
private slots:
void on_pushButtonSCSI3_clicked();
private slots:
void on_pushButtonSCSI2_clicked();
private slots:
void on_pushButtonSCSI1_clicked();
private slots:
void on_comboBoxSCSI4_currentIndexChanged(int index);
private slots:
void on_comboBoxSCSI3_currentIndexChanged(int index);
private slots:
void on_comboBoxSCSI2_currentIndexChanged(int index);
private slots:
void on_comboBoxSCSI1_currentIndexChanged(int index);
private slots:
void on_pushButtonQuaternaryIDE_clicked();
private slots:
void on_pushButtonTertiaryIDE_clicked();
private slots:
void on_pushButtonFD_clicked();
private slots:
void on_pushButtonHD_clicked();
private slots:
void on_checkBoxQuaternaryIDE_stateChanged(int arg1);
private slots:
void on_checkBoxTertiaryIDE_stateChanged(int arg1);
private slots:
void on_comboBoxFD_currentIndexChanged(int index);
private slots:
void on_comboBoxHD_currentIndexChanged(int index);
private:
Ui::SettingsStorageControllers *ui;
int machineId = 0;
};
#endif // QT_SETTINGSSTORAGECONTROLLERS_HPP

View File

@ -0,0 +1,202 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsStorageControllers</class>
<widget class="QWidget" name="SettingsStorageControllers">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>496</width>
<height>449</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>HD Controller</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonFD">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>FD Controller</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxHD"/>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="pushButtonHD">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxFD"/>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBoxTertiaryIDE">
<property name="text">
<string>Tertiary IDE Controller</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxQuaternaryIDE">
<property name="text">
<string>Quaternary IDE Controller</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButtonTertiaryIDE">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="pushButtonQuaternaryIDE">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>SCSI</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="2">
<widget class="QComboBox" name="comboBoxSCSI4"/>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="pushButtonSCSI4">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Controller 1</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="comboBoxSCSI1"/>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="comboBoxSCSI2"/>
</item>
<item row="3" column="0" rowspan="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Controller 4</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Controller 2</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="pushButtonSCSI1">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="pushButtonSCSI2">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Controller 3</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QComboBox" name="comboBoxSCSI3"/>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="pushButtonSCSI3">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCassette">
<property name="text">
<string>Cassette</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

111
src/qt/qt_ui.cpp Normal file
View File

@ -0,0 +1,111 @@
#include <cstdint>
#include <QThread>
#include <QMessageBox>
#include <QStatusBar>
#include "qt_mainwindow.hpp"
std::atomic_int resize_pending = 0;
std::atomic_int resize_w = 0;
std::atomic_int resize_h = 0;
MainWindow* main_window = nullptr;
extern "C" {
#include <86box/plat.h>
void
ui_sb_update_icon_state(int tag, int state)
{
}
void
ui_sb_update_icon(int tag, int active)
{
}
void
plat_delay_ms(uint32_t count)
{
QThread::msleep(count);
}
void
ui_sb_update_tip(int arg)
{
}
void
ui_sb_update_panes()
{
}
void ui_sb_bugui(char *str)
{
}
void ui_sb_set_ready(int ready) {}
wchar_t* ui_window_title(wchar_t* str)
{
if (str == nullptr) {
static wchar_t title[512];
int chars = main_window->windowTitle().toWCharArray(title);
title[chars] = 0;
str = title;
} else {
main_window->setWindowTitle(QString::fromWCharArray(str));
}
return str;
}
void mouse_poll() {
main_window->pollMouse();
}
void plat_resize(int w, int h) {
resize_w = w;
resize_h = h;
resize_pending = 1;
main_window->resizeContents(w, h);
}
void plat_setfullscreen(int on) {
main_window->setFullscreen(on > 0 ? true : false);
}
void plat_mouse_capture(int on) {
main_window->setMouseCapture(on > 0 ? true : false);
}
int ui_msgbox_header(int flags, void *header, void* message)
{
if (header <= (void*)7168) header = plat_get_string(reinterpret_cast<long>(header));
if (message <= (void*)7168) message = plat_get_string(reinterpret_cast<long>(message));
auto hdr = QString::fromWCharArray(reinterpret_cast<const wchar_t*>(header));
auto msg = QString::fromWCharArray(reinterpret_cast<const wchar_t*>(message));
QMessageBox box(QMessageBox::Warning, hdr, msg);
box.exec();
return 0;
}
int ui_msgbox(int flags, void *message) {
return ui_msgbox_header(flags, nullptr, message);
}
void ui_sb_set_text_w(wchar_t *wstr) {
main_window->statusBar()->showMessage(QString::fromWCharArray(wstr));
}
}

24
src/qt_resources.qrc Normal file
View File

@ -0,0 +1,24 @@
<RCC>
<qresource prefix="/settings">
<file>win/icons/machine.ico</file>
<file>win/icons/display.ico</file>
<file>win/icons/input_devices.ico</file>
<file>win/icons/sound.ico</file>
<file>win/icons/network.ico</file>
<file>win/icons/ports.ico</file>
<file>win/icons/storage_controllers.ico</file>
<file>win/icons/hard_disk.ico</file>
<file>win/icons/floppy_and_cdrom_drives.ico</file>
<file>win/icons/other_peripherals.ico</file>
<file>win/icons/other_removable_devices.ico</file>
<file>win/icons/floppy_35.ico</file>
<file>win/icons/floppy_525.ico</file>
<file>win/icons/floppy_disabled.ico</file>
<file>win/icons/cdrom_disabled.ico</file>
<file>win/icons/cdrom.ico</file>
<file>win/icons/mo.ico</file>
<file>win/icons/mo_disabled.ico</file>
<file>win/icons/zip.ico</file>
<file>win/icons/zip_disabled.ico</file>
</qresource>
</RCC>