diff --git a/command.c b/command.c index eab17a57d2..e3cb85f8fd 100644 --- a/command.c +++ b/command.c @@ -104,66 +104,6 @@ static void rescale_input_coordinates(struct MPContext *mpctx, int ix, int iy, vo->dheight, vo_fs); } -static void choice_get_min_max(const struct m_option *opt, int *min, int *max) -{ - assert(opt->type == &m_option_type_choice); - *min = INT_MAX; - *max = INT_MIN; - for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) { - *min = FFMIN(*min, alt->value); - *max = FFMAX(*max, alt->value); - } - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { - *min = FFMIN(*min, opt->min); - *max = FFMAX(*max, opt->max); - } -} - -static void check_choice(int dir, int val, bool *found, int *best, int choice) -{ - if ((dir == -1 && (!(*found) || choice > (*best)) && choice < val) || - (dir == +1 && (!(*found) || choice < (*best)) && choice > val)) - { - *found = true; - *best = choice; - } -} - -static int step_choice(const struct m_option *opt, int val, int add, bool wrap) -{ - assert(opt->type == &m_option_type_choice); - int dir = add > 0 ? +1 : -1; - bool found = false; - int best = 0; // init. value unused - - if (add == 0) - return val; - - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { - int newval = val + add; - if (val >= opt->min && val <= opt->max && - newval >= opt->min && newval <= opt->max) - { - found = true; - best = newval; - } else { - check_choice(dir, val, &found, &best, opt->min); - check_choice(dir, val, &found, &best, opt->max); - } - } - - for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) - check_choice(dir, val, &found, &best, alt->value); - - if (!found) { - int min, max; - choice_get_min_max(opt, &min, &max); - best = (dir == -1) ^ wrap ? min : max; - } - - return best; -} - static int mp_property_generic_option(struct m_option *prop, int action, void *arg, MPContext *mpctx) { @@ -182,14 +122,6 @@ static int mp_property_generic_option(struct m_option *prop, int action, case M_PROPERTY_SET: m_option_copy(opt, valptr, arg); return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - if (opt->type == &m_option_type_choice) { - int add = arg ? (*(int *)arg) : +1; - int v = *(int *) valptr; - *(int *) valptr = step_choice(opt, v, add, true); - return M_PROPERTY_OK; - } - break; } return M_PROPERTY_NOT_IMPLEMENTED; } @@ -205,12 +137,6 @@ static int mp_property_playback_speed(m_option_t *prop, int action, if (!arg) return M_PROPERTY_ERROR; opts->playback_speed = *(float *) arg; - goto set; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - opts->playback_speed += (arg ? *(float *) arg : 0.1) * - (action == M_PROPERTY_STEP_DOWN ? -1 : 1); - set: M_PROPERTY_CLAMP(prop, opts->playback_speed); // Adjust time until next frame flip for nosound mode mpctx->time_frame *= orig_speed / opts->playback_speed; @@ -359,13 +285,6 @@ static int mp_property_percent_pos(m_option_t *prop, int action, M_PROPERTY_CLAMP(prop, *(int *)arg); pos = *(int *)arg; break; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - pos = get_percent_pos(mpctx); - pos += (arg ? *(int *)arg : 10) * - (action == M_PROPERTY_STEP_UP ? 1 : -1); - M_PROPERTY_CLAMP(prop, pos); - break; default: return m_property_int_ro(prop, action, arg, get_percent_pos(mpctx)); } @@ -388,11 +307,6 @@ static int mp_property_time_pos(m_option_t *prop, int action, M_PROPERTY_CLAMP(prop, *(double *)arg); queue_seek(mpctx, MPSEEK_ABSOLUTE, *(double *)arg, 0); return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - queue_seek(mpctx, MPSEEK_RELATIVE, (arg ? *(double *)arg : 10.0) * - (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0), 0); - return M_PROPERTY_OK; } return m_property_time_ro(prop, action, arg, get_current_time(mpctx)); } @@ -431,15 +345,6 @@ static int mp_property_chapter(m_option_t *prop, int action, void *arg, step_all = *(int *)arg - chapter; chapter += step_all; break; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: { - step_all = (arg && *(int *)arg != 0 ? *(int *)arg : 1) - * (action == M_PROPERTY_STEP_UP ? 1 : -1); - chapter += step_all; - if (chapter < 0) - chapter = 0; - break; - } default: return M_PROPERTY_NOT_IMPLEMENTED; } @@ -484,9 +389,8 @@ static int mp_property_edition(m_option_t *prop, int action, void *arg, M_PROPERTY_CLAMP(prop, *(int *)arg); edition = *(int *)arg; break; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: { - edition += arg ? *(int *)arg : (action == M_PROPERTY_STEP_UP ? 1 : -1); + case M_PROPERTY_SWITCH: { + edition += *(double *)arg; if (edition < 0) edition = demuxer->num_editions - 1; if (edition >= demuxer->num_editions) @@ -574,21 +478,9 @@ static int mp_property_angle(m_option_t *prop, int action, void *arg, angle = *(int *)arg; M_PROPERTY_CLAMP(prop, angle); break; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: { - int step = 0; - if (arg) - step = *(int *)arg; - if (!step) - step = 1; - step *= (action == M_PROPERTY_STEP_UP ? 1 : -1); - angle += step; - if (angle < 1) //cycle - angle = angles; - else if (angle > angles) - angle = 1; - break; - } + case M_PROPERTY_SWITCH: + // NOTE: should cycle + return M_PROPERTY_NOT_IMPLEMENTED; default: return M_PROPERTY_NOT_IMPLEMENTED; } @@ -658,14 +550,10 @@ static int mp_property_pause(m_option_t *prop, int action, void *arg, case M_PROPERTY_SET: if (!arg) return M_PROPERTY_ERROR; - if (mpctx->paused == (bool) * (int *)arg) - return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - if (mpctx->paused) { - unpause_player(mpctx); - } else { + if (*(int *)arg) { pause_player(mpctx); + } else { + unpause_player(mpctx); } return M_PROPERTY_OK; default: @@ -695,8 +583,7 @@ static int mp_property_volume(m_option_t *prop, int action, void *arg, mixer_getbothvolume(&mpctx->mixer, &vol); return m_property_float_range(prop, action, arg, &vol); } - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: + case M_PROPERTY_SWITCH: case M_PROPERTY_SET: break; default: @@ -710,18 +597,12 @@ static int mp_property_volume(m_option_t *prop, int action, void *arg, M_PROPERTY_CLAMP(prop, *(float *) arg); mixer_setvolume(&mpctx->mixer, *(float *) arg, *(float *) arg); return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - if (arg && *(float *) arg <= 0) + case M_PROPERTY_SWITCH: + if (*(double *) arg <= 0) mixer_decvolume(&mpctx->mixer); else mixer_incvolume(&mpctx->mixer); return M_PROPERTY_OK; - case M_PROPERTY_STEP_DOWN: - if (arg && *(float *) arg <= 0) - mixer_incvolume(&mpctx->mixer); - else - mixer_decvolume(&mpctx->mixer); - return M_PROPERTY_OK; } return M_PROPERTY_NOT_IMPLEMENTED; } @@ -740,10 +621,6 @@ static int mp_property_mute(m_option_t *prop, int action, void *arg, return M_PROPERTY_ERROR; mixer_setmute(&mpctx->mixer, *(int *) arg); return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - mixer_setmute(&mpctx->mixer, !mixer_getmute(&mpctx->mixer)); - return M_PROPERTY_OK; default: return m_property_flag_ro(prop, action, arg, mixer_getmute(&mpctx->mixer)); @@ -757,9 +634,7 @@ static int mp_property_audio_delay(m_option_t *prop, int action, if (!(mpctx->sh_audio && mpctx->sh_video)) return M_PROPERTY_UNAVAILABLE; switch (action) { - case M_PROPERTY_SET: - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: { + case M_PROPERTY_SET: { int ret; float delay = audio_delay; ret = m_property_delay(prop, action, arg, &audio_delay); @@ -875,14 +750,6 @@ static int mp_property_balance(m_option_t *prop, int action, void *arg, } return M_PROPERTY_OK; } - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - mixer_getbalance(&mpctx->mixer, &bal); - bal += (arg ? *(float *)arg : .1f) * - (action == M_PROPERTY_STEP_UP ? 1.f : -1.f); - M_PROPERTY_CLAMP(prop, bal); - mixer_setbalance(&mpctx->mixer, bal); - return M_PROPERTY_OK; case M_PROPERTY_SET: if (!arg) return M_PROPERTY_ERROR; @@ -949,18 +816,13 @@ static int property_switch_track(m_option_t *prop, int action, void *arg, } return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - case M_PROPERTY_SET: { - int i = (arg ? *((int *) arg) : +1) * - (action == M_PROPERTY_STEP_DOWN ? -1 : +1); - if (action == M_PROPERTY_SET && arg) - track = mp_track_by_tid(mpctx, type, i); - else - track = track_next(mpctx, type, i > 0 ? +1 : -1, track); - mp_switch_track(mpctx, type, track); + case M_PROPERTY_SWITCH: + mp_switch_track(mpctx, type, + track_next(mpctx, type, *(double *)arg >= 0 ? +1 : -1, track)); + return M_PROPERTY_OK; + case M_PROPERTY_SET: + mp_switch_track(mpctx, type, mp_track_by_tid(mpctx, type, *(int *)arg)); return M_PROPERTY_OK; - } default: return M_PROPERTY_NOT_IMPLEMENTED; } @@ -990,7 +852,7 @@ static int mp_property_program(m_option_t *prop, int action, void *arg, return M_PROPERTY_UNAVAILABLE; switch (action) { - case M_PROPERTY_STEP_UP: + case M_PROPERTY_SWITCH: case M_PROPERTY_SET: if (action == M_PROPERTY_SET && arg) prog.progid = *((int *) arg); @@ -1030,8 +892,6 @@ static int mp_property_fullscreen(m_option_t *prop, int action, void *arg, M_PROPERTY_CLAMP(prop, *(int *) arg); if (vo_fs == !!*(int *) arg) return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: if (mpctx->video_out->config_ok) vo_control(mpctx->video_out, VOCTRL_FULLSCREEN, 0); mpctx->opts.fullscreen = vo_fs; @@ -1044,7 +904,6 @@ static int mp_property_fullscreen(m_option_t *prop, int action, void *arg, static int mp_property_deinterlace(m_option_t *prop, int action, void *arg, MPContext *mpctx) { - int deinterlace; vf_instance_t *vf; if (!mpctx->sh_video || !mpctx->sh_video->vfilter) return M_PROPERTY_UNAVAILABLE; @@ -1061,12 +920,6 @@ static int mp_property_deinterlace(m_option_t *prop, int action, M_PROPERTY_CLAMP(prop, *(int *) arg); vf->control(vf, VFCTRL_SET_DEINTERLACE, arg); return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - vf->control(vf, VFCTRL_GET_DEINTERLACE, &deinterlace); - deinterlace = !deinterlace; - vf->control(vf, VFCTRL_SET_DEINTERLACE, &deinterlace); - return M_PROPERTY_OK; } int value = 0; vf->control(vf, VFCTRL_GET_DEINTERLACE, &value); @@ -1077,11 +930,8 @@ static int colormatrix_property_helper(m_option_t *prop, int action, void *arg, MPContext *mpctx) { int r = mp_property_generic_option(prop, action, arg, mpctx); - // testing for an actual change is too much effort switch (action) { case M_PROPERTY_SET: - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: if (mpctx->sh_video) set_video_colorspace(mpctx->sh_video); break; @@ -1200,16 +1050,6 @@ static int mp_property_panscan(m_option_t *prop, int action, void *arg, vo_panscan = *(float *) arg; vo_control(mpctx->video_out, VOCTRL_SET_PANSCAN, NULL); return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - vo_panscan += (arg ? *(float *) arg : 0.1) * - (action == M_PROPERTY_STEP_DOWN ? -1 : 1); - if (vo_panscan > 1) - vo_panscan = 1; - else if (vo_panscan < 0) - vo_panscan = 0; - vo_control(mpctx->video_out, VOCTRL_SET_PANSCAN, NULL); - return M_PROPERTY_OK; default: return m_property_float_range(prop, action, arg, &vo_panscan); } @@ -1232,8 +1072,6 @@ static int mp_property_vo_flag(m_option_t *prop, int action, void *arg, M_PROPERTY_CLAMP(prop, *(int *) arg); if (*vo_var == !!*(int *) arg) return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: if (mpctx->video_out->config_ok) vo_control(mpctx->video_out, vo_ctrl, 0); return M_PROPERTY_OK; @@ -1308,15 +1146,6 @@ static int mp_property_gamma(m_option_t *prop, int action, void *arg, return M_PROPERTY_OK; } break; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - *gamma += (arg ? *(int *) arg : 1) * - (action == M_PROPERTY_STEP_DOWN ? -1 : 1); - M_PROPERTY_CLAMP(prop, *gamma); - r = set_video_colors(mpctx->sh_video, prop->name, *gamma); - if (r <= 0) - break; - return r; default: return M_PROPERTY_NOT_IMPLEMENTED; } @@ -1442,8 +1271,6 @@ static int mp_property_sub_pos(m_option_t *prop, int action, void *arg, case M_PROPERTY_SET: if (!arg) return M_PROPERTY_ERROR; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: vo_osd_changed(OSDTYPE_SUBTITLE); default: return m_property_int_range(prop, action, arg, &sub_pos); @@ -1479,8 +1306,6 @@ static int mp_property_sub_visibility(m_option_t *prop, int action, case M_PROPERTY_SET: if (!arg) return M_PROPERTY_ERROR; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: vo_osd_changed(OSDTYPE_SUBTITLE); if (vo_spudec) vo_osd_changed(OSDTYPE_SPU); @@ -1502,8 +1327,6 @@ static int mp_property_ass_use_margins(m_option_t *prop, int action, case M_PROPERTY_SET: if (!arg) return M_PROPERTY_ERROR; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: vo_osd_changed(OSDTYPE_SUBTITLE); default: return m_property_flag(prop, action, arg, &opts->ass_use_margins); @@ -1520,8 +1343,6 @@ static int mp_property_ass_vsfilter_aspect_compat(m_option_t *prop, int action, case M_PROPERTY_SET: if (!arg) return M_PROPERTY_ERROR; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: vo_osd_changed(OSDTYPE_SUBTITLE); default: return m_property_flag(prop, action, arg, @@ -1542,8 +1363,6 @@ static int mp_property_sub_forced_only(m_option_t *prop, int action, case M_PROPERTY_SET: if (!arg) return M_PROPERTY_ERROR; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: m_property_flag(prop, action, arg, &forced_subs_only); spudec_set_forced_subs_only(vo_spudec, forced_subs_only); return M_PROPERTY_OK; @@ -1569,18 +1388,6 @@ static int mp_property_sub_scale(m_option_t *prop, int action, void *arg, text_font_scale_factor = *(float *) arg; vo_osd_resized(); return M_PROPERTY_OK; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - if (opts->ass_enabled) { - opts->ass_font_scale += (arg ? *(float *) arg : 0.1) * - (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0); - M_PROPERTY_CLAMP(prop, opts->ass_font_scale); - } - text_font_scale_factor += (arg ? *(float *) arg : 0.1) * - (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0); - M_PROPERTY_CLAMP(prop, text_font_scale_factor); - vo_osd_resized(); - return M_PROPERTY_OK; default: if (opts->ass_enabled) return m_property_float_ro(prop, action, arg, opts->ass_font_scale); @@ -1603,7 +1410,6 @@ static tvi_handle_t *get_tvh(struct MPContext *mpctx) static int mp_property_tv_color(m_option_t *prop, int action, void *arg, MPContext *mpctx) { - int r, val; tvi_handle_t *tvh = get_tvh(mpctx); if (!tvh) return M_PROPERTY_UNAVAILABLE; @@ -1616,17 +1422,6 @@ static int mp_property_tv_color(m_option_t *prop, int action, void *arg, return tv_set_color_options(tvh, prop->offset, *(int *) arg); case M_PROPERTY_GET: return tv_get_color_options(tvh, prop->offset, arg); - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - if ((r = tv_get_color_options(tvh, prop->offset, &val)) >= 0) { - if (!r) - return M_PROPERTY_ERROR; - val += (arg ? *(int *) arg : 1) * - (action == M_PROPERTY_STEP_DOWN ? -1 : 1); - M_PROPERTY_CLAMP(prop, val); - return tv_set_color_options(tvh, prop->offset, val); - } - return M_PROPERTY_ERROR; } return M_PROPERTY_NOT_IMPLEMENTED; } @@ -2115,35 +1910,11 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) } case MP_CMD_SWITCH: { - void *arg = NULL; - int r, i; - double d; - int64_t o; cmd->args[0].v.s = translate_legacy_property(cmd, cmd->args[0].v.s); - if (cmd->args[1].v.f) { - m_option_t *prop; - if ((r = mp_property_do(cmd->args[0].v.s, - M_PROPERTY_GET_TYPE, - &prop, mpctx)) <= 0) - goto step_prop_err; - if (prop->type == CONF_TYPE_INT || - prop->type == CONF_TYPE_FLAG || - prop->type == &m_option_type_choice) - i = cmd->args[1].v.f, arg = &i; - else if (prop->type == CONF_TYPE_FLOAT) - arg = &cmd->args[1].v.f; - else if (prop->type == CONF_TYPE_DOUBLE || - prop->type == CONF_TYPE_TIME) - d = cmd->args[1].v.f, arg = &d; - else if (prop->type == CONF_TYPE_INT64) - o = cmd->args[1].v.f, arg = &o; - else - mp_msg(MSGT_CPLAYER, MSGL_WARN, - "Ignoring step size stepping property '%s'.\n", - cmd->args[0].v.s); - } - r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_STEP_UP, arg, mpctx); - step_prop_err: + double s = 1; + if (cmd->args[1].v.f) + s = cmd->args[1].v.f; + int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_SWITCH, &s, mpctx); if (r == M_PROPERTY_UNKNOWN) mp_msg(MSGT_CPLAYER, MSGL_WARN, "Unknown property: '%s'\n", cmd->args[0].v.s); diff --git a/m_option.c b/m_option.c index 015b8f8e20..14a1a0a3d7 100644 --- a/m_option.c +++ b/m_option.c @@ -26,15 +26,18 @@ #include #include #include +#include #include #include #include +#include +#include + #include "talloc.h" #include "m_option.h" #include "mp_msg.h" #include "stream/url.h" -#include "libavutil/avstring.h" char *m_option_strerror(int code) { @@ -128,6 +131,15 @@ static char *print_flag(const m_option_t *opt, const void *val) return talloc_strdup(NULL, "yes"); } +static void add_flag(const m_option_t *opt, void *val, double add, bool wrap) +{ + if (fabs(add) < 0.5) + return; + bool state = VAL(val) != opt->min; + state = wrap ? !state : add > 0; + VAL(val) = state ? opt->max : opt->min; +} + const m_option_type_t m_option_type_flag = { // need yes or no in config files .name = "Flag", @@ -136,10 +148,13 @@ const m_option_type_t m_option_type_flag = { .parse = parse_flag, .print = print_flag, .copy = copy_opt, + .add = add_flag, }; // Integer +#undef VAL + static int parse_longlong(const m_option_t *opt, struct bstr name, struct bstr param, void *dst) { @@ -202,7 +217,35 @@ static char *print_int(const m_option_t *opt, const void *val) { if (opt->type->size == sizeof(int64_t)) return talloc_asprintf(NULL, "%"PRId64, *(const int64_t *)val); - return talloc_asprintf(NULL, "%d", VAL(val)); + return talloc_asprintf(NULL, "%d", *(const int *)val); +} + +static void add_int64(const m_option_t *opt, void *val, double add, bool wrap) +{ + int64_t v = *(int64_t *)val; + + v = v + add; + + bool is64 = opt->type->size == sizeof(int64_t); + int64_t nmin = is64 ? INT64_MIN : INT_MIN; + int64_t nmax = is64 ? INT64_MAX : INT_MAX; + + int64_t min = (opt->flags & M_OPT_MIN) ? opt->min : nmin; + int64_t max = (opt->flags & M_OPT_MAX) ? opt->max : nmax; + + if (v < min) + v = wrap ? max : min; + if (v > max) + v = wrap ? min : max; + + *(int64_t *)val = v; +} + +static void add_int(const m_option_t *opt, void *val, double add, bool wrap) +{ + int64_t tmp = *(int *)val; + add_int64(opt, &tmp, add, wrap); + *(int *)val = tmp; } const m_option_type_t m_option_type_int = { @@ -211,6 +254,7 @@ const m_option_type_t m_option_type_int = { .parse = parse_int, .print = print_int, .copy = copy_opt, + .add = add_int, }; const m_option_type_t m_option_type_int64 = { @@ -219,6 +263,7 @@ const m_option_type_t m_option_type_int64 = { .parse = parse_int64, .print = print_int, .copy = copy_opt, + .add = add_int64, }; static int parse_intpair(const struct m_option *opt, struct bstr name, @@ -311,12 +356,74 @@ static char *print_choice(const m_option_t *opt, const void *val) abort(); } +static void choice_get_min_max(const struct m_option *opt, int *min, int *max) +{ + assert(opt->type == &m_option_type_choice); + *min = INT_MAX; + *max = INT_MIN; + for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) { + *min = FFMIN(*min, alt->value); + *max = FFMAX(*max, alt->value); + } + if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { + *min = FFMIN(*min, opt->min); + *max = FFMAX(*max, opt->max); + } +} + +static void check_choice(int dir, int val, bool *found, int *best, int choice) +{ + if ((dir == -1 && (!(*found) || choice > (*best)) && choice < val) || + (dir == +1 && (!(*found) || choice < (*best)) && choice > val)) + { + *found = true; + *best = choice; + } +} + +static void add_choice(const m_option_t *opt, void *val, double add, bool wrap) +{ + assert(opt->type == &m_option_type_choice); + int dir = add > 0 ? +1 : -1; + bool found = false; + int ival = *(int *)val; + int best = 0; // init. value unused + + if (fabs(add) < 0.5) + return; + + if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { + int newval = ival + add; + if (ival >= opt->min && ival <= opt->max && + newval >= opt->min && newval <= opt->max) + { + found = true; + best = newval; + } else { + check_choice(dir, ival, &found, &best, opt->min); + check_choice(dir, ival, &found, &best, opt->max); + } + } + + for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) + check_choice(dir, ival, &found, &best, alt->value); + + if (!found) { + int min, max; + choice_get_min_max(opt, &min, &max); + best = (dir == -1) ^ wrap ? min : max; + } + + *(int *)val = best; +} + const struct m_option_type m_option_type_choice = { .name = "String", // same as arbitrary strings in option list for now .size = sizeof(int), .parse = parse_choice, .print = print_choice, .copy = copy_opt, + .add = add_choice, }; // Float @@ -386,6 +493,23 @@ static char *print_double(const m_option_t *opt, const void *val) return talloc_asprintf(NULL, "%f", VAL(val)); } +static void add_double(const m_option_t *opt, void *val, double add, bool wrap) +{ + double v = VAL(val); + + v = v + add; + + double min = (opt->flags & M_OPT_MIN) ? opt->min : -INFINITY; + double max = (opt->flags & M_OPT_MAX) ? opt->max : +INFINITY; + + if (v < min) + v = wrap ? max : min; + if (v > max) + v = wrap ? min : max; + + VAL(val) = v; +} + const m_option_type_t m_option_type_double = { // double precision float or ratio (numerator[:/]denominator) .name = "Double", @@ -414,6 +538,13 @@ static char *print_float(const m_option_t *opt, const void *val) return talloc_asprintf(NULL, "%f", VAL(val)); } +static void add_float(const m_option_t *opt, void *val, double add, bool wrap) +{ + double tmp = VAL(val); + add_double(opt, &tmp, add, wrap); + VAL(val) = tmp; +} + const m_option_type_t m_option_type_float = { // floating point number or ratio (numerator[:/]denominator) .name = "Float", @@ -421,6 +552,7 @@ const m_option_type_t m_option_type_float = { .parse = parse_float, .print = print_float, .copy = copy_opt, + .add = add_float, }; ///////////// String @@ -1009,6 +1141,7 @@ const m_option_type_t m_option_type_time = { .parse = parse_time, .print = print_double, .copy = copy_opt, + .add = add_double, }; diff --git a/m_option.h b/m_option.h index 73752e7a56..75f9ee5925 100644 --- a/m_option.h +++ b/m_option.h @@ -222,6 +222,11 @@ struct m_option_type { * set to NULL. */ void (*free)(void *dst); + + // Add the value add to the value in val. For types that are not numeric, + // add gives merely the direction. The wrap parameter determines whether + // the value is clipped, or wraps around to the opposite max/min. + void (*add)(const m_option_t *opt, void *val, double add, bool wrap); }; // Option description diff --git a/m_property.c b/m_property.c index fac3ec8285..c35cc51f9d 100644 --- a/m_property.c +++ b/m_property.c @@ -116,6 +116,28 @@ int m_property_do(const m_option_t *prop_list, const char *name, m_option_free(opt, val); free(val); return r; + case M_PROPERTY_SWITCH: + if ((r = do_action(prop_list, name, M_PROPERTY_SWITCH, arg, ctx)) != + M_PROPERTY_NOT_IMPLEMENTED) + return r; + if ((r = + do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0) + return r; + // Fallback to m_option + if (!opt->type->add) + return M_PROPERTY_NOT_IMPLEMENTED; + val = calloc(1, opt->type->size); + if ((r = do_action(prop_list, name, M_PROPERTY_GET, val, ctx)) <= 0) { + free(val); + return r; + } + bool wrap = opt->type == &m_option_type_choice || + opt->type == &m_option_type_flag; + opt->type->add(opt, val, *(double*)arg, wrap); + r = do_action(prop_list, name, M_PROPERTY_SET, val, ctx); + m_option_free(opt, val); + free(val); + return r; } return do_action(prop_list, name, action, arg, ctx); } @@ -264,12 +286,6 @@ int m_property_int_range(const m_option_t *prop, int action, M_PROPERTY_CLAMP(prop, *(int *)arg); *var = *(int *)arg; return 1; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - *var += (arg ? *(int *)arg : 1) * - (action == M_PROPERTY_STEP_DOWN ? -1 : 1); - M_PROPERTY_CLAMP(prop, *var); - return 1; } return m_property_int_ro(prop, action, arg, *var); } @@ -292,10 +308,6 @@ int m_property_flag(const m_option_t *prop, int action, void *arg, int *var) { switch (action) { - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - *var = *var == prop->min ? prop->max : prop->min; - return 1; case M_PROPERTY_PRINT: return m_property_flag_ro(prop, action, arg, *var); } @@ -330,12 +342,6 @@ int m_property_float_range(const m_option_t *prop, int action, M_PROPERTY_CLAMP(prop, *(float *)arg); *var = *(float *)arg; return 1; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - *var += (arg ? *(float *)arg : 0.1) * - (action == M_PROPERTY_STEP_DOWN ? -1 : 1); - M_PROPERTY_CLAMP(prop, *var); - return 1; } return m_property_float_ro(prop, action, arg, *var); } diff --git a/m_property.h b/m_property.h index 902f38c77e..180dbbf618 100644 --- a/m_property.h +++ b/m_property.h @@ -58,18 +58,6 @@ */ #define M_PROPERTY_PARSE 3 -/// Increment the current value. -/** The sign of the argument is also taken into account if applicable. - * \param arg Pointer to a variable of the right type or NULL. - */ -#define M_PROPERTY_STEP_UP 4 - -/// Decrement the current value. -/** The sign of the argument is also taken into account if applicable. - * \param arg Pointer to a variable of the right type or NULL. - */ -#define M_PROPERTY_STEP_DOWN 5 - /// Get a string containg a parsable representation. /** Set the variable to a newly allocated string or NULL. * \param arg Pointer to a char* variable. @@ -82,6 +70,10 @@ /// Get a m_option describing the property. #define M_PROPERTY_GET_TYPE 8 +// Switch the property up/down by a given value. +// arg: (double) value to add to the property +#define M_PROPERTY_SWITCH 9 + ///@} /// \defgroup PropertyActionsArg Property actions argument type