[GTK3] Add PreferencesWindow GTK widget

This commit is contained in:
Maximilian Mader 2020-05-20 03:41:33 +02:00
parent 337f396eff
commit bef38d16d2
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
15 changed files with 1399 additions and 1177 deletions

View File

@ -120,35 +120,7 @@ void save_config_to_key_file(config_t *config, GKeyFile *key_file) {
}
}
void on_preferences_realize(GtkWidget *w, gpointer builder_ptr) {
GtkWindow *preferences = GTK_WINDOW(w);
GtkBuilder *builder = (GtkBuilder *) builder_ptr;
GApplication *app = G_APPLICATION(gtk_builder_get_application(builder));
update_boot_rom_selector(builder);
// Hook up the static preferences
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "rewind_duration_selector"), g_strdup_printf("%i", config.emulation.rewind_duration));
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "dmg_revision_selector"), config.emulation.dmg_revision_name);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "sgb_revision_selector"), config.emulation.sgb_revision_name);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "cgb_revision_selector"), config.emulation.cgb_revision_name);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "shader_selector"), config.video.shader);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "color_correction_selector"), config.video.color_correction_id);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "frame_blending_selector"), config.video.frame_blending_mode);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "display_border_selector"), config.video.display_border_mode);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "monochrome_palette_selector"), config.video.monochrome_palette_id);
gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "integer_scaling_toggle"), config.video.use_integer_scaling);
gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "aspect_ratio_toggle"), config.video.keep_aspect_ratio);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "highpass_filter_selector"), config.audio.high_pass_filter_id);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "sample_rate_selector"), g_strdup_printf("%i", config.audio.sample_rate));
gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "analog_speed_controls_toggle"), config.controls.analog_speed_controls);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "rumble_mode_selector"), config.controls.rumble_mode);
}
void init_config(GApplication *app, gchar *path, GDateTime **modification_date, GtkWindow *preferences) {
void init_config(GApplication *app, gchar *path, GDateTime **modification_date) {
free_config();
key_file = g_key_file_new();

View File

@ -71,12 +71,10 @@ typedef struct config_t {
config_t config;
void on_preferences_realize(GtkWidget *w, gpointer builder_ptr);
void print_config(config_t *config);
void load_config_from_key_file(config_t *config, GKeyFile *key_file);
void init_config(GApplication *app, gchar *path, GDateTime **modification_date, GtkWindow *preferences);
void init_config(GApplication *app, gchar *path, GDateTime **modification_date);
void load_config(GApplication *app, GDateTime **modification_date);
void save_config(GtkWindow *main_window, GDateTime *saved_modification_date);
void free_config(void);

View File

@ -156,7 +156,7 @@ static void gb_screen_set_property(GObject *object, guint property_id, const GVa
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
}
@ -169,7 +169,7 @@ static void gb_screen_get_property(GObject *object, guint property_id, GValue *v
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
}

View File

@ -8,7 +8,7 @@
#include "shader.h"
#define GB_SCREEN_TYPE (gb_screen_get_type())
G_DECLARE_FINAL_TYPE(GbScreen, gb_screen, SAMEBOY, BIN, GtkBin)
G_DECLARE_FINAL_TYPE(GbScreen, gb_screen, SAMEBOY, GB_SCREEN, GtkBin)
GbScreen *gb_screen_new(bool force_fallback);
void gb_screen_clear(GbScreen *self);

View File

@ -14,6 +14,7 @@
#include "check_menu_radio_group.h"
#include "gb_screen.h"
#include "preferences_window.h"
#include "vram_viewer_window.h"
// used for audio and game controllers
@ -66,7 +67,7 @@ static GuiData gui_data = {
.analog_clock_multiplier = 1.0,
};
GB_gameboy_t gb;
static GB_gameboy_t gb;
// Forward declarations of the actions
static void activate_open(GSimpleAction *action, GVariant *parameter, gpointer app);
@ -611,36 +612,6 @@ static void setup_menu(GApplication *app) {
gtk_box_pack_start(GTK_BOX(gui_data.main_window_container), GTK_WIDGET(menubar), false, false, 0);
}
// Determines if a ComboBox entry should be converted into a separator.
// Each element with a text value of `<separator>` will be converted into a separator element.
static gboolean is_separator(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) {
gchar *text = NULL;
gtk_tree_model_get(model, iter, 0, &text, -1);
gboolean result = g_strcmp0("<separator>", text) == 0;
g_free(text);
return result;
}
// Recursively goes through all children of the given container and sets
// our `is_separator` function to all children of type`GtkComboBox`
static void set_combo_box_row_separator_func(GtkContainer *container) {
GList *children = gtk_container_get_children(container);
for (GList *l = children; l; l = l->next) {
if (GTK_IS_COMBO_BOX(l->data)) {
gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(l->data), is_separator, NULL, NULL);
}
if (GTK_IS_CONTAINER(l->data)) {
set_combo_box_row_separator_func(GTK_CONTAINER(l->data));
}
}
g_list_free(children);
}
// WHY DO WE NEED SUCH AN UGLY METHOD, GTK?!
static void action_entries_set_enabled(const GActionEntry *entries, unsigned n_entries, bool value) {
// Assumes null-terminated if n_entries == -1
@ -1196,13 +1167,11 @@ static void startup(GApplication *app, gpointer null_ptr) {
action_set_enabled(app, "open_gtk_debugger", false);
#endif
gui_data.preferences = GTK_WINDOW(get_object("preferences"));
g_signal_connect(gui_data.preferences, "realize", G_CALLBACK(on_preferences_realize), (gpointer) gui_data.builder);
init_config(app, gui_data.cli_options.config_path, &gui_data.config_modification_date, gui_data.preferences);
init_config(app, gui_data.cli_options.config_path, &gui_data.config_modification_date);
gui_data.screen = gb_screen_new(gui_data.cli_options.force_software_renderer);
gui_data.vram_viewer = vram_viewer_new();
gui_data.preferences = preferences_window_new(&gb);
gui_data.vram_viewer = vram_viewer_window_new();
gui_data.memory_viewer = GTK_WINDOW(get_object("memory_viewer"));
gui_data.console = GTK_WINDOW(get_object("console"));
@ -1227,8 +1196,6 @@ static void startup(GApplication *app, gpointer null_ptr) {
setup_menu(app);
// Insert separators into `GtkComboBox`es
set_combo_box_row_separator_func(GTK_CONTAINER(gui_data.preferences));
set_combo_box_row_separator_func(GTK_CONTAINER(gui_data.vram_viewer));
set_combo_box_row_separator_func(GTK_CONTAINER(gui_data.memory_viewer));
// Define a set of window icons
@ -1314,6 +1281,25 @@ bool on_change_model(GtkWidget *widget, gpointer user_data) {
return result != GTK_RESPONSE_YES;
}
void on_preferences_notify_border(PreferencesWindow *pref, const gchar *name) {
gui_data.border_mode_changed = true;
}
void on_preferences_notify_shader(PreferencesWindow *pref, const gchar *name) {
gb_screen_set_shader(gui_data.screen, name);
}
void on_preferences_notify_sample_rate(PreferencesWindow *pref, const guint *sample_rate) {
if (*sample_rate == -1) {
gui_data.sample_rate = GB_audio_default_sample_rate();
}
else {
gui_data.sample_rate = *sample_rate;
}
init_audio();
}
static void connect_signal_handlers(GApplication *app) {
// Connect signal handlers
gtk_widget_add_events(GTK_WIDGET(gui_data.main_window), GDK_KEY_PRESS_MASK);
@ -1330,6 +1316,10 @@ static void connect_signal_handlers(GApplication *app) {
g_signal_connect(gui_data.memory_viewer, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
g_signal_connect(gui_data.console, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
g_signal_connect(gui_data.printer, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
g_signal_connect(gui_data.preferences, "pref-update::video-display-border-mode", G_CALLBACK(on_preferences_notify_border), NULL);
g_signal_connect(gui_data.preferences, "pref-update::video-shader", G_CALLBACK(on_preferences_notify_shader), NULL);
g_signal_connect(gui_data.preferences, "pref-update::audio-sample-rate", G_CALLBACK(on_preferences_notify_sample_rate), NULL);
}
static void setup_console(void) {
@ -1491,7 +1481,7 @@ static void activate_close(GSimpleAction *action, GVariant *parameter, gpointer
// app.preferences GAction
// Opens the preferences window
static void activate_preferences(GSimpleAction *action, GVariant *parameter, gpointer app) {
gtk_widget_show_all(GTK_WIDGET(get_object("preferences")));
gtk_widget_show_all(GTK_WIDGET(gui_data.preferences));
}
// app.quit GAction
@ -1553,117 +1543,6 @@ G_MODULE_EXPORT void on_open_recent_activate(GtkRecentChooser *chooser, gpointer
}
}
G_MODULE_EXPORT void on_boot_rom_location_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
const gchar *id = gtk_combo_box_get_active_id(box);
if (id == NULL) return;
if (g_strcmp0(id, "other") == 0) {
GtkFileChooserNative *native = gtk_file_chooser_native_new("Select Folder", gui_data.preferences, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "_Select", "_Cancel");
gint res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native));
if (res == GTK_RESPONSE_ACCEPT) {
config.emulation.boot_rom_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(native));
update_boot_rom_selector(gui_data.builder);
}
g_object_unref(native);
}
else {
config.emulation.boot_rom_path = (gchar *)id;
}
}
G_MODULE_EXPORT void on_cgb_model_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.emulation.cgb_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
}
G_MODULE_EXPORT void on_color_correction_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.color_correction_id = (gchar *)gtk_combo_box_get_active_id(box);
if (GB_is_inited(&gb)) {
GB_set_color_correction_mode(&gb, config_get_color_correction_mode());
}
}
G_MODULE_EXPORT void on_frame_blending_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.frame_blending_mode = (gchar *)gtk_combo_box_get_active_id(box);
}
G_MODULE_EXPORT void on_display_border_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.display_border_mode = (gchar *)gtk_combo_box_get_active_id(box);
gui_data.border_mode_changed = true;
}
G_MODULE_EXPORT void on_monochrome_palette_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.monochrome_palette_id = (gchar *)gtk_combo_box_get_active_id(box);
GB_set_palette(&gb, config_get_monochrome_palette());
}
G_MODULE_EXPORT void on_dmg_model_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.emulation.dmg_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
}
G_MODULE_EXPORT void on_graphic_filter_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.shader = (gchar *)gtk_combo_box_get_active_id(box);
gb_screen_set_shader(gui_data.screen, config.video.shader);
}
G_MODULE_EXPORT void on_highpass_filter_changed(GtkWidget *w, gpointer user_data_ptr) {
config.audio.high_pass_filter_id = (gchar *)gtk_combo_box_get_active_id(GTK_COMBO_BOX(w));
if (GB_is_inited(&gb)) {
GB_set_highpass_filter_mode(&gb, config_get_highpass_mode());
}
}
G_MODULE_EXPORT void on_keep_aspect_ratio_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkCheckButton *button = GTK_CHECK_BUTTON(w);
gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
config.video.keep_aspect_ratio = value;
}
G_MODULE_EXPORT void on_rewind_duration_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.emulation.rewind_duration = g_ascii_strtoll(gtk_combo_box_get_active_id(box), NULL, 10);
GB_set_rewind_length(&gb, config.emulation.rewind_duration);
}
G_MODULE_EXPORT void on_sample_rate_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.audio.sample_rate = g_ascii_strtoll(gtk_combo_box_get_active_id(box), NULL, 10);
if (config.audio.sample_rate == -1) {
gui_data.sample_rate = GB_audio_default_sample_rate();
}
else {
gui_data.sample_rate = config.audio.sample_rate;
}
init_audio();
}
G_MODULE_EXPORT void on_sgb_model_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.emulation.sgb_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
}
G_MODULE_EXPORT void on_use_integer_scaling_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkCheckButton *button = GTK_CHECK_BUTTON(w);
gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
config.video.use_integer_scaling = value;
}
G_MODULE_EXPORT void console_on_enter(GtkWidget *w, gpointer user_data_ptr) {
GtkEntry *input = GTK_ENTRY(w);
const gchar *_text = gtk_entry_get_text(input);
@ -1693,19 +1572,6 @@ G_MODULE_EXPORT void console_on_enter(GtkWidget *w, gpointer user_data_ptr) {
gtk_entry_set_text(input, "");
}
G_MODULE_EXPORT void on_rumble_mode_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.controls.rumble_mode = (gchar *)gtk_combo_box_get_active_id(box);
GB_set_rumble_mode(&gb, config_get_rumble_mode());
}
G_MODULE_EXPORT void on_analog_speed_controls_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkCheckButton *button = GTK_CHECK_BUTTON(w);
gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
config.controls.analog_speed_controls = value;
}
int main(int argc, char *argv[]) {
gui_data.main_thread = g_thread_self();

325
gtk3/preferences_window.c Normal file
View File

@ -0,0 +1,325 @@
#include "preferences_window.h"
#include "config.h"
#include "util.h"
struct _PreferencesWindow {
GtkWindowClass parent_class;
GtkComboBoxText *boot_rom_selector;
GtkComboBoxText *rewind_duration_selector;
GtkComboBox *dmg_revision_selector;
GtkComboBoxText *sgb_revision_selector;
GtkComboBox *cgb_revision_selector;
GtkComboBoxText *shader_selector;
GtkComboBoxText *color_correction_selector;
GtkComboBoxText *frame_blending_selector;
GtkComboBoxText *monochrome_palette_selector;
GtkComboBoxText *display_border_selector;
GtkCheckButton *integer_scaling_toggle;
GtkCheckButton *aspect_ratio_toggle;
GtkComboBoxText *highpass_filter_selector;
GtkComboBoxText *sample_rate_selector;
GtkCheckButton *analog_speed_controls_toggle;
GtkComboBoxText *rumble_mode_selector;
GtkButton *configure_joypad_skip;
GB_gameboy_t *gb;
};
G_DEFINE_TYPE(PreferencesWindow, preferences_window, GTK_TYPE_WINDOW);
typedef enum {
PROP_GB_PTR = 1,
N_PROPERTIES
} PreferencesWindowProperty;
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
typedef enum {
PREF_UPDATE,
N_SIGNALS
} PreferencesWindowSignals;
static guint preferences_signals[N_SIGNALS] = { 0, };
static void preferences_window_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
PreferencesWindow *self = (PreferencesWindow *) object;
switch ((PreferencesWindowProperty) property_id) {
case PROP_GB_PTR: self->gb = g_value_get_pointer(value); break;
default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
}
static void preferences_window_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
PreferencesWindow *self = (PreferencesWindow *) object;
switch ((PreferencesWindowProperty) property_id) {
case PROP_GB_PTR: g_value_set_pointer(value, self->gb); break;
default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
}
static void preferences_window_init(PreferencesWindow *self) {
gtk_widget_init_template(GTK_WIDGET(self));
preferences_window_update_boot_rom_selector(self);
}
static void on_boot_rom_location_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
const gchar *id = gtk_combo_box_get_active_id(box);
if (id == NULL) return;
if (g_strcmp0(id, "other") == 0) {
GtkFileChooserNative *native = gtk_file_chooser_native_new("Select Folder", GTK_WINDOW(self), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "_Select", "_Cancel");
gint res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native));
if (res == GTK_RESPONSE_ACCEPT) {
config.emulation.boot_rom_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(native));
preferences_window_update_boot_rom_selector(self);
}
g_object_unref(native);
}
else {
config.emulation.boot_rom_path = (gchar *)id;
}
}
static void on_cgb_model_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.emulation.cgb_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
}
static void on_frame_blending_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.frame_blending_mode = (gchar *)gtk_combo_box_get_active_id(box);
}
static void on_dmg_model_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.emulation.dmg_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
}
static void on_keep_aspect_ratio_changed(GtkWidget *w, PreferencesWindow *self) {
GtkCheckButton *button = GTK_CHECK_BUTTON(w);
gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
config.video.keep_aspect_ratio = value;
}
static void on_sgb_model_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.emulation.sgb_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
}
static void on_use_integer_scaling_changed(GtkWidget *w, PreferencesWindow *self) {
GtkCheckButton *button = GTK_CHECK_BUTTON(w);
gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
config.video.use_integer_scaling = value;
}
static void on_analog_speed_controls_changed(GtkWidget *w, PreferencesWindow *self) {
GtkCheckButton *button = GTK_CHECK_BUTTON(w);
gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
config.controls.analog_speed_controls = value;
}
static void on_color_correction_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.color_correction_id = (gchar *)gtk_combo_box_get_active_id(box);
if (self->gb) {
GB_set_color_correction_mode(self->gb, config_get_color_correction_mode());
}
}
static void on_monochrome_palette_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.monochrome_palette_id = (gchar *)gtk_combo_box_get_active_id(box);
if (self->gb) {
GB_set_palette(self->gb, config_get_monochrome_palette());
}
}
static void on_highpass_filter_changed(GtkWidget *w, PreferencesWindow *self) {
config.audio.high_pass_filter_id = (gchar *)gtk_combo_box_get_active_id(GTK_COMBO_BOX(w));
if (self->gb) {
GB_set_highpass_filter_mode(self->gb, config_get_highpass_mode());
}
}
static void on_rewind_duration_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.emulation.rewind_duration = g_ascii_strtoll(gtk_combo_box_get_active_id(box), NULL, 10);
if (self->gb) {
GB_set_rewind_length(self->gb, config.emulation.rewind_duration);
}
}
static void on_rumble_mode_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.controls.rumble_mode = (gchar *)gtk_combo_box_get_active_id(box);
if (self->gb) {
GB_set_rumble_mode(self->gb, config_get_rumble_mode());
}
}
static void on_display_border_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.display_border_mode = (gchar *)gtk_combo_box_get_active_id(box);
g_signal_emit(
self,
preferences_signals[PREF_UPDATE],
g_quark_from_static_string("video-display-border-mode"),
config.video.display_border_mode
);
}
static void on_graphic_filter_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.video.shader = (gchar *)gtk_combo_box_get_active_id(box);
g_signal_emit(
self,
preferences_signals[PREF_UPDATE],
g_quark_from_static_string("video-shader"),
config.video.shader
);
}
static void on_sample_rate_changed(GtkWidget *w, PreferencesWindow *self) {
GtkComboBox *box = GTK_COMBO_BOX(w);
config.audio.sample_rate = g_ascii_strtoll(gtk_combo_box_get_active_id(box), NULL, 10);
g_signal_emit(
self,
preferences_signals[PREF_UPDATE],
g_quark_from_static_string("audio-sample-rate"),
&config.audio.sample_rate
);
}
static void preferences_window_realize(GtkWidget *widget) {
PreferencesWindow *self = (PreferencesWindow *)widget;
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->rewind_duration_selector), g_strdup_printf("%i", config.emulation.rewind_duration));
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->dmg_revision_selector), config.emulation.dmg_revision_name);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->sgb_revision_selector), config.emulation.sgb_revision_name);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->cgb_revision_selector), config.emulation.cgb_revision_name);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->shader_selector), config.video.shader);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->color_correction_selector), config.video.color_correction_id);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->frame_blending_selector), config.video.frame_blending_mode);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->display_border_selector), config.video.display_border_mode);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->monochrome_palette_selector), config.video.monochrome_palette_id);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->integer_scaling_toggle), config.video.use_integer_scaling);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->aspect_ratio_toggle), config.video.keep_aspect_ratio);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->highpass_filter_selector), config.audio.high_pass_filter_id);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->sample_rate_selector), g_strdup_printf("%i", config.audio.sample_rate));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->analog_speed_controls_toggle), config.controls.analog_speed_controls);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->rumble_mode_selector), config.controls.rumble_mode);
set_combo_box_row_separator_func(GTK_CONTAINER(self));
GTK_WIDGET_CLASS(preferences_window_parent_class)->realize(widget);
}
static void preferences_window_class_init(PreferencesWindowClass *class) {
gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(class), RESOURCE_PREFIX "ui/preferences_window.ui");
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, boot_rom_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, rewind_duration_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, dmg_revision_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, sgb_revision_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, cgb_revision_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, shader_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, color_correction_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, frame_blending_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, monochrome_palette_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, display_border_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, integer_scaling_toggle);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, aspect_ratio_toggle);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, highpass_filter_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, sample_rate_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, analog_speed_controls_toggle);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, rumble_mode_selector);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, configure_joypad_skip);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_boot_rom_location_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_rewind_duration_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_dmg_model_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_sgb_model_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_cgb_model_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_graphic_filter_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_color_correction_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_frame_blending_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_monochrome_palette_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_display_border_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_use_integer_scaling_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_keep_aspect_ratio_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_highpass_filter_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_sample_rate_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_analog_speed_controls_changed);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_rumble_mode_changed);
// gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), do_refresh_joypad_menu);
// gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_default_joypad_changed);
// gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), do_configure_joypad);
// gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), do_skip_configure_joypad);
GTK_WIDGET_CLASS(class)->realize = preferences_window_realize;
obj_properties[PROP_GB_PTR] = g_param_spec_pointer(
"gb", "SameBoy core pointer", "SameBoy Core pointer (GB_gameboy_t)",
G_PARAM_CONSTRUCT | G_PARAM_READWRITE
);
G_OBJECT_CLASS(class)->set_property = preferences_window_set_property;
G_OBJECT_CLASS(class)->get_property = preferences_window_get_property;
g_object_class_install_properties(G_OBJECT_CLASS(class), N_PROPERTIES, obj_properties);
preferences_signals[PREF_UPDATE] = g_signal_new(
"pref-update", // signal name
G_TYPE_FROM_CLASS(G_OBJECT_CLASS(class)), // itype
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED, // signal_flags
0, // class_offset
NULL, // accumulator
NULL, // accumulator_data
NULL, // c_marshaller,
G_TYPE_NONE, // return_type
1, // n_params,
G_TYPE_POINTER
);
}
PreferencesWindow *preferences_window_new(GB_gameboy_t *gb) {
return g_object_new(PREFERENCES_WINDOW_TYPE, "gb", gb, NULL);
}
void preferences_window_update_boot_rom_selector(PreferencesWindow *self) {
GtkComboBoxText *combo_box = self->boot_rom_selector;
gtk_combo_box_text_remove_all(combo_box);
gtk_combo_box_text_append(combo_box, "auto", "Use Built-in Boot ROMs");
if (config.emulation.boot_rom_path != NULL && !g_str_equal(config.emulation.boot_rom_path, "auto") && !g_str_equal(config.emulation.boot_rom_path, "other")) {
gtk_combo_box_text_append(combo_box, config.emulation.boot_rom_path, config.emulation.boot_rom_path);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo_box), config.emulation.boot_rom_path);
}
else {
gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo_box), "auto");
}
gtk_combo_box_text_append_text(combo_box, "<separator>");
gtk_combo_box_text_append(combo_box, "other", "Other");
}

