Update to v070r01 release.

byuu says:

- phoenix supports onActivate, or return key pressed, on text boxes
- phoenix supports setGeometry() on all widgets
- input settings can now map analog axes and analog buttons
- analog button support is simplified over bsnes/Qt, and it supports the
  trigger inversion you see between Xbox 360 and Thrustmaster
  controllers
- load cartridge window lets you press enter in the path box to select
  the folder, but currently allows invalid folders (makes list empty)
- load cartridge won't reset your view if the folder doesn't change
  - this means the last ROM you loaded is highlighted the next time you
    go to load cartridge; you're welcome, FitzRoy :P
- removed quit system menu option
- added dummy controller port system menu options, there's no code
  behind them yet
- added power/reset menu options, dropped the power checkbox in favor of
  a standard power cycle option, removes unnecessary complexity
- added video mode scaling, 1x to 5x; and aspect ratio correction
- added video mode smooth toggle
- added audio settings panel with volume and input frequency adjustment
  - config file is where you can control output frequency and latency,
    they are too niche for a GUI
- fixed a realpath() crash on Linux when the bsnes binary was in /usr/bin
This commit is contained in:
Tim Allen 2010-09-28 00:38:32 +10:00
parent 449a3ad426
commit da5263bfc3
45 changed files with 340 additions and 43 deletions

View File

@ -1,7 +1,7 @@
include nall/Makefile include nall/Makefile
snes := snes snes := snes
profile := compatibility profile := performance
ui := ui-qt ui := ui-phoenix
# compiler # compiler
c := $(compiler) -std=gnu99 c := $(compiler) -std=gnu99

View File

@ -32,9 +32,9 @@ ifeq ($(compiler),)
ifeq ($(platform),win) ifeq ($(platform),win)
compiler := gcc compiler := gcc
else ifeq ($(platform),osx) else ifeq ($(platform),osx)
compiler := gcc-mp-4.4 compiler := gcc-mp-4.5
else else
compiler := gcc compiler := gcc-4.5
endif endif
endif endif

View File

@ -4,6 +4,7 @@ static void Button_tick(Button *self) {
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) { void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
object->widget = gtk_button_new_with_label(text); object->widget = gtk_button_new_with_label(text);
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "clicked", G_CALLBACK(Button_tick), (gpointer)this); g_signal_connect_swapped(G_OBJECT(object->widget), "clicked", G_CALLBACK(Button_tick), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont); if(parent.window->defaultFont) setFont(*parent.window->defaultFont);

View File

@ -22,6 +22,7 @@ void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsi
canvas->pitch = width * sizeof(uint32_t); canvas->pitch = width * sizeof(uint32_t);
object->widget = gtk_drawing_area_new(); object->widget = gtk_drawing_area_new();
widget->parent = &parent;
GdkColor color; GdkColor color;
color.pixel = color.red = color.green = color.blue = 0; color.pixel = color.red = color.green = color.blue = 0;
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color); gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);

View File

@ -4,6 +4,7 @@ static void CheckBox_tick(CheckBox *self) {
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) { void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
object->widget = gtk_check_button_new_with_label(text); object->widget = gtk_check_button_new_with_label(text);
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(CheckBox_tick), (gpointer)this); g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(CheckBox_tick), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont); if(parent.window->defaultFont) setFont(*parent.window->defaultFont);

View File

@ -4,6 +4,7 @@ void ComboBox_change(ComboBox *self) {
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) { void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
object->widget = gtk_combo_box_new_text(); object->widget = gtk_combo_box_new_text();
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(ComboBox_change), (gpointer)this); g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(ComboBox_change), (gpointer)this);

View File

@ -4,6 +4,7 @@ static void EditBox_change(EditBox *self) {
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) { void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
object->widget = gtk_scrolled_window_new(0, 0); object->widget = gtk_scrolled_window_new(0, 0);
widget->parent = &parent;
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);

View File

@ -76,6 +76,11 @@ struct Widget : Object {
void setEnabled(bool enabled = true); void setEnabled(bool enabled = true);
virtual bool focused(); virtual bool focused();
virtual void setFocused(); virtual void setFocused();
virtual void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
Widget();
//private:
struct Data;
Data *widget;
}; };
struct Window : Widget { struct Window : Widget {
@ -190,6 +195,7 @@ private:
}; };
struct TextBox : Widget { struct TextBox : Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange; nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = ""); void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setEditable(bool editable = true); void setEditable(bool editable = true);

View File

@ -8,6 +8,7 @@ void HorizontalSlider::create(Window &parent, unsigned x, unsigned y, unsigned w
object->position = 0; object->position = 0;
length += (length == 0); length += (length == 0);
object->widget = gtk_hscale_new_with_range(0, length - 1, 1); object->widget = gtk_hscale_new_with_range(0, length - 1, 1);
widget->parent = &parent;
gtk_scale_set_draw_value(GTK_SCALE(object->widget), false); gtk_scale_set_draw_value(GTK_SCALE(object->widget), false);
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)this); g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)this);

View File

@ -1,5 +1,6 @@
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) { void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
object->widget = gtk_label_new(text); object->widget = gtk_label_new(text);
widget->parent = &parent;
gtk_misc_set_alignment(GTK_MISC(object->widget), 0.0, 0.5); gtk_misc_set_alignment(GTK_MISC(object->widget), 0.0, 0.5);
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont); if(parent.window->defaultFont) setFont(*parent.window->defaultFont);

View File

