[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 "settings.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
#include "check_menu_radio_group.h"
|
||||||
|
|
||||||
// used for audio and game controllers
|
// used for audio and game controllers
|
||||||
#include "SDL.h"
|
#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
|
// environments and the manual call of `g_signal_connect` was needed anyway
|
||||||
// because the UI definition can’t define string arguments for signal handlers.
|
// because the UI definition can’t define string arguments for signal handlers.
|
||||||
static void create_model_menu_items() {
|
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[] = {
|
static const char *const model_names[] = {
|
||||||
"Game Boy",
|
"Game Boy",
|
||||||
"Super Game Boy",
|
"Super Game Boy",
|
||||||
"Game Boy Color",
|
"Game Boy Color",
|
||||||
"Game Boy Advance"
|
"Game Boy Advance",
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const model_codes[] = {
|
static const char *const model_codes[] = {
|
||||||
"DMG",
|
"DMG",
|
||||||
"SGB",
|
"SGB",
|
||||||
"CGB",
|
"CGB",
|
||||||
"GBA"
|
"GBA",
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find the menu item index of the previous sibling of the new menu items
|
// 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);
|
g_autoptr(GList) list = gtk_container_get_children(parent);
|
||||||
gint position = g_list_index(list, before);
|
gint position = g_list_index(list, before);
|
||||||
|
|
||||||
GSList *group = NULL;
|
CheckMenuItemGroup *model_group = check_menu_item_group_new((char **) model_names, (char **) model_codes);
|
||||||
for (int i = 0; i < sizeof(model_names) / sizeof(const char*); i++) {
|
check_menu_item_group_insert_into_menu_shell(model_group, GTK_MENU_SHELL(parent), position + 1);
|
||||||
// Create a new menu item
|
check_menu_item_group_connect_toggle_signal(model_group, on_change_model);
|
||||||
GtkWidget *item = gtk_radio_menu_item_new_with_label(group, model_names[i]);
|
check_menu_item_group_activate(model_group, config.emulation.model);
|
||||||
|
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *const peripheral_names[] = {
|
static const char *const peripheral_names[] = {
|
||||||
"None",
|
"None",
|
||||||
"Game Boy Printer",
|
"Game Boy Printer",
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const peripheral_codes[] = {
|
static const char *const peripheral_codes[] = {
|
||||||
"NONE",
|
"NONE",
|
||||||
"PRINTER",
|
"PRINTER",
|
||||||
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
GtkMenuShell *link_menu = builder_get(GTK_MENU_SHELL, "link_menu");
|
CheckMenuItemGroup *link_group = check_menu_item_group_new((char **) peripheral_names, (char **) peripheral_codes);
|
||||||
group = NULL;
|
check_menu_item_group_insert_into_menu_shell(link_group, GTK_MENU_SHELL(builder_get(GTK_MENU_SHELL, "link_menu")), 0);
|
||||||
position = 0;
|
// check_menu_item_group_connect_toggle_signal(link_group, on_change_linked_device);
|
||||||
for (int i = 0; i < sizeof(peripheral_names) / sizeof(const char*); i++) {
|
check_menu_item_group_activate(link_group, "NONE");
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create our application’s menu.
|
// Create our application’s menu.
|
||||||
@ -2100,9 +2082,18 @@ G_MODULE_EXPORT void on_quit_activate(GtkWidget *w, gpointer user_data_ptr) {
|
|||||||
quit();
|
quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
G_MODULE_EXPORT void on_change_model(GtkCheckMenuItem *check_menu_item, const gchar *model_str) {
|
bool on_change_model(GtkWidget *widget, gpointer user_data) {
|
||||||
if (!GB_is_inited(&gb) || !gtk_check_menu_item_get_active(check_menu_item)) {
|
GtkCheckMenuItem *check_menu_item = GTK_CHECK_MENU_ITEM(widget);
|
||||||
return;
|
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(
|
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
|
// Reset the CLI model override
|
||||||
gui_data.cli_options.model = -1;
|
gui_data.cli_options.model = -1;
|
||||||
|
|
||||||
// g_simple_action_set_state(action, value);
|
|
||||||
|
|
||||||
g_free(config.emulation.model);
|
g_free(config.emulation.model);
|
||||||
config.emulation.model = g_strdup(model_str);
|
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();
|
run();
|
||||||
gtk_widget_destroy(GTK_WIDGET(dialog));
|
gtk_widget_destroy(GTK_WIDGET(dialog));
|
||||||
|
|
||||||
|
return result != GTK_RESPONSE_YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void connect_signal_handlers(GApplication *app) {
|
static void connect_signal_handlers(GApplication *app) {
|
||||||
|
Loading…
Reference in New Issue
Block a user