diff --git a/gui/action.c b/gui/action.c index df199c81..86cceb45 100644 --- a/gui/action.c +++ b/gui/action.c @@ -29,6 +29,8 @@ #include "gtk_builder.h" #include "jack.h" #include "zoom.h" +#include "menu.h" +#include "studio.h" GtkAction * g_clear_xruns_and_max_dsp_action; GtkAction * g_zoom_100_action; @@ -36,6 +38,44 @@ GtkAction * g_zoom_fit_action; GtkAction * g_zoom_in_action; GtkAction * g_zoom_out_action; +static +gboolean +load_project_accelerator_activated( + GtkAccelGroup * accel_group, + GObject * acceleratable, + guint keyval, + GdkModifierType modifier) +{ + graph_view_handle view; + + view = get_current_view(); + if (get_studio_state() == STUDIO_STATE_STARTED && view != NULL && is_room_view(view)) + { + menu_request_load_project(); + } + + return TRUE; +} + +static +gboolean +unload_project_accelerator_activated( + GtkAccelGroup * accel_group, + GObject * acceleratable, + guint keyval, + GdkModifierType modifier) +{ + graph_view_handle view; + + view = get_current_view(); + if (get_studio_state() == STUDIO_STATE_STARTED && view != NULL && is_room_view(view)) + { + menu_request_unload_project(); + } + + return TRUE; +} + void init_actions_and_accelerators(void) { static GtkActionGroup * action_group_ptr; @@ -91,6 +131,20 @@ void init_actions_and_accelerators(void) gtk_action_connect_accelerator(descriptor_ptr->action_ptr); } + gtk_accel_group_connect( + accel_group_ptr, + gdk_keyval_from_name("o"), + GDK_CONTROL_MASK, + GTK_ACCEL_VISIBLE, + g_cclosure_new((GCallback)load_project_accelerator_activated, NULL, NULL)); + + gtk_accel_group_connect( + accel_group_ptr, + gdk_keyval_from_name("u"), + GDK_CONTROL_MASK, + GTK_ACCEL_VISIBLE, + g_cclosure_new((GCallback)unload_project_accelerator_activated, NULL, NULL)); + gtk_window_add_accel_group(GTK_WINDOW(g_main_win), accel_group_ptr); } diff --git a/gui/dynmenu.c b/gui/dynmenu.c index 0ffb017d..3afacb4f 100644 --- a/gui/dynmenu.c +++ b/gui/dynmenu.c @@ -40,9 +40,10 @@ struct ladish_dynmenu void * context, const char * name, void * data, + ladish_dynmenu_item_activate_callback item_activate_callback, void (* data_free)()), void * context); - void (* item_activate_callback)(const char * name, void * data); + ladish_dynmenu_item_activate_callback item_activate_callback; bool add_sensitive; gulong activate_signal_id; char * description; @@ -53,7 +54,7 @@ struct ladish_dynmenu_item_data GtkWidget * item; void * data; void (* data_free)(); - void (* item_activate_callback)(const char * name, void * data); + ladish_dynmenu_item_activate_callback item_activate_callback; }; void on_activate_item(GtkMenuItem * item, struct ladish_dynmenu_item_data * data_ptr) @@ -89,7 +90,14 @@ void free_item_data(gpointer data, GClosure * closure) #undef data_ptr #define dynmenu_ptr ((struct ladish_dynmenu *)context) -static void ladish_dynmenu_add_entry(void * context, const char * name, void * data, void (* data_free)()) +static +void +ladish_dynmenu_add_entry( + void * context, + const char * name, + void * data, + ladish_dynmenu_item_activate_callback item_activate_callback, + void (* data_free)()) { struct ladish_dynmenu_item_data * data_ptr; @@ -97,20 +105,30 @@ static void ladish_dynmenu_add_entry(void * context, const char * name, void * d //log_info("data_ptr %p allocated", data_ptr); data_ptr->data = data; data_ptr->data_free = data_free; - data_ptr->item_activate_callback = dynmenu_ptr->item_activate_callback; + data_ptr->item_activate_callback = item_activate_callback != NULL ? item_activate_callback : dynmenu_ptr->item_activate_callback; + + if (name == NULL) + { + data_ptr->item = gtk_separator_menu_item_new(); /* separator */ + gtk_widget_show(data_ptr->item); + gtk_menu_shell_append(GTK_MENU_SHELL(dynmenu_ptr->menu), data_ptr->item); + } + else + { + data_ptr->item = gtk_menu_item_new_with_label(name); + //log_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count); // refcount == 2 because of the label + gtk_widget_set_sensitive(data_ptr->item, dynmenu_ptr->add_sensitive); + gtk_widget_show(data_ptr->item); + gtk_menu_shell_append(GTK_MENU_SHELL(dynmenu_ptr->menu), data_ptr->item); + g_signal_connect_data( + G_OBJECT(data_ptr->item), + "activate", + G_CALLBACK(on_activate_item), + data_ptr, + free_item_data, + (GConnectFlags)0); + } - data_ptr->item = gtk_menu_item_new_with_label(name); - //log_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count); // refcount == 2 because of the label - gtk_widget_set_sensitive(data_ptr->item, dynmenu_ptr->add_sensitive); - gtk_widget_show(data_ptr->item); - gtk_menu_shell_append(GTK_MENU_SHELL(dynmenu_ptr->menu), data_ptr->item); - g_signal_connect_data( - G_OBJECT(data_ptr->item), - "activate", - G_CALLBACK(on_activate_item), - data_ptr, - free_item_data, - (GConnectFlags)0); dynmenu_ptr->count++; } @@ -149,7 +167,7 @@ static void populate_dynmenu_menu(GtkMenuItem * menu_item, struct ladish_dynmenu if (!dynmenu_ptr->fill_callback(ladish_dynmenu_add_entry, dynmenu_ptr)) { menu_dynmenu_clear(dynmenu_ptr); - prefix = _("Error obtaining "); + prefix = _("Error filling "); } else if (dynmenu_ptr->count == 0) { @@ -163,7 +181,7 @@ static void populate_dynmenu_menu(GtkMenuItem * menu_item, struct ladish_dynmenu text = catdup(prefix, dynmenu_ptr->description); dynmenu_ptr->add_sensitive = false; - ladish_dynmenu_add_entry(dynmenu_ptr, text != NULL ? text : prefix, NULL, NULL); + ladish_dynmenu_add_entry(dynmenu_ptr, text != NULL ? text : prefix, NULL, NULL, NULL); free(text); /* free(NULL) is safe */ } @@ -179,10 +197,11 @@ ladish_dynmenu_create( void * context, const char * name, void * data, + ladish_dynmenu_item_activate_callback item_activate_callback, void (* data_free)()), void * context), const char * description, - void (* item_activate_callback)(const char * name, void * data), + ladish_dynmenu_item_activate_callback item_activate_callback, ladish_dynmenu_handle * dynmenu_handle_ptr) { struct ladish_dynmenu * dynmenu_ptr; @@ -216,6 +235,26 @@ ladish_dynmenu_create( #define dynmenu_ptr ((struct ladish_dynmenu *)dynmenu_handle) +void +ladish_dynmenu_fill_external( + ladish_dynmenu_handle dynmenu_handle, + GtkMenu * menu) +{ + GtkWidget * menu_backup; + int count_backup; + + menu_backup = dynmenu_ptr->menu; + count_backup = dynmenu_ptr->count; + + dynmenu_ptr->menu = GTK_WIDGET(menu); + dynmenu_ptr->add_sensitive = true; + + dynmenu_ptr->fill_callback(ladish_dynmenu_add_entry, dynmenu_ptr); + + dynmenu_ptr->menu = menu_backup; + dynmenu_ptr->count = count_backup; +} + void ladish_dynmenu_destroy( ladish_dynmenu_handle dynmenu_handle) diff --git a/gui/dynmenu.h b/gui/dynmenu.h index fba86f76..ec85a298 100644 --- a/gui/dynmenu.h +++ b/gui/dynmenu.h @@ -31,6 +31,8 @@ typedef struct ladish_dynmenu_tag { int unused; } * ladish_dynmenu_handle; +typedef void (* ladish_dynmenu_item_activate_callback)(const char * name, void * data); + bool ladish_dynmenu_create( const char * menu_item, @@ -42,12 +44,18 @@ ladish_dynmenu_create( void * context, const char * name, void * data, + ladish_dynmenu_item_activate_callback item_activate_callback, void (* data_free)()), void * context), const char * description, - void (* item_activate_callback)(const char * name, void * data), + ladish_dynmenu_item_activate_callback item_activate_callback, ladish_dynmenu_handle * dynmenu_handle_ptr); +void +ladish_dynmenu_fill_external( + ladish_dynmenu_handle dynmenu_handle, + GtkMenu * menu); + void ladish_dynmenu_destroy( ladish_dynmenu_handle dynmenu_handle); diff --git a/gui/gladish.ui b/gui/gladish.ui index 66c192b4..b3675aef 100644 --- a/gui/gladish.ui +++ b/gui/gladish.ui @@ -187,72 +187,6 @@ True - - - _Load Project... - image_load_project - False - False - True - True - - - - - - _Unload Project - image_unload_project - False - False - True - True - - - - - - _Rename Project... - image_rename_project - False - False - True - True - - - - - _Save Project - image_save_project - False - False - True - True - - - - - Save Project _As... - image_save_as_project - False - False - True - True - - - - - True - - - - - R_ecently Loaded - False - False - True - True - - diff --git a/gui/graph_view.c b/gui/graph_view.c index c0640d69..cf1c6af5 100644 --- a/gui/graph_view.c +++ b/gui/graph_view.c @@ -477,3 +477,8 @@ ladish_room_proxy_handle graph_view_get_room(graph_view_handle view) { return view_ptr->room; } + +bool room_has_project(graph_view_handle view) +{ + return view_ptr->project_name != NULL; +} diff --git a/gui/graph_view.h b/gui/graph_view.h index 3ba4b9aa..ddb51a14 100644 --- a/gui/graph_view.h +++ b/gui/graph_view.h @@ -54,6 +54,7 @@ graph_view_handle get_current_view(void); canvas_handle get_current_canvas(void); const char * get_current_view_room_name(void); bool is_room_view(graph_view_handle view); +bool room_has_project(graph_view_handle view); ladish_app_supervisor_proxy_handle graph_view_get_app_supervisor(graph_view_handle view); bool app_run_custom(graph_view_handle view, const char * command, const char * name, bool run_in_terminal, uint8_t level); diff --git a/gui/menu.c b/gui/menu.c index 59a652a6..7a3445f3 100644 --- a/gui/menu.c +++ b/gui/menu.c @@ -40,10 +40,7 @@ static GtkWidget * g_menu_item_unload_studio; static GtkWidget * g_menu_item_rename_studio; static GtkWidget * g_menu_item_create_room; static GtkWidget * g_menu_item_destroy_room; -static GtkWidget * g_menu_item_load_project; -static GtkWidget * g_menu_item_unload_project; -static GtkWidget * g_menu_item_save_project; -static GtkWidget * g_menu_item_save_as_project; +static GtkWidget * g_menu_item_project; static GtkWidget * g_menu_item_daemon_exit; static GtkWidget * g_menu_item_jack_configure; static GtkWidget * g_menu_item_settings; @@ -62,7 +59,7 @@ static GtkWidget * g_menu_item_start_app; static bool g_latency_changing; -static ladish_dynmenu_handle g_recent_projects_list; +static ladish_dynmenu_handle g_project_dynmenu; typedef void (* menu_request_toggle_func)(bool visible); @@ -88,26 +85,17 @@ static void buffer_size_change_request(GtkCheckMenuItem * item_ptr, gpointer use struct ladish_recent_projects_list_closure { - GtkMenu * menu; void (* callback)( void * context, const char * name, void * data, + void (* item_activate_callback)(const char * name, void * data), void (* data_free)()); void * context; }; -static void on_load_project_main_menu(const char * name, void * data) -{ - log_info("Request to load project \"%s\":\"%s\"", name, (const char *)data); - if (!ladish_room_proxy_load_project(graph_view_get_room(get_current_view()), data)) - { - error_message_box(_("Project load failed, please inspect logs.")); - } -} - -static void on_load_project_popup_menu(const char * name, void * data) +static void on_load_project(const char * name, void * data) { log_info("Request to load project \"%s\":\"%s\"", name, (const char *)data); if (!ladish_room_proxy_load_project(graph_view_get_room(get_current_view()), data)) @@ -125,46 +113,57 @@ add_recent_project( const char * project_name, const char * project_dir) { - GtkWidget * menuitem; - - if (closure_ptr->menu != NULL) - { - menuitem = gtk_menu_item_new_with_label(project_name); - g_signal_connect_data( - menuitem, - "activate", - (GCallback)on_load_project_popup_menu, - strdup(project_dir), - (GClosureNotify)free, - (GConnectFlags)0); - gtk_menu_shell_append(GTK_MENU_SHELL(closure_ptr->menu), menuitem); - } - else - { - closure_ptr->callback(closure_ptr->context, project_name, strdup(project_dir), NULL); - } + closure_ptr->callback(closure_ptr->context, project_name, strdup(project_dir), NULL, free); } -#undef closure_ptr - +static bool -get_recent_projects_list( +fill_project_dynmenu( void (* callback)( void * context, const char * name, void * data, + void (* item_activate_callback)(const char * name, void * data), void (* data_free)()), void * context) { struct ladish_recent_projects_list_closure closure; + bool has_project; + graph_view_handle view; - closure.menu = NULL; closure.callback = callback; closure.context = context; - return ladish_room_proxy_get_recent_projects(graph_view_get_room(get_current_view()), 10, add_recent_project, &closure); + view = get_current_view(); + + if (ladish_room_proxy_get_recent_projects(graph_view_get_room(view), 10, add_recent_project, &closure)) + { + callback(context, NULL, NULL, NULL, NULL); /* add separator */ + } + + callback(context, _("Load Project..."), NULL, (ladish_dynmenu_item_activate_callback)menu_request_load_project, NULL); + + has_project = room_has_project(view); + + if (!has_project) + { + callback(context, _("Create Project..."), NULL, (ladish_dynmenu_item_activate_callback)menu_request_save_as_project, NULL); + } + + callback(context, has_project ? _("Unload Project") : _("Clear Room"), NULL, (ladish_dynmenu_item_activate_callback)menu_request_unload_project, NULL); + + if (has_project) + { + callback(context, _("Save Project"), NULL, (ladish_dynmenu_item_activate_callback)menu_request_save_project, NULL); + callback(context, _("Save Project As..."), NULL, (ladish_dynmenu_item_activate_callback)menu_request_save_as_project, NULL); + callback(context, _("Project Properties..."), NULL, (ladish_dynmenu_item_activate_callback)ladish_project_properties_dialog_run, NULL); + } + + return true; } +#undef closure_ptr + bool menu_init(void) { g_menu_item_new_studio = get_gtk_builder_widget("menu_item_new_studio"); @@ -177,10 +176,7 @@ bool menu_init(void) g_menu_item_rename_studio = get_gtk_builder_widget("menu_item_rename_studio"); g_menu_item_create_room = get_gtk_builder_widget("menu_item_create_room"); g_menu_item_destroy_room = get_gtk_builder_widget("menu_item_destroy_room"); - g_menu_item_load_project = get_gtk_builder_widget("menu_item_load_project"); - g_menu_item_unload_project = get_gtk_builder_widget("menu_item_unload_project"); - g_menu_item_save_project = get_gtk_builder_widget("menu_item_save_project"); - g_menu_item_save_as_project = get_gtk_builder_widget("menu_item_save_as_project"); + g_menu_item_project = get_gtk_builder_widget("project_menu_item"); g_menu_item_daemon_exit = get_gtk_builder_widget("menu_item_daemon_exit"); g_menu_item_jack_configure = get_gtk_builder_widget("menu_item_jack_configure"); g_menu_item_settings = get_gtk_builder_widget("menu_item_settings"); @@ -213,10 +209,6 @@ bool menu_init(void) g_signal_connect(G_OBJECT(g_menu_item_start_app), "activate", G_CALLBACK(menu_request_start_app), NULL); g_signal_connect(G_OBJECT(g_menu_item_create_room), "activate", G_CALLBACK(menu_request_create_room), NULL); g_signal_connect(G_OBJECT(g_menu_item_destroy_room), "activate", G_CALLBACK(menu_request_destroy_room), NULL); - g_signal_connect(G_OBJECT(g_menu_item_load_project), "activate", G_CALLBACK(menu_request_load_project), NULL); - g_signal_connect(G_OBJECT(g_menu_item_unload_project), "activate", G_CALLBACK(menu_request_unload_project), NULL); - g_signal_connect(G_OBJECT(g_menu_item_save_project), "activate", G_CALLBACK(menu_request_save_project), NULL); - g_signal_connect(G_OBJECT(g_menu_item_save_as_project), "activate", G_CALLBACK(menu_request_save_as_project), NULL); g_signal_connect(G_OBJECT(g_menu_item_jack_latency_32), "toggled", G_CALLBACK(buffer_size_change_request), (gpointer)32); g_signal_connect(G_OBJECT(g_menu_item_jack_latency_64), "toggled", G_CALLBACK(buffer_size_change_request), (gpointer)64); @@ -229,12 +221,12 @@ bool menu_init(void) g_signal_connect(G_OBJECT(g_menu_item_jack_latency_8192), "toggled", G_CALLBACK(buffer_size_change_request), (gpointer)8192); if (!ladish_dynmenu_create( - "menu_item_recently_loaded_projects", - "recently_loaded_projects_menu", - get_recent_projects_list, - "recent projects list", - on_load_project_main_menu, - &g_recent_projects_list)) + "project_menu_item", + "project_menu", + fill_project_dynmenu, + "project menu", + on_load_project, + &g_project_dynmenu)) { return false; } @@ -244,11 +236,13 @@ bool menu_init(void) void menu_uninit(void) { - ladish_dynmenu_destroy(g_recent_projects_list); + ladish_dynmenu_destroy(g_project_dynmenu); } void menu_studio_state_changed(unsigned int studio_state) { + graph_view_handle view; + gtk_widget_set_sensitive(g_menu_item_start_studio, studio_state == STUDIO_STATE_STOPPED); gtk_widget_set_sensitive(g_menu_item_stop_studio, studio_state == STUDIO_STATE_STARTED); gtk_widget_set_sensitive(g_menu_item_save_studio, studio_state == STUDIO_STATE_STARTED); @@ -257,6 +251,9 @@ void menu_studio_state_changed(unsigned int studio_state) gtk_widget_set_sensitive(g_menu_item_rename_studio, studio_state == STUDIO_STATE_STOPPED || studio_state == STUDIO_STATE_STARTED); gtk_widget_set_sensitive(g_menu_item_start_app, studio_state == STUDIO_STATE_STOPPED || studio_state == STUDIO_STATE_STARTED); gtk_widget_set_sensitive(g_menu_item_create_room, studio_state == STUDIO_STATE_STOPPED || studio_state == STUDIO_STATE_STARTED); + + view = get_current_view(); + gtk_widget_set_sensitive(g_menu_item_project, studio_state == STUDIO_STATE_STARTED && view != NULL && is_room_view(view)); } void menu_set_jack_latency_items_sensivity(bool sensitive) @@ -329,11 +326,7 @@ void menu_set_toolbar_visibility(bool visible) void menu_view_activated(bool room) { gtk_widget_set_sensitive(g_menu_item_destroy_room, room); - gtk_widget_set_sensitive(g_menu_item_load_project, room); - gtk_widget_set_sensitive(g_menu_item_unload_project, room); - gtk_widget_set_sensitive(g_menu_item_save_project, room); - gtk_widget_set_sensitive(g_menu_item_save_as_project, room); - gtk_widget_set_sensitive(get_gtk_builder_widget("menu_item_recently_loaded_projects"), room); + gtk_widget_set_sensitive(g_menu_item_project, room && get_studio_state() == STUDIO_STATE_STARTED); } static void on_popup_menu_action_start_app(GtkWidget * menuitem, gpointer userdata) @@ -351,30 +344,9 @@ static void on_popup_menu_action_destroy_room(GtkWidget * menuitem, gpointer use menu_request_destroy_room(); } -static void on_popup_menu_action_load_project(GtkWidget * menuitem, gpointer userdata) -{ - menu_request_load_project(); -} - -static void on_popup_menu_action_unload_project(GtkWidget * menuitem, gpointer userdata) -{ - menu_request_unload_project(); -} - -static void on_popup_menu_action_save_project(GtkWidget * menuitem, gpointer userdata) -{ - menu_request_save_project(); -} - -static void on_popup_menu_action_save_project_as(GtkWidget * menuitem, gpointer userdata) -{ - menu_request_save_as_project(); -} - void fill_view_popup_menu(GtkMenu * menu, graph_view_handle view) { GtkWidget * menuitem; - struct ladish_recent_projects_list_closure closure; log_info("filling view menu..."); @@ -387,38 +359,10 @@ void fill_view_popup_menu(GtkMenu * menu, graph_view_handle view) if (is_room_view(view)) { - closure.menu = menu; - closure.callback = NULL; - closure.context = NULL; - menuitem = gtk_separator_menu_item_new(); /* separator */ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - if (ladish_room_proxy_get_recent_projects(graph_view_get_room(get_current_view()), 10, add_recent_project, &closure)) - { - menuitem = gtk_separator_menu_item_new(); /* separator */ - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - } - - menuitem = gtk_menu_item_new_with_label(_("Load Project...")); - g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_load_project, NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - - menuitem = gtk_menu_item_new_with_label(_("Unload Project")); - g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_unload_project, NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - - menuitem = gtk_menu_item_new_with_label(_("Save Project...")); - g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_save_project, NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - - menuitem = gtk_menu_item_new_with_label(_("Save Project As...")); - g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_save_project_as, NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - - menuitem = gtk_menu_item_new_with_label(_("Project Properties...")); - g_signal_connect(menuitem, "activate", (GCallback)ladish_project_properties_dialog_run, NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + ladish_dynmenu_fill_external(g_project_dynmenu, menu); menuitem = gtk_separator_menu_item_new(); /* separator */ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); diff --git a/gui/studio_list.c b/gui/studio_list.c index 952c7fb6..fd1e8d72 100644 --- a/gui/studio_list.c +++ b/gui/studio_list.c @@ -39,6 +39,7 @@ struct ladish_studio_list_closure void * context, const char * name, void * data, + ladish_dynmenu_item_activate_callback item_activate_callback, void (* data_free)()); void * context; }; @@ -51,7 +52,7 @@ add_item( void * context, const char * studio_name) { - closure_ptr->callback(closure_ptr->context, studio_name, NULL, NULL); + closure_ptr->callback(closure_ptr->context, studio_name, NULL, NULL, NULL); } #undef closure_ptr @@ -64,6 +65,7 @@ fill_callback( void * context, const char * name, void * data, + ladish_dynmenu_item_activate_callback item_activate_callback, void (* data_free)()), void * context) {