diff --git a/gtk3/config.c b/gtk3/config.c index 112e060..016221c 100644 --- a/gtk3/config.c +++ b/gtk3/config.c @@ -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(); diff --git a/gtk3/config.h b/gtk3/config.h index 4b37f27..c7c158b 100644 --- a/gtk3/config.h +++ b/gtk3/config.h @@ -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); diff --git a/gtk3/gb_screen.c b/gtk3/gb_screen.c index 37aef51..4512eb1 100644 --- a/gtk3/gb_screen.c +++ b/gtk3/gb_screen.c @@ -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); } } @@ -365,4 +365,4 @@ void gb_screen_queue_render(GbScreen *self) { } gtk_widget_queue_draw(GTK_WIDGET(self)); -} \ No newline at end of file +} diff --git a/gtk3/gb_screen.h b/gtk3/gb_screen.h index fc0f1d3..22c7c98 100644 --- a/gtk3/gb_screen.h +++ b/gtk3/gb_screen.h @@ -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); diff --git a/gtk3/main.c b/gtk3/main.c index 2d68f2c..011d211 100644 --- a/gtk3/main.c +++ b/gtk3/main.c @@ -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 `` 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("", 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(); diff --git a/gtk3/preferences_window.c b/gtk3/preferences_window.c new file mode 100644 index 0000000..72c2725 --- /dev/null +++ b/gtk3/preferences_window.c @@ -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, ""); + gtk_combo_box_text_append(combo_box, "other", "Other"); +} diff --git a/gtk3/preferences_window.h b/gtk3/preferences_window.h new file mode 100644 index 0000000..bec34e6 --- /dev/null +++ b/gtk3/preferences_window.h @@ -0,0 +1,13 @@ +#ifndef preferences_window_h +#define preferences_window_h + +#include +#include + +#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 \ No newline at end of file diff --git a/gtk3/resources/ui/preferences_window.ui b/gtk3/resources/ui/preferences_window.ui new file mode 100644 index 0000000..9c44bff --- /dev/null +++ b/gtk3/resources/ui/preferences_window.ui @@ -0,0 +1,979 @@ + + + + + + + + + + + + + + + + + + + + + + + DMG_CPU_0 + DMG-CPU 0 + False + + + DMG_CPU_A + DMG-CPU A + False + + + DMG_CPU_B + DMG-CPU B + True + + + DMG_CPU_C + DMG-CPU C + False + + + + + + + + + + + + + + + + CPU_CGB_0 + CPU-CGB 0 + False + + + CPU_CGB_A + CPU-CGB A + False + + + CPU_CGB_B + CPU-CGB B + False + + + CPU_CGB_C + CPU-CGB C (Experimental) + True + + + CPU_CGB_D + CPU-CGB D + False + + + CPU_CGB_E + CPU-CGB E + True + + + + diff --git a/gtk3/resources/ui/window.ui b/gtk3/resources/ui/window.ui index 6ff6464..96852d0 100644 --- a/gtk3/resources/ui/window.ui +++ b/gtk3/resources/ui/window.ui @@ -71,48 +71,7 @@ Maximilian Mader https://github.com/max-m - - - - - - - - - - - - CPU_CGB_0 - CPU-CGB 0 - False - - - CPU_CGB_A - CPU-CGB A - False - - - CPU_CGB_B - CPU-CGB B - False - - - CPU_CGB_C - CPU-CGB C (Experimental) - True - - - CPU_CGB_D - CPU-CGB D - False - - - CPU_CGB_E - CPU-CGB E - True - - - + False Debug Console @@ -279,933 +238,7 @@ Maximilian Mader https://github.com/max-m - - - - - - - - - - - - DMG_CPU_0 - DMG-CPU 0 - False - - - DMG_CPU_A - DMG-CPU A - False - - - DMG_CPU_B - DMG-CPU B - True - - - DMG_CPU_C - DMG-CPU C - False - - - - - False - Preferences - False - - - True - True - - - True - False - 16 - 16 - 16 - 16 - vertical - - - True - False - Boot ROMs location: - - - False - True - 0 - - - - - True - False - 5 - 10 - - - - False - True - 1 - - - - - True - False - Rewinding Duration: - - - False - True - 2 - - - - - True - False - 5 - 10 - - 10 Seconds - 30 Seconds - 1 Minute - 2 Minutes - 5 Minutes - 10 Minutes - - - - - False - True - 3 - - - - - True - False - 5 - - - False - True - 4 - - - - - True - False - Game Boy Revision: - - - False - True - 5 - - - - - True - False - 5 - 10 - dmg_models - 0 - - - - - 2 - 2 - 1 - - - - - False - True - 6 - - - - - True - False - Super Game Boy Model: - - - False - True - 7 - - - - - True - False - 5 - 10 - - Super Game Boy (NTSC) - Super Game Boy (PAL) - Super Game Boy 2 - - - - - False - True - 8 - - - - - True - False - Game Boy Color Revision: - - - False - True - 9 - - - - - True - False - 5 - 10 - cgb_models - 0 - - - - - 2 - 2 - 1 - - - - - False - True - 10 - - - - - - - True - False - vertical - - - True - False - 2 - /io/github/sameboy/pixmaps/CPU.png - 3 - - - False - True - 0 - - - - - True - False - Emulation - - - False - True - 1 - - - - - False - - - - - True - False - 16 - 16 - 16 - 16 - vertical - - - True - False - Graphics Filter: - - - False - True - 0 - - - - - True - False - 5 - 10 - - Nearest Neighbor (Pixelated) - Bilinear (Blurry) - Smooth Bilinear (Less blurry) - Monochrome LCD Display - LCD Display - CRT Display - Scale2x - Scale4x - Anti-aliased Scale2x - Anti-aliased Scale4x - HQ2x - OmniScale (Any factor) - OmniScale Legacy - Anti-aliased OmniScale Legacy - - - - - False - True - 1 - - - - - True - False - Color Correction: - - - False - True - 2 - - - - - True - False - 5 - 10 - - Disabled - Correct Color Curves - Emulate Hardware - Preserve Brightness - Reduce contrast - - - - - False - True - 3 - - - - - True - False - Frame blending: - - - False - True - 4 - - - - - True - False - 5 - 10 - - Disabled - Simple - Accurate - - - - - False - True - 5 - - - - - True - False - Color palette for monochrome models: - - - False - True - 6 - - - - - True - False - 5 - 10 - - Greyscale - Lime (Game Boy) - Olive (Pocket) - Teal (Light) - - - - - False - True - 7 - - - - - True - False - Display Border: - - - False - True - 8 - - - - - True - False - 5 - 10 - - Never - Super Game Boy Only - Always - - - - - False - True - 9 - - - - - Use Integer Scaling - True - True - False - start - 5 - 10 - True - - - - False - True - 10 - - - - - Keep Aspect Ratio - True - True - False - start - 5 - 10 - True - - - - False - True - 11 - - - - - False - Main Menu Override - - - False - True - 12 - - - - - False - - Automatic - Force Menubar In Desktop Shell - Force Menubar In Window - Force Hamburger Menu - - - - - False - True - 13 - - - - - 1 - - - - - True - False - vertical - - - True - False - 2 - /io/github/sameboy/pixmaps/Display.png - 3 - - - False - True - 0 - - - - - True - False - Video - - - False - True - 1 - - - - - 1 - False - - - - - True - False - 14 - 16 - 16 - 16 - vertical - - - True - False - High-pass Filter: - - - False - True - 0 - - - - - True - False - 5 - 10 - - Disabled (Keep DC Offset) - Accurate (Emulate Hardware) - Preserve Waveform - - - - - False - True - 1 - - - - - True - False - Sample Rate: - - - False - True - 2 - - - - - True - False - - Default - <separator> - 44.1 kHz - 48 kHz - 96 kHz - - - - - False - True - 3 - - - - - 2 - - - - - True - False - vertical - - - True - False - 2 - /io/github/sameboy/pixmaps/Speaker.png - 3 - - - False - True - 0 - - - - - True - False - Audio - - - False - True - 1 - - - - - 2 - False - - - - - True - False - 16 - 16 - 16 - 16 - vertical - - - True - False - 10 - - - True - False - Control settings for - - - False - True - 0 - - - - - True - False - False - 5 - 5 - 0 - 0 - - Player 1 - Player 2 - Player 3 - Player 4 - - - - - False - True - 1 - - - - - True - False - : - - - False - True - 2 - - - - - False - True - 0 - - - - - True - False - False - 90 - 90 - True - - - False - True - 1 - - - - - True - False - Joypad for multiplayer games: - - - False - True - 2 - - - - - True - False - 5 - 10 - 0 - - None - - - - - False - True - 3 - - - - - True - False - 5 - - - False - True - 4 - - - - - Analog turbo and slow-motion controls - True - True - False - start - 5 - 10 - True - - - - False - False - 5 - - - - - True - False - 8 - Enable Rumble: - - - False - True - 6 - - - - - True - False - 5 - 10 - 0 - - Never - For rumble-enabled cartridges - Always - - - - - False - True - 7 - - - - - True - False - 5 - 10 - - - Configure Joypad - True - False - True - True - - - - False - True - 0 - - - - - Skip - True - False - True - True - - - - False - True - end - 1 - - - - - False - True - 8 - - - - - 3 - - - - - True - False - vertical - - - True - False - 2 - /io/github/sameboy/pixmaps/Joypad.png - 3 - - - False - True - 0 - - - - - True - False - Controls - - - False - True - 1 - - - - - 3 - False - - - - - - - - + False Memory Viewer @@ -1321,7 +354,6 @@ Maximilian Mader https://github.com/max-m application/x-gameboy-rom application/x-gameboy-color-rom - application/octet-stream *.gb diff --git a/gtk3/sameboy.gresource.xml b/gtk3/sameboy.gresource.xml index 840a49d..79256fe 100644 --- a/gtk3/sameboy.gresource.xml +++ b/gtk3/sameboy.gresource.xml @@ -2,6 +2,7 @@ ui/window.ui + ui/preferences_window.ui ui/vram_viewer_window.ui