#include "snd.h" #include "sndlib-strings.h" static GtkWidget *preferences_dialog = NULL, *load_path_text_widget = NULL; static bool prefs_unsaved = false; static char *prefs_saved_filename = NULL; static char *include_load_path = NULL; #define POWER_WAIT_TIME ((guint32)100) #define POWER_INITIAL_WAIT_TIME ((guint32)500) #define ERROR_WAIT_TIME ((guint32)5000) #if (!HAVE_GTK_WIDGET_GET_VISIBLE) #define Widget_Is_Sensitive(Wid) GTK_WIDGET_SENSITIVE(Wid) #else #define Widget_Is_Sensitive(Wid) gtk_widget_is_sensitive(Wid) #endif #define STARTUP_WIDTH 750 #define STARTUP_HEIGHT 800 typedef struct prefs_info { GtkWidget *label, *text, *arrow_up, *arrow_down, *arrow_right, *error, *toggle, *scale, *toggle2, *toggle3; GtkWidget *color, *rscl, *gscl, *bscl, *rtxt, *gtxt, *btxt, *list_menu, *radio_button; GtkAdjustment *adj, *radj, *gadj, *badj; GtkWidget **radio_buttons; bool got_error; timeout_result_t help_id, power_id, erase_id; const char *var_name, *saved_label; const char **values; int num_values, num_buttons; mus_float_t scale_max; GtkSizeGroup *color_texts, *color_scales; void (*toggle_func)(struct prefs_info *prf); void (*toggle2_func)(struct prefs_info *prf); void (*toggle3_func)(struct prefs_info *prf); void (*scale_func)(struct prefs_info *prf); void (*arrow_up_func)(struct prefs_info *prf); void (*arrow_down_func)(struct prefs_info *prf); void (*text_func)(struct prefs_info *prf); void (*color_func)(struct prefs_info *prf, double r, double g, double b); void (*reflect_func)(struct prefs_info *prf); void (*save_func)(struct prefs_info *prf, FILE *fd); const char *(*help_func)(struct prefs_info *prf); void (*clear_func)(struct prefs_info *prf); void (*revert_func)(struct prefs_info *prf); } prefs_info; static void prefs_set_dialog_title(const char *filename); static void reflect_key(prefs_info *prf, const char *key_name); static void save_key(prefs_info *prf, FILE *fd, char *(*binder)(char *key, bool c, bool m, bool x)); static void key_bind(prefs_info *prf, char *(*binder)(char *key, bool c, bool m, bool x)); static void clear_prefs_dialog_error(void); static void scale_set_color(prefs_info *prf, color_t pixel); static char *get_text(GtkWidget *w); static void set_text(GtkWidget *w, const char *value); static void post_prefs_error(const char *msg, prefs_info *data); #ifdef __GNUC__ static void va_post_prefs_error(const char *msg, prefs_info *data, ...) __attribute__ ((format (printf, 1, 0))); #else static void va_post_prefs_error(const char *msg, prefs_info *data, ...); #endif /* used in snd-prefs.c */ #define GET_TOGGLE(Toggle) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Toggle)) #define SET_TOGGLE(Toggle, Value) set_toggle_button(Toggle, Value, false, (void *)prf) #define GET_TEXT(Text) get_text(Text) #define SET_TEXT(Text, Val) set_text(Text, Val) #define free_TEXT(Val) #define TIMEOUT(Func) g_timeout_add_full(0, ERROR_WAIT_TIME, Func, (gpointer)prf, NULL) #define SET_SCALE(Value) ADJUSTMENT_SET_VALUE(prf->adj, Value) #define GET_SCALE() (ADJUSTMENT_VALUE(prf->adj) * prf->scale_max) #define SET_SENSITIVE(Wid, Val) gtk_widget_set_sensitive(Wid, Val) #define black_text(Prf) #define red_text(Prf) /* gdk_gc_set_foreground(Prf->label->style->black_gc, ss->red) no effect? */ static GtkWidget *make_basic_row(GtkWidget *box) { #if GTK_CHECK_VERSION(3, 92, 1) GtkWidget *row; row = gtk_hbox_new(false, 0); sg_box_pack_start(GTK_BOX(box), row, false, false, 0); gtk_widget_set_hexpand(GTK_WIDGET(row), true); gtk_widget_show(row); #else #if GTK_CHECK_VERSION(3, 0, 0) GtkWidget *row, *r; r = gtk_event_box_new(); /* not button! */ gtk_widget_set_hexpand(GTK_WIDGET(r), true); sg_box_pack_start(GTK_BOX(box), r, false, false, 0); add_highlight_button_style(r); gtk_widget_show(r); row = gtk_hbox_new(false, 0); gtk_container_add(GTK_CONTAINER(r), row); gtk_widget_set_hexpand(GTK_WIDGET(row), true); gtk_widget_show(row); #else GtkWidget *row; row = gtk_hbox_new(false, 0); sg_box_pack_start(GTK_BOX(box), row, false, false, 0); gtk_widget_show(row); #endif #endif return(row); } static void set_radio_button(prefs_info *prf, int which) { if ((which >= 0) && (which < prf->num_buttons)) set_toggle_button(prf->radio_buttons[which], true, false, (void *)prf); } #define which_radio_button(Prf) get_user_int_data(G_OBJECT(Prf->radio_button)) #include "snd-prefs.c" static void sg_entry_set_text(GtkEntry* entry, const char *text) { if (text) gtk_entry_set_text(entry, (gchar *)text); else gtk_entry_set_text(entry, " "); } static void set_text(GtkWidget *w, const char *value) { if (GTK_IS_ENTRY(w)) sg_entry_set_text(GTK_ENTRY(w), value); else { if (GTK_IS_ENTRY(BIN_CHILD(w))) sg_entry_set_text(GTK_ENTRY(BIN_CHILD(w)), value); } } static char *get_text(GtkWidget *w) { if (GTK_IS_ENTRY(w)) return((char *)gtk_entry_get_text(GTK_ENTRY(w))); if (GTK_IS_ENTRY(BIN_CHILD(w))) return((char *)gtk_entry_get_text(GTK_ENTRY(BIN_CHILD(w)))); return(NULL); } /* ---------------- help strings ---------------- */ static bool prefs_dialog_error_is_posted = false; static void post_prefs_dialog_error(const char *message, void *data) { gtk_window_set_title(GTK_WINDOW(preferences_dialog), (char *)message); prefs_dialog_error_is_posted = (bool)message; } static void clear_prefs_dialog_error(void) { if (prefs_dialog_error_is_posted) { prefs_dialog_error_is_posted = false; post_prefs_dialog_error(NULL, NULL); } } static void prefs_change_callback(GtkWidget *w, gpointer context) { prefs_unsaved = true; prefs_set_dialog_title(NULL); clear_prefs_dialog_error(); } static GtkSizeGroup *label_group; static GtkSizeGroup *widgets_group; static color_info *rscl_color, *gscl_color, *bscl_color; #define PACK_1 true #define PACK_2 false /* ---------------- row (main) label widget ---------------- */ static GtkWidget *make_row_label(prefs_info *prf, const char *label, GtkWidget *box) { GtkWidget *w; w = gtk_label_new(label); #if (!GTK_CHECK_VERSION(3, 0, 0)) gtk_misc_set_alignment(GTK_MISC(w), 1.0, 0.0); #else #if GTK_CHECK_VERSION(3, 14, 0) gtk_widget_set_halign(GTK_WIDGET(w), GTK_ALIGN_END); #else gtk_misc_set_alignment(GTK_MISC(w), 1.0, 0.5); #endif #endif gtk_size_group_add_widget(label_group, w); sg_box_pack_start(GTK_BOX(box), w, PACK_1, PACK_2, 0); gtk_widget_show(w); prf->saved_label = label; return(w); } /* ---------------- row inner label widget ---------------- */ static void make_row_inner_label(prefs_info *prf, const char *label, GtkWidget *box) { GtkWidget *w; w = gtk_label_new(label); sg_box_pack_start(GTK_BOX(box), w, false, false, 4); gtk_widget_show(w); } /* ---------------- row middle separator widget ---------------- */ static void make_row_middle_separator(GtkWidget *box) { GtkWidget *w; w = gtk_vseparator_new(); sg_box_pack_start(GTK_BOX(box), w, false, false, 10); gtk_widget_show(w); } /* ---------------- row inner separator widget ---------------- */ static void make_row_inner_separator(int width, GtkWidget *box) { GtkWidget *w; w = gtk_hseparator_new(); sg_box_pack_start(GTK_BOX(box), w, false, false, width); gtk_widget_show(w); } /* ---------------- row toggle widget ---------------- */ static GtkWidget *make_row_toggle_with_label(prefs_info *prf, bool current_value, GtkWidget *box, const char *label) { GtkWidget *w; if (label) w = gtk_check_button_new_with_label(label); else w = gtk_check_button_new(); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), current_value); sg_box_pack_start(GTK_BOX(box), w, false, false, 0); /* was 10 */ gtk_widget_show(w); SG_SIGNAL_CONNECT(w, "toggled", prefs_change_callback, NULL); return(w); } static GtkWidget *make_row_toggle(prefs_info *prf, bool current_value, GtkWidget *box) { return(make_row_toggle_with_label(prf, current_value, box, NULL)); } /* ---------------- error widget ---------------- */ static GtkWidget *make_row_error(prefs_info *prf, GtkWidget *box) { GtkWidget *w; w = gtk_label_new(""); sg_box_pack_end(GTK_BOX(box), w, true, false, 0); gtk_widget_show(w); return(w); } /* ---------------- row arrows ---------------- */ static gboolean remove_arrow_func(GtkWidget *w, GdkEventButton *ev, gpointer context) { prefs_info *prf = (prefs_info *)context; if (prf->power_id != 0) { g_source_remove(prf->power_id); prf->power_id = 0; } return(false); } static gint arrow_func_up(gpointer context) { prefs_info *prf = (prefs_info *)context; if (Widget_Is_Sensitive(prf->arrow_up)) { if (prf->arrow_up_func) { (*(prf->arrow_up_func))(prf); prf->power_id = g_timeout_add_full(0, POWER_WAIT_TIME, arrow_func_up, (gpointer)prf, NULL); } else prf->power_id = 0; } return(0); } static gint arrow_func_down(gpointer context) { prefs_info *prf = (prefs_info *)context; if (Widget_Is_Sensitive(prf->arrow_down)) { if (prf->arrow_down_func) { (*(prf->arrow_down_func))(prf); prf->power_id = g_timeout_add_full(0, POWER_WAIT_TIME, arrow_func_down, (gpointer)prf, NULL); } else prf->power_id = 0; } return(0); } static gboolean call_arrow_down_press(GtkWidget *w, GdkEventButton *ev, gpointer context) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->arrow_down_func)) { (*(prf->arrow_down_func))(prf); if (Widget_Is_Sensitive(w)) prf->power_id = g_timeout_add_full(0, POWER_INITIAL_WAIT_TIME, arrow_func_down, (gpointer)prf, NULL); else prf->power_id = 0; } return(false); } static gboolean call_arrow_up_press(GtkWidget *w, GdkEventButton *ev, gpointer context) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->arrow_up_func)) { (*(prf->arrow_up_func))(prf); if (Widget_Is_Sensitive(w)) prf->power_id = g_timeout_add_full(0, POWER_INITIAL_WAIT_TIME, arrow_func_up, (gpointer)prf, NULL); else prf->power_id = 0; } return(false); } static GtkWidget *make_row_arrows(prefs_info *prf, GtkWidget *box) { #if (!GTK_CHECK_VERSION(3, 92, 1)) GtkWidget *ev_up, *ev_down; #endif GtkWidget *up, *down; #if GTK_CHECK_VERSION(3, 14, 0) GtkIconTheme *icon_theme; icon_theme = gtk_icon_theme_get_default(); #endif #if (!GTK_CHECK_VERSION(3, 92, 1)) ev_down = gtk_event_box_new(); sg_box_pack_start(GTK_BOX(box), ev_down, false, false, 0); gtk_widget_show(ev_down); #endif #if GTK_CHECK_VERSION(3, 14, 0) down = gtk_image_new_from_pixbuf(gtk_icon_theme_load_icon(icon_theme, "pan-down-symbolic", 16, (GtkIconLookupFlags)0, NULL)); #else down = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_ETCHED_OUT); #endif #if (!GTK_CHECK_VERSION(3, 92, 1)) gtk_container_add(GTK_CONTAINER(ev_down), down); #else sg_box_pack_start(GTK_BOX(box), down, false, false, 0); #endif gtk_widget_show(down); #if (!GTK_CHECK_VERSION(3, 92, 1)) ev_up = gtk_event_box_new(); sg_box_pack_start(GTK_BOX(box), ev_up, false, false, 0); gtk_widget_show(ev_up); #endif #if GTK_CHECK_VERSION(3, 14, 0) up = gtk_image_new_from_pixbuf(gtk_icon_theme_load_icon(icon_theme, "pan-up-symbolic", 16, (GtkIconLookupFlags)0, NULL)); #else up = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_ETCHED_OUT); #endif #if (!GTK_CHECK_VERSION(3, 92, 1)) gtk_container_add(GTK_CONTAINER(ev_up), up); #else sg_box_pack_start(GTK_BOX(box), up, false, false, 0); #endif gtk_widget_show(up); prf->arrow_up = up; prf->arrow_down = down; #if (!GTK_CHECK_VERSION(3, 92, 1)) SG_SIGNAL_CONNECT(ev_down, "button_press_event", call_arrow_down_press, (gpointer)prf); SG_SIGNAL_CONNECT(ev_down, "button_release_event", remove_arrow_func, (gpointer)prf); SG_SIGNAL_CONNECT(ev_up, "button_press_event", call_arrow_up_press, (gpointer)prf); SG_SIGNAL_CONNECT(ev_up, "button_release_event", remove_arrow_func, (gpointer)prf); SG_SIGNAL_CONNECT(ev_down, "button_press_event", prefs_change_callback, NULL); SG_SIGNAL_CONNECT(ev_up, "button_press_event", prefs_change_callback, NULL); #else SG_SIGNAL_CONNECT(down, "button_press_event", call_arrow_down_press, (gpointer)prf); SG_SIGNAL_CONNECT(down, "button_release_event", remove_arrow_func, (gpointer)prf); SG_SIGNAL_CONNECT(up, "button_press_event", call_arrow_up_press, (gpointer)prf); SG_SIGNAL_CONNECT(up, "button_release_event", remove_arrow_func, (gpointer)prf); SG_SIGNAL_CONNECT(down, "button_press_event", prefs_change_callback, NULL); SG_SIGNAL_CONNECT(up, "button_press_event", prefs_change_callback, NULL); #endif return(up); } /* ---------------- bool row ---------------- */ static void call_toggle_func(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->toggle_func)) (*(prf->toggle_func))(prf); } static prefs_info *prefs_row_with_toggle(const char *label, const char *varname, bool current_value, GtkWidget *box, void (*toggle_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); prf->toggle = make_row_toggle(prf, current_value, hb); SG_SIGNAL_CONNECT(prf->toggle, "toggled", call_toggle_func, (gpointer)prf); return(prf); } /* ---------------- two toggles ---------------- */ static void call_toggle2_func(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->toggle2_func)) (*(prf->toggle2_func))(prf); } static prefs_info *prefs_row_with_two_toggles(const char *label, const char *varname, const char *label1, bool value1, const char *label2, bool value2, GtkWidget *box, void (*toggle_func)(prefs_info *prf), void (*toggle2_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *row, *hb; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->toggle2_func = toggle2_func; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); prf->toggle = make_row_toggle_with_label(prf, value1, hb, label1); make_row_inner_separator(20, hb); prf->toggle2 = make_row_toggle_with_label(prf, value2, hb, label2); SG_SIGNAL_CONNECT(prf->toggle, "toggled", call_toggle_func, (gpointer)prf); SG_SIGNAL_CONNECT(prf->toggle2, "toggled", call_toggle2_func, (gpointer)prf); return(prf); } /* ---------------- toggle with text ---------------- */ /* see commentary in snd-xprefs.c */ typedef struct { bool text_focussed, text_changed; prefs_info *prf; } text_info; static void text_change_callback(GtkWidget *w, gpointer context) { text_info *data = (text_info *)context; if (data->text_focussed) /* try to omit non-user actions that change the value */ data->text_changed = true; } static void text_activate_callback(GtkWidget *w, gpointer context) { text_info *data = (text_info *)context; data->text_changed = false; } static void text_grab_focus_callback(GtkWidget *w, GdkEventCrossing *ev, gpointer context) { text_info *data = (text_info *)context; if (with_pointer_focus(ss)) goto_window(w); data->text_focussed = true; } static void text_lose_focus_callback(GtkWidget *w, GdkEventCrossing *ev, gpointer context) { text_info *data = (text_info *)context; if ((data->text_focussed) && (data->text_changed) && (data->prf) && (data->prf->text_func)) { (*(data->prf->text_func))(data->prf); data->text_changed = false; } } static void call_text_func(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->text_func)) (*(prf->text_func))(prf); } static GtkWidget *make_row_text(prefs_info *prf, const char *text_value, int cols, GtkWidget *box) { int len; GtkWidget *w; GtkSettings *settings; text_info *info; len = mus_strlen(text_value); w = gtk_entry_new(); gtk_entry_set_has_frame(GTK_ENTRY(w), true); if (text_value) sg_entry_set_text(GTK_ENTRY(w), text_value); gtk_entry_set_has_frame(GTK_ENTRY(w), false); #if (!GTK_CHECK_VERSION(3, 96, 0)) if (cols > 0) gtk_entry_set_width_chars(GTK_ENTRY(w), cols); else { if (len > 24) /* sigh... */ gtk_entry_set_width_chars(GTK_ENTRY(w), len); } #endif gtk_editable_set_editable(GTK_EDITABLE(w), true); settings = gtk_widget_get_settings(w); g_object_set(settings, "gtk-entry-select-on-focus", false, NULL); sg_box_pack_start(GTK_BOX(box), w, false, false, 0); gtk_widget_show(w); info = (text_info *)calloc(1, sizeof(text_info)); info->prf = prf; SG_SIGNAL_CONNECT(w, "enter_notify_event", text_grab_focus_callback, (gpointer)info); SG_SIGNAL_CONNECT(w, "leave_notify_event", text_lose_focus_callback, (gpointer)info); SG_SIGNAL_CONNECT(w, "changed", text_change_callback, (gpointer)info); SG_SIGNAL_CONNECT(w, "activate", text_activate_callback, (gpointer)info); return(w); } static prefs_info *prefs_row_with_toggle_with_text(const char *label, const char *varname, bool current_value, const char *text_label, const char *text_value, int cols, GtkWidget *box, void (*toggle_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->text_func = text_func; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); prf->toggle = make_row_toggle(prf, current_value, hb); make_row_inner_separator(16, hb); make_row_inner_label(prf, text_label, hb); prf->text= make_row_text(prf, text_value, cols, hb); SG_SIGNAL_CONNECT(prf->toggle, "toggled", call_toggle_func, (gpointer)prf); SG_SIGNAL_CONNECT(prf->text, "activate", call_text_func, (gpointer)prf); return(prf); } static prefs_info *prefs_row_with_toggle_with_two_texts(const char *label, const char *varname, bool current_value, const char *label1, const char *text1, const char *label2, const char *text2, int cols, GtkWidget *box, void (*toggle_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->text_func = text_func; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); prf->toggle = make_row_toggle(prf, current_value, hb); make_row_inner_separator(16, hb); make_row_inner_label(prf, label1, hb); prf->text= make_row_text(prf, text1, cols, hb); make_row_inner_label(prf, label2, hb); prf->rtxt= make_row_text(prf, text2, cols, hb); SG_SIGNAL_CONNECT(prf->toggle, "toggled", call_toggle_func, (gpointer)prf); SG_SIGNAL_CONNECT(prf->text, "activate", call_text_func, (gpointer)prf); SG_SIGNAL_CONNECT(prf->rtxt, "activate", call_text_func, (gpointer)prf); return(prf); } /* ---------------- text with toggle ---------------- */ static prefs_info *prefs_row_with_text_with_toggle(const char *label, const char *varname, bool current_value, const char *toggle_label, const char *text_value, int cols, GtkWidget *box, void (*toggle_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->text_func = text_func; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); prf->text = make_row_text(prf, text_value, cols, hb); make_row_inner_separator(8, hb); make_row_inner_label(prf, toggle_label, hb); prf->toggle = make_row_toggle(prf, current_value, hb); SG_SIGNAL_CONNECT(prf->toggle, "toggled", call_toggle_func, (gpointer)prf); SG_SIGNAL_CONNECT(prf->text, "activate", call_text_func, (gpointer)prf); return(prf); } /* ---------------- text with three toggle ---------------- */ static prefs_info *prefs_row_with_text_and_three_toggles(const char *label, const char *varname, const char *text_label, int cols, const char *toggle1_label, const char *toggle2_label, const char *toggle3_label, const char *text_value, bool toggle1_value, bool toggle2_value, bool toggle3_value, GtkWidget *box, void (*text_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->text_func = text_func; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); make_row_inner_label(prf, text_label, hb); prf->text = make_row_text(prf, text_value, cols, hb); make_row_inner_separator(12, hb); make_row_inner_label(prf, toggle1_label, hb); prf->toggle = make_row_toggle(prf, toggle1_value, hb); make_row_inner_separator(4, hb); make_row_inner_label(prf, toggle2_label, hb); prf->toggle2 = make_row_toggle(prf, toggle2_value, hb); make_row_inner_separator(4, hb); make_row_inner_label(prf, toggle3_label, hb); prf->toggle3 = make_row_toggle(prf, toggle3_value, hb); SG_SIGNAL_CONNECT(prf->text, "activate", call_text_func, (gpointer)prf); return(prf); } /* ---------------- radio row ---------------- */ static void call_radio_func(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->toggle_func)) { prf->radio_button = w; (*(prf->toggle_func))(prf); } } static GtkWidget *make_row_radio_box(prefs_info *prf, const char **labels, int num_labels, int current_value, GtkWidget *box) { GtkWidget *w, *current_button; int i; w = gtk_hbox_new(false, 0); sg_box_pack_start(GTK_BOX(box), w, false, false, 0); gtk_widget_show(w); prf->radio_buttons = (GtkWidget **)calloc(num_labels, sizeof(GtkWidget *)); prf->num_buttons = num_labels; for (i = 0; i < num_labels; i++) { if (i == 0) current_button = gtk_radio_button_new_with_label(NULL, labels[i]); else current_button = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(prf->radio_buttons[0])), labels[i]); prf->radio_buttons[i] = current_button; sg_box_pack_start(GTK_BOX(w), current_button, false, false, 0); set_user_int_data(G_OBJECT(current_button), i); gtk_widget_show(current_button); SG_SIGNAL_CONNECT(current_button, "clicked", call_radio_func, (gpointer)prf); SG_SIGNAL_CONNECT(current_button, "clicked", prefs_change_callback, NULL); } if (current_value != -1) set_toggle_button(prf->radio_buttons[current_value], true, false, (void *)prf); return(w); } static prefs_info *prefs_row_with_radio_box(const char *label, const char *varname, const char **labels, int num_labels, int current_value, GtkWidget *box, void (*toggle_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); prf->toggle = make_row_radio_box(prf, labels, num_labels, current_value, hb); return(prf); } static prefs_info *prefs_row_with_radio_box_and_number(const char *label, const char *varname, const char **labels, int num_labels, int current_value, const char *text_value, int text_cols, GtkWidget *box, void (*toggle_func)(prefs_info *prf), void (*arrow_up_func)(prefs_info *prf), void (*arrow_down_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *row, *hb; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->text_func = text_func; prf->arrow_up_func = arrow_up_func; prf->arrow_down_func = arrow_down_func; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); prf->toggle = make_row_radio_box(prf, labels, num_labels, current_value, hb); prf->text = make_row_text(prf, text_value, text_cols, hb); prf->arrow_up = make_row_arrows(prf, hb); SG_SIGNAL_CONNECT(prf->text, "activate", call_text_func, (gpointer)prf); return(prf); } /* ---------------- scale row ---------------- */ static void call_scale_func(GtkAdjustment *w, gpointer context) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->scale_func)) (*(prf->scale_func))(prf); } static void call_scale_text_func(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->text_func)) (*(prf->text_func))(prf); } static void prefs_scale_callback(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; float_to_textfield(prf->text, ADJUSTMENT_VALUE(prf->adj) * prf->scale_max); } static prefs_info *prefs_row_with_scale(const char *label, const char *varname, mus_float_t max_val, mus_float_t current_value, GtkWidget *box, void (*scale_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; char *str; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->scale_max = max_val; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); str = (char *)calloc(12, sizeof(char)); snprintf(str, 12, "%.3f", current_value); prf->text = make_row_text(prf, str, 6, hb); free(str); prf->adj = (GtkAdjustment *)gtk_adjustment_new(current_value /max_val, 0.0, 1.01, 0.001, 0.01, .01); prf->scale = gtk_hscale_new(GTK_ADJUSTMENT(prf->adj)); sg_box_pack_start(GTK_BOX(hb), prf->scale, true, true, 4); gtk_widget_show(prf->scale); gtk_range_set_update_policy(GTK_RANGE(GTK_SCALE(prf->scale)), GTK_UPDATE_CONTINUOUS); gtk_scale_set_draw_value(GTK_SCALE(prf->scale), false); prf->scale_func = scale_func; prf->text_func = text_func; SG_SIGNAL_CONNECT(prf->scale, "value_changed", call_scale_func, (gpointer)prf); SG_SIGNAL_CONNECT(prf->scale, "value_changed", prefs_change_callback, NULL); SG_SIGNAL_CONNECT(prf->scale, "value_changed", prefs_scale_callback, (gpointer)prf); SG_SIGNAL_CONNECT(prf->text, "activate", call_scale_text_func, (gpointer)prf); return(prf); } /* ---------------- text row ---------------- */ static prefs_info *prefs_row_with_text(const char *label, const char *varname, const char *value, GtkWidget *box, void (*text_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); prf->text = make_row_text(prf, value, 0, hb); prf->text_func = text_func; SG_SIGNAL_CONNECT(prf->text, "activate", call_text_func, (gpointer)prf); return(prf); } /* ---------------- two texts in a row ---------------- */ static prefs_info *prefs_row_with_two_texts(const char *label, const char *varname, const char *label1, const char *text1, const char *label2, const char *text2, int cols, GtkWidget *box, void (*text_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); make_row_inner_label(prf, label1, hb); prf->text = make_row_text(prf, text1, cols, hb); make_row_inner_label(prf, label2, hb); prf->rtxt = make_row_text(prf, text2, cols, hb); prf->text_func = text_func; SG_SIGNAL_CONNECT(prf->text, "activate", call_text_func, (gpointer)prf); SG_SIGNAL_CONNECT(prf->rtxt, "activate", call_text_func, (gpointer)prf); return(prf); } /* ---------------- number row ---------------- */ static prefs_info *prefs_row_with_number(const char *label, const char *varname, const char *value, int cols, GtkWidget *box, void (*arrow_up_func)(prefs_info *prf), void (*arrow_down_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); prf->text = make_row_text(prf, value, cols, hb); prf->arrow_up = make_row_arrows(prf, hb); prf->error = make_row_error(prf, hb); prf->text_func = text_func; prf->arrow_up_func = arrow_up_func; prf->arrow_down_func = arrow_down_func; SG_SIGNAL_CONNECT(prf->text, "activate", call_text_func, (gpointer)prf); return(prf); } /* ---------------- list row ---------------- */ static prefs_info *prefs_row_with_list(const char *label, const char *varname, const char *value, const char **values, int num_values, GtkWidget *box, void (*text_func)(prefs_info *prf), char *(*completion_func)(widget_t w, const char *text, void *context), void *completion_context) { int i; prefs_info *prf; GtkWidget *hb, *row; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); #if GTK_CHECK_VERSION(3, 0, 0) prf->text = gtk_combo_box_text_new_with_entry(); for (i = 0; i < num_values; i++) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(prf->text), (values[i]) ? values[i] : " "); #else prf->text = gtk_combo_box_entry_new_text(); for (i = 0; i < num_values; i++) gtk_combo_box_append_text(GTK_COMBO_BOX(prf->text), (values[i]) ? values[i] : " "); #endif sg_entry_set_text(GTK_ENTRY(BIN_CHILD(prf->text)), value); sg_box_pack_start(GTK_BOX(hb), prf->text, false, false, 4); gtk_widget_show(prf->text); prf->error = make_row_error(prf, hb); prf->text_func = text_func; SG_SIGNAL_CONNECT(prf->text, "changed", call_text_func, (gpointer)prf); SG_SIGNAL_CONNECT(prf->text, "changed", prefs_change_callback, NULL); return(prf); } /* ---------------- color selector row(s) ---------------- */ static void pixel_to_rgb(color_t pix, double *r, double *g, double *b) { (*r) = rgb_to_float(pix->red); (*g) = rgb_to_float(pix->green); (*b) = rgb_to_float(pix->blue); } #if GTK_CHECK_VERSION(3, 92, 0) static void display_color(GtkWidget *w, color_t pixel) {} #else #if GTK_CHECK_VERSION(3, 0, 0) static void display_color(GtkWidget *w, color_t pixel) { cairo_t *cr; #if GTK_CHECK_VERSION(3, 22, 0) GdkWindow *window; GdkDrawingContext *context; window = WIDGET_TO_WINDOW(w); context = gdk_window_begin_draw_frame(window, gdk_window_get_visible_region(window)); cr = gdk_drawing_context_get_cairo_context(context); #else cr = gdk_cairo_create(WIDGET_TO_WINDOW(w)); #endif cairo_set_source_rgba(cr, pixel->red, pixel->green, pixel->blue, pixel->alpha); cairo_rectangle(cr, 0, 0, widget_width(w), widget_height(w)); cairo_fill(cr); #if GTK_CHECK_VERSION(3, 22, 0) gdk_window_end_draw_frame(window, context); #else cairo_destroy(cr); #endif } #endif #endif static void scale_set_color(prefs_info *prf, color_t pixel) { double r = 0.0, g = 0.0, b = 0.0; pixel_to_rgb(pixel, &r, &g, &b); float_to_textfield(prf->rtxt, r); ADJUSTMENT_SET_VALUE(prf->radj, r); float_to_textfield(prf->gtxt, g); ADJUSTMENT_SET_VALUE(prf->gadj, g); float_to_textfield(prf->btxt, b); ADJUSTMENT_SET_VALUE(prf->badj, b); #if GTK_CHECK_VERSION(3, 0, 0) display_color(prf->color, pixel); #else widget_modify_bg(prf->color, GTK_STATE_NORMAL, pixel); #endif } static void reflect_color(prefs_info *prf) { mus_float_t r, g, b; color_info *current_color; r = ADJUSTMENT_VALUE(prf->radj); g = ADJUSTMENT_VALUE(prf->gadj); b = ADJUSTMENT_VALUE(prf->badj); current_color = rgb_to_color(r, g, b); #if GTK_CHECK_VERSION(3, 0, 0) display_color(prf->color, current_color); #else widget_modify_bg(prf->color, GTK_STATE_NORMAL, current_color); #endif float_to_textfield(prf->rtxt, r); float_to_textfield(prf->gtxt, g); float_to_textfield(prf->btxt, b); } static void prefs_color_callback(GtkWidget *w, gpointer context) { reflect_color((prefs_info *)context); } static gint unpost_color_error(gpointer data) { prefs_info *prf = (prefs_info *)data; prf->got_error = false; gtk_label_set_text(GTK_LABEL(prf->label), prf->saved_label); reflect_color(prf); return(0); } static void errors_to_color_text(const char *msg, void *data) { prefs_info *prf = (prefs_info *)data; prf->got_error = true; gtk_label_set_text(GTK_LABEL(prf->label), msg); TIMEOUT(unpost_color_error); } static void prefs_r_callback(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; char *str; double r; str = (char *)gtk_entry_get_text(GTK_ENTRY(w)); redirect_errors_to(errors_to_color_text, context); r = (double)string_to_mus_float_t(str, 0.0, "red amount"); redirect_errors_to(NULL, NULL); if (!(prf->got_error)) { ADJUSTMENT_SET_VALUE(prf->radj, (double)mus_fclamp(0.0, r, 1.0)); reflect_color(prf); } } static void prefs_g_callback(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; char *str; double r; str = (char *)gtk_entry_get_text(GTK_ENTRY(w)); redirect_errors_to(errors_to_color_text, context); r = (double)string_to_mus_float_t(str, 0.0, "green amount"); redirect_errors_to(NULL, NULL); if (!(prf->got_error)) { ADJUSTMENT_SET_VALUE(prf->gadj, (double)mus_fclamp(0.0, r, 1.0)); reflect_color(prf); } } static void prefs_b_callback(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; char *str; double r; str = (char *)gtk_entry_get_text(GTK_ENTRY(w)); redirect_errors_to(errors_to_color_text, context); r = (double)string_to_mus_float_t(str, 0.0, "blue amount"); redirect_errors_to(NULL, NULL); if (!(prf->got_error)) { ADJUSTMENT_SET_VALUE(prf->badj, (double)mus_fclamp(0.0, r, 1.0)); reflect_color(prf); } } static void prefs_call_color_func_callback(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->color_func)) { double r, g, b; r = ADJUSTMENT_VALUE(prf->radj); g = ADJUSTMENT_VALUE(prf->gadj); b = ADJUSTMENT_VALUE(prf->badj); (*(prf->color_func))(prf, r, g, b); } } #if GTK_CHECK_VERSION(3, 92, 0) static void drawer_expose(GtkDrawingArea *w, cairo_t *cr, int width, int height, gpointer data) { prefs_info *prf = (prefs_info *)data; mus_float_t r, g, b; r = ADJUSTMENT_VALUE(prf->radj); g = ADJUSTMENT_VALUE(prf->gadj); b = ADJUSTMENT_VALUE(prf->badj); cairo_set_source_rgb(cr, r, g, b); cairo_paint(cr); } #else #if GTK_CHECK_VERSION(3, 0, 0) static gboolean drawer_expose(GtkWidget *w, GdkEventExpose *ev, gpointer data) { prefs_info *prf = (prefs_info *)data; mus_float_t r, g, b; color_info *current_color; r = ADJUSTMENT_VALUE(prf->radj); g = ADJUSTMENT_VALUE(prf->gadj); b = ADJUSTMENT_VALUE(prf->badj); current_color = rgb_to_color(r, g, b); display_color(prf->color, current_color); return(false); } #endif #endif static prefs_info *prefs_color_selector_row(const char *label, const char *varname, color_t current_pixel, GtkWidget *box, void (*color_func)(prefs_info *prf, double r, double g, double b)) { prefs_info *prf; GtkWidget *hb, *row, *row2, *sep3; double r = 0.0, g = 0.0, b = 0.0; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; pixel_to_rgb(current_pixel, &r, &g, &b); /* first row */ row = make_basic_row(box); prf->label = make_row_label(prf, label, row); hb = gtk_hbox_new(false, 0); gtk_size_group_add_widget(widgets_group, hb); sg_box_pack_start(GTK_BOX(row), hb, false, false, 0); gtk_widget_show(hb); make_row_middle_separator(hb); { GtkWidget *frame; frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); prf->color_texts = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); sg_box_pack_start(GTK_BOX(hb), frame, false, false, 4); gtk_size_group_add_widget(prf->color_texts, frame); prf->color = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER(frame), prf->color); #if GTK_CHECK_VERSION(3, 92, 0) gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(prf->color), widget_width(prf->color)); gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(prf->color), widget_height(prf->color)); gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(prf->color), drawer_expose, prf, NULL); #else #if GTK_CHECK_VERSION(3, 0, 0) SG_SIGNAL_CONNECT(prf->color, DRAW_SIGNAL, drawer_expose, prf); gtk_widget_set_hexpand(GTK_WIDGET(prf->color), true); gtk_widget_set_vexpand(GTK_WIDGET(prf->color), true); #else widget_modify_bg(prf->color, GTK_STATE_NORMAL, current_pixel); #endif #endif gtk_widget_show(prf->color); gtk_widget_show(frame); } make_row_inner_separator(8, hb); prf->rtxt = make_row_text(prf, NULL, 6, hb); gtk_size_group_add_widget(prf->color_texts, prf->rtxt); float_to_textfield(prf->rtxt, r); prf->gtxt = make_row_text(prf, NULL, 6, hb); gtk_size_group_add_widget(prf->color_texts, prf->gtxt); float_to_textfield(prf->gtxt, g); prf->btxt = make_row_text(prf, NULL, 6, hb); gtk_size_group_add_widget(prf->color_texts, prf->btxt); float_to_textfield(prf->btxt, b); /* second row */ row2 = gtk_hbox_new(false, 0); sg_box_pack_start(GTK_BOX(box), row2, false, false, 0); gtk_widget_show(row2); make_row_inner_separator(20, row2); prf->radj = (GtkAdjustment *)gtk_adjustment_new(r, 0.0, 1.01, 0.001, 0.01, .01); prf->rscl = gtk_hscale_new(GTK_ADJUSTMENT(prf->radj)); gtk_widget_set_name(prf->rscl, "prefs_color_scale"); sg_box_pack_start(GTK_BOX(row2), prf->rscl, true, true, 4); #if (!GTK_CHECK_VERSION(3, 0, 0)) widget_modify_bg(prf->rscl, GTK_STATE_NORMAL, rscl_color); /* this is the slider except when clicked */ widget_modify_bg(prf->rscl, GTK_STATE_PRELIGHT, rscl_color); /* this is the slider when clicked */ #else add_red_scale_style(prf->rscl); #endif gtk_widget_show(prf->rscl); gtk_range_set_update_policy(GTK_RANGE(GTK_SCALE(prf->rscl)), GTK_UPDATE_CONTINUOUS); gtk_scale_set_draw_value(GTK_SCALE(prf->rscl), false); prf->gadj = (GtkAdjustment *)gtk_adjustment_new(g, 0.0, 1.01, 0.001, 0.01, .01); prf->gscl = gtk_hscale_new(GTK_ADJUSTMENT(prf->gadj)); gtk_widget_set_name(prf->gscl, "prefs_color_scale"); sg_box_pack_start(GTK_BOX(row2), prf->gscl, true, true, 4); #if (!GTK_CHECK_VERSION(3, 0, 0)) widget_modify_bg(prf->gscl, GTK_STATE_NORMAL, gscl_color); widget_modify_bg(prf->gscl, GTK_STATE_PRELIGHT, gscl_color); #else add_green_scale_style(prf->gscl); #endif gtk_widget_show(prf->gscl); gtk_range_set_update_policy(GTK_RANGE(GTK_SCALE(prf->gscl)), GTK_UPDATE_CONTINUOUS); gtk_scale_set_draw_value(GTK_SCALE(prf->gscl), false); prf->badj = (GtkAdjustment *)gtk_adjustment_new(b, 0.0, 1.01, 0.001, 0.01, .01); prf->bscl = gtk_hscale_new(GTK_ADJUSTMENT(prf->badj)); gtk_widget_set_name(prf->bscl, "prefs_color_scale"); sg_box_pack_start(GTK_BOX(row2), prf->bscl, true, true, 4); #if (!GTK_CHECK_VERSION(3, 0, 0)) widget_modify_bg(prf->bscl, GTK_STATE_NORMAL, bscl_color); widget_modify_bg(prf->bscl, GTK_STATE_PRELIGHT, bscl_color); #else add_blue_scale_style(prf->bscl); #endif gtk_widget_show(prf->bscl); gtk_range_set_update_policy(GTK_RANGE(GTK_SCALE(prf->bscl)), GTK_UPDATE_CONTINUOUS); gtk_scale_set_draw_value(GTK_SCALE(prf->bscl), false); sep3 = gtk_hseparator_new(); sg_box_pack_end(GTK_BOX(row2), sep3, false, false, 20); gtk_widget_show(sep3); SG_SIGNAL_CONNECT(prf->rtxt, "activate", prefs_r_callback, (gpointer)prf); SG_SIGNAL_CONNECT(prf->gtxt, "activate", prefs_g_callback, (gpointer)prf); SG_SIGNAL_CONNECT(prf->btxt, "activate", prefs_b_callback, (gpointer)prf); SG_SIGNAL_CONNECT(prf->radj, "value_changed", prefs_call_color_func_callback, (gpointer)prf); SG_SIGNAL_CONNECT(prf->gadj, "value_changed", prefs_call_color_func_callback, (gpointer)prf); SG_SIGNAL_CONNECT(prf->badj, "value_changed", prefs_call_color_func_callback, (gpointer)prf); SG_SIGNAL_CONNECT(prf->radj, "value_changed", prefs_change_callback, NULL); SG_SIGNAL_CONNECT(prf->gadj, "value_changed", prefs_change_callback, NULL); SG_SIGNAL_CONNECT(prf->badj, "value_changed", prefs_change_callback, NULL); SG_SIGNAL_CONNECT(prf->radj, "value_changed", prefs_color_callback, (gpointer)prf); SG_SIGNAL_CONNECT(prf->gadj, "value_changed", prefs_color_callback, (gpointer)prf); SG_SIGNAL_CONNECT(prf->badj, "value_changed", prefs_color_callback, (gpointer)prf); prf->color_func = color_func; return(prf); } /* ---------------- topic separator ---------------- */ static void make_inter_topic_separator(GtkWidget *topics) { GtkWidget *w; w = gtk_hseparator_new(); sg_box_pack_start(GTK_BOX(topics), w, false, false, 0); gtk_widget_show(w); /* height = INTER_TOPIC_SPACE no line */ } /* ---------------- variable separator ---------------- */ static void make_inter_variable_separator(GtkWidget *topics) { GtkWidget *w; w = gtk_hseparator_new(); sg_box_pack_start(GTK_BOX(topics), w, false, false, 0); gtk_widget_show(w); /* height = INTER_VARIABLE_SPACE no line */ } /* ---------------- top-level contents label ---------------- */ static void make_top_level_label(const char *label, GtkWidget *parent) { GtkWidget *w1, *w2, *w3; char *str; w1 = gtk_vseparator_new(); sg_box_pack_start(GTK_BOX(parent), w1, false, false, 6); gtk_widget_show(w1); str = mus_format("%s", label); #if (!GTK_CHECK_VERSION(3, 0, 0)) w2 = gtk_label_new(label); gtk_label_set_markup(GTK_LABEL(w2), str); gtk_label_set_use_markup(GTK_LABEL(w2), true); gtk_misc_set_alignment(GTK_MISC(w2), 0.01, 0.5); #else w2 = gtk_button_new_with_label(label); add_highlight_button_style(w2); gtk_label_set_markup(GTK_LABEL(BIN_CHILD(w2)), str); gtk_label_set_use_markup(GTK_LABEL(BIN_CHILD(w2)), true); #if GTK_CHECK_VERSION(3, 14, 0) gtk_widget_set_halign(GTK_WIDGET(w2), GTK_ALIGN_START); #else gtk_misc_set_alignment(GTK_MISC(BIN_CHILD(w2)), 0.01, 0.5); #endif #endif free(str); sg_box_pack_start(GTK_BOX(parent), w2, false, false, 0); gtk_widget_show(w2); w3 = gtk_vseparator_new(); sg_box_pack_start(GTK_BOX(parent), w3, false, false, 6); gtk_widget_show(w3); make_inter_variable_separator(parent); } static GtkWidget *make_top_level_box(GtkWidget *topics) { GtkWidget *w, *frame; frame = gtk_frame_new(NULL); sg_box_pack_start(GTK_BOX(topics), frame, true, true, 0); gtk_widget_show(frame); w = gtk_vbox_new(false, 2); gtk_container_add(GTK_CONTAINER(frame), w); gtk_widget_show(w); return(w); } static void make_inner_label(const char *label, GtkWidget *parent) { GtkWidget *w, *w1, *w2; char *str; w1 = gtk_vseparator_new(); sg_box_pack_start(GTK_BOX(parent), w1, false, false, 4); gtk_widget_show(w1); str = mus_format("%s", label); #if (!GTK_CHECK_VERSION(3, 0, 0)) w = gtk_label_new(label); gtk_label_set_markup(GTK_LABEL(w), str); gtk_label_set_use_markup(GTK_LABEL(w), true); gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5); #else w = gtk_button_new_with_label(label); add_highlight_button_style(w); gtk_label_set_markup(GTK_LABEL(BIN_CHILD(w)), str); gtk_label_set_use_markup(GTK_LABEL(BIN_CHILD(w)), true); #if GTK_CHECK_VERSION(3, 14, 0) gtk_widget_set_halign(GTK_WIDGET(w), GTK_ALIGN_START); #else gtk_misc_set_alignment(GTK_MISC(BIN_CHILD(w)), 0.0, 0.5); #endif #endif free(str); sg_box_pack_start(GTK_BOX(parent), w, false, false, 0); gtk_widget_show(w); w2 = gtk_vseparator_new(); sg_box_pack_start(GTK_BOX(parent), w2, false, false, 4); gtk_widget_show(w2); make_inter_variable_separator(parent); } /* ---------------- base buttons ---------------- */ static gint preferences_delete_callback(GtkWidget *w, GdkEvent *event, gpointer context) { clear_prefs_dialog_error(); gtk_widget_hide(preferences_dialog); return(true); } static void preferences_dismiss_callback(GtkWidget *w, gpointer context) { clear_prefs_dialog_error(); gtk_widget_hide(preferences_dialog); } static void preferences_help_callback(GtkWidget *w, gpointer context) { snd_help("preferences", "This dialog sets various global variables. 'Save' then writes the new values \ to ~/.snd_prefs_ruby|forth|s7 so that they take effect the next time you start Snd. 'Revert' resets each variable either to \ its value when the Preferences dialog was started, or to the last saved value. 'Clear' resets each variable to its default value (its \ value when Snd starts, before loading initialization files). 'Help' starts this dialog, and as long as it's active, it will post helpful \ information if the mouse lingers over some variable -- sort of a tooltip that stays out of your way. \ You can also request help on a given topic by clicking the variable name on the far right.", WITH_WORD_WRAP); } static void prefs_set_dialog_title(const char *filename) { char *str; if (filename) { if (prefs_saved_filename) free(prefs_saved_filename); prefs_saved_filename = mus_strdup(filename); } if (prefs_saved_filename) str = mus_format("Preferences%s (saved in %s)\n", (prefs_unsaved) ? "*" : "", prefs_saved_filename); else str = mus_format("Preferences%s", (prefs_unsaved) ? "*" : ""); gtk_window_set_title(GTK_WINDOW(preferences_dialog), str); free(str); } static void preferences_revert_callback(GtkWidget *w, gpointer context) { preferences_revert_or_clear(true); } static void preferences_clear_callback(GtkWidget *w, gpointer context) { preferences_revert_or_clear(false); } #if HAVE_EXTENSION_LANGUAGE static void preferences_save_callback(GtkWidget *w, gpointer context) { clear_prefs_dialog_error(); redirect_snd_error_to(post_prefs_dialog_error, NULL); redirect_snd_warning_to(post_prefs_dialog_error, NULL); save_prefs(); redirect_snd_error_to(NULL, NULL); redirect_snd_warning_to(NULL, NULL); } #endif /* ---------------- errors ---------------- */ static void clear_prefs_error(GtkWidget *w, gpointer context) { prefs_info *prf = (prefs_info *)context; g_signal_handler_disconnect(prf->text, prf->erase_id); prf->erase_id = 0; set_label(prf->error, ""); } static void post_prefs_error(const char *msg, prefs_info *prf) { prf->got_error = true; set_label(prf->error, msg); if (prf->erase_id != 0) g_signal_handler_disconnect(prf->text, prf->erase_id); prf->erase_id = SG_SIGNAL_CONNECT(prf->text, "changed", clear_prefs_error, (gpointer)prf); } static void va_post_prefs_error(const char *msg, prefs_info *data, ...) { char *buf; va_list ap; va_start(ap, data); buf = vstr(msg, ap); va_end(ap); post_prefs_error(buf, data); free(buf); } /* ---------------- preferences dialog ---------------- */ widget_t make_preferences_dialog(void) { GtkWidget *save_button, *revert_button, *clear_button, *help_button, *dismiss_button, *topics, *scroller; prefs_info *prf; char *str; if (preferences_dialog) { gtk_widget_show(preferences_dialog); return(preferences_dialog); } preferences_dialog = snd_gtk_dialog_new(); #if GTK_CHECK_VERSION(3, 14, 0) gtk_window_set_transient_for(GTK_WINDOW(preferences_dialog), GTK_WINDOW(main_shell(ss))); #endif gtk_window_set_title(GTK_WINDOW(preferences_dialog), "Preferences"); sg_make_resizable(preferences_dialog); /* sg_container_set_border_width (GTK_CONTAINER(preferences_dialog), 10); */ gtk_widget_realize(preferences_dialog); #if (!GTK_CHECK_VERSION(3, 22, 0)) if ((STARTUP_WIDTH < gdk_screen_width()) && (STARTUP_HEIGHT < gdk_screen_height())) #endif gtk_window_resize(GTK_WINDOW(preferences_dialog), STARTUP_WIDTH, STARTUP_HEIGHT); help_button = gtk_dialog_add_button(GTK_DIALOG(preferences_dialog), "Help", GTK_RESPONSE_NONE); revert_button = gtk_dialog_add_button(GTK_DIALOG(preferences_dialog), "Revert", GTK_RESPONSE_NONE); clear_button = gtk_dialog_add_button(GTK_DIALOG(preferences_dialog), "Clear", GTK_RESPONSE_NONE); dismiss_button = gtk_dialog_add_button(GTK_DIALOG(preferences_dialog), "Go away", GTK_RESPONSE_NONE); #if HAVE_EXTENSION_LANGUAGE save_button = gtk_dialog_add_button(GTK_DIALOG(preferences_dialog), "Save", GTK_RESPONSE_NONE); gtk_widget_set_name(save_button, "dialog_button"); #endif gtk_widget_set_name(help_button, "dialog_button"); gtk_widget_set_name(revert_button, "dialog_button"); gtk_widget_set_name(clear_button, "dialog_button"); gtk_widget_set_name(dismiss_button, "dialog_button"); #if GTK_CHECK_VERSION(3, 0, 0) add_highlight_button_style(dismiss_button); add_highlight_button_style(revert_button); add_highlight_button_style(clear_button); #if HAVE_EXTENSION_LANGUAGE add_highlight_button_style(save_button); #endif add_highlight_button_style(help_button); #endif SG_SIGNAL_CONNECT(preferences_dialog, "delete_event", preferences_delete_callback, NULL); SG_SIGNAL_CONNECT(dismiss_button, "clicked", preferences_dismiss_callback, NULL); SG_SIGNAL_CONNECT(revert_button, "clicked", preferences_revert_callback, NULL); SG_SIGNAL_CONNECT(clear_button, "clicked", preferences_clear_callback, NULL); #if HAVE_EXTENSION_LANGUAGE SG_SIGNAL_CONNECT(save_button, "clicked", preferences_save_callback, NULL); #endif SG_SIGNAL_CONNECT(help_button, "clicked", preferences_help_callback, NULL); gtk_widget_show(dismiss_button); #if HAVE_EXTENSION_LANGUAGE gtk_widget_show(save_button); #endif gtk_widget_show(revert_button); gtk_widget_show(clear_button); gtk_widget_show(help_button); topics = gtk_vbox_new(false, 0); scroller = gtk_scrolled_window_new(NULL, NULL); sg_box_pack_start(GTK_BOX(DIALOG_CONTENT_AREA(preferences_dialog)), scroller, true, true, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); #if HAVE_GTK_HEADER_BAR_NEW gtk_container_add(GTK_CONTAINER(scroller), topics); #else gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroller), topics); #endif gtk_widget_show(topics); gtk_widget_show(scroller); label_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); widgets_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); #if 0 /* these are really garish */ rscl_color = rgb_to_color(1.0, 0.0, 0.0); gscl_color = rgb_to_color(0.0, 1.0, 0.0); bscl_color = rgb_to_color(0.0, 0.0, 1.0); #else rscl_color = rgb_to_color(1.0, 0.4, 0.4); gscl_color = rgb_to_color(0.56, 1.0, 0.56); bscl_color = rgb_to_color(0.68, 0.84, 1.0); #endif /* ---------------- overall behavior ---------------- */ { GtkWidget *dpy_box; char *str1, *str2; /* ---------------- overall behavior ----------------*/ dpy_box = make_top_level_box(topics); make_top_level_label("overall behavior choices", dpy_box); str1 = mus_format("%d", ss->init_window_width); str2 = mus_format("%d", ss->init_window_height); rts_init_window_width = ss->init_window_width; rts_init_window_height = ss->init_window_height; prf = prefs_row_with_two_texts("start up size", S_window_width, "width:", str1, "height:", str2, 6, dpy_box, startup_size_text); remember_pref(prf, reflect_init_window_size, save_init_window_size, help_init_window_size, clear_init_window_size, revert_init_window_size); free(str2); free(str1); make_inter_variable_separator(dpy_box); prf = prefs_row_with_toggle("ask before overwriting anything", S_ask_before_overwrite, rts_ask_before_overwrite = ask_before_overwrite(ss), dpy_box, overwrite_toggle); remember_pref(prf, reflect_ask_before_overwrite, save_ask_before_overwrite, help_ask_before_overwrite, NULL, revert_ask_before_overwrite); make_inter_variable_separator(dpy_box); prf = prefs_row_with_toggle("ask about unsaved edits before exiting", S_ask_about_unsaved_edits, rts_unsaved_edits = ask_about_unsaved_edits(ss), dpy_box, unsaved_edits_toggle); remember_pref(prf, reflect_unsaved_edits, save_unsaved_edits, help_unsaved_edits, clear_unsaved_edits, revert_unsaved_edits); make_inter_variable_separator(dpy_box); prf = prefs_row_with_toggle("include thumbnail graph in upper right corner", S_with_inset_graph, rts_with_inset_graph = with_inset_graph(ss), dpy_box, with_inset_graph_toggle); remember_pref(prf, reflect_with_inset_graph, save_with_inset_graph, help_inset_graph, clear_with_inset_graph, revert_with_inset_graph); make_inter_variable_separator(dpy_box); prf = prefs_row_with_toggle("resize main window as sounds open and close", S_auto_resize, rts_auto_resize = auto_resize(ss), dpy_box, resize_toggle); remember_pref(prf, reflect_auto_resize, save_auto_resize, help_auto_resize, NULL, revert_auto_resize); make_inter_variable_separator(dpy_box); prf = prefs_row_with_toggle("pointer focus", S_with_pointer_focus, rts_with_pointer_focus = with_pointer_focus(ss), dpy_box, with_pointer_focus_toggle); remember_pref(prf, reflect_with_pointer_focus, save_with_pointer_focus, help_pointer_focus, clear_with_pointer_focus, revert_with_pointer_focus); make_inter_variable_separator(dpy_box); rts_sync_style = sync_style(ss); prf = prefs_row_with_two_toggles("operate on all channels together", S_sync, "within each sound", rts_sync_style == SYNC_BY_SOUND, "across all sounds", rts_sync_style == SYNC_ALL, dpy_box, sync1_choice, sync2_choice); remember_pref(prf, reflect_sync_style, save_sync_style, help_sync_style, clear_sync_style, revert_sync_style); make_inter_variable_separator(dpy_box); rts_remember_sound_state = remember_sound_state(ss); prf = prefs_row_with_toggle("restore a sound's state if reopened later", S_remember_sound_state, rts_remember_sound_state, dpy_box, toggle_remember_sound_state); remember_pref(prf, reflect_remember_sound_state, save_remember_sound_state, help_remember_sound_state, clear_remember_sound_state, revert_remember_sound_state); make_inter_variable_separator(dpy_box); prf = prefs_row_with_toggle("show the control panel upon opening a sound", S_show_controls, rts_show_controls = in_show_controls(ss), dpy_box, controls_toggle); remember_pref(prf, reflect_show_controls, save_show_controls, help_show_controls, NULL, revert_show_controls); make_inter_variable_separator(dpy_box); include_peak_env_directory = mus_strdup(peak_env_dir(ss)); rts_peak_env_directory = mus_strdup(include_peak_env_directory); include_peak_envs = find_peak_envs(); rts_peak_envs = include_peak_envs; prf = prefs_row_with_toggle_with_text("save peak envs to speed up initial display", S_peak_env_dir, include_peak_envs, "directory:", include_peak_env_directory, 25, dpy_box, peak_envs_toggle, peak_envs_text); remember_pref(prf, reflect_peak_envs, save_peak_envs, help_peak_envs, clear_peak_envs, revert_peak_envs); make_inter_variable_separator(dpy_box); str = mus_format("%d", rts_max_regions = max_regions(ss)); prf = prefs_row_with_toggle_with_text("selection creates an associated region", S_selection_creates_region, rts_selection_creates_region = selection_creates_region(ss), "max regions:", str, 5, dpy_box, selection_creates_region_toggle, max_regions_text); remember_pref(prf, reflect_selection_creates_region, save_selection_creates_region, help_selection_creates_region, NULL, revert_selection_creates_region); free(str); make_inter_variable_separator(dpy_box); rts_with_toolbar = with_toolbar(ss); prf = prefs_row_with_toggle("include a toolbar", S_with_toolbar, rts_with_toolbar, dpy_box, toggle_with_toolbar); remember_pref(prf, reflect_with_toolbar, save_with_toolbar, help_with_toolbar, clear_with_toolbar, revert_with_toolbar); make_inter_variable_separator(dpy_box); rts_with_tooltips = with_tooltips(ss); prf = prefs_row_with_toggle("enable tooltips", S_with_tooltips, rts_with_tooltips, dpy_box, toggle_with_tooltips); remember_pref(prf, reflect_with_tooltips, save_with_tooltips, help_with_tooltips, clear_with_tooltips, revert_with_tooltips); make_inter_variable_separator(dpy_box); rts_with_menu_icons = with_menu_icons(ss); prf = prefs_row_with_toggle("enable menu icons (gtk only)", S_with_menu_icons, rts_with_menu_icons, dpy_box, toggle_with_menu_icons); remember_pref(prf, reflect_with_menu_icons, save_with_menu_icons, help_with_menu_icons, clear_with_menu_icons, revert_with_menu_icons); /* ---------------- file options ---------------- */ make_inter_variable_separator(dpy_box); make_inner_label(" file options", dpy_box); rts_load_path = find_sources(); prf = prefs_row_with_text("directory containing Snd's " Xen_language " files", "load path", rts_load_path, dpy_box, load_path_text); remember_pref(prf, reflect_load_path, NULL, help_load_path, clear_load_path, revert_load_path); load_path_text_widget = prf->text; make_inter_variable_separator(dpy_box); prf = prefs_row_with_toggle("display only sound files in various file lists", S_just_sounds, rts_just_sounds = just_sounds(ss), dpy_box, just_sounds_toggle); remember_pref(prf, prefs_reflect_just_sounds, save_just_sounds, help_just_sounds, NULL, revert_just_sounds); make_inter_variable_separator(dpy_box); rts_temp_dir = mus_strdup(temp_dir(ss)); prf = prefs_row_with_text("directory for temporary files", S_temp_dir, temp_dir(ss), dpy_box, temp_dir_text); remember_pref(prf, reflect_temp_dir, save_temp_dir, help_temp_dir, NULL, revert_temp_dir); make_inter_variable_separator(dpy_box); rts_save_dir = mus_strdup(save_dir(ss)); prf = prefs_row_with_text("directory for save-state files", S_save_dir, save_dir(ss), dpy_box, save_dir_text); remember_pref(prf, reflect_save_dir, save_save_dir, help_save_dir, NULL, revert_save_dir); make_inter_variable_separator(dpy_box); rts_save_state_file = mus_strdup(save_state_file(ss)); prf = prefs_row_with_text("default save-state filename", S_save_state_file, save_state_file(ss), dpy_box, save_state_file_text); remember_pref(prf, reflect_save_state_file, save_save_state_file, help_save_state_file, NULL, revert_save_state_file); #if HAVE_LADSPA make_inter_variable_separator(dpy_box); rts_ladspa_dir = mus_strdup(ladspa_dir(ss)); prf = prefs_row_with_text("directory for ladspa plugins", S_ladspa_dir, ladspa_dir(ss), dpy_box, ladspa_dir_text); remember_pref(prf, reflect_ladspa_dir, save_ladspa_dir, help_ladspa_dir, NULL, revert_ladspa_dir); #endif make_inter_variable_separator(dpy_box); rts_html_program = mus_strdup(html_program(ss)); prf = prefs_row_with_text("external program to read HTML files via snd-help", S_html_program, html_program(ss), dpy_box, html_program_text); remember_pref(prf, reflect_html_program, save_html_program, help_html_program, NULL, revert_html_program); make_inter_variable_separator(dpy_box); rts_default_output_chans = default_output_chans(ss); prf = prefs_row_with_radio_box("default new sound attributes: chans", S_default_output_chans, output_chan_choices, NUM_OUTPUT_CHAN_CHOICES, -1, dpy_box, default_output_chans_choice); remember_pref(prf, reflect_default_output_chans, save_default_output_chans, help_default_output_chans, NULL, revert_default_output_chans); reflect_default_output_chans(prf); rts_default_output_srate = default_output_srate(ss); prf = prefs_row_with_radio_box("srate", S_default_output_srate, output_srate_choices, NUM_OUTPUT_SRATE_CHOICES, -1, dpy_box, default_output_srate_choice); remember_pref(prf, reflect_default_output_srate, save_default_output_srate, help_default_output_srate, NULL, revert_default_output_srate); reflect_default_output_srate(prf); rts_default_output_header_type = default_output_header_type(ss); prf = prefs_row_with_radio_box("header type", S_default_output_header_type, output_header_type_choices, NUM_OUTPUT_HEADER_TYPE_CHOICES, -1, dpy_box, default_output_header_type_choice); output_header_type_prf = prf; remember_pref(prf, reflect_default_output_header_type, save_default_output_header_type, help_default_output_header_type, NULL, revert_default_output_header_type); rts_default_output_sample_type = default_output_sample_type(ss); prf = prefs_row_with_radio_box("sample type", S_default_output_sample_type, output_sample_type_choices, NUM_OUTPUT_SAMPLE_TYPE_CHOICES, -1, dpy_box, default_output_sample_type_choice); output_sample_type_prf = prf; remember_pref(prf, reflect_default_output_sample_type, save_default_output_sample_type, help_default_output_sample_type, NULL, revert_default_output_sample_type); reflect_default_output_header_type(output_header_type_prf); reflect_default_output_sample_type(output_sample_type_prf); make_inter_variable_separator(dpy_box); { int i, srate = 0, chans = 0; mus_sample_t samp_type = MUS_UNKNOWN_SAMPLE; mus_header_raw_defaults(&srate, &chans, &samp_type); str = mus_format("%d", chans); str1 = mus_format("%d", srate); rts_raw_chans = chans; rts_raw_srate = srate; rts_raw_sample_type = samp_type; raw_sample_type_choices = (char **)calloc(MUS_NUM_SAMPLES - 1, sizeof(char *)); for (i = 1; i < MUS_NUM_SAMPLES; i++) raw_sample_type_choices[i - 1] = raw_sample_type_to_string((mus_sample_t)i); /* skip MUS_UNKNOWN_SAMPLE = 0 */ prf = prefs_row_with_text("default raw sound attributes: chans", S_mus_header_raw_defaults, str, dpy_box, raw_chans_choice); remember_pref(prf, reflect_raw_chans, save_raw_chans, help_raw_chans, NULL, revert_raw_chans); prf = prefs_row_with_text("srate", S_mus_header_raw_defaults, str1, dpy_box, raw_srate_choice); remember_pref(prf, reflect_raw_srate, save_raw_srate, help_raw_srate, NULL, revert_raw_srate); free(str); free(str1); prf = prefs_row_with_list("sample type", S_mus_header_raw_defaults, raw_sample_type_choices[samp_type - 1], (const char **)raw_sample_type_choices, MUS_NUM_SAMPLES - 1, dpy_box, raw_sample_type_from_text, NULL, NULL); remember_pref(prf, reflect_raw_sample_type, save_raw_sample_type, help_raw_sample_type, NULL, revert_raw_sample_type); } make_inter_variable_separator(dpy_box); /* ---------------- additional keys ---------------- */ { key_info *ki; make_inner_label(" additional keys", dpy_box); ki = find_prefs_key("play-from-cursor"); prf = prefs_row_with_text_and_three_toggles("play all chans from cursor", S_play, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, bind_play_from_cursor); remember_pref(prf, reflect_play_from_cursor, save_pfc, help_play_from_cursor, clear_play_from_cursor, NULL); free(ki); make_inter_variable_separator(dpy_box); ki = find_prefs_key("show-all"); prf = prefs_row_with_text_and_three_toggles("show entire sound", S_x_bounds, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, bind_show_all); remember_pref(prf, reflect_show_all, save_show_all, help_show_all, clear_show_all, NULL); free(ki); make_inter_variable_separator(dpy_box); ki = find_prefs_key("select-all"); prf = prefs_row_with_text_and_three_toggles("select entire sound", S_select_all, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, bind_select_all); remember_pref(prf, reflect_select_all, save_select_all, help_select_all, clear_select_all, NULL); free(ki); make_inter_variable_separator(dpy_box); ki = find_prefs_key("show-selection"); prf = prefs_row_with_text_and_three_toggles("show current selection", "show-selection", "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, bind_show_selection); remember_pref(prf, reflect_show_selection, save_show_selection, help_show_selection, clear_show_selection, NULL); free(ki); make_inter_variable_separator(dpy_box); ki = find_prefs_key("revert-sound"); prf = prefs_row_with_text_and_three_toggles("undo all edits (revert)", S_revert_sound, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, bind_revert); remember_pref(prf, reflect_revert, save_revert, help_revert, clear_revert_sound, NULL); free(ki); make_inter_variable_separator(dpy_box); ki = find_prefs_key("exit"); prf = prefs_row_with_text_and_three_toggles("exit from Snd", S_exit, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, bind_exit); remember_pref(prf, reflect_exit, save_exit, help_exit, clear_exit, NULL); free(ki); make_inter_variable_separator(dpy_box); ki = find_prefs_key("goto-maxamp"); prf = prefs_row_with_text_and_three_toggles("move cursor to channel's maximum sample", S_maxamp_position, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, bind_goto_maxamp); remember_pref(prf, reflect_goto_maxamp, save_goto_maxamp, help_goto_maxamp, clear_goto_maxamp, NULL); free(ki); } /* ---------------- cursor options ---------------- */ make_inter_variable_separator(dpy_box); make_inner_label(" cursor options", dpy_box); prf = prefs_row_with_toggle("report cursor location as it moves", S_with_verbose_cursor, rts_with_verbose_cursor = with_verbose_cursor(ss), dpy_box, with_verbose_cursor_toggle); remember_pref(prf, reflect_with_verbose_cursor, save_with_verbose_cursor, help_with_verbose_cursor, NULL, revert_with_verbose_cursor); make_inter_variable_separator(dpy_box); { char *str1; str = mus_format("%.2f", rts_cursor_update_interval = cursor_update_interval(ss)); str1 = mus_format("%d", rts_cursor_location_offset = cursor_location_offset(ss)); prf = prefs_row_with_toggle_with_two_texts("track current location while playing", S_with_tracking_cursor, (rts_with_tracking_cursor = with_tracking_cursor(ss)), "update:", str, "offset:", str1, 8, dpy_box, with_tracking_cursor_toggle, cursor_location_text); remember_pref(prf, reflect_with_tracking_cursor, save_with_tracking_cursor, help_with_tracking_cursor, NULL, revert_with_tracking_cursor); free(str); free(str1); } make_inter_variable_separator(dpy_box); str = mus_format("%d", rts_cursor_size = cursor_size(ss)); prf = prefs_row_with_number("size", S_cursor_size, str, 4, dpy_box, cursor_size_up, cursor_size_down, cursor_size_from_text); remember_pref(prf, reflect_cursor_size, save_cursor_size, help_cursor_size, NULL, revert_cursor_size); free(str); if (cursor_size(ss) <= 0) gtk_widget_set_sensitive(prf->arrow_down, false); make_inter_variable_separator(dpy_box); prf = prefs_row_with_radio_box("shape", S_cursor_style, cursor_styles, NUM_CURSOR_STYLES, rts_cursor_style = cursor_style(ss), dpy_box, cursor_style_choice); remember_pref(prf, reflect_cursor_style, save_cursor_style, help_cursor_style, NULL, revert_cursor_style); make_inter_variable_separator(dpy_box); prf = prefs_row_with_radio_box("tracking cursor shape", S_tracking_cursor_style, cursor_styles, NUM_CURSOR_STYLES, rts_tracking_cursor_style = tracking_cursor_style(ss), dpy_box, tracking_cursor_style_choice); remember_pref(prf, reflect_tracking_cursor_style, save_tracking_cursor_style, help_tracking_cursor_style, NULL, revert_tracking_cursor_style); make_inter_variable_separator(dpy_box); saved_cursor_color = ss->cursor_color; prf = prefs_color_selector_row("color", S_cursor_color, ss->cursor_color, dpy_box, cursor_color_func); remember_pref(prf, NULL, save_cursor_color, help_cursor_color, clear_cursor_color, revert_cursor_color); /* ---------------- (overall) colors ---------------- */ make_inter_variable_separator(dpy_box); make_inner_label(" colors", dpy_box); saved_basic_color = ss->basic_color; prf = prefs_color_selector_row("main background color", S_basic_color, ss->basic_color, dpy_box, basic_color_func); remember_pref(prf, NULL, save_basic_color, help_basic_color, clear_basic_color, revert_basic_color); make_inter_variable_separator(dpy_box); saved_highlight_color = ss->highlight_color; prf = prefs_color_selector_row("main highlight color", S_highlight_color, ss->highlight_color, dpy_box, highlight_color_func); remember_pref(prf, NULL, save_highlight_color, help_highlight_color, clear_highlight_color, revert_highlight_color); make_inter_variable_separator(dpy_box); saved_position_color = ss->position_color; prf = prefs_color_selector_row("second highlight color", S_position_color, ss->position_color, dpy_box, position_color_func); remember_pref(prf, NULL, save_position_color, help_position_color, clear_position_color, revert_position_color); make_inter_variable_separator(dpy_box); saved_zoom_color = ss->zoom_color; prf = prefs_color_selector_row("third highlight color", S_zoom_color, ss->zoom_color, dpy_box, zoom_color_func); remember_pref(prf, NULL, save_zoom_color, help_zoom_color, clear_zoom_color, revert_zoom_color); } make_inter_topic_separator(topics); /* -------- graphs -------- */ { GtkWidget *grf_box; /* ---------------- graph options ---------------- */ grf_box = make_top_level_box(topics); make_top_level_label("graph options", grf_box); prf = prefs_row_with_radio_box("how to connect the dots", S_graph_style, graph_styles, NUM_GRAPH_STYLES, rts_graph_style = graph_style(ss), grf_box, graph_style_choice); remember_pref(prf, reflect_graph_style, save_graph_style, help_graph_style, NULL, revert_graph_style); make_inter_variable_separator(grf_box); str = mus_format("%d", rts_dot_size = dot_size(ss)); prf = prefs_row_with_number("dot size", S_dot_size, str, 4, grf_box, dot_size_up, dot_size_down, dot_size_from_text); remember_pref(prf, reflect_dot_size, save_dot_size, help_dot_size, NULL, revert_dot_size); free(str); if (dot_size(ss) <= 0) gtk_widget_set_sensitive(prf->arrow_down, false); make_inter_variable_separator(grf_box); rts_initial_beg = initial_beg(ss); rts_initial_dur = initial_dur(ss); str = mus_format("%.2f : %.2f", rts_initial_beg, rts_initial_dur); prf = prefs_row_with_text_with_toggle("initial graph x bounds", S_initial_graph_hook, (rts_full_duration = show_full_duration(ss)), "show full duration", str, 16, grf_box, initial_bounds_toggle, initial_bounds_text); free(str); remember_pref(prf, reflect_initial_bounds, save_initial_bounds, help_initial_bounds, clear_initial_bounds, revert_initial_bounds); make_inter_variable_separator(grf_box); prf = prefs_row_with_radio_box("how to layout multichannel graphs", S_channel_style, channel_styles, NUM_CHANNEL_STYLES, rts_channel_style = channel_style(ss), grf_box, channel_style_choice); remember_pref(prf, reflect_channel_style, save_channel_style, help_channel_style, NULL, revert_channel_style); make_inter_variable_separator(grf_box); prf = prefs_row_with_toggle("layout wave and fft graphs horizontally", S_graphs_horizontal, rts_graphs_horizontal = graphs_horizontal(ss), grf_box, graphs_horizontal_toggle); remember_pref(prf, reflect_graphs_horizontal, save_graphs_horizontal, help_graphs_horizontal, NULL, revert_graphs_horizontal); make_inter_variable_separator(grf_box); prf = prefs_row_with_toggle("include y=0 line in sound graphs", S_show_y_zero, rts_show_y_zero = show_y_zero(ss), grf_box, y_zero_toggle); remember_pref(prf, reflect_show_y_zero, save_show_y_zero, help_show_y_zero, NULL, revert_show_y_zero); make_inter_variable_separator(grf_box); rts_show_grid = show_grid(ss); prf = prefs_row_with_toggle("include a grid in sound graphs", S_show_grid, rts_show_grid == WITH_GRID, grf_box, grid_toggle); remember_pref(prf, reflect_show_grid, save_show_grid, help_show_grid, NULL, revert_show_grid); make_inter_variable_separator(grf_box); prf = prefs_row_with_scale("grid density", S_grid_density, 2.0, rts_grid_density = grid_density(ss), grf_box, grid_density_scale_callback, grid_density_text_callback); remember_pref(prf, reflect_grid_density, save_grid_density, help_grid_density, NULL, revert_grid_density); make_inter_variable_separator(grf_box); rts_show_axes = show_axes(ss); prf = prefs_row_with_list("what axes to display", S_show_axes, show_axes_choices[(int)rts_show_axes], show_axes_choices, NUM_SHOW_AXES, grf_box, show_axes_from_text, NULL, NULL); remember_pref(prf, reflect_show_axes, save_show_axes, help_show_axes, clear_show_axes, revert_show_axes); make_inter_variable_separator(grf_box); rts_x_axis_style = x_axis_style(ss); prf = prefs_row_with_list("time division", S_x_axis_style, x_axis_styles[(int)rts_x_axis_style], x_axis_styles, NUM_X_AXIS_STYLES, grf_box, x_axis_style_from_text, NULL, NULL); remember_pref(prf, reflect_x_axis_style, save_x_axis_style, help_x_axis_style, clear_x_axis_style, revert_x_axis_style); make_inter_variable_separator(grf_box); prf = prefs_row_with_toggle("include smpte info", "show-smpte-label", rts_with_smpte_label = with_smpte_label(ss), grf_box, smpte_toggle); remember_pref(prf, reflect_smpte, save_smpte, help_smpte, clear_smpte, revert_smpte); /* ---------------- (graph) colors ---------------- */ make_inter_variable_separator(grf_box); make_inner_label(" colors", grf_box); saved_data_color = ss->data_color; prf = prefs_color_selector_row("unselected data (waveform) color", S_data_color, ss->data_color, grf_box, data_color_func); remember_pref(prf, NULL, save_data_color, help_data_color, clear_data_color, revert_data_color); make_inter_variable_separator(grf_box); saved_graph_color = ss->graph_color; prf = prefs_color_selector_row("unselected graph (background) color", S_graph_color, ss->graph_color, grf_box, graph_color_func); remember_pref(prf, NULL, save_graph_color, help_graph_color, clear_graph_color, revert_graph_color); make_inter_variable_separator(grf_box); saved_selected_data_color = ss->selected_data_color; prf = prefs_color_selector_row("selected channel data (waveform) color", S_selected_data_color, ss->selected_data_color, grf_box, selected_data_color_func); remember_pref(prf, NULL, save_selected_data_color, help_selected_data_color, clear_selected_data_color, revert_selected_data_color); make_inter_variable_separator(grf_box); saved_selected_graph_color = ss->selected_graph_color; prf = prefs_color_selector_row("selected channel graph (background) color", S_selected_graph_color, ss->selected_graph_color, grf_box, selected_graph_color_func); remember_pref(prf, NULL, save_selected_graph_color, help_selected_graph_color, clear_selected_graph_color, revert_selected_graph_color); make_inter_variable_separator(grf_box); saved_selection_color = ss->selection_color; prf = prefs_color_selector_row("selection color", S_selection_color, ss->selection_color, grf_box, selection_color_func); remember_pref(prf, NULL, save_selection_color, help_selection_color, clear_selection_color, revert_selection_color); /* ---------------- (graph) fonts ---------------- */ make_inter_variable_separator(grf_box); make_inner_label(" fonts", grf_box); rts_axis_label_font = mus_strdup(axis_label_font(ss)); prf = prefs_row_with_text("axis label font", S_axis_label_font, axis_label_font(ss), grf_box, axis_label_font_text); remember_pref(prf, reflect_axis_label_font, save_axis_label_font, help_axis_label_font, clear_axis_label_font, revert_axis_label_font); make_inter_variable_separator(grf_box); rts_axis_numbers_font = mus_strdup(axis_numbers_font(ss)); prf = prefs_row_with_text("axis number font", S_axis_numbers_font, axis_numbers_font(ss), grf_box, axis_numbers_font_text); remember_pref(prf, reflect_axis_numbers_font, save_axis_numbers_font, help_axis_numbers_font, clear_axis_numbers_font, revert_axis_numbers_font); make_inter_variable_separator(grf_box); rts_peaks_font = mus_strdup(peaks_font(ss)); prf = prefs_row_with_text("fft peaks font", S_peaks_font, peaks_font(ss), grf_box, peaks_font_text); remember_pref(prf, reflect_peaks_font, save_peaks_font, help_peaks_font, clear_peaks_font, revert_peaks_font); make_inter_variable_separator(grf_box); rts_bold_peaks_font = mus_strdup(bold_peaks_font(ss)); prf = prefs_row_with_text("fft peaks bold font (for main peaks)", S_bold_peaks_font, bold_peaks_font(ss), grf_box, bold_peaks_font_text); remember_pref(prf, reflect_bold_peaks_font, save_bold_peaks_font, help_bold_peaks_font, clear_bold_peaks_font, revert_bold_peaks_font); make_inter_variable_separator(grf_box); rts_tiny_font = mus_strdup(tiny_font(ss)); prf = prefs_row_with_text("tiny font (for various annotations)", S_peaks_font, tiny_font(ss), grf_box, tiny_font_text); remember_pref(prf, reflect_tiny_font, save_tiny_font, help_tiny_font, clear_tiny_font, revert_tiny_font); } make_inter_topic_separator(topics); /* -------- transform -------- */ { GtkWidget *fft_box; /* ---------------- transform options ---------------- */ fft_box = make_top_level_box(topics); make_top_level_label("transform options", fft_box); rts_fft_size = transform_size(ss); str = mus_format("%" print_mus_long, rts_fft_size); prf = prefs_row_with_number("size", S_transform_size, str, 12, fft_box, fft_size_up, fft_size_down, fft_size_from_text); remember_pref(prf, reflect_fft_size, save_fft_size, help_fft_size, NULL, revert_fft_size); free(str); if (transform_size(ss) <= 2) gtk_widget_set_sensitive(prf->arrow_down, false); make_inter_variable_separator(fft_box); prf = prefs_row_with_radio_box("transform graph choice", S_transform_graph_type, transform_graph_types, NUM_TRANSFORM_GRAPH_TYPES, rts_transform_graph_type = transform_graph_type(ss), fft_box, transform_graph_type_choice); remember_pref(prf, reflect_transform_graph_type, save_transform_graph_type, help_transform_graph_type, NULL, revert_transform_graph_type); make_inter_variable_separator(fft_box); rts_transform_type = transform_type(ss); prf = prefs_row_with_list("transform", S_transform_type, transform_types[rts_transform_type], transform_types, NUM_BUILTIN_TRANSFORM_TYPES, fft_box, transform_type_from_text, transform_type_completer, NULL); remember_pref(prf, reflect_transform_type, save_transform_type, help_transform_type, clear_transform_type, revert_transform_type); make_inter_variable_separator(fft_box); rts_fft_window = fft_window(ss); prf = prefs_row_with_list("data window", S_fft_window, mus_fft_window_name(rts_fft_window), mus_fft_window_names(), MUS_NUM_FFT_WINDOWS, fft_box, fft_window_from_text, fft_window_completer, NULL); remember_pref(prf, reflect_fft_window, save_fft_window, help_fft_window, clear_fft_window, revert_fft_window); make_inter_variable_separator(fft_box); prf = prefs_row_with_scale("data window family parameter", S_fft_window_beta, 1.0, rts_fft_window_beta = fft_window_beta(ss), fft_box, fft_window_beta_scale_callback, fft_window_beta_text_callback); remember_pref(prf, reflect_fft_window_beta, save_fft_window_beta, help_fft_window_beta, NULL, revert_fft_window_beta); make_inter_variable_separator(fft_box); str = mus_format("%d", rts_max_transform_peaks = max_transform_peaks(ss)); prf = prefs_row_with_toggle_with_text("show fft peak data", S_show_transform_peaks, rts_show_transform_peaks = show_transform_peaks(ss), "max peaks:", str, 5, fft_box, transform_peaks_toggle, max_peaks_text); remember_pref(prf, reflect_transform_peaks, save_transform_peaks, help_transform_peaks, NULL, revert_transform_peaks); free(str); make_inter_variable_separator(fft_box); { const char **cmaps; int i, len; len = num_colormaps(); cmaps = (const char **)calloc(len, sizeof(const char *)); for (i = 0; i < len; i++) cmaps[i] = (const char *)colormap_name(i); rts_colormap = color_map(ss); prf = prefs_row_with_list("sonogram colormap", S_colormap, cmaps[rts_colormap], cmaps, len, fft_box, colormap_from_text, colormap_completer, NULL); remember_pref(prf, reflect_colormap, save_colormap, help_colormap, clear_colormap, revert_colormap); free(cmaps); } make_inter_variable_separator(fft_box); prf = prefs_row_with_toggle("y axis as log magnitude (dB)", S_fft_log_magnitude, rts_fft_log_magnitude = fft_log_magnitude(ss), fft_box, log_magnitude_toggle); remember_pref(prf, reflect_fft_log_magnitude, save_fft_log_magnitude, help_fft_log_magnitude, NULL, revert_fft_log_magnitude); make_inter_variable_separator(fft_box); str = mus_format("%.1f", rts_min_dB = min_dB(ss)); prf = prefs_row_with_text("minimum y-axis dB value", S_min_dB, str, fft_box, min_dB_text); remember_pref(prf, reflect_min_dB, save_min_dB, help_min_dB, NULL, revert_min_dB); free(str); make_inter_variable_separator(fft_box); prf = prefs_row_with_toggle("x axis as log freq", S_fft_log_frequency, rts_fft_log_frequency = fft_log_frequency(ss), fft_box, log_frequency_toggle); remember_pref(prf, reflect_fft_log_frequency, save_fft_log_frequency, help_fft_log_frequency, NULL, revert_fft_log_frequency); make_inter_variable_separator(fft_box); prf = prefs_row_with_radio_box("normalization", S_transform_normalization, transform_normalizations, NUM_TRANSFORM_NORMALIZATIONS, rts_transform_normalization = transform_normalization(ss), fft_box, transform_normalization_choice); remember_pref(prf, reflect_transform_normalization, save_transform_normalization, help_transform_normalization, NULL, revert_transform_normalization); } make_inter_topic_separator(topics); /* -------- marks, mixes, and regions -------- */ { GtkWidget *mmr_box; char *str1, *str2; /* ---------------- marks and mixes ---------------- */ mmr_box = make_top_level_box(topics); make_top_level_label("marks and mixes", mmr_box); saved_mark_color = ss->mark_color; prf = prefs_color_selector_row("mark and mix tag color", S_mark_color, ss->mark_color, mmr_box, mark_color_func); remember_pref(prf, NULL, save_mark_color, help_mark_color, clear_mark_color, revert_mark_color); make_inter_variable_separator(mmr_box); str1 = mus_format("%d", rts_mark_tag_width = mark_tag_width(ss)); str2 = mus_format("%d", rts_mark_tag_height = mark_tag_height(ss)); prf = prefs_row_with_two_texts("mark tag size", S_mark_tag_width, "width:", str1, "height:", str2, 4, mmr_box, mark_tag_size_text); remember_pref(prf, reflect_mark_tag_size, save_mark_tag_size, help_mark_tag_size, NULL, revert_mark_tag_size); free(str2); free(str1); make_inter_variable_separator(mmr_box); str1 = mus_format("%d", rts_mix_tag_width = mix_tag_width(ss)); str2 = mus_format("%d", rts_mix_tag_height = mix_tag_height(ss)); prf = prefs_row_with_two_texts("mix tag size", S_mix_tag_width, "width:", str1, "height:", str2, 4, mmr_box, mix_tag_size_text); remember_pref(prf, reflect_mix_tag_size, save_mix_tag_size, help_mix_tag_size, NULL, revert_mix_tag_size); free(str2); free(str1); make_inter_variable_separator(mmr_box); saved_mix_color = ss->mix_color; prf = prefs_color_selector_row("mix waveform color", S_mix_color, ss->mix_color, mmr_box, mix_color_func); remember_pref(prf, NULL, save_mix_color, help_mix_color, clear_mix_color, revert_mix_color); make_inter_variable_separator(mmr_box); str = mus_format("%d", rts_mix_waveform_height = mix_waveform_height(ss)); prf = prefs_row_with_toggle_with_text("show mix waveforms (attached to the mix tag)", S_show_mix_waveforms, rts_show_mix_waveforms = show_mix_waveforms(ss), "max waveform height:", str, 5, mmr_box, show_mix_waveforms_toggle, mix_waveform_height_text); remember_pref(prf, reflect_mix_waveforms, save_mix_waveforms, help_mix_waveforms, NULL, revert_mix_waveforms); free(str); } make_inter_topic_separator(topics); /* -------- clm -------- */ { GtkWidget *clm_box; /* ---------------- clm options ---------------- */ clm_box = make_top_level_box(topics); make_top_level_label("clm", clm_box); str = mus_format("%d", rts_speed_control_tones = speed_control_tones(ss)); rts_speed_control_style = speed_control_style(ss); prf = prefs_row_with_radio_box_and_number("speed control choice", S_speed_control_style, speed_control_styles, NUM_SPEED_CONTROL_STYLES, (int)speed_control_style(ss), str, 6, clm_box, speed_control_choice, speed_control_up, speed_control_down, speed_control_text); remember_pref(prf, reflect_speed_control, save_speed_control, help_speed_control, NULL, revert_speed_control); free(str); make_inter_variable_separator(clm_box); str = mus_format("%d", rts_sinc_width = sinc_width(ss)); prf = prefs_row_with_text("sinc interpolation width in srate converter", S_sinc_width, str, clm_box, sinc_width_text); remember_pref(prf, reflect_sinc_width, save_sinc_width, help_sinc_width, NULL, revert_sinc_width); free(str); } make_inter_topic_separator(topics); /* -------- programming -------- */ { GtkWidget *prg_box; /* ---------------- listener options ---------------- */ prg_box = make_top_level_box(topics); make_top_level_label("listener options", prg_box); prf = prefs_row_with_toggle("show listener at start up", S_show_listener, rts_show_listener = listener_is_visible(), prg_box, show_listener_toggle); remember_pref(prf, reflect_show_listener, save_show_listener, help_show_listener, clear_show_listener, revert_show_listener); make_inter_variable_separator(prg_box); rts_listener_prompt = mus_strdup(listener_prompt(ss)); prf = prefs_row_with_text("prompt", S_listener_prompt, listener_prompt(ss), prg_box, listener_prompt_text); remember_pref(prf, reflect_listener_prompt, save_listener_prompt, help_listener_prompt, NULL, revert_listener_prompt); make_inter_variable_separator(prg_box); str = mus_format("%d", rts_print_length = print_length(ss)); prf = prefs_row_with_text("number of vector elements to display", S_print_length, str, prg_box, print_length_text); remember_pref(prf, reflect_print_length, save_print_length, help_print_length, NULL, revert_print_length); free(str); make_inter_variable_separator(prg_box); rts_listener_font = mus_strdup(listener_font(ss)); prf = prefs_row_with_text("font", S_listener_font, listener_font(ss), prg_box, listener_font_text); remember_pref(prf, reflect_listener_font, save_listener_font, help_listener_font, clear_listener_font, revert_listener_font); make_inter_variable_separator(prg_box); saved_listener_color = ss->listener_color; prf = prefs_color_selector_row("background color", S_listener_color, ss->listener_color, prg_box, listener_color_func); remember_pref(prf, NULL, save_listener_color, help_listener_color, clear_listener_color, revert_listener_color); make_inter_variable_separator(prg_box); saved_listener_text_color = ss->listener_text_color; prf = prefs_color_selector_row("text color", S_listener_text_color, ss->listener_text_color, prg_box, listener_text_color_func); remember_pref(prf, NULL, save_listener_text_color, help_listener_text_color, clear_listener_text_color, revert_listener_text_color); } /* -------- audio -------- */ { GtkWidget *aud_box; /* ---------------- audio options ---------------- */ aud_box = make_top_level_box(topics); make_top_level_label("audio options", aud_box); str = mus_format("%d", rts_dac_size = dac_size(ss)); prf = prefs_row_with_text("dac buffer size", S_dac_size, str, aud_box, dac_size_text); remember_pref(prf, reflect_dac_size, save_dac_size, help_dac_size, NULL, revert_dac_size); free(str); make_inter_variable_separator(aud_box); prf = prefs_row_with_toggle("fold in otherwise unplayable channels", S_dac_combines_channels, rts_dac_combines_channels = dac_combines_channels(ss), aud_box, dac_combines_channels_toggle); remember_pref(prf, reflect_dac_combines_channels, save_dac_combines_channels, help_dac_combines_channels, NULL, revert_dac_combines_channels); } set_dialog_widget(PREFERENCES_DIALOG, preferences_dialog); gtk_widget_show(preferences_dialog); prefs_unsaved = false; prefs_set_dialog_title(NULL); return(preferences_dialog); }