13
gtk3/preferences_window.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef preferences_window_h
#define preferences_window_h
#include <gtk/gtk.h>
#include <Core/gb.h>
#define PREFERENCES_WINDOW_TYPE (preferences_window_get_type())
G_DECLARE_FINAL_TYPE(PreferencesWindow, preferences_window, SAMEBOY, PREFERENCES_WINDOW, GtkWindow)
PreferencesWindow *preferences_window_new(GB_gameboy_t *gb);
void preferences_window_update_boot_rom_selector(PreferencesWindow *self);
#endif

View File

@ -0,0 +1,979 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.36.0
The MIT License (MIT)
Copyright (c) 2015-2019 Lior Halphon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Author: Maximilian Mader
-->
<interface>
<requires lib="gtk+" version="3.22"/>
<!-- interface-license-type mit -->
<!-- interface-name SameBoy -->
<!-- interface-description SameBoy is an open source Game Boy (DMG) and Game Boy Color (CGB) emulator, written in portable C. -->
<!-- interface-copyright 2015-2019 Lior Halphon -->
<!-- interface-authors Maximilian Mader -->
<template class="PreferencesWindow">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Preferences</property>
<property name="resizable">False</property>
<child>
<object class="GtkNotebook">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">16</property>
<property name="margin_right">16</property>
<property name="margin_top">16</property>
<property name="margin_bottom">16</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Boot ROMs location:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="boot_rom_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<signal name="changed" handler="on_boot_rom_location_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Rewinding Duration:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="rewind_duration_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="10" translatable="yes">10 Seconds</item>
<item id="30" translatable="yes">30 Seconds</item>
<item id="60" translatable="yes">1 Minute</item>
<item id="120" translatable="yes">2 Minutes</item>
<item id="300" translatable="yes">5 Minutes</item>
<item id="600" translatable="yes">10 Minutes</item>
</items>
<signal name="changed" handler="on_rewind_duration_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Game Boy Revision:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="dmg_revision_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="model">dmg_models</property>
<property name="id_column">0</property>
<signal name="changed" handler="on_dmg_model_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="sensitive">2</attribute>
<attribute name="font">2</attribute>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Super Game Boy Model:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="sgb_revision_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="SGB1_NTSC" translatable="yes">Super Game Boy (NTSC)</item>
<item id="SGB1_PAL" translatable="yes">Super Game Boy (PAL)</item>
<item id="SGB2" translatable="yes">Super Game Boy 2</item>
</items>
<signal name="changed" handler="on_sgb_model_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Game Boy Color Revision:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">9</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="cgb_revision_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="model">cgb_models</property>
<property name="id_column">0</property>
<signal name="changed" handler="on_cgb_model_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="sensitive">2</attribute>
<attribute name="font">2</attribute>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">10</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="resource">/io/github/sameboy/pixmaps/CPU.png</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Emulation</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">16</property>
<property name="margin_right">16</property>
<property name="margin_top">16</property>
<property name="margin_bottom">16</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Graphics Filter:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="shader_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="NearestNeighbor" translatable="yes">Nearest Neighbor (Pixelated)</item>
<item id="Bilinear" translatable="yes">Bilinear (Blurry)</item>
<item id="SmoothBilinear" translatable="yes">Smooth Bilinear (Less blurry)</item>
<item id="MonoLCD" translatable="yes">Monochrome LCD Display</item>
<item id="LCD" translatable="yes">LCD Display</item>
<item id="CRT" translatable="yes">CRT Display</item>
<item id="Scale2x" translatable="yes">Scale2x</item>
<item id="Scale4x" translatable="yes">Scale4x</item>
<item id="AAScale2x" translatable="yes">Anti-aliased Scale2x</item>
<item id="AAScale4x" translatable="yes">Anti-aliased Scale4x</item>
<item id="HQ2x" translatable="yes">HQ2x</item>
<item id="OmniScale" translatable="yes">OmniScale (Any factor)</item>
<item id="OmniScaleLegacy" translatable="yes">OmniScale Legacy</item>
<item id="AAOmniScaleLegacy" translatable="yes">Anti-aliased OmniScale Legacy</item>
</items>
<signal name="changed" handler="on_graphic_filter_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Color Correction:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="color_correction_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="disabled" translatable="yes">Disabled</item>
<item id="correct_color_curves" translatable="yes">Correct Color Curves</item>
<item id="emulate_hardware" translatable="yes">Emulate Hardware</item>
<item id="preserve_brightness" translatable="yes">Preserve Brightness</item>
<item id="reduce_contrast" translatable="yes">Reduce contrast</item>
</items>
<signal name="changed" handler="on_color_correction_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Frame blending:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="frame_blending_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="disabled" translatable="yes">Disabled</item>
<item id="simple" translatable="yes">Simple</item>
<item id="accurate" translatable="yes">Accurate</item>
</items>
<signal name="changed" handler="on_frame_blending_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Color palette for monochrome models:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="monochrome_palette_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="greyscale" translatable="yes">Greyscale</item>
<item id="lime" translatable="yes">Lime (Game Boy)</item>
<item id="olive" translatable="yes">Olive (Pocket)</item>
<item id="teal" translatable="yes">Teal (Light)</item>
</items>
<signal name="changed" handler="on_monochrome_palette_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Display Border:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="display_border_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="never" translatable="yes">Never</item>
<item id="sgb_only" translatable="yes">Super Game Boy Only</item>
<item id="always" translatable="yes">Always</item>
</items>
<signal name="changed" handler="on_display_border_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">9</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="integer_scaling_toggle">
<property name="label" translatable="yes">Use Integer Scaling</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_use_integer_scaling_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">10</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="aspect_ratio_toggle">
<property name="label" translatable="yes">Keep Aspect Ratio</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_keep_aspect_ratio_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">11</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="resource">/io/github/sameboy/pixmaps/Display.png</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">14</property>
<property name="margin_right">16</property>
<property name="margin_top">16</property>
<property name="margin_bottom">16</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">High-pass Filter:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="highpass_filter_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="disabled" translatable="yes">Disabled (Keep DC Offset)</item>
<item id="emulate_hardware" translatable="yes">Accurate (Emulate Hardware)</item>
<item id="preserve_waveform" translatable="yes">Preserve Waveform</item>
</items>
<signal name="changed" handler="on_highpass_filter_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Sample Rate:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="sample_rate_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<items>
<item id="-1" translatable="yes">Default</item>
<item translatable="yes">&lt;separator&gt;</item>
<item id="44100" translatable="yes">44.1 kHz</item>
<item id="48000" translatable="yes">48 kHz</item>
<item id="96000" translatable="yes">96 kHz</item>
</items>
<signal name="changed" handler="on_sample_rate_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child type="tab">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="resource">/io/github/sameboy/pixmaps/Speaker.png</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">2</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">16</property>
<property name="margin_right">16</property>
<property name="margin_top">16</property>
<property name="margin_bottom">16</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">10</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Control settings for</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="active">0</property>
<property name="active_id">0</property>
<items>
<item id="0" translatable="yes">Player 1</item>
<item id="1" translatable="yes">Player 2</item>
<item id="2" translatable="yes">Player 3</item>
<item id="3" translatable="yes">Player 4</item>
</items>
<signal name="changed" handler="do_refresh_joypad_menu" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="margin_top">90</property>
<property name="margin_bottom">90</property>
<property name="active">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Joypad for multiplayer games:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="active">0</property>
<items>
<item id="none" translatable="yes">None</item>
</items>
<signal name="changed" handler="on_default_joypad_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="analog_speed_controls_toggle">
<property name="label" translatable="yes">Analog turbo and slow-motion controls</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_analog_speed_controls_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">8</property>
<property name="label" translatable="yes">Enable Rumble:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="rumble_mode_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="active">0</property>
<items>
<item id="never" translatable="yes">Never</item>
<item id="rumble_cartridges" translatable="yes">For rumble-enabled cartridges</item>
<item id="always" translatable="yes">Always</item>
</items>
<signal name="changed" handler="on_rumble_mode_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Configure Joypad</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="activate" handler="do_configure_joypad" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="configure_joypad_skip">
<property name="label" translatable="yes">Skip</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="activate" handler="do_skip_configure_joypad" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
<child type="tab">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="resource">/io/github/sameboy/pixmaps/Joypad.png</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Controls</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">3</property>
<property name="tab_fill">False</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</template>
<object class="GtkListStore" id="dmg_models">
<columns>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name value -->
<column type="gchararray"/>
<!-- column-name enabled -->
<column type="gboolean"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">DMG_CPU_0</col>
<col id="1" translatable="yes">DMG-CPU 0</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">DMG_CPU_A</col>
<col id="1" translatable="yes">DMG-CPU A</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">DMG_CPU_B</col>
<col id="1" translatable="yes">DMG-CPU B</col>
<col id="2">True</col>
</row>
<row>
<col id="0" translatable="yes">DMG_CPU_C</col>
<col id="1" translatable="yes">DMG-CPU C</col>
<col id="2">False</col>
</row>
</data>
</object>
<object class="GtkListStore" id="cgb_models">
<columns>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name value -->
<column type="gchararray"/>
<!-- column-name enabled -->
<column type="gboolean"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">CPU_CGB_0</col>
<col id="1" translatable="yes">CPU-CGB 0</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_A</col>
<col id="1" translatable="yes">CPU-CGB A</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_B</col>
<col id="1" translatable="yes">CPU-CGB B</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_C</col>
<col id="1" translatable="yes">CPU-CGB C (Experimental)</col>
<col id="2">True</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_D</col>
<col id="1" translatable="yes">CPU-CGB D</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_E</col>
<col id="1" translatable="yes">CPU-CGB E</col>
<col id="2">True</col>
</row>
</data>
</object>
</interface>

