summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2012-09-18 14:00:08 +0200
committerwm4 <wm4@nowhere>2012-10-12 10:10:31 +0200
commitcac7702565b560d5a16bc82bf553d1a4c08297e1 (patch)
tree5d1246e28da246dc26fa54de267c35545ac0f09f
parent3d67041089c7945dcea0162c0038e495d588b379 (diff)
downloadmpv-cac7702565b560d5a16bc82bf553d1a4c08297e1.tar.bz2
mpv-cac7702565b560d5a16bc82bf553d1a4c08297e1.tar.xz
commands: handle property stepping in a generic way
Instead of forcing each property implementation implement its own logic for M_PROPERTY_STEP_UP/M_PROPERTY_STEP_DOWN, handle it in the generic property code. Rename the M_PROPERTY_STEP_UP command to M_PROPERTY_SWITCH (the other property command, M_PROPERTY_STEP_DOWN, isn't needed anymore: stepping downwards is done by passing a negative argument). Always use double as argument type; it makes the code easier, and covers all property types. Move the code which does the actual type-specific value stepping to m_option.c (the idea is that m_option handles types). Some properties still have custom handlers implemented with M_PROPERTY_SWITCH. They can't be mapped to the generic mechanism, because their value range is dynamic or entirely unknown. For some properties, the default step stride is changed to 1. This is no issue, because the default bindings in input.conf all use an explicit stride in the affected cases.
-rw-r--r--command.c275
-rw-r--r--m_option.c137
-rw-r--r--m_option.h5
-rw-r--r--m_property.c38
-rw-r--r--m_property.h16
5 files changed, 189 insertions, 282 deletions
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 <math.h>
#include <stdio.h>
#include <stdarg.h>
+#include <limits.h>
#include <inttypes.h>
#include <unistd.h>
#include <assert.h>
+#include <libavutil/common.h>
+#include <libavutil/avstring.h>
+
#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