/*================================================================== * SwamiUIProp.c - Swami sound font GTK tree 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. * * To contact the author of this program: * Email: Josh Green * Swami homepage: http://swami.sourceforge.net *==================================================================*/ #include #include #include #include #include #include "glade_interface.h" #include "SwamiUIObject.h" #include "SwamiUIProp.h" #include "i18n.h" #include "util.h" /* signals */ enum { LAST_SIGNAL }; // static guint prop_signals[LAST_SIGNAL] = {0}; /* Local Prototypes */ static void swamiui_prop_class_init (SwamiUIPropClass *klass); static void swamiui_prop_init (SwamiUIProp *prop); static void sync_widget_to_property (GtkWidget *glade_widg, char *widg_key, IPItem *item, char *property); static void sync_property_to_widget (GtkWidget *glade_widg, char *widg_key, IPItem *item, char *property); static GtkWidget *prop_create_inst_zone_widg (void); static void prop_cb_izone_set_toggled (GtkWidget *btn, GtkWidget *spbtn); static void prop_inst_zone_update (GtkWidget *glade_widg, IPZone *zone); static void prop_inst_zone_commit (GtkWidget *glade_widg, IPZone *zone); /* functions */ guint swamiui_prop_get_type (void) { static guint obj_type = 0; if (!obj_type) { GtkTypeInfo obj_info = { "SwamiUIProp", sizeof (SwamiUIProp), sizeof (SwamiUIPropClass), (GtkClassInitFunc) swamiui_prop_class_init, (GtkObjectInitFunc) swamiui_prop_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; obj_type = gtk_type_unique (gtk_vbox_get_type (), &obj_info); } return obj_type; } static void swamiui_prop_class_init (SwamiUIPropClass *klass) { } static void swamiui_prop_init (SwamiUIProp *prop) { prop->glade_widg = NULL; prop->item = NULL; } /** * Create a new Swami properties object * @item Sound font item to create a properties widget for * Returns: Swami properties object */ GtkWidget * swamiui_prop_new (void) { return (GTK_WIDGET (gtk_type_new (swamiui_prop_get_type ()))); } /** * Check if an item type is supported by SwamiUIProp object * @type Item type to check * Returns: TRUE if item type is supported by SwamiUIProp object, * FALSE otherwise */ gboolean swamiui_prop_item_supported (int type) { return (type == IPITEM_SFONT || type == IPITEM_PRESET || type == IPITEM_INST || type == IPITEM_SAMPLE || type == IPITEM_ZONE); } /** * Set the patch item to set properties of * @prop Properties object * @item Patch item to create a property editing widget for. */ void swamiui_prop_set_item (SwamiUIProp *prop, IPItem *item) { GtkWidget *widg = NULL; g_return_if_fail (prop != NULL); g_return_if_fail (SWAMIUI_IS_PROP (prop)); if (prop->item) { instp_item_unref (prop->item); /* -- unref old item */ gtk_container_foreach (GTK_CONTAINER (prop), (GtkCallback)gtk_widget_destroy, NULL); prop->item = NULL; } if (item && (widg = swamiui_prop_create_widget (prop, item))) { prop->item = item; instp_item_ref (prop->item); /* ++ reference item */ prop->glade_widg = widg; gtk_box_pack_start (GTK_BOX (prop), widg, TRUE, TRUE, 0); swamiui_prop_update (prop); } } /** * Create a property editing widget for a sound font item * @item Sound font item to edit properties of. * Returns: The property editing widget or NULL if no properties for the * given item type. */ GtkWidget * swamiui_prop_create_widget (SwamiUIProp *prop, IPItem *item) { GtkWidget *widg; g_return_val_if_fail (item != NULL, NULL); switch (item->type) { case IPITEM_SFONT: widg = create_glade_PropSfont (); widg = swamiui_util_rip_guts (widg, "glade_PropSfont"); break; case IPITEM_PRESET: widg = create_glade_PropPreset (); widg = swamiui_util_rip_guts (widg, "glade_PropPreset"); break; case IPITEM_INST: widg = create_glade_PropInst (); widg = swamiui_util_rip_guts (widg, "glade_PropInst"); break; case IPITEM_SAMPLE: widg = create_glade_PropSample (); widg = swamiui_util_rip_guts (widg, "glade_PropSample"); break; case IPITEM_ZONE: if (item->parent && INSTP_IS_INST (item->parent)) widg = prop_create_inst_zone_widg (); break; default: return (NULL); } if (widg) { gtk_object_set_data (GTK_OBJECT (widg), "_prop", prop); gtk_widget_show (widg); } return (widg); } /** * Update a properties object * @prop Properties object to update * * Re-synchronizes property's widgets to its patch item. */ void swamiui_prop_update (SwamiUIProp *prop) { IPItem *item; GtkWidget *gw; g_return_if_fail (prop != NULL); g_return_if_fail (SWAMIUI_IS_PROP (prop)); if (!prop->item) return; gw = prop->glade_widg; item = prop->item; switch (item->type) { case IPITEM_SFONT: sync_widget_to_property (gw, "EntryName", item, "name"); sync_widget_to_property (gw, "EntryAuthor", item, "author"); sync_widget_to_property (gw, "EntryCopyright", item, "copyright"); sync_widget_to_property (gw, "EntryProduct", item, "product"); sync_widget_to_property (gw, "EntryDate", item, "date"); sync_widget_to_property (gw, "LabelVersion", item, "version"); sync_widget_to_property (gw, "LabelEngine", item, "engine"); sync_widget_to_property (gw, "TextComment", item, "comment"); /* FIXME! what about software created:edited and ROM fields? */ break; case IPITEM_PRESET: sync_widget_to_property (gw, "EntryName", item, "name"); sync_widget_to_property (gw, "SpinBtnBank", item, "bank"); sync_widget_to_property (gw, "SpinBtnPsetnum", item, "psetnum"); break; case IPITEM_INST: sync_widget_to_property (gw, "EntryName", item, "name"); break; case IPITEM_SAMPLE: sync_widget_to_property (gw, "EntryName", item, "name"); sync_widget_to_property (gw, "SpinBtnRate", item, "samplerate"); sync_widget_to_property (gw, "SpinBtnNote", item, "origpitch"); sync_widget_to_property (gw, "SpinBtnTuning", item, "pitchadj"); break; case IPITEM_ZONE: if (item->parent && INSTP_IS_INST (item->parent)) prop_inst_zone_update (gw, INSTP_ZONE (item)); break; default: return; } } /** * Commit widget controls to item's properties * @err_msg OUTPUT: If the control values are invalid this pointer will * be set to a descriptive message of why they're invalid. Text should \b NOT * be freed or modified. If this pointer is NULL then no message will be * stored. * Returns: TRUE if values were committed, FALSE otherwise (duplicate item, etc) */ gboolean swamiui_prop_commit (SwamiUIProp *prop, char **err_msg) { IPItem *item; GtkWidget *gw; if (err_msg) *err_msg = NULL; g_return_val_if_fail (prop != NULL, FALSE); g_return_val_if_fail (SWAMIUI_IS_PROP (prop), FALSE); if (!prop->item) return (FALSE); /* FIXME - Lock item */ /* check if properties are valid */ if (!swamiui_prop_is_valid (prop, err_msg)) return (FALSE); gw = prop->glade_widg; item = prop->item; switch (item->type) { case IPITEM_SFONT: sync_property_to_widget (gw, "EntryName", item, "name"); sync_property_to_widget (gw, "EntryAuthor", item, "author"); sync_property_to_widget (gw, "EntryCopyright", item, "copyright"); sync_property_to_widget (gw, "EntryProduct", item, "product"); sync_property_to_widget (gw, "EntryDate", item, "date"); sync_property_to_widget (gw, "LabelVersion", item, "version"); sync_property_to_widget (gw, "LabelEngine", item, "engine"); sync_property_to_widget (gw, "TextComment", item, "comment"); /* FIXME! what about software created:edited and ROM fields? */ break; case IPITEM_PRESET: sync_property_to_widget (gw, "EntryName", item, "name"); sync_property_to_widget (gw, "SpinBtnBank", item, "bank"); sync_property_to_widget (gw, "SpinBtnPsetnum", item, "psetnum"); break; case IPITEM_INST: sync_property_to_widget (gw, "EntryName", item, "name"); break; case IPITEM_SAMPLE: sync_property_to_widget (gw, "EntryName", item, "name"); sync_property_to_widget (gw, "SpinBtnRate", item, "samplerate"); sync_property_to_widget (gw, "SpinBtnNote", item, "origpitch"); sync_property_to_widget (gw, "SpinBtnTuning", item, "pitchadj"); break; case IPITEM_ZONE: if (item->parent && INSTP_IS_INST (item->parent)) prop_inst_zone_commit (gw, INSTP_ZONE (item)); break; default: return (FALSE); } return (TRUE); } /** * Check if the widget values are valid * @prop Properties object * @err_msg OUTPUT: If the control values are invalid this pointer will * be set to a descriptive message of why they're invalid. Text should \b NOT * be freed or modified. If this pointer is NULL then no message will be * stored. * Returns: TRUE if widget control values are valid to set the * properties sound font item to, FALSE if not (duplicate item, etc). */ gboolean swamiui_prop_is_valid (SwamiUIProp *prop, char **err_msg) { IPSFont *sf; IPItem *item; IPPreset *preset; GtkWidget *gw, *widg; gboolean valid = TRUE; char *name; int bank, psetnum; if (err_msg) *err_msg = ""; g_return_val_if_fail (prop != NULL, FALSE); g_return_val_if_fail (SWAMIUI_IS_PROP (prop), FALSE); if (!prop->item) return (FALSE); gw = prop->glade_widg; switch (prop->item->type) { case IPITEM_SFONT: break; case IPITEM_PRESET: item = instp_item_parent (prop->item); if (!item) break; /* no parent, no duplicates */ sf = INSTP_SFONT (item); widg = gtk_object_get_data (GTK_OBJECT (gw), "EntryName"); name = gtk_entry_get_text (GTK_ENTRY (widg)); widg = gtk_object_get_data (GTK_OBJECT (gw), "SpinBtnBank"); bank = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widg)); widg = gtk_object_get_data (GTK_OBJECT (gw), "SpinBtnPsetnum"); psetnum = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widg)); preset = instp_find_preset (sf, name, bank, psetnum, INSTP_PRESET (prop->item)); if (preset) { int matched = 0; char *s; valid = FALSE; if (err_msg) { if (swami_item_get_int (swami_object, prop->item, "bank") == bank && swami_item_get_int (swami_object, prop->item, "psetnum") == psetnum) matched = 1; s = swami_item_get_string (swami_object, prop->item, "name"); if (strcmp (s, name) == 0) matched |= 2; g_free (s); switch (matched) { case 1: *err_msg = _("Duplicate bank and preset numbers"); break; case 2: *err_msg = _("Duplicate preset name"); break; case 3: *err_msg = _("Duplicate bank, preset number and name"); break; } } } break; case IPITEM_INST: item = instp_item_parent (prop->item); if (!item) break; /* no parent, no duplicates */ sf = INSTP_SFONT (item); widg = gtk_object_get_data (GTK_OBJECT (gw), "EntryName"); name = gtk_entry_get_text (GTK_ENTRY (widg)); if (instp_find_inst (sf, name, INSTP_INST (prop->item))) { valid = FALSE; if (err_msg) *err_msg = _("Duplicate instrument name"); } break; case IPITEM_SAMPLE: item = instp_item_parent (prop->item); if (!item) break; /* no parent, no duplicates */ sf = INSTP_SFONT (item); widg = gtk_object_get_data (GTK_OBJECT (gw), "EntryName"); name = gtk_entry_get_text (GTK_ENTRY (widg)); if (instp_find_sample (sf, name, INSTP_SAMPLE (prop->item))) { valid = FALSE; if (err_msg) *err_msg = _("Duplicate sample name"); } break; case IPITEM_ZONE: break; default: valid = FALSE; break; } return (valid); } /* synchronize a widget to an IPItem's property */ static void sync_widget_to_property (GtkWidget *glade_widg, char *widg_key, IPItem *item, char *property) { GtkWidget *widg; guint type; int i; char *s, *s2; widg = gtk_object_get_data (GTK_OBJECT (glade_widg), widg_key); if (!widg) { g_critical ("glade_widg has no child named \"%s\"", widg_key); return; } type = GTK_OBJECT_TYPE (widg); if (type == GTK_TYPE_ENTRY) { s = swami_item_get_string (swami_object, item, property); if (s) { gtk_entry_set_text (GTK_ENTRY (widg), s); g_free (s); } else gtk_entry_set_text (GTK_ENTRY (widg), ""); } else if (type == GTK_TYPE_TEXT) { s = swami_item_get_string (swami_object, item, property); gtk_editable_delete_text (GTK_EDITABLE (widg), 0, -1); /* delete all */ if (!s) return; /* for NULL string property values */ s2 = swamiui_util_str_crlf2lf (s); /* convert crlf -> lf */ g_free (s); i = 0; gtk_editable_insert_text (GTK_EDITABLE (widg), s2, strlen (s2), &i); g_free (s2); } else if (type == GTK_TYPE_SPIN_BUTTON) { i = swami_item_get_int (swami_object, item, property); gtk_spin_button_set_value (GTK_SPIN_BUTTON (widg), (float)i); } else if (type == GTK_TYPE_LABEL) { /* FIXME */ } else return; } /* synchronize an IPItem's property to a widget */ static void sync_property_to_widget (GtkWidget *glade_widg, char *widg_key, IPItem *item, char *property) { GtkWidget *widg; guint type; int i; char *s, *s2; widg = gtk_object_get_data (GTK_OBJECT (glade_widg), widg_key); if (!widg) { g_critical ("glade_widg has no child named \"%s\"", widg_key); return; } type = GTK_OBJECT_TYPE (widg); if (type == GTK_TYPE_ENTRY) { s = gtk_entry_get_text (GTK_ENTRY (widg)); swami_item_set_string (swami_object, item, property, s); } else if (type == GTK_TYPE_TEXT) { s = gtk_editable_get_chars (GTK_EDITABLE (widg), 0, -1); s2 = swamiui_util_str_lf2crlf (s); /* convert lf -> crlf */ g_free (s); swami_item_set_string (swami_object, item, property, s2); g_free (s2); } else if (type == GTK_TYPE_SPIN_BUTTON) { i = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widg)); swami_item_set_int (swami_object, item, property, i); } else return; } /* routine to create instrument zone properties widget */ static GtkWidget * prop_create_inst_zone_widg (void) { GtkWidget *izone; GtkWidget *widg; GtkWidget *spbtn; izone = create_glade_PropIZone (); izone = swamiui_util_rip_guts (izone, "glade_PropIZone"); widg = gtk_object_get_data (GTK_OBJECT (izone), "CHKRoot"); spbtn = gtk_object_get_data (GTK_OBJECT (izone), "SPBRoot"); gtk_signal_connect (GTK_OBJECT (widg), "toggled", GTK_SIGNAL_FUNC (prop_cb_izone_set_toggled), spbtn); widg = gtk_object_get_data (GTK_OBJECT (izone), "CHKExclusive"); spbtn = gtk_object_get_data (GTK_OBJECT (izone), "SPBExclusive"); gtk_signal_connect (GTK_OBJECT (widg), "toggled", GTK_SIGNAL_FUNC (prop_cb_izone_set_toggled), spbtn); widg = gtk_object_get_data (GTK_OBJECT (izone), "CHKFixedNote"); spbtn = gtk_object_get_data (GTK_OBJECT (izone), "SPBFixedNote"); gtk_signal_connect (GTK_OBJECT (widg), "toggled", GTK_SIGNAL_FUNC (prop_cb_izone_set_toggled), spbtn); widg = gtk_object_get_data (GTK_OBJECT (izone), "CHKFixedVel"); spbtn = gtk_object_get_data (GTK_OBJECT (izone), "SPBFixedVel"); gtk_signal_connect (GTK_OBJECT (widg), "toggled", GTK_SIGNAL_FUNC (prop_cb_izone_set_toggled), spbtn); return (izone); } /* generator "set" toggle buttons callback */ static void prop_cb_izone_set_toggled (GtkWidget *btn, GtkWidget *spbtn) { gboolean active; active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (btn)); gtk_widget_set_sensitive (spbtn, active); } static void prop_inst_zone_update (GtkWidget *glade_widg, IPZone *zone) { GtkWidget *widg; IPGenAmount amt; gboolean set; set = instp_zone_get_gen (zone, IPGEN_OVERRIDE_ROOT_KEY, &amt); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "SPBRoot"); gtk_spin_button_set_value (GTK_SPIN_BUTTON (widg), (float)amt.sword); gtk_widget_set_sensitive (widg, set); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "CHKRoot"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widg), set); set = instp_zone_get_gen (zone, IPGEN_EXCLUSIVE_CLASS, &amt); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "SPBExclusive"); gtk_spin_button_set_value (GTK_SPIN_BUTTON (widg), (float)amt.uword); gtk_widget_set_sensitive (widg, set); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "CHKExclusive"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widg), set); set = instp_zone_get_gen (zone, IPGEN_KEY_NUM, &amt); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "SPBFixedNote"); gtk_spin_button_set_value (GTK_SPIN_BUTTON (widg), (float)amt.sword); gtk_widget_set_sensitive (widg, set); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "CHKFixedNote"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widg), set); set = instp_zone_get_gen (zone, IPGEN_VELOCITY, &amt); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "SPBFixedVel"); gtk_spin_button_set_value (GTK_SPIN_BUTTON (widg), (float)amt.sword); gtk_widget_set_sensitive (widg, set); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "CHKFixedVel"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widg), set); } static void prop_inst_zone_commit (GtkWidget *glade_widg, IPZone *zone) { GtkWidget *widg; IPGenAmount amt; gboolean set; widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "CHKRoot"); set = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widg)); if (set) { widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "SPBRoot"); amt.uword = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widg)); instp_zone_set_gen (zone, IPGEN_OVERRIDE_ROOT_KEY, amt); } else instp_zone_unset_gen (zone, IPGEN_OVERRIDE_ROOT_KEY); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "CHKExclusive"); set = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widg)); if (set) { widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "SPBExclusive"); amt.uword = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widg)); instp_zone_set_gen (zone, IPGEN_EXCLUSIVE_CLASS, amt); } else instp_zone_unset_gen (zone, IPGEN_EXCLUSIVE_CLASS); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "CHKFixedNote"); set = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widg)); if (set) { widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "SPBFixedNote"); amt.uword = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widg)); instp_zone_set_gen (zone, IPGEN_KEY_NUM, amt); } else instp_zone_unset_gen (zone, IPGEN_KEY_NUM); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "CHKFixedVel"); set = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widg)); if (set) { widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "SPBFixedVel"); amt.uword = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widg)); instp_zone_set_gen (zone, IPGEN_VELOCITY, amt); } else instp_zone_unset_gen (zone, IPGEN_VELOCITY); }