View File

@ -71,48 +71,7 @@ Maximilian Mader https://github.com/max-m</property>
<placeholder/>
</child>
</object>
<object class="GtkListStore" id="cgb_models">
<columns>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name value -->
<column type="gchararray"/>
<!-- column-name enabled -->
<column type="gboolean"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">CPU_CGB_0</col>
<col id="1" translatable="yes">CPU-CGB 0</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_A</col>
<col id="1" translatable="yes">CPU-CGB A</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_B</col>
<col id="1" translatable="yes">CPU-CGB B</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_C</col>
<col id="1" translatable="yes">CPU-CGB C (Experimental)</col>
<col id="2">True</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_D</col>
<col id="1" translatable="yes">CPU-CGB D</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">CPU_CGB_E</col>
<col id="1" translatable="yes">CPU-CGB E</col>
<col id="2">True</col>
</row>
</data>
</object>
<object class="GtkWindow" id="console">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Debug Console</property>
@ -279,933 +238,7 @@ Maximilian Mader https://github.com/max-m</property>
<class name="debug-console"/>
</style>
</object>
<object class="GtkListStore" id="dmg_models">
<columns>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name value -->
<column type="gchararray"/>
<!-- column-name enabled -->
<column type="gboolean"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">DMG_CPU_0</col>
<col id="1" translatable="yes">DMG-CPU 0</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">DMG_CPU_A</col>
<col id="1" translatable="yes">DMG-CPU A</col>
<col id="2">False</col>
</row>
<row>
<col id="0" translatable="yes">DMG_CPU_B</col>
<col id="1" translatable="yes">DMG-CPU B</col>
<col id="2">True</col>
</row>
<row>
<col id="0" translatable="yes">DMG_CPU_C</col>
<col id="1" translatable="yes">DMG-CPU C</col>
<col id="2">False</col>
</row>
</data>
</object>
<object class="GtkWindow" id="preferences">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Preferences</property>
<property name="resizable">False</property>
<child>
<object class="GtkNotebook">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">16</property>
<property name="margin_right">16</property>
<property name="margin_top">16</property>
<property name="margin_bottom">16</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Boot ROMs location:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="boot_rom_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<signal name="changed" handler="on_boot_rom_location_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Rewinding Duration:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="rewind_duration_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="10" translatable="yes">10 Seconds</item>
<item id="30" translatable="yes">30 Seconds</item>
<item id="60" translatable="yes">1 Minute</item>
<item id="120" translatable="yes">2 Minutes</item>
<item id="300" translatable="yes">5 Minutes</item>
<item id="600" translatable="yes">10 Minutes</item>
</items>
<signal name="changed" handler="on_rewind_duration_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Game Boy Revision:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="dmg_revision_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="model">dmg_models</property>
<property name="id_column">0</property>
<signal name="changed" handler="on_dmg_model_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="sensitive">2</attribute>
<attribute name="font">2</attribute>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Super Game Boy Model:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="sgb_revision_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="SGB1_NTSC" translatable="yes">Super Game Boy (NTSC)</item>
<item id="SGB1_PAL" translatable="yes">Super Game Boy (PAL)</item>
<item id="SGB2" translatable="yes">Super Game Boy 2</item>
</items>
<signal name="changed" handler="on_sgb_model_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Game Boy Color Revision:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">9</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="cgb_revision_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="model">cgb_models</property>
<property name="id_column">0</property>
<signal name="changed" handler="on_cgb_model_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="sensitive">2</attribute>
<attribute name="font">2</attribute>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">10</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="resource">/io/github/sameboy/pixmaps/CPU.png</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Emulation</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">16</property>
<property name="margin_right">16</property>
<property name="margin_top">16</property>
<property name="margin_bottom">16</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Graphics Filter:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="shader_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="NearestNeighbor" translatable="yes">Nearest Neighbor (Pixelated)</item>
<item id="Bilinear" translatable="yes">Bilinear (Blurry)</item>
<item id="SmoothBilinear" translatable="yes">Smooth Bilinear (Less blurry)</item>
<item id="MonoLCD" translatable="yes">Monochrome LCD Display</item>
<item id="LCD" translatable="yes">LCD Display</item>
<item id="CRT" translatable="yes">CRT Display</item>
<item id="Scale2x" translatable="yes">Scale2x</item>
<item id="Scale4x" translatable="yes">Scale4x</item>
<item id="AAScale2x" translatable="yes">Anti-aliased Scale2x</item>
<item id="AAScale4x" translatable="yes">Anti-aliased Scale4x</item>
<item id="HQ2x" translatable="yes">HQ2x</item>
<item id="OmniScale" translatable="yes">OmniScale (Any factor)</item>
<item id="OmniScaleLegacy" translatable="yes">OmniScale Legacy</item>
<item id="AAOmniScaleLegacy" translatable="yes">Anti-aliased OmniScale Legacy</item>
</items>
<signal name="changed" handler="on_graphic_filter_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Color Correction:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="color_correction_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="disabled" translatable="yes">Disabled</item>
<item id="correct_color_curves" translatable="yes">Correct Color Curves</item>
<item id="emulate_hardware" translatable="yes">Emulate Hardware</item>
<item id="preserve_brightness" translatable="yes">Preserve Brightness</item>
<item id="reduce_contrast" translatable="yes">Reduce contrast</item>
</items>
<signal name="changed" handler="on_color_correction_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Frame blending:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="frame_blending_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="disabled" translatable="yes">Disabled</item>
<item id="simple" translatable="yes">Simple</item>
<item id="accurate" translatable="yes">Accurate</item>
</items>
<signal name="changed" handler="on_frame_blending_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Color palette for monochrome models:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="monochrome_palette_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="greyscale" translatable="yes">Greyscale</item>
<item id="lime" translatable="yes">Lime (Game Boy)</item>
<item id="olive" translatable="yes">Olive (Pocket)</item>
<item id="teal" translatable="yes">Teal (Light)</item>
</items>
<signal name="changed" handler="on_monochrome_palette_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Display Border:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="display_border_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="never" translatable="yes">Never</item>
<item id="sgb_only" translatable="yes">Super Game Boy Only</item>
<item id="always" translatable="yes">Always</item>
</items>
<signal name="changed" handler="on_display_border_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">9</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="integer_scaling_toggle">
<property name="label" translatable="yes">Use Integer Scaling</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_use_integer_scaling_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">10</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="aspect_ratio_toggle">
<property name="label" translatable="yes">Keep Aspect Ratio</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_keep_aspect_ratio_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">11</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="menubar_override_selector_label">
<property name="can_focus">False</property>
<property name="label" translatable="yes">Main Menu Override</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">12</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="menubar_override_selector">
<property name="can_focus">False</property>
<items>
<item id="auto" translatable="yes">Automatic</item>
<item id="show_in_shell" translatable="yes">Force Menubar In Desktop Shell</item>
<item id="show_in_window" translatable="yes">Force Menubar In Window</item>
<item id="show_hamburger" translatable="yes">Force Hamburger Menu</item>
</items>
<signal name="changed" handler="on_color_menubar_override_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">13</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="resource">/io/github/sameboy/pixmaps/Display.png</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">14</property>
<property name="margin_right">16</property>
<property name="margin_top">16</property>
<property name="margin_bottom">16</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">High-pass Filter:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="highpass_filter_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<items>
<item id="disabled" translatable="yes">Disabled (Keep DC Offset)</item>
<item id="emulate_hardware" translatable="yes">Accurate (Emulate Hardware)</item>
<item id="preserve_waveform" translatable="yes">Preserve Waveform</item>
</items>
<signal name="changed" handler="on_highpass_filter_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Sample Rate:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="sample_rate_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<items>
<item id="-1" translatable="yes">Default</item>
<item translatable="yes">&lt;separator&gt;</item>
<item id="44100" translatable="yes">44.1 kHz</item>
<item id="48000" translatable="yes">48 kHz</item>
<item id="96000" translatable="yes">96 kHz</item>
</items>
<signal name="changed" handler="on_sample_rate_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child type="tab">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="resource">/io/github/sameboy/pixmaps/Speaker.png</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">2</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">16</property>
<property name="margin_right">16</property>
<property name="margin_top">16</property>
<property name="margin_bottom">16</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">10</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Control settings for</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="active">0</property>
<property name="active_id">0</property>
<items>
<item id="0" translatable="yes">Player 1</item>
<item id="1" translatable="yes">Player 2</item>
<item id="2" translatable="yes">Player 3</item>
<item id="3" translatable="yes">Player 4</item>
</items>
<signal name="changed" handler="do_refresh_joypad_menu" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="margin_top">90</property>
<property name="margin_bottom">90</property>
<property name="active">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Joypad for multiplayer games:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="active">0</property>
<items>
<item id="none" translatable="yes">None</item>
</items>
<signal name="changed" handler="on_default_joypad_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="analog_speed_controls_toggle">
<property name="label" translatable="yes">Analog turbo and slow-motion controls</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_analog_speed_controls_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">8</property>
<property name="label" translatable="yes">Enable Rumble:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="rumble_mode_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="active">0</property>
<items>
<item id="never" translatable="yes">Never</item>
<item id="rumble_cartridges" translatable="yes">For rumble-enabled cartridges</item>
<item id="always" translatable="yes">Always</item>
</items>
<signal name="changed" handler="on_rumble_mode_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Configure Joypad</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="activate" handler="do_configure_joypad" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="configure_joypad_skip">
<property name="label" translatable="yes">Skip</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="activate" handler="do_skip_configure_joypad" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
<child type="tab">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="resource">/io/github/sameboy/pixmaps/Joypad.png</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Controls</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">3</property>
<property name="tab_fill">False</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
<object class="GtkWindow" id="memory_viewer">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Memory Viewer</property>
@ -1321,7 +354,6 @@ Maximilian Mader https://github.com/max-m</property>
<mime-types>
<mime-type>application/x-gameboy-rom</mime-type>
<mime-type>application/x-gameboy-color-rom</mime-type>
<mime-type>application/octet-stream</mime-type>
</mime-types>
<patterns>
<pattern>*.gb</pattern>

