From 07cfd70941c089946225134645bc1781e392c4b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Sun, 3 Jan 2010 14:18:53 +0100 Subject: [PATCH] display values correctly (offsets, correct steps, suffixes, labels) --- effects.c | 230 +++++++++++++++++++++++++++++++++++++++--------------- effects.h | 24 +++++- gui.c | 200 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 369 insertions(+), 85 deletions(-) diff --git a/effects.c b/effects.c index d2448e9..01e5fa4 100644 --- a/effects.c +++ b/effects.c @@ -93,26 +93,31 @@ static gchar *ips_scale_labels[] = { static gchar *on_off_labels[] = { "Off", "On", + NULL, }; static gchar *odd_even_labels[] = { "Odd", "Even", + NULL, }; static gchar *chorus_vibrato_labels[] = { "Chorus", "Vibrato", + NULL, }; static gchar *loose_tight_labels[] = { "Loose", "Tight", + NULL, }; static gchar *pickup_type_labels[] = { "SC>HB", "HB>SC", + NULL, }; static gchar *fast_medium_slow_labels[] = { @@ -135,12 +140,14 @@ static gchar *comp_ratio_labels[] = { "10:1", "20:1", "Inf:1", + NULL, }; static gchar *eq_bandwidth_labels[] = { "Wide", "Medium", "Narrow", + NULL, }; static gchar *eq_low_freq_labels[] = { @@ -182,6 +189,7 @@ static gchar *eq_low_freq_labels[] = { "450Hz", "475Hz", "500Hz", + NULL, }; static gchar *eq_mid_freq_labels[] = { @@ -231,6 +239,7 @@ static gchar *eq_mid_freq_labels[] = { "3.55kHz", "3.75kHz", "4kHz", + NULL, }; static gchar *eq_high_freq_labels[] = { @@ -259,232 +268,309 @@ static gchar *eq_high_freq_labels[] = { "7.1kHz", "7.5kHz", "8kHz", + NULL, }; static gchar *amp_channel_labels[] = { "1", "2", "Warped", + NULL, +}; + +static gchar *rhold_labels[] = { + "RHold", + NULL, }; static EffectValues values_1_2_warp = { - 0.0, 2.0, amp_channel_labels, + .min = 0.0, .max = 2.0, + .type = VALUE_TYPE_LABEL, + .labels = amp_channel_labels, }; static EffectValues values_0_to_99 = { - 0.0, 99.0, NULL, + .min = 0.0, .max = 99.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_1_to_4 = { - 0.0, 3.0, NULL, + .min = 0.0, .max = 3.0, + .type = VALUE_TYPE_OFFSET, + .offset = 1, }; static EffectValues values_warp_0_to_98 = { - /** \todo make this display properly (display text is value + 1) */ - 0.0, 98.0, NULL, + .min = 0.0, .max = 98.0, + .type = VALUE_TYPE_OFFSET, + .offset = 1, }; static EffectValues values_0_to_9 = { - 0.0, 9.0, NULL, + .min = 0.0, .max = 9.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_0_to_49 = { - 0.0, 49.0, NULL, + .min = 0.0, .max = 49.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_0_to_12 = { - 0.0, 12.0, NULL, + .min = 0.0, .max = 12.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_0_to_15 = { - 0.0, 15.0, NULL, + .min = 0.0, .max = 15.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_0_to_20 = { - 0.0, 20.0, NULL, + .min = 0.0, .max = 20.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_m12_to_12_semitones = { /** \todo make this display properly (display range -12.0 to 12.0 semitones) */ - 0.0, 48.0, NULL, + .min = 0.0, .max = 48.0, .type = VALUE_TYPE_PLAIN, +/* .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "semitones", .offset = -12, */ }; static EffectValues values_m24_to_24_step2 = { - /** \todo make this display properly (display range -24 to 24) */ - 0.0, 24.0, NULL, + .min = 0.0, .max = 24.0, + .type = VALUE_TYPE_OFFSET | VALUE_TYPE_STEP, + .offset = -12, .step = 2.0, }; + static EffectValues values_m24_to_24 = { - /** \todo make this display properly (display range -24 to 24) */ - 0.0, 48.0, NULL, + .min = 0.0, .max = 48.0, + .type = VALUE_TYPE_OFFSET, + .offset = -24, }; static EffectValues values_m12_to_24 = { - /** \todo make this display properly (display range -12 to 24) */ - 0.0, 36.0, NULL, + .min = 0.0, .max = 36.0, + .type = VALUE_TYPE_OFFSET, + .offset = -12, }; static EffectValues values_comp_ratio = { - 0.0, 12.0, comp_ratio_labels, + .min = 0.0, .max = 12.0, + .type = VALUE_TYPE_LABEL, + .labels = comp_ratio_labels, }; static EffectValues values_fast_medium_slow = { - 0.0, 2.0, fast_medium_slow_labels, + .min = 0.0, .max = 2.0, + .type = VALUE_TYPE_LABEL, + .labels = fast_medium_slow_labels, }; static EffectValues values_eq_db = { - /** \todo make those display properly (display range -12dB to 12dB) */ - 0.0, 24.0, NULL, + .min = 0.0, .max = 24.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "dB", .offset = -12, }; static EffectValues values_eq_bass_hz = { - /** \todo make those display properly (display range 50hz to 300hz) */ - 0.0, 250.0, NULL, + .min = 0.0, .max = 250.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "hz", .offset = 50, }; static EffectValues values_eq_mid_hz = { - /** \todo make this display properly (display range 300 to 5000) */ - 0.0, 4700.0, NULL, + .min = 0.0, .max = 4700.0, + .type = VALUE_TYPE_OFFSET, + .offset = 300, }; static EffectValues values_eq_treb_hz = { - /** \todo make this display properly (display range 500 to 8000) */ - 0.0, 7500.0, NULL, + .min = 0.0, .max = 7500.0, + .type = VALUE_TYPE_OFFSET, + .offset = 500, }; static EffectValues values_eq_bandwidth = { - 0.0, 2.0, eq_bandwidth_labels, + .min = 0.0, .max = 2.0, + .type = VALUE_TYPE_LABEL, + .labels = eq_bandwidth_labels, }; static EffectValues values_eq_low_freq = { - 0.0, 37.0, eq_low_freq_labels, + .min = 0.0, .max = 37.0, + .type = VALUE_TYPE_LABEL, + .labels = eq_low_freq_labels, }; static EffectValues values_eq_mid_freq = { - 0.0, 45.0, eq_mid_freq_labels, + .min = 0.0, .max = 45.0, + .type = VALUE_TYPE_LABEL, + .labels = eq_mid_freq_labels, }; static EffectValues values_eq_high_freq = { - 0.0, 24.0, eq_high_freq_labels, + .min = 0.0, .max = 24.0, + .type = VALUE_TYPE_LABEL, + .labels = eq_high_freq_labels, }; static EffectValues values_200hz_to_1_5khz = { /** \todo make this display properly (display range 200 Hz to 1.5 kHz) */ - 0.0, 130.0, NULL, + .min = 0.0, .max = 130.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_waveform = { - 0.0, 2.0, wave_labels, + .min = 0.0, .max = 2.0, + .type = VALUE_TYPE_LABEL, + .labels = wave_labels, }; static EffectValues values_balance = { /** \todo make this display properly */ - 0.0, 198.0, NULL, + 0.0, 198.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_synth_talk_release = { /** \todo make last value display properly */ - 0.0, 100.0, NULL, + 0.0, 100.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_whammy_amount = { - 0.0, 15.0, whammy_labels, + .min = 0.0, .max = 15.0, + .type = VALUE_TYPE_LABEL, + .labels = whammy_labels, }; static EffectValues values_ips_shift = { - 0.0, 13.0, ips_shift_labels, + .min = 0.0, .max = 13.0, + .type = VALUE_TYPE_LABEL, + .labels = ips_shift_labels, }; static EffectValues values_ips_key = { - 0.0, 11.0, ips_key_labels, + .min = 0.0, .max = 11.0, + .type = VALUE_TYPE_LABEL, + .labels = ips_key_labels, }; static EffectValues values_ips_scale = { - 0.0, 5.0, ips_scale_labels, + .min = 0.0, .max = 5.0, + .type = VALUE_TYPE_LABEL, + .labels = ips_scale_labels, }; static EffectValues values_predelay_time = { - /** \todo make this display properly (1ms to 20ms) */ - 0.0, 19.0, NULL, + .min = 0.0, .max = 19.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "ms", .offset = 1, +}; + +static EffectValues values_delay_time_extra = { + /* display as 1.0 sec (99) to 5.0 sec (139) */ + .min = 99.0, .max = 139.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET | + VALUE_TYPE_STEP | VALUE_TYPE_DECIMAL, + .suffix = "sec", .offset = -89, + .step = 0.1, .decimal = 1, }; static EffectValues values_delay_time = { - /** \todo make this display properly (10 msec to 5 sec) */ - 0.0, 139.0, NULL, + /* 0 to 139, extended by values_delay_time_extra */ + .min = 0.0, .max = 98.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET | + VALUE_TYPE_STEP | VALUE_TYPE_EXTRA, + .suffix = "msec", .offset = 1, + .step = 10.0, .extra = &values_delay_time_extra, }; static EffectValues values_delay_time_0_760 = { /** \todo make this display properly */ - 0.0, 760.0, NULL, + 0.0, 760.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_delay_time_0_2000 = { /** \todo make this display properly */ - 0.0, 2000.0, NULL, + 0.0, 2000.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_delay_time_0_4650 = { /** \todo make this display properly */ - 0.0, 4650.0, NULL, + 0.0, 4650.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_delay_time_0_4990 = { /** \todo make this display properly */ - 0.0, 4990.0, NULL, + 0.0, 4990.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_delay_time_0_5000 = { /** \todo make this display properly */ - 0.0, 5000.0, NULL, + 0.0, 5000.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_delay_repeats_extra = { + .min = 100.0, .max = 100.0, + .type = VALUE_TYPE_LABEL, + .labels = rhold_labels }; static EffectValues values_delay_repeats = { - /** \todo make last value display properly */ - 0.0, 100.0, NULL, + /* 0 to 100, extended by values_delay_repeats_extra */ + .min = 0.0, .max = 99.0, + .type = VALUE_TYPE_EXTRA, + .extra = &values_delay_repeats_extra, }; static EffectValues values_delay_thresh = { /** \todo make last value display properly */ - 0.0, 100.0, NULL, + 0.0, 100.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_delay_repeat_rate_0_286 = { /** \todo make this display properly */ - 0.0, 286.0, NULL, + 0.0, 286.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_delay_spread_0_49 = { /** \todo make this display properly */ - 0.0, 49.0, NULL, + 0.0, 49.0, .type = VALUE_TYPE_PLAIN, }; static EffectValues values_on_off = { - 0.0, 1.0, on_off_labels, + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = on_off_labels, }; static EffectValues values_odd_even = { - 0.0, 1.0, odd_even_labels, + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = odd_even_labels, }; static EffectValues values_chorus_vibrato = { - 0.0, 1.0, chorus_vibrato_labels, + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = chorus_vibrato_labels, }; static EffectValues values_loose_tight = { - 0.0, 1.0, loose_tight_labels, + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = loose_tight_labels, }; static EffectValues values_pickup_type = { - 0.0, 1.0, pickup_type_labels, + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = pickup_type_labels, }; static EffectValues values_1_to_10_step_0p1 = { - /** \todo make this display properly (1.0, 1.1, ...., 10.0) */ - 0.0, 90.0, NULL, + .min = 0.0, .max = 90.0, + .type = VALUE_TYPE_OFFSET | VALUE_TYPE_STEP | VALUE_TYPE_DECIMAL, + .offset = 10, .step = 0.1, .decimal = 1, }; static EffectValues values_rp_mix = { /** \todo make this display properly (USB 0, USB 1, USB 2 ... USB 49, USB RP, RP 49, RP 48 ... RP 1, RP 0) */ - 0.0, 100.0, NULL, + .min = 0.0, .max = 100.0, .type = VALUE_TYPE_PLAIN, }; static EffectSettings usb_settings[] = { @@ -2678,6 +2764,28 @@ void modifier_group_free(ModifierGroup *modifier_group) g_slice_free(ModifierGroup, modifier_group); } +/** + * \param values EffectValues to examine + * \param min return location for minimum value + * \param max return location for maximum value + * \param custom return location for custom flag + * + * Retrieves information about provided EffectValues, custom is set to TRUE if values type isn't VALUE_TYPE_PLAIN. + **/ +void get_values_info(EffectValues *values, + gdouble *min, gdouble *max, gboolean *custom) +{ + g_return_if_fail(values != NULL); + + *min = values->min; + *custom = (values->type != VALUE_TYPE_PLAIN); + + while ((values->type & VALUE_TYPE_EXTRA) && (values->extra != NULL)) + values = values->extra; + + *max = values->max; +} + /** * \param device_id Device ID * \param family_id Family ID diff --git a/effects.h b/effects.h index 5ae2faf..40e95f7 100644 --- a/effects.h +++ b/effects.h @@ -19,10 +19,30 @@ #include -typedef struct { +enum { + VALUE_TYPE_PLAIN = 0, /**< value displayed directly */ + VALUE_TYPE_SUFFIX = 1 << 0, /**< use suffix for displaying */ + VALUE_TYPE_OFFSET = 1 << 1, /**< use value offset */ + VALUE_TYPE_STEP = 1 << 2, /**< use value step different than 1 */ + VALUE_TYPE_LABEL = 1 << 3, /**< use value labels (overrides any other option) */ + VALUE_TYPE_EXTRA = 1 << 4, /**< use extra values */ + VALUE_TYPE_DECIMAL= 1 << 5, /**< display decimal places */ +} ValueType; + +typedef struct _EffectValues { gdouble min; /**< Minumum value */ gdouble max; /**< Maximum value */ + gint type; /**< value type bitmask (ValueType) */ + GStrv labels; /**< value labels */ + gint offset; /**< value offset */ + gdouble step; /**< value step */ + gchar *suffix; /**< value suffix */ + + struct _EffectValues *extra; + /**< additional value range, + use it when there're different range types */ + gint decimal; /**< amount of decimal places to display */ } EffectValues; typedef struct { @@ -85,6 +105,8 @@ typedef struct { ModifierGroup *modifier_linkable_list(); void modifier_group_free(ModifierGroup *modifier_group); +void get_values_info(EffectValues *values, + gdouble *min, gdouble *max, gboolean *custom); gboolean get_device_info(unsigned char device_id, unsigned char family_id, unsigned char product_id, Device **device); diff --git a/gui.c b/gui.c index 76f720b..1fb4567 100644 --- a/gui.c +++ b/gui.c @@ -15,6 +15,7 @@ */ #include +#include #include "gdigi.h" #include "gui.h" #include "effects.h" @@ -56,6 +57,169 @@ void show_error_message(GtkWidget *parent, gchar *message) gtk_widget_destroy(msg); } +/** + * \param value value to examine + * \param values EffectValues to check value against + * + * Examines whether value fits inside values range for given EffectValues. + * + * \return TRUE is value fits inside range, otherwise FALSE. + **/ +static gboolean check_value_range(gint value, EffectValues *values) +{ + if (((gint) values->min <= value) && (value <= (gint) values->max)) + return TRUE; + else + return FALSE; +} + +/** + * \param spin a GtkSpinButton + * \param new_val return value for valid input + * \param values signal user data, EffectValues for this parameter + * + * Custom GtkSpinButton "input" handler for EffectValues with non plain type. + * + * \return TRUE if new_val was set, otherwise FALSE. + **/ +static gboolean custom_value_input_cb(GtkSpinButton *spin, gdouble *new_val, EffectValues *values) +{ + gchar *text = g_strdup(gtk_entry_get_text(GTK_ENTRY(spin))); + gchar *err = NULL; + gdouble value; + + for (;;) { + if (values->type & VALUE_TYPE_LABEL) { + /** search labels for value */ + gint n; + for (n = 0; values->labels[n] != NULL; n++) { + if (g_strcmp0(values->labels[n], text) == 0) { + /* Value found */ + *new_val = values->min + (gdouble)n; + g_free(text); + return TRUE; + } + } + + /* Value not found */ + if (values->type & VALUE_TYPE_EXTRA) { + values = values->extra; + continue; + } else { + g_free(text); + return FALSE; + } + } + + if (values->type & VALUE_TYPE_SUFFIX) { + /* remove suffix from entry text */ + gchar *tmp; + + tmp = strstr(text, values->suffix); + if (tmp != NULL) { + gchar *temp = g_strndup(text, tmp - text); + g_free(text); + text = temp; + } + } + + g_strstrip(text); + + value = g_strtod(text, &err); + if (*err) { + if (values->type & VALUE_TYPE_EXTRA) { + values = values->extra; + continue; + } else { + g_free(text); + return FALSE; + } + } + + if (values->type & VALUE_TYPE_STEP) { + value /= values->step; + } + + if (values->type & VALUE_TYPE_OFFSET) { + value -= values->offset; + } + + if (check_value_range((gint) value, values) == FALSE) { + if (values->type & VALUE_TYPE_EXTRA) { + values = values->extra; + continue; + } else { + g_free(text); + return FALSE; + } + } + + *new_val = value; + + g_free(text); + + return TRUE; + } +} + +/** + * \param spin a GtkSpinButton + * \param values signal user data, EffectValues for this parameter + * + * Custom GtkSpinButton "output" handler for EffectValues with non plain type. + * + * \return TRUE if text was set, otherwise FALSE. + **/ +static gboolean custom_value_output_cb(GtkSpinButton *spin, EffectValues *values) +{ + GtkAdjustment *adj; + gchar *text; + gdouble value; + + adj = gtk_spin_button_get_adjustment(spin); + value = gtk_adjustment_get_value(adj); + + while (check_value_range(value, values) == FALSE) { + if (values->type & VALUE_TYPE_EXTRA) { + values = values->extra; + } else { + g_message("custom_value_output_cb called with out of bounds value"); + return FALSE; + } + } + + if (values->type & VALUE_TYPE_LABEL) { + gtk_entry_set_text(GTK_ENTRY(spin), values->labels[(gint) value - (gint) values->min]); + return TRUE; + } + + if (values->type & VALUE_TYPE_OFFSET) { + value += (gdouble) values->offset; + } + + if (values->type & VALUE_TYPE_STEP) { + value *= values->step; + } + + if (values->type & VALUE_TYPE_DECIMAL) { + text = g_strdup_printf("%.*f", values->decimal, value); + } else { + text = g_strdup_printf("%d", (gint) value); + } + + if (values->type & VALUE_TYPE_SUFFIX) { + gchar *tmp; + tmp = g_strdup_printf("%s %s", text, values->suffix); + g_free(text); + text = tmp; + } + + gtk_entry_set_text(GTK_ENTRY(spin), text); + g_free(text); + + return TRUE; +} + /** * \param adj the object which emitted the signal * \param setting setting controlled by adj @@ -71,20 +235,6 @@ void value_changed_option_cb(GtkAdjustment *adj, EffectSettings *setting) g_object_get(G_OBJECT(adj), "value", &val, NULL); set_option(setting->id, setting->position, (gint)val); } - - if (setting->values != NULL && setting->values->labels != NULL) { - GtkWidget *label; - gint x; - gdouble val = -1.0; - g_object_get(G_OBJECT(adj), "value", &val, NULL); - - x = (gint)val; - - if ((x >= setting->values->min) && (x <= setting->values->max)) { - label = g_object_get_data(G_OBJECT(adj), "label"); - gtk_label_set_text(GTK_LABEL(label), setting->values->labels[x]); - } - } } /** @@ -248,20 +398,24 @@ GtkWidget *create_table(EffectSettings *settings, gint amt, GHashTable *widget_t table = gtk_table_new(3, amt, FALSE); for (x = 0; xmin, settings[x].values->max, + adj = gtk_adjustment_new(0.0, min, max, 1.0, /* step increment */ - MAX((settings[x].values->max / 100), 5.0), /* page increment */ + MAX((max / 100), 5.0), /* page increment */ 0.0); knob = gtk_knob_new(GTK_ADJUSTMENT(adj), knob_anim); - if (settings[x].values->labels == NULL) { - widget = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0); - gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE); - gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(widget), GTK_UPDATE_IF_VALID); - } else { - widget = gtk_label_new(settings[x].values->labels[0]); - g_object_set_data(G_OBJECT(adj), "label", widget); + widget = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0); + gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), FALSE); + gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(widget), GTK_UPDATE_IF_VALID); + if (custom == TRUE) { + g_signal_connect(G_OBJECT(widget), "input", G_CALLBACK(custom_value_input_cb), settings[x].values); + g_signal_connect(G_OBJECT(widget), "output", G_CALLBACK(custom_value_output_cb), settings[x].values); } widget_tree_add(adj, settings[x].id, settings[x].position, -1, -1);