diff --git a/player/command.c b/player/command.c index 6e7389d666..da5d985c17 100644 --- a/player/command.c +++ b/player/command.c @@ -243,6 +243,78 @@ void mark_seek(struct MPContext *mpctx) cmd->last_seek_time = now; } +static char *skip_n_lines(char *text, int lines) +{ + while (text && lines > 0) { + char *next = strchr(text, '\n'); + text = next ? next + 1 : NULL; + lines--; + } + return text; +} + +static int count_lines(char *text) +{ + int count = 0; + while (text) { + char *next = strchr(text, '\n'); + if (!next || (next[0] == '\n' && !next[1])) + break; + text = next + 1; + count++; + } + return count; +} + +// Given a huge string separated by new lines, attempts to cut off text above +// the current line to keep the line visible, and below to keep rendering +// performance up. pos gives the current line (0 for the first line). +// "text" might be returned as is, or it can be freed and a new allocation is +// returned. +// This is only a heuristic - we can't deal with line breaking. +static char *cut_osd_list(struct MPContext *mpctx, char *text, int pos) +{ + int screen_h, font_h; + osd_get_text_size(mpctx->osd, &screen_h, &font_h); + int max_lines = screen_h / MPMAX(font_h, 1) - 1; + + if (!text || max_lines < 5) + return text; + + int count = count_lines(text); + if (count <= max_lines) + return text; + + char *new = talloc_strdup(NULL, ""); + + int start = pos - max_lines / 2; + if (start == 1) + start = 0; // avoid weird transition when pad_h becomes visible + int pad_h = start > 0; + if (pad_h) + new = talloc_strdup_append_buffer(new, "\342\206\221 (hidden items)\n"); + + int space = max_lines - pad_h - 1; + int pad_t = count - start > space; + if (!pad_t) + start = count - space; + + char *head = skip_n_lines(text, start); + if (!head) { + talloc_free(new); + return text; + } + + char *tail = skip_n_lines(head, max_lines - pad_h - pad_t); + new = talloc_asprintf_append_buffer(new, "%.*s", + (int)(tail ? tail - head : strlen(head)), head); + if (pad_t) + new = talloc_strdup_append_buffer(new, "\342\206\223 (hidden items)\n"); + + talloc_free(text); + return new; +} + static char *format_file_size(int64_t size) { double s = size; @@ -3321,9 +3393,10 @@ static int mp_property_playlist(void *ctx, struct m_property *prop, { MPContext *mpctx = ctx; if (action == M_PROPERTY_PRINT) { + struct playlist *pl = mpctx->playlist; char *res = talloc_strdup(NULL, ""); - for (struct playlist_entry *e = mpctx->playlist->first; e; e = e->next) + for (struct playlist_entry *e = pl->first; e; e = e->next) { char *p = e->filename; if (!mp_is_url(bstr0(p))) { @@ -3331,12 +3404,12 @@ static int mp_property_playlist(void *ctx, struct m_property *prop, if (s[0]) p = s; } - const char *m = mpctx->playlist->current == e ? - list_current : list_normal; + const char *m = pl->current == e ? list_current : list_normal; res = talloc_asprintf_append(res, "%s%s\n", m, p); } - *(char **)arg = res; + *(char **)arg = + cut_osd_list(mpctx, res, playlist_entry_to_index(pl, pl->current)); return M_PROPERTY_OK; } diff --git a/sub/osd.h b/sub/osd.h index f0ebc3b827..aef1c60b33 100644 --- a/sub/osd.h +++ b/sub/osd.h @@ -201,6 +201,7 @@ void osd_rescale_bitmaps(struct sub_bitmaps *imgs, int frame_w, int frame_h, // defined in osd_libass.c and osd_dummy.c void osd_set_external(struct osd_state *osd, void *id, int res_x, int res_y, char *text); +void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h); void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function); #endif /* MPLAYER_SUB_H */ diff --git a/sub/osd_dummy.c b/sub/osd_dummy.c index f7710ae2df..0e6b802cef 100644 --- a/sub/osd_dummy.c +++ b/sub/osd_dummy.c @@ -28,3 +28,9 @@ void osd_set_external(struct osd_state *osd, void *id, int res_x, int res_y, char *text) { } + +void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h) +{ + *out_screen_h = 0; + *out_font_h = 0; +} diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 454d0387a4..44fcf6d269 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -219,13 +219,10 @@ static ASS_Event *add_osd_ass_event_escaped(ASS_Track *track, const char *style, return e; } -static void update_osd_text(struct osd_state *osd, struct osd_object *obj) +static ASS_Style *prepare_osd_ass(struct osd_state *osd, struct osd_object *obj) { struct MPOpts *opts = osd->opts; - if (!obj->text[0]) - return; - create_ass_track(osd, obj, &obj->ass, 0, 0); struct osd_style_opts font = *opts->osd_style; @@ -236,10 +233,31 @@ static void update_osd_text(struct osd_state *osd, struct osd_object *obj) if (!opts->osd_scale_by_window) playresy *= 720.0 / obj->vo_res.h; - mp_ass_set_style(get_style(&obj->ass, "OSD"), playresy, &font); + ASS_Style *style = get_style(&obj->ass, "OSD"); + mp_ass_set_style(style, playresy, &font); + return style; +} + +static void update_osd_text(struct osd_state *osd, struct osd_object *obj) +{ + + if (!obj->text[0]) + return; + + prepare_osd_ass(osd, obj); add_osd_ass_event_escaped(obj->ass.track, "OSD", obj->text); } +void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h) +{ + pthread_mutex_lock(&osd->lock); + struct osd_object *obj = osd->objs[OSDTYPE_OSD]; + ASS_Style *style = prepare_osd_ass(osd, obj); + *out_screen_h = obj->ass.track->PlayResY - style->MarginV; + *out_font_h = style->FontSize; + pthread_mutex_unlock(&osd->lock); +} + // align: -1 .. +1 // frame: size of the containing area // obj: size of the object that should be positioned inside the area