@ -16,6 +16,7 @@ static void ListBox_activate(ListBox *self) {
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) { void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
listBox->selection = -1; listBox->selection = -1;
object->widget = gtk_scrolled_window_new(0, 0); object->widget = gtk_scrolled_window_new(0, 0);
widget->parent = &parent;
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);

View File

@ -17,6 +17,10 @@ struct Font::Data {
PangoFontDescription *font; PangoFontDescription *font;
}; };
struct Widget::Data {
Window *parent;
};
struct Window::Data { struct Window::Data {
Font *defaultFont; Font *defaultFont;
}; };

View File

@ -1,5 +1,6 @@
void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) { void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
object->widget = gtk_progress_bar_new(); object->widget = gtk_progress_bar_new();
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y); gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget); gtk_widget_show(object->widget);

View File

@ -6,6 +6,7 @@ void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un
first = this; first = this;
object->parentWindow = &parent; object->parentWindow = &parent;
object->widget = gtk_radio_button_new_with_label(0, text); object->widget = gtk_radio_button_new_with_label(0, text);
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(RadioBox_tick), (gpointer)this); g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(RadioBox_tick), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont); if(parent.window->defaultFont) setFont(*parent.window->defaultFont);

View File

@ -1,11 +1,17 @@
static void TextBox_activate(TextBox *self) {
if(self->onActivate) self->onActivate();
}
static void TextBox_change(TextBox *self) { static void TextBox_change(TextBox *self) {
if(self->object->locked == false && self->onChange) self->onChange(); if(self->object->locked == false && self->onChange) self->onChange();
} }
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) { void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
object->widget = gtk_entry_new(); object->widget = gtk_entry_new();
widget->parent = &parent;
gtk_entry_set_text(GTK_ENTRY(object->widget), text); gtk_entry_set_text(GTK_ENTRY(object->widget), text);
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "activate", G_CALLBACK(TextBox_activate), (gpointer)this);
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(TextBox_change), (gpointer)this); g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(TextBox_change), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont); if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y); gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);

View File

@ -8,6 +8,7 @@ void VerticalSlider::create(Window &parent, unsigned x, unsigned y, unsigned wid
object->position = 0; object->position = 0;
length += (length == 0); length += (length == 0);
object->widget = gtk_vscale_new_with_range(0, length - 1, 1); object->widget = gtk_vscale_new_with_range(0, length - 1, 1);
widget->parent = &parent;
gtk_scale_set_draw_value(GTK_SCALE(object->widget), false); gtk_scale_set_draw_value(GTK_SCALE(object->widget), false);
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)this); g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)this);

View File

@ -1,5 +1,6 @@
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) { void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
object->widget = gtk_drawing_area_new(); object->widget = gtk_drawing_area_new();
widget->parent = &parent;
gtk_widget_set_double_buffered(object->widget, false); gtk_widget_set_double_buffered(object->widget, false);
gtk_widget_set_size_request(object->widget, width, height); gtk_widget_set_size_request(object->widget, width, height);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y); gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);

View File

@ -34,3 +34,14 @@ void Widget::setFocused() {
if(visible() == false) setVisible(true); if(visible() == false) setVisible(true);
gtk_widget_grab_focus(object->widget); gtk_widget_grab_focus(object->widget);
} }
void Widget::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
if(widget->parent == 0) return;
gtk_fixed_move(GTK_FIXED(widget->parent->object->formContainer), object->widget, x, y);
gtk_widget_set_size_request(object->widget, width, height);
}
Widget::Widget() {
widget = new Widget::Data;
widget->parent = 0;
}

View File

@ -27,7 +27,9 @@ unsigned ComboBox::selection() {
} }
void ComboBox::setSelection(unsigned row) { void ComboBox::setSelection(unsigned row) {
object->locked = true;
comboBox->setCurrentIndex(row); comboBox->setCurrentIndex(row);
object->locked = false;
} }
ComboBox::ComboBox() { ComboBox::ComboBox() {

View File

@ -255,6 +255,7 @@ struct RadioBox : Widget {
}; };
struct TextBox : Widget { struct TextBox : Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange; nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = ""); void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setEditable(bool editable = true); void setEditable(bool editable = true);

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'qt.moc.hpp' ** Meta object code from reading C++ file 'qt.moc.hpp'
** **
** Created: Sat Sep 25 06:31:14 2010 ** Created: Mon Sep 27 04:00:47 2010
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!
@ -761,7 +761,7 @@ static const uint qt_meta_data_TextBox__Data[] = {
4, // revision 4, // revision
0, // classname 0, // classname
0, 0, // classinfo 0, 0, // classinfo
1, 14, // methods 2, 14, // methods
0, 0, // properties 0, 0, // properties
0, 0, // enums/sets 0, 0, // enums/sets
0, 0, // constructors 0, 0, // constructors
@ -770,12 +770,13 @@ static const uint qt_meta_data_TextBox__Data[] = {
// slots: signature, parameters, type, tag, flags // slots: signature, parameters, type, tag, flags
15, 14, 14, 14, 0x0a, 15, 14, 14, 14, 0x0a,
28, 14, 14, 14, 0x0a,
0 // eod 0 // eod
}; };
static const char qt_meta_stringdata_TextBox__Data[] = { static const char qt_meta_stringdata_TextBox__Data[] = {
"TextBox::Data\0\0onChange()\0" "TextBox::Data\0\0onActivate()\0onChange()\0"
}; };
const QMetaObject TextBox::Data::staticMetaObject = { const QMetaObject TextBox::Data::staticMetaObject = {
@ -807,10 +808,11 @@ int TextBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
return _id; return _id;
if (_c == QMetaObject::InvokeMetaMethod) { if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) { switch (_id) {
case 0: onChange(); break; case 0: onActivate(); break;
case 1: onChange(); break;
default: ; default: ;
} }
_id -= 1; _id -= 2;
} }
return _id; return _id;
} }