View File

@ -2,6 +2,7 @@
<gresources>
<gresource prefix="/io/github/sameboy">
<file preprocess="xml-stripblanks" compressed="true">ui/window.ui</file>
<file preprocess="xml-stripblanks" compressed="true">ui/preferences_window.ui</file>
<file preprocess="xml-stripblanks" compressed="true">ui/vram_viewer_window.ui</file>
<!--
<file preprocess="xml-stripblanks">gtk/menus.ui</file>

View File

@ -3,6 +3,7 @@
#include "SDL.h"
#include "gb_screen.h"
#include "preferences_window.h"
#include "vram_viewer_window.h"
typedef struct{
@ -40,9 +41,9 @@ typedef struct GuiData {
GtkBox *main_window_container;
GbScreen *screen;
GtkWindow *preferences;
PreferencesWindow *preferences;
VramViewerWindow *vram_viewer;
GtkWindow *memory_viewer;
GtkWindow *console;
GtkWindow *printer;

View File

@ -112,3 +112,33 @@ GtkWidget *menubar_to_menu(GtkMenuBar *menubar) {
return menu;
}
// Determines if a ComboBox entry should be converted into a separator.
// Each element with a text value of `<separator>` will be converted into a separator element.
gboolean is_separator(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) {
gchar *text = NULL;
gtk_tree_model_get(model, iter, 0, &text, -1);
gboolean result = g_strcmp0("<separator>", text) == 0;
g_free(text);
return result;
}
// Recursively goes through all children of the given container and sets
// our `is_separator` function to all children of type`GtkComboBox`
void set_combo_box_row_separator_func(GtkContainer *container) {
GList *children = gtk_container_get_children(container);
for (GList *l = children; l; l = l->next) {
if (GTK_IS_COMBO_BOX(l->data)) {
gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(l->data), is_separator, NULL, NULL);
}
if (GTK_IS_CONTAINER(l->data)) {
set_combo_box_row_separator_func(GTK_CONTAINER(l->data));
}
}
g_list_free(children);
}

View File

@ -22,4 +22,7 @@ GB_model_t config_get_model_type(GuiData *gui_data);
GtkWidget *menubar_to_menu(GtkMenuBar *menubar);
gboolean is_separator(GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
void set_combo_box_row_separator_func(GtkContainer *container);
#endif

View File

@ -45,7 +45,7 @@ struct _VramViewerWindow {
G_DEFINE_TYPE(VramViewerWindow, vram_viewer_window, GTK_TYPE_WINDOW);
static void visible_tab_changed(GObject *stack, GParamSpec *pspec, VramViewerWindow *window) {
if (gtk_widget_in_destruction (GTK_WIDGET (stack))) return;
if (gtk_widget_in_destruction(GTK_WIDGET (stack))) return;
gtk_label_set_text(window->status, "");
}
@ -208,7 +208,7 @@ static gboolean tilemap_canvas_motion(GtkWidget *widget, GdkEventMotion *event,
int x, y;
if (event->is_hint) {
gdk_window_get_pointer (event->window, &x, &y, NULL);
gdk_window_get_pointer(event->window, &x, &y, NULL);
}
else {
x = event->x;
@ -309,6 +309,8 @@ static void vram_viewer_window_init(VramViewerWindow *window) {
gtk_widget_add_events(GTK_WIDGET(window->tileset_canvas), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
gtk_widget_add_events(GTK_WIDGET(window->tilemap_canvas), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
set_combo_box_row_separator_func(GTK_CONTAINER(window));
}
static void vram_viewer_finalize(GObject *object) {
@ -351,8 +353,8 @@ static void vram_viewer_window_class_init(VramViewerWindowClass *class) {
G_OBJECT_CLASS(class)->finalize = vram_viewer_finalize;
}
VramViewerWindow *vram_viewer_new(void) {
return g_object_new (VRAM_VIEWER_WINDOW_TYPE, NULL);
VramViewerWindow *vram_viewer_window_new(void) {
return g_object_new(VRAM_VIEWER_WINDOW_TYPE, NULL);
}
const gchar *vram_viewer_active_tab_name(VramViewerWindow *window) {

View File

@ -6,14 +6,14 @@
#include <stdint.h>
#define VRAM_VIEWER_WINDOW_TYPE (vram_viewer_window_get_type())
G_DECLARE_FINAL_TYPE(VramViewerWindow, vram_viewer_window, SAMEBOY, WINDOW, GtkWindow)
G_DECLARE_FINAL_TYPE(VramViewerWindow, vram_viewer_window, SAMEBOY, VRAM_VIEWER_WINDOW, GtkWindow)
#define VRAM_VIEWER_TAB_TILESET "tileset"
#define VRAM_VIEWER_TAB_TILEMAP "tilemap"
#define VRAM_VIEWER_TAB_SPRITES "sprites"
#define VRAM_VIEWER_TAB_PALETTES "palettes"
VramViewerWindow *vram_viewer_new(void);
VramViewerWindow *vram_viewer_window_new(void);
const gchar *vram_viewer_active_tab_name(VramViewerWindow *window);