/* * SwamiUITreeMenu.c - Swami Tree right-click menu object * * Swami * Copyright (C) 1999-2003 Josh Green * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA or point your web browser to http://www.gnu.org. */ #include #include #include #include "SwamiUITreeMenu.h" #include "SwamiUIObject.h" #include "SwamiUITree.h" #include "item_paste.h" #include "i18n.h" /* to make entering functions in rmu_items array easier */ typedef void (*RMU_Func) (); /* menu item enumerations (keep in sync with rmu_items[] below) */ typedef enum { RMU_Spacer, /* A horizontal line menu spacer */ RMU_Paste, RMU_Delete, RMU_Close, RMU_Properties, RMU_Save, RMU_Save_As, RMU_Export_Samples, RMU_Unset_Gens, RMU_Copy_Gens, RMU_Paste_Gens, /* RMU_Dump, RMU_Find, RMU_Generate_Sample, */ RMU_Goto_Instrument, RMU_Goto_Sample, RMU_New_Preset, RMU_New_Instrument, RMU_Load_Samples, RMU_Global_Zone, RMU_Wtbl_Load, RMU_New_Mapping, RMU_END } RMUItemType; /* return values for RMU_ModFunc's */ enum { MODFUNC_NORMAL, MODFUNC_INSENSITIVE, MODFUNC_INVISIBLE }; /* RMU_ModFunc is called for each RMU_Item and allows for run time modification of menu items (sensitivity and visibility) */ typedef gint (*RMU_ModFunc) (RMUItemType type, IPItem *item); typedef struct { char flag; /* S = single, M = multi, R = right click multi */ char *label; /* menu label text */ char *accel; /* key accelerator */ RMU_ModFunc modfunc; /* menu item modify function */ RMU_Func func; /* function to call when item is activated */ gpointer func_data; /* data to pass to function */ } RMU_Item; /* callback wrapper functions */ static void swamiui_cb_paste (GList *item_list); static void swamiui_cb_wtbl_load_patch (GList *item_list); static void swamiui_cb_new_item (GList *item_list, gpointer data); static void swamiui_cb_goto_zone_refitem (GList *item_list); static void swamiui_cb_load_samples (GList *item_list); static void swamiui_cb_copy_gens (GList *item_list); static void swamiui_cb_paste_gens (GList *item_list); /* RMU_ModFunc definitions */ static gint rmumod_goto_zoneref (RMUItemType type, IPItem *item); /* Menu items (keep in sync with RMUItemType menu enumerations above) */ static RMU_Item rmu_items[] = { { 'R', N_("Paste"), NULL, NULL, swamiui_cb_paste, NULL }, { 'M', N_("Delete"), "D", NULL, swamiui_delete_items, NULL }, { 'M', N_("Close"), NULL, NULL, swamiui_close_files, NULL }, { 'M', N_("Properties"), "R", NULL, swamiui_item_properties, NULL }, { 'M', N_("Save"), NULL, NULL, swamiui_save_files, GINT_TO_POINTER (FALSE) }, { 'M', N_("Save As"), NULL, NULL, swamiui_save_files, GINT_TO_POINTER(TRUE)}, { 'M', N_("Export Samples"), NULL, NULL, swamiui_export_samples, NULL }, { 'M', N_("Unset Generators"), NULL, NULL, swamiui_unset_gens, NULL }, { 'S', N_("Copy Generators"), NULL, NULL, swamiui_cb_copy_gens, NULL }, { 'S', N_("Paste Generators"), NULL, NULL, swamiui_cb_paste_gens, NULL }, /* { 'S', N_("Dump"), NULL, NULL, NULL, NULL }, { 'S', N_("Find"), NULL, NULL, NULL, GINT_TO_POINTER (TRUE) }, { 'S', N_("Generate Sample"), NULL, NULL, NULL, NULL }, */ { 'S', N_("Goto Instrument"), NULL, rmumod_goto_zoneref, swamiui_cb_goto_zone_refitem, NULL }, { 'S', N_("Goto Sample"), NULL, rmumod_goto_zoneref, swamiui_cb_goto_zone_refitem, NULL }, { 'S', N_("New Preset"), NULL, NULL, swamiui_cb_new_item, GINT_TO_POINTER (IPITEM_PRESET) }, { 'S', N_("New Instrument"), NULL, NULL, swamiui_cb_new_item, GINT_TO_POINTER (IPITEM_INST) }, { 'S', N_("Load Samples"), NULL, NULL, swamiui_cb_load_samples, NULL }, { 'S', N_("Global Zone"), "G", NULL, swamiui_cb_new_item, GINT_TO_POINTER (IPITEM_ZONE) }, { 'S', N_("Wavetable Load"), "L", NULL, swamiui_cb_wtbl_load_patch, NULL }, { 'S', N_("New Mapping"), NULL, NULL, NULL, NULL } }; static RMUItemType rmu_sfont[] = { /* menu for sound font root nodes */ RMU_Properties, RMU_Save, RMU_Save_As, RMU_Close, RMU_Paste, // RMU_Find, // RMU_Dump, RMU_Wtbl_Load, RMU_Spacer, RMU_New_Preset, RMU_New_Instrument, RMU_Load_Samples, // RMU_Generate_Sample, RMU_END }; static RMUItemType rmu_presetroots[] = { /* menu for preset tree roots */ RMU_New_Preset, RMU_Paste, // RMU_Find, RMU_END }; static RMUItemType rmu_preset[] = { /* Menu for presets */ RMU_Properties, RMU_Global_Zone, RMU_Paste, RMU_Delete, RMU_Wtbl_Load, RMU_Spacer, RMU_New_Preset, // RMU_Find, RMU_END }; static RMUItemType rmu_pzone[] = { /* Menu for preset zones */ RMU_Goto_Instrument, RMU_Delete, RMU_Unset_Gens, RMU_Copy_Gens, RMU_Paste_Gens, RMU_END }; static RMUItemType rmu_instroot[] = { /* Menu for instrument root tree */ RMU_New_Instrument, RMU_Paste, // RMU_Find, RMU_END }; static RMUItemType rmu_inst[] = { /* Menu for instruments */ RMU_Properties, RMU_Global_Zone, RMU_Paste, RMU_Delete, RMU_Wtbl_Load, RMU_Spacer, RMU_New_Instrument, // RMU_Find, RMU_END }; static RMUItemType rmu_izone[] = { /* Menu for instrument zones */ RMU_Properties, RMU_Goto_Sample, RMU_Delete, RMU_Unset_Gens, RMU_Copy_Gens, RMU_Paste_Gens, RMU_END }; static RMUItemType rmu_sampleroot[] = { /* Menu for sample root tree */ RMU_Load_Samples, // RMU_Generate_Sample, RMU_Paste, // RMU_Find, RMU_END }; static RMUItemType rmu_sample[] = { /* Menu for samples */ RMU_Properties, RMU_Export_Samples, RMU_Delete, RMU_Wtbl_Load, RMU_Spacer, RMU_Load_Samples, // RMU_Generate_Sample, // RMU_Find, RMU_END }; static RMUItemType rmu_vbank[] = { RMU_Properties, RMU_Save, RMU_Save_As, RMU_Close, RMU_Wtbl_Load, RMU_END }; static RMUItemType rmu_vbank_defbank[] = { RMU_Properties, RMU_Paste, RMU_END }; static RMUItemType rmu_vbank_maproot[] = { RMU_New_Mapping, RMU_Paste, RMU_END }; static RMUItemType rmu_vbank_map[] = { RMU_Properties, RMU_Delete, RMU_Wtbl_Load, RMU_Spacer, RMU_Paste, RMU_END }; RMUItemType *rmu_menus[SWAMIUI_TREE_LAST + 1] = { NULL, /* IPITEM_NONE */ rmu_sfont, /* IPITEM_SFONT */ rmu_preset, /* IPITEM_PRESET */ rmu_inst, /* IPITEM_INST */ rmu_sample, /* IPITEM_SAMPLE */ NULL, /* IPITEM_SAMPLE_DATA */ NULL, /* IPITEM_ZONE (we determine type of zone) */ rmu_vbank, /* IPITEM_VBANK */ rmu_vbank_map, /* IPITEM_VBANK_MAP */ rmu_presetroots, /* SWAMIUI_TREE_PRESET_ROOT */ rmu_presetroots, /* SWAMIUI_TREE_PRESET_MELODIC */ rmu_presetroots, /* SWAMIUI_TREE_PRESET_PERCUSS */ rmu_instroot, /* SWAMIUI_TREE_INST_ROOT */ rmu_sampleroot, /* SWAMIUI_TREE_SAMPLE_ROOT */ rmu_sampleroot, /* SWAMIUI_TREE_SAMPLE_USER */ rmu_sampleroot, /* SWAMIUI_TREE_SAMPLE_ROM */ rmu_vbank_defbank, /* SWAMIUI_TREE_VBANK_DEFAULT */ rmu_vbank_maproot /* SWAMIUI_TREE_VBANK_MAP_ROOT */ }; static void swamiui_treemenu_class_init (SwamiUITreeMenuClass *klass); static void swamiui_treemenu_init (SwamiUITreeMenu *treemenu); static void swamiui_treemenu_activate (GtkMenuItem *mitem, SwamiUITreeMenu *treemenu); static void treemenu_cb_foreach_remove (GtkWidget *widg, gpointer data); static GtkWidget *treemenu_get_menu_item (SwamiUITreeMenu *treemenu, RMUItemType type); static gboolean treemenu_cb_selection_done (GtkMenuShell *menushell, SwamiUITreeMenu *treemenu); guint swamiui_treemenu_get_type (void) { static guint obj_type = 0; if (!obj_type) { GtkTypeInfo obj_info = { "SwamiUITreeMenu", sizeof (SwamiUITreeMenu), sizeof (SwamiUITreeMenuClass), (GtkClassInitFunc) swamiui_treemenu_class_init, (GtkObjectInitFunc) swamiui_treemenu_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; obj_type = gtk_type_unique (gtk_menu_get_type (), &obj_info); } return obj_type; } /* initialize treemenu class */ static void swamiui_treemenu_class_init (SwamiUITreeMenuClass *klass) { klass->active_treemenu = NULL; } /* initialize treemenu object */ static void swamiui_treemenu_init (SwamiUITreeMenu *treemenu) { GtkWidget *mitem; RMU_Item *ritem; guint key, mods; int i; gtk_signal_connect (GTK_OBJECT (treemenu), "selection-done", (GtkSignalFunc)treemenu_cb_selection_done, treemenu); /* create menu item array */ treemenu->mitem_array = g_array_new (FALSE, FALSE, sizeof (GtkWidget *)); g_array_set_size (treemenu->mitem_array, RMU_END - 1); /* create key accelerator group */ treemenu->accel_group = gtk_accel_group_new (); /* accel group is locked so virtual piano keys don't erronously get assigned to menu entries. FIXME - Can we block only keys with no modifiers? */ gtk_accel_group_lock (treemenu->accel_group); gtk_window_add_accel_group (GTK_WINDOW (swamiui_object->main_window), treemenu->accel_group); i = RMU_Spacer; while (++i < RMU_END) /* Loop over menu items */ { ritem = &rmu_items[i - 1]; /* create menu item */ mitem = gtk_menu_item_new_with_label (_(ritem->label)); g_array_index (treemenu->mitem_array, GtkWidget *, i - 1) = mitem; gtk_object_set_data (GTK_OBJECT (mitem), "ritem", ritem); /* connect menu item to callback function */ if (ritem->func) gtk_signal_connect (GTK_OBJECT (mitem), "activate", swamiui_treemenu_activate, treemenu); /* parse key accelerator and add it to menu item */ if (ritem->accel) { gtk_accelerator_parse (ritem->accel, &key, &mods); gtk_widget_add_accelerator (mitem, "activate", treemenu->accel_group, key, mods, GTK_ACCEL_VISIBLE); } } } /* callback when a menu item is activated */ static void swamiui_treemenu_activate (GtkMenuItem *mitem, SwamiUITreeMenu *treemenu) { SwamiUITreeMenuClass *klass; RMU_Item *ritem; GList *sel; IPItem *item; klass = gtk_type_class (swamiui_treemenu_get_type ()); ritem = gtk_object_get_data (GTK_OBJECT (mitem), "ritem"); klass->active_treemenu = treemenu; /* update active treemenu pointer */ if (ritem->flag == 'M') /* right click selection (rclick item 1st) */ { sel = swamiui_tree_get_selection (treemenu->tree); if (sel && ritem->func) (*ritem->func)(sel, ritem->func_data); swamiui_tree_free_selection (sel); } else if (ritem->flag == 'R') /* multi selection */ { sel = swamiui_tree_get_selection_rclick (treemenu->tree); if (sel && ritem->func) (*ritem->func)(sel, ritem->func_data); swamiui_tree_free_selection (sel); } else /* single selection */ { item = swamiui_tree_get_selection_single (treemenu->tree); if (item && ritem->func) { if (!swamiui_tree_item_is_dummy (item)) instp_item_ref (item); sel = NULL; sel = g_list_append (sel, item); (*ritem->func)(sel, ritem->func_data); g_list_free (sel); if (!swamiui_tree_item_is_dummy (item)) instp_item_unref (item); } } klass->active_treemenu = NULL; /* reset active treemenu pointer */ } /** * swamiui_treemenu_new: * @bind_tree: #SwamiUITree to bind menu to * * Create a new Swami tree menu object * * Returns: Swami tree menu object */ GtkWidget * swamiui_treemenu_new (SwamiUITree *bind_tree) { SwamiUITreeMenu *treemenu; g_return_val_if_fail (bind_tree != NULL, NULL); treemenu = gtk_type_new (swamiui_treemenu_get_type ()); treemenu->tree = bind_tree; return (GTK_WIDGET (treemenu)); } /** * swamiui_treemenu_popup: * @treemenu: Tree menu object * @button: Mouse button press value from GDKEvent * @time: Time value from GDKEvent * * Popup tree menu */ void swamiui_treemenu_popup (SwamiUITreeMenu *treemenu, guint button, guint32 time) { IPItem *rclick; RMUItemType *menu; GtkWidget *mitem; RMU_Item *ritem; IPItem *item; int i; rclick = swamiui_tree_get_rclick_item (treemenu->tree); /* sanity check */ if (!rclick || rclick->type <= IPITEM_NONE || rclick->type > SWAMIUI_TREE_LAST) return; if (rclick->type == IPITEM_ZONE) /* right click on a zone? */ { if (!rclick->parent) return; /* determine zone type (preset or instrument) */ if (rclick->parent->type == IPITEM_PRESET) menu = rmu_pzone; else menu = rmu_izone; } else if (!(menu = rmu_menus[rclick->type])) return; /* should not happen, just in case */ gtk_container_foreach (GTK_CONTAINER (treemenu), (GtkCallback)treemenu_cb_foreach_remove, treemenu); item = swamiui_tree_get_selection_single (treemenu->tree); if (item) /* Single selected item */ { i = 0; while (menu[i] != RMU_END) { mitem = treemenu_get_menu_item (treemenu, menu[i]); gtk_menu_append (GTK_MENU (treemenu), mitem); i++; } } else /* Multiple selected items */ { i = RMU_Spacer + 1; while (i < RMU_END) /* Loop over menu items */ { ritem = &rmu_items[i - 1]; /* use type 'M'ulti or 'R'ight click items */ if (ritem->flag == 'M' || ritem->flag == 'R') { mitem = treemenu_get_menu_item (treemenu, i); gtk_menu_append (GTK_MENU (treemenu), mitem); } i++; } } gtk_widget_show (GTK_WIDGET (treemenu)); gtk_menu_popup (GTK_MENU (treemenu), NULL, NULL, NULL, NULL, button, time); } static void treemenu_cb_foreach_remove (GtkWidget *widg, gpointer data) { gtk_container_remove (GTK_CONTAINER (data), widg); } static GtkWidget * treemenu_get_menu_item (SwamiUITreeMenu *treemenu, RMUItemType type) { GtkWidget *mitem; gboolean sensitive = TRUE; gboolean show = TRUE; if (type == RMU_Spacer) { mitem = gtk_menu_item_new (); sensitive = FALSE; } else { mitem = g_array_index (treemenu->mitem_array, GtkWidget *, type - 1); if (rmu_items[type - 1].modfunc) { IPItem *rclick_item; rclick_item = swamiui_tree_get_rclick_item (treemenu->tree); switch ((*rmu_items[type - 1].modfunc)(type, rclick_item)) { case MODFUNC_INSENSITIVE: sensitive = FALSE; break; case MODFUNC_INVISIBLE: show = FALSE; break; default: break; } } } gtk_widget_set_sensitive (mitem, sensitive); if (show) gtk_widget_show (mitem); else gtk_widget_hide (mitem); return (mitem); } static gboolean treemenu_cb_selection_done (GtkMenuShell *menushell, SwamiUITreeMenu *treemenu) { IPItem *rclick_item; rclick_item = swamiui_tree_get_rclick_item (treemenu->tree); /* remove highlight from right clicked item */ if (rclick_item) swamiui_tree_unhighlight_item (treemenu->tree, rclick_item); swamiui_tree_set_rclick_item (treemenu->tree, NULL); return (FALSE); } /* SwamiUITreeMenu callback wrappers */ /* wrapper for paste routine */ static void swamiui_cb_paste (GList *item_list) { swamiui_paste_items (INSTP_ITEM (item_list->data), item_list->next); } /* wrapper for swamiui_wtbl_load_patch */ static void swamiui_cb_wtbl_load_patch (GList *item_list) { swamiui_wtbl_load_patch (INSTP_ITEM (item_list->data)); } /* wrapper for swamiui_new_item */ static void swamiui_cb_new_item (GList *item_list, gpointer data) { int type = GPOINTER_TO_INT (data); swamiui_new_item (INSTP_ITEM (item_list->data), type); } /* wrapper for swamiui_goto_zone_refitem */ static void swamiui_cb_goto_zone_refitem (GList *item_list) { IPZone *zone; SwamiUITreeMenuClass *klass; klass = gtk_type_class (swamiui_treemenu_get_type ()); if (!INSTP_IS_ZONE (item_list->data)) return; zone = INSTP_ZONE (item_list->data); swamiui_goto_zone_refitem (zone, klass->active_treemenu->tree); } /* wrapper for swamiui_load_samples */ static void swamiui_cb_load_samples (GList *item_list) { swamiui_load_samples (INSTP_ITEM (item_list->data)); } /* wrapper for swamiui_copy_gens */ static void swamiui_cb_copy_gens (GList *item_list) { swamiui_copy_gens (INSTP_ITEM (item_list->data)); } /* wrapper for swamiui_paste_gens */ static void swamiui_cb_paste_gens (GList *item_list) { swamiui_paste_gens (INSTP_ITEM (item_list->data)); } /* RMU_ModFunc's */ /* menu item modify function for "Goto Instrument" and "Goto Sample" disable menu item if its a global zone */ static int rmumod_goto_zoneref (RMUItemType type, IPItem *item) { if (!INSTP_ZONE (item)->refitem) return (MODFUNC_INVISIBLE); return (MODFUNC_NORMAL); }