View File

@ -164,7 +164,7 @@ public:
public slots: public slots:
void onChange() { void onChange() {
if(self.onChange) self.onChange(); if(self.object->locked == false && self.onChange) self.onChange();
} }
}; };
@ -262,6 +262,10 @@ public:
} }
public slots: public slots:
void onActivate() {
if(self.onActivate) self.onActivate();
}
void onChange() { void onChange() {
if(self.onChange) self.onChange(); if(self.onChange) self.onChange();
} }

View File

@ -4,6 +4,7 @@ void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
textBox->setText(text); textBox->setText(text);
if(parent.window->defaultFont) textBox->setFont(*parent.window->defaultFont); if(parent.window->defaultFont) textBox->setFont(*parent.window->defaultFont);
textBox->show(); textBox->show();
textBox->connect(textBox, SIGNAL(returnPressed()), SLOT(onActivate()));
textBox->connect(textBox, SIGNAL(textEdited(const QString&)), SLOT(onChange())); textBox->connect(textBox, SIGNAL(textEdited(const QString&)), SLOT(onChange()));
} }

View File

@ -28,6 +28,10 @@ void Widget::setFocused() {
SetFocus(widget->window); SetFocus(widget->window);
} }
void Widget::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
SetWindowPos(widget->window, NULL, x, y, width, height, SWP_NOZORDER);
}
Widget::Widget() { Widget::Widget() {
os.objects.append(this); os.objects.append(this);
widget = new Widget::Data; widget = new Widget::Data;

View File

@ -211,11 +211,18 @@ static void OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
info.cbSize = sizeof(GUITHREADINFO); info.cbSize = sizeof(GUITHREADINFO);
GetGUIThreadInfo(GetCurrentThreadId(), &info); GetGUIThreadInfo(GetCurrentThreadId(), &info);
Object *object_ptr = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA); Object *object_ptr = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
if(object_ptr && dynamic_cast<ListBox*>(object_ptr)) { if(object_ptr) {
if(dynamic_cast<ListBox*>(object_ptr)) {
ListBox &listBox = (ListBox&)*object_ptr; ListBox &listBox = (ListBox&)*object_ptr;
if(wparam == VK_RETURN) { if(wparam == VK_RETURN) {
if(listBox.onActivate) listBox.onActivate(); if(listBox.onActivate) listBox.onActivate();
} }
} else if(dynamic_cast<TextBox*>(object_ptr)) {
TextBox &textBox = (TextBox&)*object_ptr;
if(wparam == VK_RETURN) {
if(textBox.onActivate) textBox.onActivate();
}
}
} }
} }
} }

View File

@ -84,6 +84,7 @@ struct Widget : Object {
void setEnabled(bool enabled = true); void setEnabled(bool enabled = true);
bool focused(); bool focused();
void setFocused(); void setFocused();
virtual void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
Widget(); Widget();
//private: //private:
struct Data; struct Data;
@ -211,6 +212,7 @@ struct RadioBox : Widget {
}; };
struct TextBox : Widget { struct TextBox : Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange; nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = ""); void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
nall::string text(); nall::string text();

View File

@ -1,7 +1,7 @@
namespace SNES { namespace SNES {
namespace Info { namespace Info {
static const char Name[] = "bsnes"; static const char Name[] = "bsnes";
static const char Version[] = "070"; static const char Version[] = "070.01";
static const unsigned SerializerVersion = 13; static const unsigned SerializerVersion = 13;
} }
} }

View File

