[GTK3] Use an abstraction over GtkCheckMenuItem instead of GtkRadioMenuItem
This commit is contained in:
parent
1d7034fb88
commit
45e62a2f26
79
gtk3/check_menu_radio_group.c
Normal file
79
gtk3/check_menu_radio_group.c
Normal file
@ -0,0 +1,79 @@
|
||||
#include "check_menu_radio_group.h"
|
||||
|
||||
void check_menu_item_group_handler(GtkCheckMenuItem *item, CheckMenuItemGroupHandlerData *data) {
|
||||
bool cancel = false;
|
||||
|
||||
if (data->handler) {
|
||||
cancel = data->handler(GTK_WIDGET(item), (gpointer) data->arg);
|
||||
}
|
||||
|
||||
GValue value = G_VALUE_INIT;
|
||||
g_value_init(&value, G_TYPE_BOOLEAN);
|
||||
|
||||
if (cancel) {
|
||||
g_value_set_boolean(&value, false);
|
||||
g_object_set_property(G_OBJECT(item), "active", &value);
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < data->group->count; i++) {
|
||||
GtkCheckMenuItem *cur = GTK_CHECK_MENU_ITEM(data->group->items[i]);
|
||||
g_value_set_boolean(&value, cur == item);
|
||||
g_object_set_property(G_OBJECT(cur), "active", &value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CheckMenuItemGroup *check_menu_item_group_new(char **names, char **args) {
|
||||
unsigned name_count = 0;
|
||||
|
||||
if (names != NULL) {
|
||||
for (char **ptr = names; *ptr != NULL; ptr++, name_count++);
|
||||
}
|
||||
|
||||
CheckMenuItemGroup *group = g_malloc0(sizeof(CheckMenuItemGroup));
|
||||
group->count = name_count;
|
||||
group->items = g_malloc0(sizeof(GtkWidget*) * name_count);
|
||||
group->handlers = g_malloc0(sizeof(CheckMenuItemGroupHandlerData*) * name_count);
|
||||
|
||||
for (unsigned i = 0; i < name_count; i++) {
|
||||
group->items[i] = gtk_check_menu_item_new_with_label(names[i]);
|
||||
|
||||
group->handlers[i] = g_malloc0(sizeof(CheckMenuItemGroupHandlerData));
|
||||
group->handlers[i]->group = group;
|
||||
group->handlers[i]->arg = args[i];
|
||||
g_signal_connect(group->items[i], "toggled", G_CALLBACK(check_menu_item_group_handler), group->handlers[i]);
|
||||
|
||||
gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(group->items[i]), true);
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
void check_menu_item_group_activate(CheckMenuItemGroup *group, char *arg) {
|
||||
GValue value = G_VALUE_INIT;
|
||||
g_value_init(&value, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean(&value, false);
|
||||
|
||||
for (unsigned i = 0; i < group->count; i++) {
|
||||
GtkCheckMenuItem *cur = GTK_CHECK_MENU_ITEM(group->items[i]);
|
||||
|
||||
if (g_strcmp0(arg, group->handlers[i]->arg) == 0) {
|
||||
gtk_check_menu_item_set_active(cur, true);
|
||||
}
|
||||
else {
|
||||
g_object_set_property(G_OBJECT(cur), "active", &value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_menu_item_group_connect_toggle_signal(CheckMenuItemGroup *group, bool (*handler)(GtkWidget *, gpointer)) {
|
||||
for (unsigned i = 0; i < group->count; i++) {
|
||||
group->handlers[i]->handler = handler;
|
||||
}
|
||||
}
|
||||
|
||||
void check_menu_item_group_insert_into_menu_shell(CheckMenuItemGroup *group, GtkMenuShell *menu_shell, gint position) {
|
||||
for (unsigned i = 0; i < group->count; i++) {
|
||||
gtk_menu_shell_insert(menu_shell, group->items[i], position + i);
|
||||
}
|
||||
}
|
24
gtk3/check_menu_radio_group.h
Normal file
24
gtk3/check_menu_radio_group.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef check_menu_radio_group_h
|
||||
#define check_menu_radio_group_h
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
typedef struct CheckMenuItemGroupHandlerData {
|
||||
struct CheckMenuItemGroup *group;
|
||||
char *arg;
|
||||
bool (*handler)(GtkWidget *, void *);
|
||||
} CheckMenuItemGroupHandlerData;
|
||||
|
||||
typedef struct CheckMenuItemGroup {
|
||||
unsigned count;
|
||||
GtkWidget **items;
|
||||
CheckMenuItemGroupHandlerData **handlers;
|
||||
} CheckMenuItemGroup;
|
||||
|
||||
CheckMenuItemGroup *check_menu_item_group_new(char **names, char **args);
|
||||
void check_menu_item_group_activate(CheckMenuItemGroup *group, char *arg);
|
||||
void check_menu_item_group_connect_toggle_signal(CheckMenuItemGroup *group, bool (*handler)(GtkWidget *, gpointer));
|
||||
void check_menu_item_group_insert_into_menu_shell(CheckMenuItemGroup *group, GtkMenuShell *menu_shell, gint position);
|
||||
|
||||
#endif
|
69
gtk3/main.c
69
gtk3/main.c
@ -11,6 +11,7 @@
|
||||
|
||||
#include "settings.h"
|
||||
#include "shader.h"
|
||||
#include "check_menu_radio_group.h"
|
||||
|
||||
// used for audio and game controllers
|
||||
#include "SDL.h"
|
||||
@ -822,20 +823,22 @@ GtkWidget *menubar_to_menu(GtkMenuBar *menubar) {
|
||||
// environments and the manual call of `g_signal_connect` was needed anyway
|
||||
// because the UI definition can’t define string arguments for signal handlers.
|
||||
static void create_model_menu_items() {
|
||||
void on_change_model(GtkCheckMenuItem *check_menu_item, const gchar *model_str);
|
||||
bool on_change_model(GtkWidget *, gpointer);
|
||||
|
||||
static const char *const model_names[] = {
|
||||
"Game Boy",
|
||||
"Super Game Boy",
|
||||
"Game Boy Color",
|
||||
"Game Boy Advance"
|
||||
"Game Boy Advance",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const model_codes[] = {
|
||||
"DMG",
|
||||
"SGB",
|
||||
"CGB",
|
||||
"GBA"
|
||||
"GBA",
|
||||
NULL
|
||||
};
|
||||
|
||||
// Find the menu item index of the previous sibling of the new menu items
|
||||
@ -844,48 +847,27 @@ static void create_model_menu_items() {
|
||||
g_autoptr(GList) list = gtk_container_get_children(parent);
|
||||
gint position = g_list_index(list, before);
|
||||
|
||||
GSList *group = NULL;
|
||||
for (int i = 0; i < sizeof(model_names) / sizeof(const char*); i++) {
|
||||
// Create a new menu item
|
||||
GtkWidget *item = gtk_radio_menu_item_new_with_label(group, model_names[i]);
|
||||
|
||||
// Add it to the existing menu
|
||||
gtk_menu_shell_insert(GTK_MENU_SHELL(parent), item, ++position);
|
||||
g_signal_connect(item, "toggled", G_CALLBACK(on_change_model), (gpointer) model_codes[i]);
|
||||
|
||||
if (g_strcmp0(config.emulation.model, model_codes[i]) == 0) {
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), true);
|
||||
}
|
||||
|
||||
if (i == 0) group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
|
||||
}
|
||||
CheckMenuItemGroup *model_group = check_menu_item_group_new((char **) model_names, (char **) model_codes);
|
||||
check_menu_item_group_insert_into_menu_shell(model_group, GTK_MENU_SHELL(parent), position + 1);
|
||||
check_menu_item_group_connect_toggle_signal(model_group, on_change_model);
|
||||
check_menu_item_group_activate(model_group, config.emulation.model);
|
||||
|
||||
static const char *const peripheral_names[] = {
|
||||
"None",
|
||||
"Game Boy Printer",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const peripheral_codes[] = {
|
||||
"NONE",
|
||||
"PRINTER",
|
||||
NULL,
|
||||
};
|
||||
|
||||
GtkMenuShell *link_menu = builder_get(GTK_MENU_SHELL, "link_menu");
|
||||
group = NULL;
|
||||
position = 0;
|
||||
for (int i = 0; i < sizeof(peripheral_names) / sizeof(const char*); i++) {
|
||||
// Create a new menu item
|
||||
GtkWidget *item = gtk_radio_menu_item_new_with_label(group, peripheral_names[i]);
|
||||
|
||||
// Add it to the existing menu
|
||||
gtk_menu_shell_insert(link_menu, item, position++);
|
||||
// g_signal_connect(item, "toggled", G_CALLBACK(on_change_linked_device, (gpointer) peripheral_codes[i]);
|
||||
|
||||
if (i == 0) {
|
||||
group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), true);
|
||||
}
|
||||
}
|
||||
CheckMenuItemGroup *link_group = check_menu_item_group_new((char **) peripheral_names, (char **) peripheral_codes);
|
||||
check_menu_item_group_insert_into_menu_shell(link_group, GTK_MENU_SHELL(builder_get(GTK_MENU_SHELL, "link_menu")), 0);
|
||||
// check_menu_item_group_connect_toggle_signal(link_group, on_change_linked_device);
|
||||
check_menu_item_group_activate(link_group, "NONE");
|
||||
}
|
||||
|
||||
// Create our application’s menu.
|
||||
@ -2100,9 +2082,18 @@ G_MODULE_EXPORT void on_quit_activate(GtkWidget *w, gpointer user_data_ptr) {
|
||||
quit();
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void on_change_model(GtkCheckMenuItem *check_menu_item, const gchar *model_str) {
|
||||
if (!GB_is_inited(&gb) || !gtk_check_menu_item_get_active(check_menu_item)) {
|
||||
return;
|
||||
bool on_change_model(GtkWidget *widget, gpointer user_data) {
|
||||
GtkCheckMenuItem *check_menu_item = GTK_CHECK_MENU_ITEM(widget);
|
||||
gchar *model_str = (gchar *) user_data;
|
||||
|
||||
if (!gtk_check_menu_item_get_active(check_menu_item)) {
|
||||
return true;
|
||||
}
|
||||
else if (!GB_is_inited(&gb)) {
|
||||
gui_data.cli_options.model = -1;
|
||||
config.emulation.model = g_strdup(model_str);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(
|
||||
@ -2121,8 +2112,6 @@ G_MODULE_EXPORT void on_change_model(GtkCheckMenuItem *check_menu_item, const gc
|
||||
// Reset the CLI model override
|
||||
gui_data.cli_options.model = -1;
|
||||
|
||||
// g_simple_action_set_state(action, value);
|
||||
|
||||
g_free(config.emulation.model);
|
||||
config.emulation.model = g_strdup(model_str);
|
||||
|
||||
@ -2135,6 +2124,8 @@ G_MODULE_EXPORT void on_change_model(GtkCheckMenuItem *check_menu_item, const gc
|
||||
|
||||
run();
|
||||
gtk_widget_destroy(GTK_WIDGET(dialog));
|
||||
|
||||
return result != GTK_RESPONSE_YES;
|
||||
}
|
||||
|
||||
static void connect_signal_handlers(GApplication *app) {
|
||||
|
Loading…
Reference in New Issue
Block a user