mirror of
https://github.com/mpv-player/mpv
synced 2024-12-28 18:12:22 +00:00
command: use scale_units to add/cycle integer properties
This adds check_property_scalable, which returns true if the property is backed by a floating-point number. When the add or cycle commands operate on these properties, they can benefit from the fractional scale value in cmd->scale. When the property is not backed by a floating-point number, cmd->scale_units is used instead, so for axis events, the property is only incrmented when the user scrolls one full unit. This solution isn't perfect, because in some cases integer-backed properties could benefit from accurate scrolling. For example, if an axis is bound to "cycle audio 5", the cycle command could be made to change the audio track by one when the user scrolls 1/5th of a unit, though this behaviour would require more changes to the options system.
This commit is contained in:
parent
937128697f
commit
89fd3e1d9d
@ -140,7 +140,7 @@ struct mp_cmd *mp_input_parse_cmd_node(struct mp_log *log, mpv_node *node)
|
||||
{
|
||||
struct mp_cmd *cmd = talloc_ptrtype(NULL, cmd);
|
||||
talloc_set_destructor(cmd, destroy_cmd);
|
||||
*cmd = (struct mp_cmd) { .scale = 1, };
|
||||
*cmd = (struct mp_cmd) { .scale = 1, .scale_units = 1 };
|
||||
|
||||
if (node->format != MPV_FORMAT_NODE_ARRAY)
|
||||
goto error;
|
||||
@ -254,6 +254,7 @@ static struct mp_cmd *parse_cmd_str(struct mp_log *log, void *tmp,
|
||||
*cmd = (struct mp_cmd) {
|
||||
.flags = MP_ON_OSD_AUTO | MP_EXPAND_PROPERTIES,
|
||||
.scale = 1,
|
||||
.scale_units = 1,
|
||||
};
|
||||
|
||||
ctx->str = bstr_lstrip(ctx->str);
|
||||
|
@ -618,11 +618,13 @@ static void interpret_key(struct input_ctx *ictx, int code, double scale,
|
||||
|
||||
if (mp_input_is_scalable_cmd(cmd)) {
|
||||
cmd->scale = scale;
|
||||
cmd->scale_units = scale_units;
|
||||
mp_input_queue_cmd(ictx, cmd);
|
||||
} else {
|
||||
// Non-scalable commands won't understand cmd->scale, so synthesize
|
||||
// multiple commands with cmd->scale = 1
|
||||
cmd->scale = 1;
|
||||
cmd->scale_units = 1;
|
||||
// Avoid spamming the player with too many commands
|
||||
scale_units = FFMIN(scale_units, 20);
|
||||
for (int i = 0; i < scale_units - 1; i++)
|
||||
|
@ -85,6 +85,7 @@ typedef struct mp_cmd {
|
||||
int mouse_x, mouse_y;
|
||||
struct mp_cmd *queue_next;
|
||||
double scale; // for scaling numeric arguments
|
||||
int scale_units;
|
||||
const struct mp_cmd_def *def;
|
||||
char *sender; // name of the client API user which sent this
|
||||
char *key_name; // string representation of the key binding
|
||||
|
@ -4783,6 +4783,20 @@ static bool check_property_autorepeat(char *property, struct MPContext *mpctx)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Whether changes to this property (add/cycle cmds) benefit from cmd->scale
|
||||
static bool check_property_scalable(char *property, struct MPContext *mpctx)
|
||||
{
|
||||
struct m_option prop = {0};
|
||||
if (mp_property_do(property, M_PROPERTY_GET_TYPE, &prop, mpctx) <= 0)
|
||||
return true;
|
||||
|
||||
// These properties are backed by a floating-point number
|
||||
return prop.type == &m_option_type_float ||
|
||||
prop.type == &m_option_type_double ||
|
||||
prop.type == &m_option_type_time ||
|
||||
prop.type == &m_option_type_aspect;
|
||||
}
|
||||
|
||||
static struct mpv_node *add_map_entry(struct mpv_node *dst, const char *key)
|
||||
{
|
||||
struct mpv_node_list *list = dst->u.list;
|
||||
@ -4925,27 +4939,35 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
|
||||
case MP_CMD_CYCLE:
|
||||
{
|
||||
char *property = cmd->args[0].v.s;
|
||||
struct m_property_switch_arg s = {
|
||||
.inc = cmd->args[1].v.d * cmd->scale,
|
||||
.wrap = cmd->id == MP_CMD_CYCLE,
|
||||
};
|
||||
if (cmd->repeated && !check_property_autorepeat(property, mpctx)) {
|
||||
MP_VERBOSE(mpctx, "Dropping command '%.*s' from auto-repeated key.\n",
|
||||
BSTR_P(cmd->original));
|
||||
break;
|
||||
}
|
||||
int r = mp_property_do(property, M_PROPERTY_SWITCH, &s, mpctx);
|
||||
if (r == M_PROPERTY_OK || r == M_PROPERTY_UNAVAILABLE) {
|
||||
show_property_osd(mpctx, property, on_osd);
|
||||
} else if (r == M_PROPERTY_UNKNOWN) {
|
||||
set_osd_msg(mpctx, osdl, osd_duration,
|
||||
"Unknown property: '%s'", property);
|
||||
return -1;
|
||||
} else if (r <= 0) {
|
||||
set_osd_msg(mpctx, osdl, osd_duration,
|
||||
"Failed to increment property '%s' by %g",
|
||||
property, s.inc);
|
||||
return -1;
|
||||
double scale = 1;
|
||||
int scale_units = cmd->scale_units;
|
||||
if (check_property_scalable(property, mpctx)) {
|
||||
scale = cmd->scale;
|
||||
scale_units = 1;
|
||||
}
|
||||
for (int i = 0; i < scale_units; i++) {
|
||||
struct m_property_switch_arg s = {
|
||||
.inc = cmd->args[1].v.d * scale,
|
||||
.wrap = cmd->id == MP_CMD_CYCLE,
|
||||
};
|
||||
int r = mp_property_do(property, M_PROPERTY_SWITCH, &s, mpctx);
|
||||
if (r == M_PROPERTY_OK || r == M_PROPERTY_UNAVAILABLE) {
|
||||
show_property_osd(mpctx, property, on_osd);
|
||||
} else if (r == M_PROPERTY_UNKNOWN) {
|
||||
set_osd_msg(mpctx, osdl, osd_duration,
|
||||
"Unknown property: '%s'", property);
|
||||
return -1;
|
||||
} else if (r <= 0) {
|
||||
set_osd_msg(mpctx, osdl, osd_duration,
|
||||
"Failed to increment property '%s' by %g",
|
||||
property, s.inc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user