summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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