code dump - mostly done implementing media menus

This commit is contained in:
Joakim L. Gilje
2021-12-03 11:38:00 +01:00
parent 9823ff4488
commit 363f582a81
16 changed files with 1588 additions and 290 deletions

View File

@@ -18,7 +18,8 @@ add_library(ui STATIC
qt_mainwindow.ui
qt_machinestatus.cpp
qt_machinestatus.hpp
#qt_machinestatus.ui
qt_mediamenu.cpp
qt_mediamenu.hpp
qt_gleswidget.cpp
qt_gleswidget.hpp
@@ -67,6 +68,9 @@ add_library(ui STATIC
qt_filefield.cpp
qt_filefield.hpp
qt_filefield.ui
qt_newfloppydialog.cpp
qt_newfloppydialog.hpp
qt_newfloppydialog.ui
qt_harddiskdialog.cpp
qt_harddiskdialog.hpp
qt_harddiskdialog.ui

View File

@@ -39,83 +39,6 @@
#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)
{
@@ -130,135 +53,3 @@ plat_cdrom_ui_update(uint8_t id, uint8_t reload)
//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();
}

View File

@@ -23,9 +23,9 @@ void FileField::setFileName(const QString &fileName) {
void FileField::on_pushButton_clicked() {
QString fileName;
if (createFile_) {
fileName = QFileDialog::getSaveFileName(this, "Create...");
fileName = QFileDialog::getSaveFileName(this, "Create...", QString(), filter_, &selectedFilter_);
} else {
fileName = QFileDialog::getOpenFileName(this, "Open...");
fileName = QFileDialog::getOpenFileName(this, "Open...", QString(), filter_, &selectedFilter_);
}
fileName_ = fileName;

View File

@@ -18,6 +18,9 @@ public:
QString fileName() const { return fileName_; }
void setFileName(const QString& fileName);
void setFilter(const QString& filter) { filter_ = filter; }
QString selectedFilter() const { return selectedFilter_; }
void setCreateFile(bool createFile) { createFile_ = createFile; }
signals:
@@ -29,6 +32,8 @@ private slots:
private:
Ui::FileField *ui;
QString fileName_;
QString selectedFilter_;
QString filter_;
bool createFile_ = false;
};

View File

@@ -337,7 +337,7 @@ void HarddiskDialog::onCreateNewFile() {
_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 (*.*)");
QString vhdParent = QFileDialog::getOpenFileName(this, "Select the parent VHD", QString(), "VHD files (*.vhd);;All files (*)");
if (vhdParent.isEmpty()) {
return;
}

View File

@@ -196,6 +196,7 @@ struct MachineStatus::States {
std::array<StateActive, HDD_BUS_USB> hdds;
StateActive net;
std::unique_ptr<QLabel> sound;
std::unique_ptr<QLabel> text;
};
MachineStatus::MachineStatus(QObject *parent) :
@@ -206,6 +207,81 @@ MachineStatus::MachineStatus(QObject *parent) :
MachineStatus::~MachineStatus() = default;
bool MachineStatus::hasCassette() {
return cassette_enable > 0 ? true : false;
}
bool MachineStatus::hasCartridge() {
return machines[machine].flags & MACHINE_CARTRIDGE;
}
bool MachineStatus::hasIDE() {
return machines[machine].flags & MACHINE_IDE_QUAD;
}
bool MachineStatus::hasSCSI() {
return machines[machine].flags & MACHINE_SCSI_DUAL;
}
void MachineStatus::iterateFDD(const std::function<void (int)> &cb) {
for (int i = 0; i < FDD_NUM; ++i) {
if (fdd_get_type(i) != 0) {
cb(i);
}
}
}
void MachineStatus::iterateCDROM(const std::function<void (int)> &cb) {
auto hdc_name = QString(hdc_get_internal_name(hdc_current));
for (size_t i = 0; i < CDROM_NUM; i++) {
/* Could be Internal or External IDE.. */
if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) &&
!hasIDE() && hdc_name != QStringLiteral("ide"))
continue;
if ((cdrom[i].bus_type == CDROM_BUS_SCSI) && !hasSCSI() &&
(scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) &&
(scsi_card_current[2] == 0) && (scsi_card_current[3] == 0))
continue;
if (cdrom[i].bus_type != 0) {
cb(i);
}
}
}
void MachineStatus::iterateZIP(const std::function<void (int)> &cb) {
auto hdc_name = QString(hdc_get_internal_name(hdc_current));
for (size_t i = 0; i < ZIP_NUM; i++) {
/* Could be Internal or External IDE.. */
if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) &&
!hasIDE() && hdc_name != QStringLiteral("ide"))
continue;
if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && !hasSCSI() &&
(scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) &&
(scsi_card_current[2] == 0) && (scsi_card_current[3] == 0))
continue;
if (zip_drives[i].bus_type != 0) {
cb(i);
}
}
}
void MachineStatus::iterateMO(const std::function<void (int)> &cb) {
auto hdc_name = QString(hdc_get_internal_name(hdc_current));
for (size_t i = 0; i < MO_NUM; i++) {
/* Could be Internal or External IDE.. */
if ((mo_drives[i].bus_type == MO_BUS_ATAPI) &&
!hasIDE() && hdc_name != QStringLiteral("ide"))
continue;
if ((mo_drives[i].bus_type == MO_BUS_SCSI) && !hasSCSI() &&
(scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) &&
(scsi_card_current[2] == 0) && (scsi_card_current[3] == 0))
continue;
if (mo_drives[i].bus_type != 0) {
cb(i);
}
}
}
static int hdd_count(int bus) {
int c = 0;
int i;
@@ -220,12 +296,9 @@ static int hdd_count(int bus) {
}
void MachineStatus::refresh(QStatusBar* sbar) {
bool has_cart = machines[machine].flags & MACHINE_CARTRIDGE;
bool has_mfm = machines[machine].flags & MACHINE_MFM;
bool has_xta = machines[machine].flags & MACHINE_XTA;
bool has_esdi = machines[machine].flags & MACHINE_ESDI;
bool has_ide = machines[machine].flags & MACHINE_IDE_QUAD;
bool has_scsi = machines[machine].flags & MACHINE_SCSI_DUAL;
int c_mfm = hdd_count(HDD_BUS_MFM);
int c_esdi = hdd_count(HDD_BUS_ESDI);
@@ -262,7 +335,7 @@ void MachineStatus::refresh(QStatusBar* sbar) {
sbar->addWidget(d->cassette.label.get());
}
if (has_cart) {
if (hasCartridge()) {
for (int i = 0; i < 2; ++i) {
d->cartridge[i].label = std::make_unique<QLabel>();
d->cartridge[i].setEmpty(QString(cart_fns[i]).isEmpty());
@@ -270,73 +343,43 @@ void MachineStatus::refresh(QStatusBar* sbar) {
}
}
for (size_t i = 0; i < FDD_NUM; ++i) {
if (fdd_get_type(i) != 0) {
d->fdd[i].label = std::make_unique<QLabel>();
int t = fdd_get_type(i);
if (t == 0) {
d->fdd[i].pixmaps = &d->pixmaps.floppy_disabled;
} else if (t >= 1 && t <= 6) {
d->fdd[i].pixmaps = &d->pixmaps.floppy_525;
} else {
d->fdd[i].pixmaps = &d->pixmaps.floppy_35;
}
d->fdd[i].setEmpty(QString(floppyfns[i]).isEmpty());
d->fdd[i].setActive(false);
sbar->addWidget(d->fdd[i].label.get());
iterateFDD([this, sbar](int i) {
int t = fdd_get_type(i);
if (t == 0) {
d->fdd[i].pixmaps = &d->pixmaps.floppy_disabled;
} else if (t >= 1 && t <= 6) {
d->fdd[i].pixmaps = &d->pixmaps.floppy_525;
} else {
d->fdd[i].pixmaps = &d->pixmaps.floppy_35;
}
}
d->fdd[i].label = std::make_unique<QLabel>();
d->fdd[i].setEmpty(QString(floppyfns[i]).isEmpty());
d->fdd[i].setActive(false);
sbar->addWidget(d->fdd[i].label.get());
});
iterateCDROM([this, sbar](int i) {
d->cdrom[i].label = std::make_unique<QLabel>();
d->cdrom[i].setEmpty(cdrom[i].host_drive != 200 || QString(cdrom[i].image_path).isEmpty());
d->cdrom[i].setActive(false);
sbar->addWidget(d->cdrom[i].label.get());
});
iterateZIP([this, sbar](int i) {
d->zip[i].label = std::make_unique<QLabel>();
d->zip[i].setEmpty(QString(zip_drives[i].image_path).isEmpty());
d->zip[i].setActive(false);
sbar->addWidget(d->zip[i].label.get());
});
iterateMO([this, sbar](int i) {
d->mo[i].label = std::make_unique<QLabel>();
d->mo[i].setEmpty(QString(mo_drives[i].image_path).isEmpty());
d->mo[i].setActive(false);
sbar->addWidget(d->mo[i].label.get());
});
auto hdc_name = QString(hdc_get_internal_name(hdc_current));
for (size_t i = 0; i < CDROM_NUM; i++) {
/* Could be Internal or External IDE.. */
if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) &&
!has_ide && hdc_name != QStringLiteral("ide"))
continue;
if ((cdrom[i].bus_type == CDROM_BUS_SCSI) && !has_scsi &&
(scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) &&
(scsi_card_current[2] == 0) && (scsi_card_current[3] == 0))
continue;
if (cdrom[i].bus_type != 0) {
d->cdrom[i].label = std::make_unique<QLabel>();
d->cdrom[i].setEmpty(cdrom[i].host_drive != 200 || QString(cdrom[i].image_path).isEmpty());
d->cdrom[i].setActive(false);
sbar->addWidget(d->cdrom[i].label.get());
}
}
for (size_t i = 0; i < ZIP_NUM; i++) {
/* Could be Internal or External IDE.. */
if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) &&
!has_ide && hdc_name != QStringLiteral("ide"))
continue;
if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && !has_scsi &&
(scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) &&
(scsi_card_current[2] == 0) && (scsi_card_current[3] == 0))
continue;
if (zip_drives[i].bus_type != 0) {
d->zip[i].label = std::make_unique<QLabel>();
d->zip[i].setEmpty(QString(zip_drives[i].image_path).isEmpty());
d->zip[i].setActive(false);
sbar->addWidget(d->zip[i].label.get());
}
}
for (size_t i = 0; i < MO_NUM; i++) {
/* Could be Internal or External IDE.. */
if ((mo_drives[i].bus_type == MO_BUS_ATAPI) &&
!has_ide && hdc_name != QStringLiteral("ide"))
continue;
if ((mo_drives[i].bus_type == MO_BUS_SCSI) && !has_scsi &&
(scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) &&
(scsi_card_current[2] == 0) && (scsi_card_current[3] == 0))
continue;
if (mo_drives[i].bus_type != 0) {
d->mo[i].label = std::make_unique<QLabel>();
d->mo[i].setEmpty(QString(mo_drives[i].image_path).isEmpty());
d->mo[i].setActive(false);
sbar->addWidget(d->mo[i].label.get());
}
}
if ((has_mfm || hdc_name == QStringLiteral("st506")) && c_mfm > 0) {
d->hdds[HDD_BUS_MFM].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_MFM].setActive(false);
@@ -352,12 +395,12 @@ void MachineStatus::refresh(QStatusBar* sbar) {
d->hdds[HDD_BUS_XTA].setActive(false);
sbar->addWidget(d->hdds[HDD_BUS_XTA].label.get());
}
if ((has_ide || hdc_name == QStringLiteral("xtide") || hdc_name == QStringLiteral("ide")) && c_ide > 0) {
if ((hasIDE() || hdc_name == QStringLiteral("xtide") || hdc_name == QStringLiteral("ide")) && c_ide > 0) {
d->hdds[HDD_BUS_IDE].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_IDE].setActive(false);
sbar->addWidget(d->hdds[HDD_BUS_IDE].label.get());
}
if ((has_scsi || (scsi_card_current[0] != 0) || (scsi_card_current[1] != 0) ||
if ((hasSCSI() || (scsi_card_current[0] != 0) || (scsi_card_current[1] != 0) ||
(scsi_card_current[2] != 0) || (scsi_card_current[3] != 0)) && c_scsi > 0) {
d->hdds[HDD_BUS_SCSI].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_SCSI].setActive(false);
@@ -372,6 +415,8 @@ void MachineStatus::refresh(QStatusBar* sbar) {
d->sound = std::make_unique<QLabel>();
d->sound->setPixmap(d->pixmaps.sound);
sbar->addWidget(d->sound.get());
d->text = std::make_unique<QLabel>();
sbar->addWidget(d->text.get());
}
void MachineStatus::setActivity(int tag, bool active) {
@@ -440,3 +485,7 @@ void MachineStatus::setEmpty(int tag, bool empty) {
}
}
void MachineStatus::message(const QString &msg) {
d->text->setText(msg);
}

View File

@@ -13,10 +13,19 @@ public:
explicit MachineStatus(QObject *parent = nullptr);
~MachineStatus();
static bool hasCassette();
static bool hasCartridge();
static bool hasIDE();
static bool hasSCSI();
static void iterateFDD(const std::function<void(int i)>& cb);
static void iterateCDROM(const std::function<void(int i)>& cb);
static void iterateZIP(const std::function<void(int i)>& cb);
static void iterateMO(const std::function<void(int i)>& cb);
public slots:
void refresh(QStatusBar* sbar);
void setActivity(int tag, bool active);
void setEmpty(int tag, bool active);
void message(const QString& msg);
private:
struct States;

View File

@@ -24,6 +24,7 @@ extern "C" {
#include "qt_settings.hpp"
#include "qt_gleswidget.hpp"
#include "qt_machinestatus.hpp"
#include "qt_mediamenu.hpp"
#ifdef __unix__
#include <X11/Xlib.h>
@@ -40,6 +41,8 @@ MainWindow::MainWindow(QWidget *parent) :
{
Q_INIT_RESOURCE(qt_resources);
status = std::make_unique<MachineStatus>(this);
mm = std::make_shared<MediaMenu>(this);
MediaMenu::ptr = mm;
ui->setupUi(this);
video_setblit(qt_blit);
@@ -84,12 +87,10 @@ MainWindow::MainWindow(QWidget *parent) :
connect(this, &MainWindow::updateStatusBarPanes, this, [this] {
status->refresh(ui->statusbar);
});
connect(this, &MainWindow::updateStatusBarActivity, this, [this](int i, bool b) {
status->setActivity(i, b);
});
connect(this, &MainWindow::updateStatusBarEmpty, this, [this](int i, bool b) {
status->setEmpty(i, b);
});
connect(this, &MainWindow::updateStatusBarPanes, this, &MainWindow::refreshMediaMenu);
connect(this, &MainWindow::updateStatusBarActivity, status.get(), &MachineStatus::setActivity);
connect(this, &MainWindow::updateStatusBarEmpty, status.get(), &MachineStatus::setEmpty);
connect(this, &MainWindow::statusBarMessage, status.get(), &MachineStatus::message);
ui->actionKeyboard_requires_capture->setChecked(kbd_req_capture);
ui->actionRight_CTRL_is_left_ALT->setChecked(rctrl_is_lalt);
@@ -684,6 +685,10 @@ void MainWindow::getTitle(wchar_t *title)
}
}
void MainWindow::refreshMediaMenu() {
mm->refresh(ui->menuMedia);
}
void MainWindow::showMessage(const QString& header, const QString& message) {
if (QThread::currentThread() == this->thread()) {
showMessage_(header, message);

View File

@@ -5,6 +5,10 @@
#include <QLabel>
#include <QEvent>
#include <memory>
class MediaMenu;
namespace Ui {
class MainWindow;
}
@@ -27,6 +31,7 @@ signals:
void paint(const QImage& image);
void resizeContents(int w, int h);
void pollMouse();
void statusBarMessage(const QString& msg);
void updateStatusBarPanes();
void updateStatusBarActivity(int tag, bool active);
void updateStatusBarEmpty(int tag, bool empty);
@@ -48,6 +53,7 @@ private slots:
void on_actionRight_CTRL_is_left_ALT_triggered();
void on_actionKeyboard_requires_capture_triggered();
void refreshMediaMenu();
void showMessage_(const QString& header, const QString& message);
void setTitle_(const wchar_t* title);
void getTitle_(wchar_t* title);
@@ -57,6 +63,7 @@ protected:
private:
Ui::MainWindow *ui;
std::unique_ptr<MachineStatus> status;
std::shared_ptr<MediaMenu> mm;
};
#endif // QT_MAINWINDOW_HPP

View File

@@ -78,8 +78,14 @@
</property>
<addaction name="actionFullscreen"/>
</widget>
<widget class="QMenu" name="menuMedia">
<property name="title">
<string>Media</string>
</property>
</widget>
<addaction name="menuAction"/>
<addaction name="menuView"/>
<addaction name="menuMedia"/>
<addaction name="menuTools"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>

533
src/qt/qt_mediamenu.cpp Normal file
View File

@@ -0,0 +1,533 @@
#include "qt_mediamenu.hpp"
#include "qt_machinestatus.hpp"
#include <QMenu>
#include <QFileDialog>
#include <QMessageBox>
extern "C" {
#include <86box/config.h>
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/plat.h>
#include <86box/cassette.h>
#include <86box/cartridge.h>
#include <86box/fdd.h>
#include <86box/fdd_86f.h>
#include <86box/cdrom.h>
#include <86box/scsi_device.h>
#include <86box/zip.h>
#include <86box/mo.h>
#include <86box/sound.h>
#include <86box/ui.h>
};
#include "qt_newfloppydialog.hpp"
std::shared_ptr<MediaMenu> MediaMenu::ptr;
MediaMenu::MediaMenu(QWidget* parent) : QObject(parent) {
parentWidget = parent;
}
void MediaMenu::refresh(QMenu *parentMenu) {
parentMenu->clear();
if(MachineStatus::hasCassette()) {
cassetteMenu = parentMenu->addMenu("");
cassetteMenu->addAction("New Image", [this]() { cassetteNewImage(); });
cassetteMenu->addSeparator();
cassetteMenu->addAction("Existing Image", [this]() { cassetteSelectImage(false); });
cassetteMenu->addAction("Existing Image (Write Protected)", [this]() { cassetteSelectImage(true); });
cassetteMenu->addSeparator();
cassetteMenu->addAction("Record")->setCheckable(true);
cassetteMenu->addAction("Play")->setCheckable(true);
cassetteMenu->addAction("Rewing");
cassetteMenu->addAction("Fast Forward");
cassetteMenu->addSeparator();
cassetteMenu->addAction("Eject", [this]() { cassetteEject(); });
cassetteUpdateMenu();
}
cartridgeMenus.clear();
if (MachineStatus::hasCartridge()) {
for(int i = 0; i < 2; i++) {
auto* menu = parentMenu->addMenu("");
menu->addAction("Image", [this, i]() { cartridgeSelectImage(i); });
menu->addSeparator();
menu->addAction("Eject", [this, i]() { cartridgeEject(i); });
cartridgeMenus.append(menu);
cartridgeUpdateMenu(i);
}
}
floppyMenus.clear();
MachineStatus::iterateFDD([this, parentMenu](int i) {
auto* menu = parentMenu->addMenu("");
menu->addAction("New Image", [this, i]() { floppyNewImage(i); });
menu->addSeparator();
menu->addAction("Existing Image", [this, i]() { floppySelectImage(i, false); });
menu->addAction("Existing Image (Write Protected)", [this, i]() { floppySelectImage(i, true); });
menu->addSeparator();
menu->addAction("Export to 86F", [this, i]() { floppyExportTo86f(i); });
menu->addSeparator();
menu->addAction("Eject", [this, i]() { floppyEject(i); });
floppyMenus.append(menu);
floppyUpdateMenu(i);
});
cdromMenus.clear();
MachineStatus::iterateCDROM([this, parentMenu](int i) {
auto* menu = parentMenu->addMenu("");
cdromMutePos = menu->children().count();
menu->addAction("Mute", [this, i]() { cdromMute(i); })->setCheckable(true);
menu->addSeparator();
cdromEmptyPos = menu->children().count();
menu->addAction("Empty", [this, i]() { cdromEject(i); })->setCheckable(true);
cdromReloadPos = menu->children().count();
menu->addAction("Reload previous image", [this, i]() { cdromReload(i); });
menu->addSeparator();
cdromImagePos = menu->children().count();
menu->addAction("Image", [this, i]() { cdromMount(i); })->setCheckable(true);
cdromMenus.append(menu);
cdromUpdateMenu(i);
});
zipMenus.clear();
MachineStatus::iterateZIP([this, parentMenu](int i) {
auto* menu = parentMenu->addMenu("");
menu->addAction("New Image", [this, i]() { zipNewImage(i); });
menu->addSeparator();
menu->addAction("Existing Image", [this, i]() { zipSelectImage(i, false); });
menu->addAction("Existing Image (Write Protected)", [this, i]() { zipSelectImage(i, true); });
menu->addSeparator();
zipEjectPos = menu->children().count();
menu->addAction("Eject", [this, i]() { zipEject(i); });
zipReloadPos = menu->children().count();
menu->addAction("Reload previous image", [this, i]() { zipReload(i); });
zipMenus.append(menu);
zipUpdateMenu(i);
});
moMenus.clear();
MachineStatus::iterateMO([this, parentMenu](int i) {
auto* menu = parentMenu->addMenu("");
menu->addAction("New Image", [this, i]() { moNewImage(i); });
menu->addSeparator();
menu->addAction("Existing Image", [this, i]() { moSelectImage(i, false); });
menu->addAction("Existing Image (Write Protected)", [this, i]() { moSelectImage(i, true); });
menu->addSeparator();
moEjectPos = menu->children().count();
menu->addAction("Eject", [this, i]() { moEject(i); });
moReloadPos = menu->children().count();
menu->addAction("Reload previous image", [this, i]() { moReload(i); });
moMenus.append(menu);
moUpdateMenu(i);
});
}
void MediaMenu::cassetteNewImage() {
auto filename = QFileDialog::getSaveFileName(parentWidget, "Create...");
QFileInfo fileinfo(filename);
if (fileinfo.suffix().isEmpty()) {
filename.append(".cas");
}
cassetteMount(filename, false);
}
void MediaMenu::cassetteSelectImage(bool wp) {
auto filename = QFileDialog::getOpenFileName(parentWidget, "Open", QString(), "Cassette images (*.pcm;*.raw;*.wav;*.cas);;All files (*)");
cassetteMount(filename, wp);
}
void MediaMenu::cassetteMount(const QString& filename, bool wp) {
pc_cas_set_fname(cassette, nullptr);
memset(cassette_fname, 0, sizeof(cassette_fname));
cassette_ui_writeprot = wp ? 1 : 0;
if (! filename.isEmpty()) {
QByteArray filenameBytes = filename.toUtf8();
strncpy(cassette_fname, filenameBytes.data(), sizeof(cassette_fname));
pc_cas_set_fname(cassette, cassette_fname);
}
ui_sb_update_icon_state(SB_CASSETTE, filename.isEmpty() ? 1 : 0);
ui_sb_update_tip(SB_CASSETTE);
cassetteUpdateMenu();
config_save();
}
void MediaMenu::cassetteEject() {
pc_cas_set_fname(cassette, nullptr);
memset(cassette_fname, 0, sizeof(cassette_fname));
ui_sb_update_icon_state(SB_CASSETTE, 1);
ui_sb_update_tip(SB_CASSETTE);
cassetteUpdateMenu();
config_save();
}
void MediaMenu::cassetteUpdateMenu() {
QString name = cassette_fname;
cassetteMenu->setTitle(QString("Cassette: %1").arg(name.isEmpty() ? "(empty)" : name));
}
void MediaMenu::cartridgeSelectImage(int i) {
auto filename = QFileDialog::getOpenFileName(parentWidget, "Open", QString(), "Cartridge images (*.a;*.b;*.jrc);;All files (*)");
if (filename.isEmpty()) {
return;
}
cart_close(i);
QByteArray filenameBytes = filename.toUtf8();
cart_load(i, filenameBytes.data());
ui_sb_update_icon_state(SB_CARTRIDGE | i, filename.isEmpty() ? 1 : 0);
ui_sb_update_tip(SB_CARTRIDGE | i);
cartridgeUpdateMenu(i);
config_save();
}
void MediaMenu::cartridgeEject(int i) {
cart_close(i);
ui_sb_update_icon_state(SB_CARTRIDGE | i, 1);
ui_sb_update_tip(SB_CARTRIDGE | i);
cartridgeUpdateMenu(i);
config_save();
}
void MediaMenu::cartridgeUpdateMenu(int i) {
QString name = cart_fns[i];
cartridgeMenus[i]->setTitle(QString("Cartridge %1: %2").arg(QString::number(i+1), name.isEmpty() ? "(empty)" : name));
}
void MediaMenu::floppyNewImage(int i) {
NewFloppyDialog dialog(NewFloppyDialog::MediaType::Floppy, parentWidget);
switch (dialog.exec()) {
case QDialog::Accepted:
QByteArray filename = dialog.fileName().toUtf8();
floppyMount(i, filename, false);
break;
}
}
void MediaMenu::floppySelectImage(int i, bool wp) {
auto filename = QFileDialog::getOpenFileName(parentWidget, "Open", QString(), "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF);;Advanced sector images (*.IMD;*.JSON;*.TD0);;Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?);;Flux images (*.FDI);;Surface images (*.86F;*.MFM);;All files (*)");
floppyMount(i, filename, wp);
}
void MediaMenu::floppyMount(int i, const QString &filename, bool wp) {
fdd_close(i);
ui_writeprot[i] = wp ? 1 : 0;
if (! filename.isEmpty()) {
QByteArray filenameBytes = filename.toUtf8();
fdd_load(i, filenameBytes.data());
}
ui_sb_update_icon_state(SB_FLOPPY | i, filename.isEmpty() ? 1 : 0);
ui_sb_update_tip(SB_FLOPPY | i);
floppyUpdateMenu(i);
config_save();
}
void MediaMenu::floppyEject(int i) {
fdd_close(i);
ui_sb_update_icon_state(SB_FLOPPY | i, 1);
ui_sb_update_tip(SB_FLOPPY | i);
floppyUpdateMenu(i);
config_save();
}
void MediaMenu::floppyExportTo86f(int i) {
auto filename = QFileDialog::getSaveFileName(parentWidget, "Save as 86f", QString(), "Surface images (*.86f)");
if (! filename.isEmpty()) {
QByteArray filenameBytes = filename.toUtf8();
plat_pause(1);
if (d86f_export(i, filenameBytes.data()) == 0) {
QMessageBox::critical(parentWidget, "Unable to write file", "Make sure the file is being saved to a writable directory");
}
plat_pause(0);
}
}
void MediaMenu::floppyUpdateMenu(int i) {
QString name = floppyfns[i];
int type = fdd_get_type(i);
floppyMenus[i]->setTitle(QString("Floppy %1 (%2): %3").arg(QString::number(i+1), fdd_getname(type), name.isEmpty() ? "(empty)" : name));
}
void MediaMenu::cdromMute(int i) {
cdrom[i].sound_on ^= 1;
config_save();
cdromUpdateMenu(i);
sound_cd_thread_reset();
}
void MediaMenu::cdromMount(int i) {
QString dir;
QFileInfo fi(cdrom[i].image_path);
auto filename = QFileDialog::getOpenFileName(parentWidget, "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0", fi.canonicalPath());
if (filename.isEmpty()) {
auto* imageMenu = dynamic_cast<QAction*>(cdromMenus[i]->children()[cdromImagePos]);
imageMenu->setChecked(false);
return;
}
QByteArray fn = filename.toUtf8().data();
cdrom[i].prev_host_drive = cdrom[i].host_drive;
strcpy(cdrom[i].prev_image_path, cdrom[i].image_path);
if (cdrom[i].ops && cdrom[i].ops->exit)
cdrom[i].ops->exit(&(cdrom[i]));
cdrom[i].ops = nullptr;
memset(cdrom[i].image_path, 0, sizeof(cdrom[i].image_path));
cdrom_image_open(&(cdrom[i]), fn.data());
/* Signal media change to the emulated machine. */
if (cdrom[i].insert)
cdrom[i].insert(cdrom[i].priv);
cdrom[i].host_drive = (strlen(cdrom[i].image_path) == 0) ? 0 : 200;
if (cdrom[i].host_drive == 200) {
ui_sb_update_icon_state(SB_CDROM | i, 0);
} else {
ui_sb_update_icon_state(SB_CDROM | i, 1);
}
ui_sb_update_tip(SB_CDROM | i);
cdromUpdateMenu(i);
config_save();
}
void MediaMenu::cdromEject(int i) {
cdrom_eject(i);
cdromUpdateMenu(i);
}
void MediaMenu::cdromReload(int i) {
cdrom_reload(i);
cdromUpdateMenu(i);
}
void MediaMenu::cdromUpdateMenu(int i) {
QString name = cdrom[i].image_path;
auto* menu = cdromMenus[i];
auto childs = menu->children();
auto* muteMenu = dynamic_cast<QAction*>(childs[cdromMutePos]);
muteMenu->setChecked(cdrom[i].sound_on == 0);
auto* imageMenu = dynamic_cast<QAction*>(childs[cdromImagePos]);
auto* emptyMenu = dynamic_cast<QAction*>(childs[cdromEmptyPos]);
imageMenu->setChecked(cdrom[i].host_drive == 200);
emptyMenu->setChecked(cdrom[i].host_drive != 200);
auto* prevMenu = dynamic_cast<QAction*>(childs[cdromReloadPos]);
prevMenu->setEnabled(cdrom[i].prev_host_drive != 0);
QString busName = "Unknown Bus";
switch (cdrom[i].bus_type) {
case CDROM_BUS_ATAPI:
busName = "ATAPI";
break;
case CDROM_BUS_SCSI:
busName = "SCSI";
break;
}
menu->setTitle(QString("CD-ROM %1 (%2): %3").arg(QString::number(i+1), busName, name.isEmpty() ? "(empty)" : name));
}
void MediaMenu::zipNewImage(int i) {
NewFloppyDialog dialog(NewFloppyDialog::MediaType::Zip, parentWidget);
switch (dialog.exec()) {
case QDialog::Accepted:
QByteArray filename = dialog.fileName().toUtf8();
zipMount(i, filename, false);
break;
}
}
void MediaMenu::zipSelectImage(int i, bool wp) {
auto filename = QFileDialog::getOpenFileName(parentWidget, "Open", QString(), "ZIP images (*.im?;*.zdi);;All files (*)");
zipMount(i, filename, wp);
}
void MediaMenu::zipMount(int i, const QString &filename, bool wp) {
zip_t *dev = (zip_t *) zip_drives[i].priv;
zip_disk_close(dev);
zip_drives[i].read_only = wp;
if (! filename.isEmpty()) {
QByteArray filenameBytes = filename.toUtf8();
zip_load(dev, filenameBytes.data());
zip_insert(dev);
}
ui_sb_update_icon_state(SB_ZIP | i, filename.isEmpty() ? 1 : 0);
ui_sb_update_tip(SB_ZIP | i);
zipUpdateMenu(i);
config_save();
}
void MediaMenu::zipEject(int i) {
zip_t *dev = (zip_t *) zip_drives[i].priv;
zip_disk_close(dev);
if (zip_drives[i].bus_type) {
/* Signal disk change to the emulated machine. */
zip_insert(dev);
}
ui_sb_update_icon_state(SB_ZIP | i, 1);
ui_sb_update_tip(SB_ZIP | i);
zipUpdateMenu(i);
config_save();
}
void MediaMenu::zipReload(int i) {
zip_t *dev = (zip_t *) zip_drives[i].priv;
zip_disk_reload(dev);
if (strlen(zip_drives[i].image_path) == 0) {
ui_sb_update_icon_state(SB_ZIP|i, 1);
} else {
ui_sb_update_icon_state(SB_ZIP|i, 0);
}
ui_sb_update_tip(SB_ZIP|i);
zipUpdateMenu(i);
config_save();
}
void MediaMenu::zipUpdateMenu(int i) {
QString name = zip_drives[i].image_path;
QString prev_name = zip_drives[i].prev_image_path;
auto* menu = zipMenus[i];
auto childs = menu->children();
auto* ejectMenu = dynamic_cast<QAction*>(childs[zipEjectPos]);
auto* reloadMenu = dynamic_cast<QAction*>(childs[zipReloadPos]);
ejectMenu->setEnabled(!name.isEmpty());
reloadMenu->setEnabled(!prev_name.isEmpty());
QString busName = "Unknown Bus";
switch (zip_drives[i].bus_type) {
case ZIP_BUS_ATAPI:
busName = "ATAPI";
break;
case ZIP_BUS_SCSI:
busName = "SCSI";
break;
}
menu->setTitle(QString("ZIP %1 %2 (%3): %4").arg((zip_drives[i].is_250 > 0) ? "250" : "100", QString::number(i+1), busName, name.isEmpty() ? "(empty)" : name));
}
void MediaMenu::moNewImage(int i) {
NewFloppyDialog dialog(NewFloppyDialog::MediaType::Mo, parentWidget);
switch (dialog.exec()) {
case QDialog::Accepted:
QByteArray filename = dialog.fileName().toUtf8();
moMount(i, filename, false);
break;
}
}
void MediaMenu::moSelectImage(int i, bool wp) {
auto filename = QFileDialog::getOpenFileName(parentWidget, "Open", QString(), "MO images (*.im?;*.mdi);;All files (*)");
moMount(i, filename, wp);
}
void MediaMenu::moMount(int i, const QString &filename, bool wp) {
mo_t *dev = (mo_t *) mo_drives[i].priv;
mo_disk_close(dev);
mo_drives[i].read_only = wp;
if (! filename.isEmpty()) {
QByteArray filenameBytes = filename.toUtf8();
mo_load(dev, filenameBytes.data());
mo_insert(dev);
}
ui_sb_update_icon_state(SB_MO | i, filename.isEmpty() ? 1 : 0);
ui_sb_update_tip(SB_MO | i);
moUpdateMenu(i);
config_save();
}
void MediaMenu::moEject(int i) {
mo_t *dev = (mo_t *) mo_drives[i].priv;
mo_disk_close(dev);
if (mo_drives[i].bus_type) {
/* Signal disk change to the emulated machine. */
mo_insert(dev);
}
ui_sb_update_icon_state(SB_MO | i, 1);
ui_sb_update_tip(SB_MO | i);
moUpdateMenu(i);
config_save();
}
void MediaMenu::moReload(int i) {
mo_t *dev = (mo_t *) mo_drives[i].priv;
mo_disk_reload(dev);
if (strlen(mo_drives[i].image_path) == 0) {
ui_sb_update_icon_state(SB_MO|i, 1);
} else {
ui_sb_update_icon_state(SB_MO|i, 0);
}
ui_sb_update_tip(SB_MO|i);
moUpdateMenu(i);
config_save();
}
void MediaMenu::moUpdateMenu(int i) {
QString name = mo_drives[i].image_path;
QString prev_name = mo_drives[i].prev_image_path;
auto* menu = moMenus[i];
auto childs = menu->children();
auto* ejectMenu = dynamic_cast<QAction*>(childs[moEjectPos]);
auto* reloadMenu = dynamic_cast<QAction*>(childs[moReloadPos]);
ejectMenu->setEnabled(!name.isEmpty());
reloadMenu->setEnabled(!prev_name.isEmpty());
QString busName = "Unknown Bus";
switch (mo_drives[i].bus_type) {
case MO_BUS_ATAPI:
busName = "ATAPI";
break;
case MO_BUS_SCSI:
busName = "SCSI";
break;
}
menu->setTitle(QString("MO %1 (%2): %3").arg(QString::number(i+1), busName, name.isEmpty() ? "(empty)" : name));
}
// callbacks from 86box C code
extern "C" {
void zip_eject(uint8_t id) {
MediaMenu::ptr->zipEject(id);
}
void zip_reload(uint8_t id) {
MediaMenu::ptr->zipReload(id);
}
void mo_eject(uint8_t id) {
MediaMenu::ptr->moEject(id);
}
void mo_reload(uint8_t id) {
MediaMenu::ptr->moReload(id);
}
}

76
src/qt/qt_mediamenu.hpp Normal file
View File

@@ -0,0 +1,76 @@
#pragma once
#include <memory>
#include <QObject>
class QMenu;
class MediaMenu : QObject
{
Q_OBJECT
public:
MediaMenu(QWidget* parent);
void refresh(QMenu* parentMenu);
// because some 86box C-only code needs to call zip and
// mo eject directly
static std::shared_ptr<MediaMenu> ptr;
void cassetteNewImage();
void cassetteSelectImage(bool wp);
void cassetteMount(const QString& filename, bool wp);
void cassetteEject();
void cassetteUpdateMenu();
void cartridgeSelectImage(int i);
void cartridgeEject(int i);
void cartridgeUpdateMenu(int i);
void floppyNewImage(int i);
void floppySelectImage(int i, bool wp);
void floppyMount(int i, const QString& filename, bool wp);
void floppyEject(int i);
void floppyExportTo86f(int i);
void floppyUpdateMenu(int i);
void cdromMute(int i);
void cdromMount(int i);
void cdromEject(int i);
void cdromReload(int i);
void cdromUpdateMenu(int i);
void zipNewImage(int i);
void zipSelectImage(int i, bool wp);
void zipMount(int i, const QString& filename, bool wp);
void zipEject(int i);
void zipReload(int i);
void zipUpdateMenu(int i);
void moNewImage(int i);
void moSelectImage(int i, bool wp);
void moMount(int i, const QString& filename, bool wp);
void moEject(int i);
void moReload(int i);
void moUpdateMenu(int i);
private:
QWidget* parentWidget = nullptr;
QMenu* cassetteMenu = nullptr;
QList<QMenu*> cartridgeMenus;
QList<QMenu*> floppyMenus;
QList<QMenu*> cdromMenus;
QList<QMenu*> zipMenus;
QList<QMenu*> moMenus;
int cdromMutePos;
int cdromEmptyPos;
int cdromReloadPos;
int cdromImagePos;
int zipEjectPos;
int zipReloadPos;
int moEjectPos;
int moReloadPos;
};

View File

@@ -0,0 +1,648 @@
#include "qt_newfloppydialog.hpp"
#include "ui_qt_newfloppydialog.h"
#include "qt_models_common.hpp"
extern "C" {
#include <86box/random.h>
#include <86box/scsi_device.h>
#include <86box/zip.h>
#include <86box/mo.h>
}
#include <QFile>
#include <QFileInfo>
#include <QMessageBox>
#include <QProgressDialog>
#include <thread>
struct disk_size_t {
int hole;
int sides;
int data_rate;
int encoding;
int rpm;
int tracks;
int sectors; /* For IMG and Japanese FDI only. */
int sector_len; /* For IMG and Japanese FDI only. */
int media_desc;
int spc;
int num_fats;
int spfat;
int root_dir_entries;
};
static const disk_size_t disk_sizes[14] = { { 0, 1, 2, 1, 0, 40, 8, 2, 0xfe, 2, 2, 1, 64 }, /* 160k */
{ 0, 1, 2, 1, 0, 40, 9, 2, 0xfc, 2, 2, 1, 64 }, /* 180k */
{ 0, 2, 2, 1, 0, 40, 8, 2, 0xff, 2, 2, 1, 112 }, /* 320k */
{ 0, 2, 2, 1, 0, 40, 9, 2, 0xfd, 2, 2, 2, 112 }, /* 360k */
{ 0, 2, 2, 1, 0, 80, 8, 2, 0xfb, 2, 2, 2, 112 }, /* 640k */
{ 0, 2, 2, 1, 0, 80, 9, 2, 0xf9, 2, 2, 3, 112 }, /* 720k */
{ 1, 2, 0, 1, 1, 80, 15, 2, 0xf9, 1, 2, 7, 224 }, /* 1.2M */
{ 1, 2, 0, 1, 1, 77, 8, 3, 0xfe, 1, 2, 2, 192 }, /* 1.25M */
{ 1, 2, 0, 1, 0, 80, 18, 2, 0xf0, 1, 2, 9, 224 }, /* 1.44M */
{ 1, 2, 0, 1, 0, 80, 21, 2, 0xf0, 2, 2, 5, 16 }, /* DMF cluster 1024 */
{ 1, 2, 0, 1, 0, 80, 21, 2, 0xf0, 4, 2, 3, 16 }, /* DMF cluster 2048 */
{ 2, 2, 3, 1, 0, 80, 36, 2, 0xf0, 2, 2, 9, 240 }, /* 2.88M */
{ 0, 64, 0, 0, 0, 96, 32, 2, 0, 0, 0, 0, 0 }, /* ZIP 100 */
{ 0, 64, 0, 0, 0, 239, 32, 2, 0, 0, 0, 0, 0 } }; /* ZIP 250 */
static const QStringList rpmModes = {
"Perfect RPM",
"1%% below perfect RPM",
"1.5%% below perfect RPM",
"2%% below perfect RPM",
};
static const QStringList floppyTypes = {
"160 kB",
"180 kB",
"320 kB",
"360 kB",
"640 kB",
"720 kB",
"1.2 MB",
"1.25 MB",
"1.44 MB",
"DMF (cluster 1024)",
"DMF (cluster 2048)",
"2.88 MB",
};
static const QStringList zipTypes = {
"ZIP 100",
"ZIP 250",
};
static const QStringList moTypes = {
"3.5\" 128Mb M.O. (ISO 10090)",
"3.5\" 230Mb M.O. (ISO 13963)",
"3.5\" 540Mb M.O. (ISO 15498)",
"3.5\" 640Mb M.O. (ISO 15498)",
"3.5\" 1.3Gb M.O. (GigaMO)",
"3.5\" 2.3Gb M.O. (GigaMO 2)",
"5.25\" 600Mb M.O.",
"5.25\" 650Mb M.O.",
"5.25\" 1Gb M.O.",
"5.25\" 1.3Gb M.O.",
};
NewFloppyDialog::NewFloppyDialog(MediaType type, QWidget *parent) :
QDialog(parent),
ui(new Ui::NewFloppyDialog),
mediaType_(type)
{
ui->setupUi(this);
ui->fileField->setCreateFile(true);
auto* model = ui->comboBoxSize->model();
switch (type) {
case MediaType::Floppy:
for (int i = 0; i < floppyTypes.size(); ++i) {
Models::AddEntry(model, floppyTypes[i], i);
}
break;
case MediaType::Zip:
for (int i = 0; i < zipTypes.size(); ++i) {
Models::AddEntry(model, zipTypes[i], i);
}
break;
case MediaType::Mo:
for (int i = 0; i < moTypes.size(); ++i) {
Models::AddEntry(model, moTypes[i], i);
}
break;
}
model = ui->comboBoxRpm->model();
for (int i = 0; i < rpmModes.size(); ++i) {
Models::AddEntry(model, rpmModes[i], i);
}
connect(ui->fileField, &FileField::fileSelected, this, [this](const QString& filename) {
bool hide = true;
if (mediaType_ == MediaType::Floppy) {
if (QFileInfo(filename).suffix().toLower() == QStringLiteral("86f")) {
hide = false;
}
}
ui->labelRpm->setHidden(hide);
ui->comboBoxRpm->setHidden(hide);
});
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &NewFloppyDialog::onCreate);
ui->labelRpm->setHidden(true);
ui->comboBoxRpm->setHidden(true);
}
NewFloppyDialog::~NewFloppyDialog() {
delete ui;
}
QString NewFloppyDialog::fileName() const{
return ui->fileField->fileName();
}
void NewFloppyDialog::onCreate() {
auto filename = ui->fileField->fileName();
QFileInfo fi(filename);
FileType fileType;
QProgressDialog progress("Creating floppy image", QString(), 0, 100, this);
connect(this, &NewFloppyDialog::fileProgress, &progress, &QProgressDialog::setValue);
switch (mediaType_) {
case MediaType::Floppy:
if (fi.suffix().toLower() == QStringLiteral("86f")) {
if (create86f(filename, disk_sizes[ui->comboBoxSize->currentIndex()], ui->comboBoxRpm->currentIndex())) {
return;
}
} else {
fileType = fi.suffix().toLower() == QStringLiteral("zdi") ? FileType::Fdi : FileType::Img;
if (createSectorImage(filename, disk_sizes[ui->comboBoxSize->currentIndex()], fileType)) {
return;
}
}
break;
case MediaType::Zip:
{
fileType = fi.suffix().toLower() == QStringLiteral("zdi") ? FileType::Zdi: FileType::Img;
std::atomic_bool res;
std::thread t([this, &res, filename, fileType, &progress] {
res = createZipSectorImage(filename, disk_sizes[ui->comboBoxSize->currentIndex() + 12], fileType, progress);
});
progress.exec();
t.join();
if (res) {
return;
}
}
break;
case MediaType::Mo:
{
fileType = fi.suffix().toLower() == QStringLiteral("mdi") ? FileType::Mdi: FileType::Img;
std::atomic_bool res;
std::thread t([this, &res, filename, fileType, &progress] {
res = createMoSectorImage(filename, ui->comboBoxSize->currentIndex(), fileType, progress);
});
progress.exec();
t.join();
if (res) {
return;
}
}
break;
}
QMessageBox::critical(this, "Unable to write file", "Make sure the file is being saved to a writable directory");
reject();
}
bool NewFloppyDialog::create86f(const QString& filename, const disk_size_t& disk_size, uint8_t rpm_mode)
{
uint32_t magic = 0x46423638;
uint16_t version = 0x020C;
uint16_t dflags = 0;
uint16_t tflags = 0;
uint32_t index_hole_pos = 0;
uint32_t tarray[512];
uint32_t array_size;
uint32_t track_base, track_size;
int i;
uint32_t shift = 0;
dflags = 0; /* Has surface data? - Assume no for now. */
dflags |= (disk_size.hole << 1); /* Hole */
dflags |= ((disk_size.sides - 1) << 3); /* Sides. */
dflags |= (0 << 4); /* Write protect? - Assume no for now. */
dflags |= (rpm_mode << 5); /* RPM mode. */
dflags |= (0 << 7); /* Has extra bit cells? - Assume no for now. */
tflags = disk_size.data_rate; /* Data rate. */
tflags |= (disk_size.encoding << 3); /* Encoding. */
tflags |= (disk_size.rpm << 5); /* RPM. */
switch (disk_size.hole) {
case 0:
case 1:
default:
switch(rpm_mode) {
case 1:
array_size = 25250;
break;
case 2:
array_size = 25374;
break;
case 3:
array_size = 25750;
break;
default:
array_size = 25000;
break;
}
break;
case 2:
switch(rpm_mode) {
case 1:
array_size = 50500;
break;
case 2:
array_size = 50750;
break;
case 3:
array_size = 51000;
break;
default:
array_size = 50000;
break;
}
break;
}
QByteArray bytes(array_size, 0);
memset(tarray, 0, 2048);
QFile file(filename);
if (! file.open(QIODevice::WriteOnly)) {
return false;
}
QDataStream stream(&file);
stream << magic;
stream << version;
stream << dflags;
track_size = array_size + 6;
track_base = 8 + ((disk_size.sides == 2) ? 2048 : 1024);
if (disk_size.tracks <= 43)
shift = 1;
for (i = 0; i < (disk_size.tracks * disk_size.sides) << shift; i++)
tarray[i] = track_base + (i * track_size);
stream.writeRawData(reinterpret_cast<const char *>(tarray), (disk_size.sides == 2) ? 2048 : 1024);
int max = i < (disk_size.tracks * disk_size.sides) << shift;
for (i = 0; i < max; i++) {
stream << tflags;
stream << index_hole_pos;
stream.writeRawData(bytes, bytes.size());
}
return true;
}
bool NewFloppyDialog::createSectorImage(const QString &filename, const disk_size_t& disk_size, FileType type)
{
uint32_t total_size = 0;
uint32_t total_sectors = 0;
uint32_t sector_bytes = 0;
uint32_t root_dir_bytes = 0;
uint32_t fat_size = 0;
uint32_t fat1_offs = 0;
uint32_t fat2_offs = 0;
uint32_t zero_bytes = 0;
uint16_t base = 0x1000;
QFile file(filename);
if (! file.open(QIODevice::WriteOnly)) {
return false;
}
QDataStream stream(&file);
sector_bytes = (128 << disk_size.sector_len);
total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors;
if (total_sectors > ZIP_SECTORS)
total_sectors = ZIP_250_SECTORS;
total_size = total_sectors * sector_bytes;
root_dir_bytes = (disk_size.root_dir_entries << 5);
fat_size = (disk_size.spfat * sector_bytes);
fat1_offs = sector_bytes;
fat2_offs = fat1_offs + fat_size;
zero_bytes = fat2_offs + fat_size + root_dir_bytes;
if (type == FileType::Fdi) {
QByteArray bytes(base, 0);
auto empty = bytes.data();
*(uint32_t *) &(empty[0x08]) = (uint32_t) base;
*(uint32_t *) &(empty[0x0C]) = total_size;
*(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes;
*(uint8_t *) &(empty[0x14]) = (uint8_t) disk_size.sectors;
*(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sides;
*(uint8_t *) &(empty[0x1C]) = (uint8_t) disk_size.tracks;
stream.writeRawData(empty, base);
}
QByteArray bytes(total_size, 0);
auto empty = bytes.data();
memset(empty + zero_bytes, 0xF6, total_size - zero_bytes);
empty[0x00] = 0xEB; /* Jump to make MS-DOS happy. */
empty[0x01] = 0x58;
empty[0x02] = 0x90;
empty[0x03] = 0x38; /* '86BOX5.0' OEM ID. */
empty[0x04] = 0x36;
empty[0x05] = 0x42;
empty[0x06] = 0x4F;
empty[0x07] = 0x58;
empty[0x08] = 0x35;
empty[0x09] = 0x2E;
empty[0x0A] = 0x30;
*(uint16_t *) &(empty[0x0B]) = (uint16_t) sector_bytes;
*(uint8_t *) &(empty[0x0D]) = (uint8_t) disk_size.spc;
*(uint16_t *) &(empty[0x0E]) = (uint16_t) 1;
*(uint8_t *) &(empty[0x10]) = (uint8_t) disk_size.num_fats;
*(uint16_t *) &(empty[0x11]) = (uint16_t) disk_size.root_dir_entries;
*(uint16_t *) &(empty[0x13]) = (uint16_t) total_sectors;
*(uint8_t *) &(empty[0x15]) = (uint8_t) disk_size.media_desc;
*(uint16_t *) &(empty[0x16]) = (uint16_t) disk_size.spfat;
*(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sectors;
*(uint8_t *) &(empty[0x1A]) = (uint8_t) disk_size.sides;
empty[0x26] = 0x29; /* ')' followed by randomly-generated volume serial number. */
empty[0x27] = random_generate();
empty[0x28] = random_generate();
empty[0x29] = random_generate();
empty[0x2A] = random_generate();
memset(&(empty[0x2B]), 0x20, 11);
empty[0x36] = 'F';
empty[0x37] = 'A';
empty[0x38] = 'T';
empty[0x39] = '1';
empty[0x3A] = '2';
memset(&(empty[0x3B]), 0x20, 0x0003);
empty[0x1FE] = 0x55;
empty[0x1FF] = 0xAA;
empty[fat1_offs + 0x00] = empty[fat2_offs + 0x00] = empty[0x15];
empty[fat1_offs + 0x01] = empty[fat2_offs + 0x01] = 0xFF;
empty[fat1_offs + 0x02] = empty[fat2_offs + 0x02] = 0xFF;
stream.writeRawData(empty, total_size);
return true;
}
bool NewFloppyDialog::createZipSectorImage(const QString &filename, const disk_size_t& disk_size, FileType type, QProgressDialog& pbar)
{
uint32_t total_size = 0;
uint32_t total_sectors = 0;
uint32_t sector_bytes = 0;
uint32_t root_dir_bytes = 0;
uint32_t fat_size = 0;
uint32_t fat1_offs = 0;
uint32_t fat2_offs = 0;
uint32_t zero_bytes = 0;
uint16_t base = 0x1000;
uint32_t pbar_max = 0;
QFile file(filename);
if (! file.open(QIODevice::WriteOnly)) {
return false;
}
QDataStream stream(&file);
sector_bytes = (128 << disk_size.sector_len);
total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors;
if (total_sectors > ZIP_SECTORS)
total_sectors = ZIP_250_SECTORS;
total_size = total_sectors * sector_bytes;
root_dir_bytes = (disk_size.root_dir_entries << 5);
fat_size = (disk_size.spfat * sector_bytes);
fat1_offs = sector_bytes;
fat2_offs = fat1_offs + fat_size;
zero_bytes = fat2_offs + fat_size + root_dir_bytes;
pbar_max = total_size;
if (type == FileType::Zdi) {
pbar_max += base;
}
pbar_max >>= 11;
if (type == FileType::Zdi) {
QByteArray data(base, 0);
auto empty = data.data();
*(uint32_t *) &(empty[0x08]) = (uint32_t) base;
*(uint32_t *) &(empty[0x0C]) = total_size;
*(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes;
*(uint8_t *) &(empty[0x14]) = (uint8_t) disk_size.sectors;
*(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sides;
*(uint8_t *) &(empty[0x1C]) = (uint8_t) disk_size.tracks;
stream.writeRawData(empty, base);
pbar_max -= 2;
}
QByteArray bytes(total_size, 0);
auto empty = bytes.data();
if (total_sectors == ZIP_SECTORS) {
/* ZIP 100 */
/* MBR */
*(uint64_t *) &(empty[0x0000]) = 0x2054524150492EEBLL;
*(uint64_t *) &(empty[0x0008]) = 0x3930302065646F63LL;
*(uint64_t *) &(empty[0x0010]) = 0x67656D6F49202D20LL;
*(uint64_t *) &(empty[0x0018]) = 0x726F70726F432061LL;
*(uint64_t *) &(empty[0x0020]) = 0x202D206E6F697461LL;
*(uint64_t *) &(empty[0x0028]) = 0x30392F33322F3131LL;
*(uint64_t *) &(empty[0x01AE]) = 0x0116010100E90644LL;
*(uint64_t *) &(empty[0x01B6]) = 0xED08BBE5014E0135LL;
*(uint64_t *) &(empty[0x01BE]) = 0xFFFFFE06FFFFFE80LL;
*(uint64_t *) &(empty[0x01C6]) = 0x0002FFE000000020LL;
*(uint16_t *) &(empty[0x01FE]) = 0xAA55;
/* 31 sectors filled with 0x48 */
memset(&(empty[0x0200]), 0x48, 0x3E00);
/* Boot sector */
*(uint64_t *) &(empty[0x4000]) = 0x584F4236389058EBLL;
*(uint64_t *) &(empty[0x4008]) = 0x0008040200302E35LL;
*(uint64_t *) &(empty[0x4010]) = 0x00C0F80000020002LL;
*(uint64_t *) &(empty[0x4018]) = 0x0000002000FF003FLL;
*(uint32_t *) &(empty[0x4020]) = 0x0002FFE0;
*(uint16_t *) &(empty[0x4024]) = 0x0080;
empty[0x4026] = 0x29; /* ')' followed by randomly-generated volume serial number. */
empty[0x4027] = random_generate();
empty[0x4028] = random_generate();
empty[0x4029] = random_generate();
empty[0x402A] = random_generate();
memset(&(empty[0x402B]), 0x00, 0x000B);
memset(&(empty[0x4036]), 0x20, 0x0008);
empty[0x4036] = 'F';
empty[0x4037] = 'A';
empty[0x4038] = 'T';
empty[0x4039] = '1';
empty[0x403A] = '6';
memset(&(empty[0x403B]), 0x20, 0x0003);
empty[0x41FE] = 0x55;
empty[0x41FF] = 0xAA;
empty[0x5000] = empty[0x1D000] = empty[0x4015];
empty[0x5001] = empty[0x1D001] = 0xFF;
empty[0x5002] = empty[0x1D002] = 0xFF;
empty[0x5003] = empty[0x1D003] = 0xFF;
/* Root directory = 0x35000
Data = 0x39000 */
} else {
/* ZIP 250 */
/* MBR */
*(uint64_t *) &(empty[0x0000]) = 0x2054524150492EEBLL;
*(uint64_t *) &(empty[0x0008]) = 0x3930302065646F63LL;
*(uint64_t *) &(empty[0x0010]) = 0x67656D6F49202D20LL;
*(uint64_t *) &(empty[0x0018]) = 0x726F70726F432061LL;
*(uint64_t *) &(empty[0x0020]) = 0x202D206E6F697461LL;
*(uint64_t *) &(empty[0x0028]) = 0x30392F33322F3131LL;
*(uint64_t *) &(empty[0x01AE]) = 0x0116010100E900E9LL;
*(uint64_t *) &(empty[0x01B6]) = 0x2E32A7AC014E0135LL;
*(uint64_t *) &(empty[0x01EE]) = 0xEE203F0600010180LL;
*(uint64_t *) &(empty[0x01F6]) = 0x000777E000000020LL;
*(uint16_t *) &(empty[0x01FE]) = 0xAA55;
/* 31 sectors filled with 0x48 */
memset(&(empty[0x0200]), 0x48, 0x3E00);
/* The second sector begins with some strange data
in my reference image. */
*(uint64_t *) &(empty[0x0200]) = 0x3831393230334409LL;
*(uint64_t *) &(empty[0x0208]) = 0x6A57766964483130LL;
*(uint64_t *) &(empty[0x0210]) = 0x3C3A34676063653FLL;
*(uint64_t *) &(empty[0x0218]) = 0x586A56A8502C4161LL;
*(uint64_t *) &(empty[0x0220]) = 0x6F2D702535673D6CLL;
*(uint64_t *) &(empty[0x0228]) = 0x255421B8602D3456LL;
*(uint64_t *) &(empty[0x0230]) = 0x577B22447B52603ELL;
*(uint64_t *) &(empty[0x0238]) = 0x46412CC871396170LL;
*(uint64_t *) &(empty[0x0240]) = 0x704F55237C5E2626LL;
*(uint64_t *) &(empty[0x0248]) = 0x6C7932C87D5C3C20LL;
*(uint64_t *) &(empty[0x0250]) = 0x2C50503E47543D6ELL;
*(uint64_t *) &(empty[0x0258]) = 0x46394E807721536ALL;
*(uint64_t *) &(empty[0x0260]) = 0x505823223F245325LL;
*(uint64_t *) &(empty[0x0268]) = 0x365C79B0393B5B6ELL;
/* Boot sector */
*(uint64_t *) &(empty[0x4000]) = 0x584F4236389058EBLL;
*(uint64_t *) &(empty[0x4008]) = 0x0001080200302E35LL;
*(uint64_t *) &(empty[0x4010]) = 0x00EFF80000020002LL;
*(uint64_t *) &(empty[0x4018]) = 0x0000002000400020LL;
*(uint32_t *) &(empty[0x4020]) = 0x000777E0;
*(uint16_t *) &(empty[0x4024]) = 0x0080;
empty[0x4026] = 0x29; /* ')' followed by randomly-generated volume serial number. */
empty[0x4027] = random_generate();
empty[0x4028] = random_generate();
empty[0x4029] = random_generate();
empty[0x402A] = random_generate();
memset(&(empty[0x402B]), 0x00, 0x000B);
memset(&(empty[0x4036]), 0x20, 0x0008);
empty[0x4036] = 'F';
empty[0x4037] = 'A';
empty[0x4038] = 'T';
empty[0x4039] = '1';
empty[0x403A] = '6';
memset(&(empty[0x403B]), 0x20, 0x0003);
empty[0x41FE] = 0x55;
empty[0x41FF] = 0xAA;
empty[0x4200] = empty[0x22000] = empty[0x4015];
empty[0x4201] = empty[0x22001] = 0xFF;
empty[0x4202] = empty[0x22002] = 0xFF;
empty[0x4203] = empty[0x22003] = 0xFF;
/* Root directory = 0x3FE00
Data = 0x38200 */
}
pbar.setMaximum(pbar_max);
for (uint32_t i = 0; i < pbar_max; i++) {
stream.writeRawData(&empty[i << 11], 2048);
fileProgress(i);
}
fileProgress(pbar_max);
return true;
}
bool NewFloppyDialog::createMoSectorImage(const QString& filename, int8_t disk_size, FileType type, QProgressDialog& pbar)
{
const mo_type_t *dp = &mo_types[disk_size];
uint32_t total_size = 0, total_size2;
uint32_t total_sectors = 0;
uint32_t sector_bytes = 0;
uint16_t base = 0x1000;
uint32_t pbar_max = 0, blocks_num;
QFile file(filename);
if (! file.open(QIODevice::WriteOnly)) {
return false;
}
QDataStream stream(&file);
sector_bytes = dp->bytes_per_sector;
total_sectors = dp->sectors;
total_size = total_sectors * sector_bytes;
total_size2 = (total_size >> 20) << 20;
total_size2 = total_size - total_size2;
pbar_max = total_size;
pbar_max >>= 20;
blocks_num = pbar_max;
if (type == FileType::Mdi)
pbar_max++;
if (total_size2 == 0)
pbar_max++;
if (type == FileType::Mdi) {
QByteArray bytes(base, 0);
auto empty = bytes.data();
*(uint32_t *) &(empty[0x08]) = (uint32_t) base;
*(uint32_t *) &(empty[0x0C]) = total_size;
*(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes;
*(uint8_t *) &(empty[0x14]) = (uint8_t) 25;
*(uint8_t *) &(empty[0x18]) = (uint8_t) 64;
*(uint8_t *) &(empty[0x1C]) = (uint8_t) (dp->sectors / 64) / 25;
stream.writeRawData(empty, base);
}
QByteArray bytes(1048576, 0);
auto empty = bytes.data();
pbar.setMaximum(blocks_num);
for (uint32_t i = 0; i < blocks_num; i++) {
stream.writeRawData(empty, bytes.size());
fileProgress(i);
}
if (total_size2 > 0) {
QByteArray extra_bytes(total_size2, 0);
stream.writeRawData(extra_bytes.data(), total_size2);
}
fileProgress(blocks_num);
return true;
}

View File

@@ -0,0 +1,50 @@
#ifndef QT_NEWFLOPPYDIALOG_HPP
#define QT_NEWFLOPPYDIALOG_HPP
#include <QDialog>
namespace Ui {
class NewFloppyDialog;
}
struct disk_size_t;
class QProgressDialog;
class NewFloppyDialog : public QDialog
{
Q_OBJECT
public:
enum class MediaType {
Floppy,
Zip,
Mo,
};
enum class FileType {
Img,
Fdi,
Zdi,
Mdi,
};
explicit NewFloppyDialog(MediaType type, QWidget *parent = nullptr);
~NewFloppyDialog();
QString fileName() const;
signals:
void fileProgress(int i);
private slots:
void onCreate();
private:
Ui::NewFloppyDialog *ui;
MediaType mediaType_;
bool create86f(const QString& filename, const disk_size_t& disk_size, uint8_t rpm_mode);
bool createSectorImage(const QString& filename, const disk_size_t& disk_size, FileType type);
bool createZipSectorImage(const QString& filename, const disk_size_t& disk_size, FileType type, QProgressDialog& pbar);
bool createMoSectorImage(const QString& filename, int8_t disk_size, FileType type, QProgressDialog& pbar);
};
#endif // QT_NEWFLOPPYDIALOG_HPP

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewFloppyDialog</class>
<widget class="QDialog" name="NewFloppyDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>287</width>
<height>140</height>
</rect>
</property>
<property name="windowTitle">
<string>New Image</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxSize"/>
</item>
<item row="4" 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="5" column="0" colspan="2">
<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>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>File Name</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Disk Size</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="FileField" name="fileField" native="true"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelRpm">
<property name="text">
<string>RPM Mode</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxRpm"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>FileField</class>
<extends>QWidget</extends>
<header>qt_filefield.hpp</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>NewFloppyDialog</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>NewFloppyDialog</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

@@ -91,7 +91,7 @@ ui_sb_update_panes() {
}
void ui_sb_bugui(char *str) {
main_window->statusBar()->showMessage(str);
main_window->statusBarMessage(str);
}
void ui_sb_set_ready(int ready) {