@ -8,19 +8,15 @@ bool Cartridge::loadNormal(const char *filename) {
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, lstring() << baseXML); SNES::cartridge.load(SNES::Cartridge::Mode::Normal, lstring() << baseXML);
loadMemory(SNES::memory::cartram, baseName, ".srm"); loadMemory(SNES::memory::cartram, baseName, ".srm");
loadMemory(SNES::memory::cartrtc, baseName, ".rtc"); loadMemory(SNES::memory::cartrtc, baseName, ".rtc");
cheatEditor.load(baseName); utility.cartridgeLoaded();
utility.setTitle(notdir(baseName));
utility.showMessage(string("Loaded ", notdir(baseName)));
config.path.current = dir(baseName);
return true; return true;
} }
void Cartridge::unload() { void Cartridge::unload() {
if(SNES::cartridge.loaded() == false) return; if(SNES::cartridge.loaded() == false) return;
cheatEditor.save(baseName);
saveMemory(SNES::memory::cartram, baseName, ".srm"); saveMemory(SNES::memory::cartram, baseName, ".srm");
saveMemory(SNES::memory::cartrtc, baseName, ".rtc"); saveMemory(SNES::memory::cartrtc, baseName, ".rtc");
SNES::cartridge.unload(); utility.cartridgeUnloaded();
} }
bool Cartridge::loadCartridge(SNES::MappedRAM &memory, string &XML, const char *filename) { bool Cartridge::loadCartridge(SNES::MappedRAM &memory, string &XML, const char *filename) {

View File

@ -14,6 +14,9 @@ void Configuration::create() {
attach(video.driver = "", "video.driver"); attach(video.driver = "", "video.driver");
attach(video.synchronize = false, "video.synchronize"); attach(video.synchronize = false, "video.synchronize");
attach(video.smooth = true, "video.smooth");
attach(video.scale = 2, "video.scale");
attach(video.aspectRatioCorrection = true, "video.aspectRatioCorrection");
attach(video.contrast = 100, "video.contrast"); attach(video.contrast = 100, "video.contrast");
attach(video.brightness = 100, "video.brightness"); attach(video.brightness = 100, "video.brightness");
attach(video.gamma = 100, "video.gamma"); attach(video.gamma = 100, "video.gamma");
@ -22,6 +25,10 @@ void Configuration::create() {
attach(audio.driver = "", "audio.driver"); attach(audio.driver = "", "audio.driver");
attach(audio.synchronize = true, "audio.synchronize"); attach(audio.synchronize = true, "audio.synchronize");
attach(audio.mute = false, "audio.mute"); attach(audio.mute = false, "audio.mute");
attach(audio.volume = 100, "audio.volume");
attach(audio.latency = 60, "audio.latency");
attach(audio.inputFrequency = 32000, "audio.inputFrequency");
attach(audio.outputFrequency = 44100, "audio.outputFrequency");
attach(input.driver = "", "input.driver"); attach(input.driver = "", "input.driver");

View File

@ -8,6 +8,9 @@ struct Configuration : public configuration {
struct Video { struct Video {
string driver; string driver;
bool synchronize; bool synchronize;
bool smooth;
unsigned scale;
bool aspectRatioCorrection;
unsigned contrast; unsigned contrast;
unsigned brightness; unsigned brightness;
unsigned gamma; unsigned gamma;
@ -18,6 +21,10 @@ struct Configuration : public configuration {
string driver; string driver;
bool synchronize; bool synchronize;
bool mute; bool mute;
unsigned volume;
unsigned latency;
unsigned inputFrequency;
unsigned outputFrequency;
} audio; } audio;
struct Input { struct Input {

View File

@ -16,6 +16,7 @@ void FileBrowser::create() {
setGeometry(160, 160, 640, y); setGeometry(160, 160, 640, y);
pathBox.onActivate = []() { fileBrowser.setFolder(fileBrowser.pathBox.text()); };
browseButton.onTick = { &FileBrowser::folderBrowse, this }; browseButton.onTick = { &FileBrowser::folderBrowse, this };
upButton.onTick = { &FileBrowser::folderUp, this }; upButton.onTick = { &FileBrowser::folderUp, this };
contentsBox.onActivate = { &FileBrowser::fileActivate, this }; contentsBox.onActivate = { &FileBrowser::fileActivate, this };
@ -29,6 +30,10 @@ void FileBrowser::fileOpen(const char *pathname) {
} }
void FileBrowser::setFolder(const char *pathname) { void FileBrowser::setFolder(const char *pathname) {
string path = pathname;
path.rtrim("/");
if(folder == path) return;
contentsBox.reset(); contentsBox.reset();
contents.reset(); contents.reset();
@ -42,6 +47,7 @@ void FileBrowser::setFolder(const char *pathname) {
} }
foreach(item, contents) contentsBox.addItem(item); foreach(item, contents) contentsBox.addItem(item);
contentsBox.setSelection(0); contentsBox.setSelection(0);
contentsBox.setFocused();
} }
void FileBrowser::folderBrowse() { void FileBrowser::folderBrowse() {
@ -61,7 +67,6 @@ void FileBrowser::fileActivate() {
} else { } else {
filename = string(folder, "/", filename); filename = string(folder, "/", filename);
cartridge.loadNormal(filename); cartridge.loadNormal(filename);
SNES::system.power();
setVisible(false); setVisible(false);
} }
} }

View File

@ -9,18 +9,42 @@ void MainWindow::create() {
system.create(*this, "System"); system.create(*this, "System");
systemLoadCartridge.create(system, "Load Cartridge ..."); systemLoadCartridge.create(system, "Load Cartridge ...");
systemSeparator.create(system); systemSeparator1.create(system);
systemQuit.create(system, "Quit"); systemPower.create(system, "Power Cycle");
systemReset.create(system, "Reset");
systemSeparator2.create(system);
systemPort1.create(system, "Controller Port 1");
systemPort1.setEnabled(false);
systemPort2.create(system, "Controller Port 2");
systemPort2.setEnabled(false);
settings.create(*this, "Settings"); settings.create(*this, "Settings");
settingsVideoMode.create(settings, "Video Mode");
settingsVideoMode1x.create(settingsVideoMode, "Scale 1x");
settingsVideoMode2x.create(settingsVideoMode1x, "Scale 2x");
settingsVideoMode3x.create(settingsVideoMode1x, "Scale 3x");
settingsVideoMode4x.create(settingsVideoMode1x, "Scale 4x");
settingsVideoMode5x.create(settingsVideoMode1x, "Scale 5x");
if(config.video.scale == 1) settingsVideoMode1x.setChecked();
if(config.video.scale == 2) settingsVideoMode2x.setChecked();
if(config.video.scale == 3) settingsVideoMode3x.setChecked();
if(config.video.scale == 4) settingsVideoMode4x.setChecked();
if(config.video.scale == 5) settingsVideoMode5x.setChecked();
settingsVideoModeSeparator.create(settingsVideoMode);
settingsVideoModeAspectRatioCorrection.create(settingsVideoMode, "Correct Aspect Ratio");
settingsVideoModeAspectRatioCorrection.setChecked(config.video.aspectRatioCorrection);
settingsSmoothVideo.create(settings, "Smooth Video");
settingsSmoothVideo.setChecked(config.video.smooth);
settingsSeparator1.create(settings);
settingsSynchronizeVideo.create(settings, "Synchronize Video"); settingsSynchronizeVideo.create(settings, "Synchronize Video");
settingsSynchronizeVideo.setChecked(config.video.synchronize); settingsSynchronizeVideo.setChecked(config.video.synchronize);
settingsSynchronizeAudio.create(settings, "Synchronize Audio"); settingsSynchronizeAudio.create(settings, "Synchronize Audio");
settingsSynchronizeAudio.setChecked(config.audio.synchronize); settingsSynchronizeAudio.setChecked(config.audio.synchronize);
settingsMuteAudio.create(settings, "Mute Audio"); settingsMuteAudio.create(settings, "Mute Audio");
settingsMuteAudio.setChecked(config.audio.mute); settingsMuteAudio.setChecked(config.audio.mute);
settingsSeparator.create(settings); settingsSeparator2.create(settings);
settingsVideo.create(settings, "Video Settings ..."); settingsVideo.create(settings, "Video Settings ...");
settingsAudio.create(settings, "Audio Settings ...");
settingsInput.create(settings, "Input Settings ..."); settingsInput.create(settings, "Input Settings ...");
settingsAdvanced.create(settings, "Advanced Settings ..."); settingsAdvanced.create(settings, "Advanced Settings ...");
@ -52,7 +76,30 @@ void MainWindow::create() {
utility.loadCartridgeNormal(); utility.loadCartridgeNormal();
}; };
systemQuit.onTick = []() { application.quit = true; }; systemPower.onTick = []() {
SNES::system.power();
utility.showMessage("System was power cycled");
};
systemReset.onTick = []() {
SNES::system.reset();
utility.showMessage("System was reset");
};
settingsVideoMode1x.onTick = []() { utility.setScale(1); };
settingsVideoMode2x.onTick = []() { utility.setScale(2); };
settingsVideoMode3x.onTick = []() { utility.setScale(3); };
settingsVideoMode4x.onTick = []() { utility.setScale(4); };
settingsVideoMode5x.onTick = []() { utility.setScale(5); };
settingsVideoModeAspectRatioCorrection.onTick = []() {
utility.setAspectRatioCorrection(mainWindow.settingsVideoModeAspectRatioCorrection.checked());
};
settingsSmoothVideo.onTick = []() {
config.video.smooth = mainWindow.settingsSmoothVideo.checked();
video.set(Video::Filter, (unsigned)config.video.smooth);
};
settingsSynchronizeVideo.onTick = []() { settingsSynchronizeVideo.onTick = []() {
config.video.synchronize = mainWindow.settingsSynchronizeVideo.checked(); config.video.synchronize = mainWindow.settingsSynchronizeVideo.checked();
@ -67,6 +114,7 @@ void MainWindow::create() {
settingsMuteAudio.onTick = []() { config.audio.mute = mainWindow.settingsMuteAudio.checked(); }; settingsMuteAudio.onTick = []() { config.audio.mute = mainWindow.settingsMuteAudio.checked(); };
settingsVideo.onTick = []() { videoSettings.setVisible(); }; settingsVideo.onTick = []() { videoSettings.setVisible(); };
settingsAudio.onTick = []() { audioSettings.setVisible(); };
settingsInput.onTick = []() { inputSettings.setVisible(); }; settingsInput.onTick = []() { inputSettings.setVisible(); };
settingsAdvanced.onTick = []() { advancedSettings.setVisible(); }; settingsAdvanced.onTick = []() { advancedSettings.setVisible(); };
@ -98,4 +146,20 @@ void MainWindow::create() {
application.quit = true; application.quit = true;
return false; return false;
}; };
synchronize();
}
void MainWindow::synchronize() {
if(SNES::cartridge.loaded() == false) {
systemPower.setEnabled(false);
systemReset.setEnabled(false);
toolsStateSave.setEnabled(false);
toolsStateLoad.setEnabled(false);
} else {
systemPower.setEnabled(true);
systemReset.setEnabled(true);
toolsStateSave.setEnabled(true);
toolsStateLoad.setEnabled(true);
}
} }

View File

@ -1,14 +1,29 @@
struct MainWindow : Window { struct MainWindow : Window {
Menu system; Menu system;
MenuItem systemLoadCartridge; MenuItem systemLoadCartridge;
MenuSeparator systemSeparator; MenuSeparator systemSeparator1;
MenuItem systemQuit; MenuItem systemPower;
MenuItem systemReset;
MenuSeparator systemSeparator2;
Menu systemPort1;
Menu systemPort2;
Menu settings; Menu settings;
Menu settingsVideoMode;
MenuRadioItem settingsVideoMode1x;
MenuRadioItem settingsVideoMode2x;
MenuRadioItem settingsVideoMode3x;
MenuRadioItem settingsVideoMode4x;
MenuRadioItem settingsVideoMode5x;
MenuSeparator settingsVideoModeSeparator;
MenuCheckItem settingsVideoModeAspectRatioCorrection;
MenuCheckItem settingsSmoothVideo;
MenuSeparator settingsSeparator1;
MenuCheckItem settingsSynchronizeVideo; MenuCheckItem settingsSynchronizeVideo;
MenuCheckItem settingsSynchronizeAudio; MenuCheckItem settingsSynchronizeAudio;
MenuCheckItem settingsMuteAudio; MenuCheckItem settingsMuteAudio;
MenuSeparator settingsSeparator; MenuSeparator settingsSeparator2;
MenuItem settingsVideo; MenuItem settingsVideo;
MenuItem settingsAudio;
MenuItem settingsInput; MenuItem settingsInput;
MenuItem settingsAdvanced; MenuItem settingsAdvanced;
Menu tools; Menu tools;
@ -31,6 +46,7 @@ struct MainWindow : Window {
Viewport viewport; Viewport viewport;
void create(); void create();
void synchronize();
}; };
extern MainWindow mainWindow; extern MainWindow mainWindow;

View File

@ -6,6 +6,8 @@ void InputMapper::AbstractInput::bind() {
else if(strend(mapping, ".Down")) type = Type::HatDown; else if(strend(mapping, ".Down")) type = Type::HatDown;
else if(strend(mapping, ".Left")) type = Type::HatLeft; else if(strend(mapping, ".Left")) type = Type::HatLeft;
else if(strend(mapping, ".Right")) type = Type::HatRight; else if(strend(mapping, ".Right")) type = Type::HatRight;
else if(strend(mapping, ".Lo")) type = Type::AxisLo;
else if(strend(mapping, ".Hi")) type = Type::AxisHi;
else type = Type::Button; else type = Type::Button;
string mappingValue = mapping; string mappingValue = mapping;
@ -21,6 +23,8 @@ int16_t InputMapper::DigitalInput::poll() {
case AbstractInput::Type::HatDown: return (bool)(value & Joypad::HatDown); case AbstractInput::Type::HatDown: return (bool)(value & Joypad::HatDown);
case AbstractInput::Type::HatLeft: return (bool)(value & Joypad::HatLeft); case AbstractInput::Type::HatLeft: return (bool)(value & Joypad::HatLeft);
case AbstractInput::Type::HatRight: return (bool)(value & Joypad::HatRight); case AbstractInput::Type::HatRight: return (bool)(value & Joypad::HatRight);
case AbstractInput::Type::AxisLo: return (bool)(value < -16384);
case AbstractInput::Type::AxisHi: return (bool)(value > +16384);
} }
} }
@ -206,3 +210,7 @@ int16_t InputMapper::poll(bool port, SNES::Input::Device device, unsigned index,
} }
return 0; return 0;
} }
int16_t InputMapper::value(unsigned scancode) {
return state[activeState][scancode];
}

View File

@ -1,6 +1,6 @@
struct InputMapper { struct InputMapper {
struct AbstractInput { struct AbstractInput {
enum class Type : unsigned { Button, HatUp, HatDown, HatLeft, HatRight } type; enum class Type : unsigned { Button, HatUp, HatDown, HatLeft, HatRight, AxisLo, AxisHi } type;
string name; string name;
string mapping; string mapping;
unsigned scancode; unsigned scancode;
@ -76,6 +76,7 @@ struct InputMapper {
void bind(); void bind();
void poll(); void poll();
int16_t poll(bool port, SNES::Input::Device device, unsigned index, unsigned id); int16_t poll(bool port, SNES::Input::Device device, unsigned index, unsigned id);
int16_t value(unsigned scancode);
}; };
extern InputMapper inputMapper; extern InputMapper inputMapper;

View File

@ -11,10 +11,10 @@ void Application::main(int argc, char **argv) {
inputMapper.create(); inputMapper.create();
char temp[PATH_MAX]; char temp[PATH_MAX];
config.path.base = realpath(argv[0], temp); if(realpath(argv[0], temp)) config.path.base = temp;
config.path.base.transform("\\", "/"); config.path.base.transform("\\", "/");
config.path.base = dir(config.path.base); config.path.base = dir(config.path.base);
config.path.user = userpath(temp); if(userpath(temp)) config.path.user = temp;
config.path.user.transform("\\", "/"); config.path.user.transform("\\", "/");
if(strend(config.path.user, "/") == false) config.path.user.append("/"); if(strend(config.path.user, "/") == false) config.path.user.append("/");
config.path.user.append(".bsnes/"); config.path.user.append(".bsnes/");
@ -41,16 +41,18 @@ void Application::main(int argc, char **argv) {
mainWindow.create(); mainWindow.create();
fileBrowser.create(); fileBrowser.create();
videoSettings.create(); videoSettings.create();
audioSettings.create();
inputSettings.create(); inputSettings.create();
advancedSettings.create(); advancedSettings.create();
cheatEditor.create(); cheatEditor.create();
utility.setScale(config.video.scale);
mainWindow.setVisible(); mainWindow.setVisible();
os.run(); os.run();
video.driver(config.video.driver); video.driver(config.video.driver);
video.set(Video::Handle, mainWindow.viewport.handle()); video.set(Video::Handle, mainWindow.viewport.handle());
video.set(Video::Synchronize, config.video.synchronize); video.set(Video::Synchronize, config.video.synchronize);
video.set(Video::Filter, (unsigned)Video::FilterLinear); video.set(Video::Filter, (unsigned)config.video.smooth);
if(video.init() == false) { if(video.init() == false) {
MessageWindow::critical(mainWindow, "Failed to initialize video."); MessageWindow::critical(mainWindow, "Failed to initialize video.");
video.driver("None"); video.driver("None");
@ -60,7 +62,11 @@ void Application::main(int argc, char **argv) {
audio.driver(config.audio.driver); audio.driver(config.audio.driver);
audio.set(Audio::Handle, mainWindow.viewport.handle()); audio.set(Audio::Handle, mainWindow.viewport.handle());
audio.set(Audio::Synchronize, config.audio.synchronize); audio.set(Audio::Synchronize, config.audio.synchronize);
audio.set(Audio::Frequency, (unsigned)32000); audio.set(Audio::Volume, config.audio.volume);
audio.set(Audio::Latency, config.audio.latency);
audio.set(Audio::Frequency, config.audio.outputFrequency);
audio.set(Audio::Resample, true);
audio.set(Audio::ResampleRatio, (double)config.audio.inputFrequency / (double)config.audio.outputFrequency);
if(audio.init() == false) { if(audio.init() == false) {
MessageWindow::critical(mainWindow, "Failed to initialize audio."); MessageWindow::critical(mainWindow, "Failed to initialize audio.");
audio.driver("None"); audio.driver("None");
@ -76,10 +82,7 @@ void Application::main(int argc, char **argv) {
} }
SNES::system.init(&interface); SNES::system.init(&interface);
if(argc == 2) { if(argc == 2) cartridge.loadNormal(argv[1]);
cartridge.loadNormal(argv[1]);
SNES::system.power();
}
while(quit == false) { while(quit == false) {
os.run(); os.run();

View File

@ -0,0 +1,33 @@
AudioSettings audioSettings;
void AudioSettings::create() {
application.windows.append(this);
Window::create(0, 0, 256, 256, "Audio Settings");
setDefaultFont(application.proportionalFont);
unsigned x = 5, y = 5;
volumeLabel.create(*this, x, y, 70, Style::SliderHeight, "Volume:");
volumeValue.create(*this, x + 70, y, 60, Style::SliderHeight, "100%");
volumeSlider.create(*this, x + 130, y, 300, Style::SliderHeight, 201); y += Style::SliderHeight + 5;
volumeSlider.setPosition(config.audio.volume);
frequencyLabel.create(*this, x, y, 70, Style::SliderHeight, "Frequency:");
frequencyValue.create(*this, x + 70, y, 60, Style::SliderHeight, "32000hz");
frequencySlider.create(*this, x + 130, y, 300, Style::SliderHeight, 2001); y += Style::SliderHeight + 5;
frequencySlider.setPosition(config.audio.inputFrequency - 31000);
volumeSlider.onChange = []() {
config.audio.volume = audioSettings.volumeSlider.position();
audio.set(Audio::Volume, config.audio.volume);
audioSettings.volumeValue.setText(string(config.audio.volume, "%"));
};
frequencySlider.onChange = []() {
config.audio.inputFrequency = audioSettings.frequencySlider.position() + 31000;
audio.set(Audio::ResampleRatio, (double)config.audio.inputFrequency / (double)config.audio.outputFrequency);
audioSettings.frequencyValue.setText(string(config.audio.inputFrequency, "hz"));
};
setGeometry(160, 160, 440, y);
}

View File

@ -0,0 +1,12 @@
struct AudioSettings : Window {
Label volumeLabel;
Label volumeValue;
HorizontalSlider volumeSlider;
Label frequencyLabel;
Label frequencyValue;
HorizontalSlider frequencySlider;
void create();
};
extern AudioSettings audioSettings;

View File

@ -17,7 +17,7 @@ void InputSettings::create() {
deviceLabel.create(*this, x + 255, y, 50, Style::ComboBoxHeight, "Device:"); deviceLabel.create(*this, x + 255, y, 50, Style::ComboBoxHeight, "Device:");
deviceBox.create(*this, x + 305, y, 200, Style::ComboBoxHeight); y += Style::ComboBoxHeight + 5; deviceBox.create(*this, x + 305, y, 200, Style::ComboBoxHeight); y += Style::ComboBoxHeight + 5;
mappingList.create(*this, x, y, 505, 300, "Name\tMapping"); y += 300 + 5; mappingList.create(*this, x, y, 505, 265, "Name\tMapping"); y += 265 + 5;
mappingList.setHeaderVisible(); mappingList.setHeaderVisible();
mappingList.setFocused(); mappingList.setFocused();
@ -104,8 +104,41 @@ void InputSettings::inputEvent(uint16_t scancode, int16_t value) {
else if(value == Joypad::HatDown) setMapping(string(mapping, ".Down")); else if(value == Joypad::HatDown) setMapping(string(mapping, ".Down"));
else if(value == Joypad::HatLeft) setMapping(string(mapping, ".Left")); else if(value == Joypad::HatLeft) setMapping(string(mapping, ".Left"));
else if(value == Joypad::HatRight) setMapping(string(mapping, ".Right")); else if(value == Joypad::HatRight) setMapping(string(mapping, ".Right"));
} else if(Joypad::isAnyAxis(scancode)) {
if(joypadsCalibrated == false) return calibrateJoypads();
unsigned joypadNumber = Joypad::numberDecode(scancode);
unsigned axisNumber = Joypad::axisDecode(scancode);
int16_t calibration = joypadCalibration[joypadNumber][axisNumber];
if(calibration > -12288 && calibration < +12288 && value < -24576) setMapping(string(mapping, ".Lo"));
else if(calibration > -12288 && calibration < +12288 && value > +24576) setMapping(string(mapping, ".Hi"));
else if(calibration <= -12288 && value >= +12288) setMapping(string(mapping, ".Hi"));
else if(calibration >= +12288 && value <= -12288) setMapping(string(mapping, ".Lo"));
} else if(Joypad::isAnyButton(scancode) && value) { } else if(Joypad::isAnyButton(scancode) && value) {
setMapping(mapping); setMapping(mapping);
} }
} }
} }
void InputSettings::calibrateJoypads() {
if(joypadsCalibrating == true) return;
joypadsCalibrating = true;
MessageWindow::information(*this,
"Analog joypads must be calibrated prior to use.\n\n"
"Please move all analog axes, and press all analog buttons.\n"
"Please do this for every controller you wish to use.\n"
"Once finished, please let go of all axes and buttons, and press OK."
);
inputMapper.poll();
for(unsigned j = 0; j < Joypad::Count &&j<2; j++) {
for(unsigned a = 0; a < Joypad::Axes; a++) {
joypadCalibration[j][a] = inputMapper.value(joypad(j).axis(a));
}
}
joypadsCalibrating = false;
joypadsCalibrated = true;
}
InputSettings::InputSettings() {
joypadsCalibrated = false;
joypadsCalibrating = false;
}

View File

@ -6,9 +6,15 @@ struct InputSettings : Window {
ListBox mappingList; ListBox mappingList;
void inputEvent(uint16_t scancode, int16_t value); void inputEvent(uint16_t scancode, int16_t value);
void calibrateJoypads();
void create(); void create();
InputSettings();
private: private:
bool joypadsCalibrated;
bool joypadsCalibrating;
int16_t joypadCalibration[Joypad::Count][Joypad::Axes];
void portChanged(); void portChanged();
void deviceChanged(); void deviceChanged();
void setMapping(const char *mapping); void setMapping(const char *mapping);

View File

@ -1,4 +1,5 @@
#include "../base.hpp" #include "../base.hpp"
#include "video.cpp" #include "video.cpp"
#include "audio.cpp"
#include "input.cpp" #include "input.cpp"
#include "advanced.cpp" #include "advanced.cpp"

View File

@ -1,3 +1,4 @@
#include "video.hpp" #include "video.hpp"
#include "audio.hpp"
#include "input.hpp" #include "input.hpp"
#include "advanced.hpp" #include "advanced.hpp"

View File

@ -22,9 +22,9 @@ void VideoSettings::create() {
gammaValue.create (*this, x + 80, y, 50, Style::SliderHeight, "100%"); gammaValue.create (*this, x + 80, y, 50, Style::SliderHeight, "100%");
gammaSlider.create (*this, x + 130, y, 300, Style::SliderHeight, 201); y += Style::SliderHeight + 5; gammaSlider.create (*this, x + 130, y, 300, Style::SliderHeight, 201); y += Style::SliderHeight + 5;
gammaRampCheck.create (*this, x, y, 430, 15, "Enable NTSC gamma ramp simulation"); y += 15; gammaRampCheck.create (*this, x, y, 430, Style::CheckBoxHeight, "Enable NTSC gamma ramp simulation"); y += Style::CheckBoxHeight + 5;
setGeometry(160, 160, 440, y + 5); setGeometry(160, 160, 440, y);
contrastSlider.setPosition(config.video.contrast); contrastSlider.setPosition(config.video.contrast);
brightnessSlider.setPosition(config.video.brightness); brightnessSlider.setPosition(config.video.brightness);

View File

@ -11,7 +11,14 @@ void Utility::setTitle(const char *text) {
void Utility::updateStatus() { void Utility::updateStatus() {
time_t currentTime = time(0); time_t currentTime = time(0);
string text = ((currentTime - statusTime) > 3) ? statusText : statusMessage; string text;
if((currentTime - statusTime) <= 3) {
text = statusMessage;
} else if(SNES::cartridge.loaded() == false) {
text = "No cartridge loaded";
} else {
text = statusText;
}
if(text != statusCurrentText) { if(text != statusCurrentText) {
mainWindow.setStatusText(statusCurrentText = text); mainWindow.setStatusText(statusCurrentText = text);
} }
@ -27,6 +34,35 @@ void Utility::showMessage(const char *text) {
statusTime = time(0); statusTime = time(0);
} }
void Utility::setScale(unsigned scale) {
config.video.scale = scale;
unsigned width = 256 * scale;
unsigned height = 224 * scale;
if(config.video.aspectRatioCorrection) width *= 54.0 / 47.0; //PAL = 32.0 / 23.0
mainWindow.viewport.setGeometry(0, 0, width, height);
mainWindow.setGeometry(128, 128, width, height);
}
void Utility::setAspectRatioCorrection(bool aspectRatioCorrection) {
config.video.aspectRatioCorrection = aspectRatioCorrection;
setScale(config.video.scale);
}
void Utility::cartridgeLoaded() {
SNES::system.power();
cheatEditor.load(cartridge.baseName);
mainWindow.synchronize();
utility.setTitle(notdir(cartridge.baseName));
utility.showMessage(string("Loaded ", notdir(cartridge.baseName)));
config.path.current = dir(cartridge.baseName);
}
void Utility::cartridgeUnloaded() {
SNES::cartridge.unload();
cheatEditor.save(cartridge.baseName);
mainWindow.synchronize();
}
void Utility::loadCartridgeNormal() { void Utility::loadCartridgeNormal() {
if(config.settings.useNativeDialogs == false) { if(config.settings.useNativeDialogs == false) {
fileBrowser.fileOpen(config.path.current); fileBrowser.fileOpen(config.path.current);

View File

@ -1,9 +1,15 @@
struct Utility { struct Utility : property<Utility> {
void setTitle(const char *text); void setTitle(const char *text);
void updateStatus(); void updateStatus();
void setStatus(const char *text); void setStatus(const char *text);
void showMessage(const char *text); void showMessage(const char *text);
void setScale(unsigned scale);
void setAspectRatioCorrection(bool aspectRatioCorrection);
void cartridgeLoaded();
void cartridgeUnloaded();
void loadCartridgeNormal(); void loadCartridgeNormal();
void saveState(unsigned slot); void saveState(unsigned slot);
void loadState(unsigned slot); void loadState(unsigned slot);