14#include <pango/pangocairo.h>
15static int font_cmp(
const void *p1,
const void *p2);
19static void fill_bckg(lives_painter_t *cr,
double x,
double y,
double dx,
double dy) {
27static void getxypos(LingoLayout *layout,
int *px,
int *py,
int width,
int height,
boolean cent,
double *pw,
double *ph) {
38 lingo_layout_get_size(layout, &w_, &h_);
41 d = ((double)h_) / (double)LINGO_SCALE;
45 if (py) *py = height - (int) * ph;
47 d = ((double)w_) / (double)LINGO_SCALE;
50 if (px) *px = cent ? (width - (int)d) >> 1 : 0.;
54static char *rewrap_text(
char *text) {
67 boolean needs_nl =
FALSE;
68 int numlines, maxline = -1;
71 if (!text || !(*text))
return NULL;
73 jtext = lives_strdup(
"");
75 lines = lives_strsplit(text,
"\n", numlines);
77 for (i = 0; i < numlines; i++) {
84 lives_strfreev(lines);
87 for (i = 0; i < numlines; i++) {
90 for (j = maxlen - 1; j > 0; j--) {
93 if (lines[i][j - 1] ==
' ') {
95 first = lives_strndup(lines[i], j);
97 second = lines[i] + j;
106 lines[i][maxlen - 1] = 0;
108 lives_snprintf(&lines[i][maxlen - 4], 4,
"%s",
"...");
113 lines[i][maxlen - 1] = 0;
115 lives_snprintf(&lines[i][maxlen - 4], 4,
"%s",
"...");
123 lives_strfreev(lines);
128static char *remove_first_line(
char *text) {
131 for (i = 0; i < tlen; i++) {
132 if (text[i] ==
'\n')
return lives_strdup(text + i + 1);
138static char *deparagraph(
char *text) {
141 int i, j = 0, nlcnt = 0;
143 for (i = 0; text[i]; i++) {
144 if (text[i] ==
'\n') {
145 if (!text[i + 1] || text[i + 1] ==
'\n') nlcnt++;
152 for (i = 0; text[i]; i++) {
153 xtext[j++] = text[i];
154 if (text[i] ==
'\n') {
155 if (!text[i + 1] || text[i + 1] ==
'\n') xtext[j++] =
' ';
166 lives_colRGBA64_t *bg,
int dwidth,
int dheight,
double x_bg,
double y_bg,
double x_text,
double y_text) {
170 if (bg) b_alpha = (double)bg->
alpha / 65535.;
171 if (fg) f_alpha = (double)fg->
alpha / 65535.;
177 lingo_layout_set_text(layout,
"", -1);
180 fill_bckg(cr, x_bg, y_bg, dwidth, dheight);
206 char *readytext, *testtext = NULL, *newtext = NULL, *tmp, *xx;
210 int w = 0, h = 0, pw;
215 boolean heightdone =
FALSE;
216 boolean needs_newline =
FALSE;
220 ctx = lives_widget_create_lingo_context(widget);
221 if (!ctx || !LINGO_IS_CONTEXT(ctx))
return NULL;
223 layout = lingo_layout_new(ctx);
224 if (!layout || !LINGO_IS_LAYOUT(layout)) {
229 readytext = lives_strdup(
"");
232 if (!msg)
return NULL;
234 if (
error != WEED_SUCCESS)
return NULL;
235 if (!newtext)
return NULL;
237 if (slen > 0 && newtext[slen - 1] ==
'\n') {
242 g_print(
"Got msg:%s\ntotal is now %d lines\n", newtext, totlines);
247 if (
error != WEED_SUCCESS)
return NULL;
258 if (
error != WEED_SUCCESS)
break;
262 g_print(
"Got msg:%s\ntotal is now %d lines\n", newtext, totlines);
267 if (
error != WEED_SUCCESS)
break;
273 needs_newline =
TRUE;
274 lingo_layout_set_text(layout,
"", -1);
276 layout = lingo_layout_new(ctx);
277 testtext = deparagraph(testtext);
278 lingo_layout_set_text(layout, testtext, -1);
279 lingo_layout_get_size(layout, &w, &h);
285 g_print(
"Sizes %d %d window, %d %d layout ()\n", width, height, w, h);
290 g_print(
"Too high !\n");
296 tmp = remove_first_line(newtext);
302 g_print(
"Retry with (%d) |%s|\n", totlines, newtext);
307 g_print(
"Testing with:%s:\n", testtext);
309 lingo_layout_set_text(layout,
"", -1);
311 layout = lingo_layout_new(ctx);
312 lingo_layout_set_width(layout, width * LINGO_SCALE);
313 testtext = deparagraph(testtext);
314 lingo_layout_set_text(layout, testtext, -1);
315 lingo_layout_get_size(layout, NULL, &h);
323 if (0 && w > width) {
324 int jumpval = 1, dirn = -1, tjump = 0;
328 g_print(
"Too wide !!!\n");
335 tjump = dirn * jumpval;
343 if (whint == 0 || whint + 4 > slen) {
344 xx = lives_strndup(newtext, slen + tjump);
346 xx = lives_strndup(newtext, whint + 4 + tjump);
348 tmp = rewrap_text(xx);
351 g_print(
"Retry with (%d) |%s|\n", totlines, xx);
355 lingo_layout_set_text(layout,
"", -1);
357 layout = lingo_layout_new(ctx);
359 tmp = deparagraph(tmp);
360 lingo_layout_set_text(layout, tmp, -1);
361 lingo_layout_get_size(layout, &pw, NULL);
362 w = pw / LINGO_SCALE;
366 if (whint <= 0 || (ll = (
int)
lives_strlen(tmp)) < whint) whint = ll;
379 g_print(
"Width OK now\n");
391 readytext = testtext;
394 g_print(
"|%s| passed size tests\n", readytext);
396 if (heightdone)
break;
403 if (linecount) *linecount = totlines;
406 g_print(
"|%s| FINAL !!\n", readytext);
418 char **font_list = NULL;
421 ctx = gdk_pango_context_get();
424 pfm = pango_context_get_font_map(ctx);
427 PangoFontFamily **pff = NULL;
428 pango_font_map_list_families(pfm, &pff, &num);
430 font_list = (
char **)
lives_malloc((num + 1) *
sizeof(
char *));
432 for (i = 0; i < num; ++i)
433 font_list[i] = lives_strdup(pango_font_family_get_name(pff[i]));
434 font_list[num] = NULL;
435 qsort(font_list, num,
sizeof(
char *), font_cmp);
445 QStringList qsl = qfd.families();
446 font_list = (
char **)
lives_malloc((qsl.size() + 1) *
sizeof(
char *));
447 for (i = 0; i < qsl.size(); i++) {
448 font_list[i] = lives_strdup(qsl.at(i).toUtf8().constData());
456static int font_cmp(
const void *p1,
const void *p2) {
457 const char *s1 = (
const char *)(*(
char **)p1);
458 const char *s2 = (
const char *)(*(
char **)p2);
459 char *u1 = lives_utf8_casefold(s1, -1);
460 char *u2 = lives_utf8_casefold(s2, -1);
468LingoLayout *
render_text_to_cr(LiVESWidget *widget, lives_painter_t *cr,
const char *text,
const char *fontname,
470 boolean center,
boolean rising,
double *top,
int *offs_x,
int dwidth,
int *dheight) {
482 LingoFontDescription *font = NULL;
485 int x_pos = 0, y_pos = 0;
486 double lwidth = (double)dwidth, lheight = (
double)(*dheight);
488 if (!cr)
return NULL;
492 LingoContext *ctx = gtk_widget_get_pango_context(widget);
493 layout = lingo_layout_new(ctx);
495 layout = pango_cairo_create_layout(cr);
496 if (!layout)
return NULL;
498 font = lingo_font_description_new();
499 pango_font_description_set_family(font, fontname);
500 pango_font_description_set_absolute_size(font, size * LINGO_SCALE);
501 pango_layout_set_font_description(layout, font);
504 lingo_layout_set_markup(layout, text, -1);
507 if (center) lingo_layout_set_alignment(layout, LINGO_ALIGN_CENTER);
508 else lingo_layout_set_alignment(layout, LINGO_ALIGN_LEFT);
510 getxypos(layout, &x_pos, &y_pos, dwidth, *dheight, center, &lwidth, &lheight);
511 if (lwidth > dwidth) {
512 lingo_layout_set_width(layout, dwidth * LINGO_SCALE);
515 lwidth = (double)dwidth;
516 lheight = (double)(*dheight);
517 getxypos(layout, &x_pos, &y_pos, dwidth, *dheight, center, &lwidth, &lheight);
520 if (!rising) y_pos = (double) * dheight * *top;
530 if (font) lingo_font_description_free(font);
537 layout_to_lives_painter(layout, cr, mode, fg, bg, lwidth, lheight, x_pos, y_pos, x_pos, y_pos);
544 if (!text)
return layer;
549 const char *font =
"Sans";
550 boolean fake_gamma =
FALSE;
564 weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_LINEAR);
572 boolean center,
boolean rising,
double top) {
576 lives_painter_t *cr = NULL;
585 int lheight = height;
586 int gamma = WEED_GAMMA_UNKNOWN, offsx = 0;
600 if (ipsize == opsize) {
614 fg_col, bg_col, center, rising, &top, &offsx, width, &lheight);
620 if (top * height + lheight < height) {
622 boolean rbswapped =
FALSE;
626 xsrc = src + (int)(top * height) * row;
653 layout =
render_text_to_cr(NULL, cr, text, fontname, size, mode, fg_col, bg_col, center,
FALSE, &ztop, &offsx, width, &height);
654 if (layout && LINGO_IS_LAYOUT(layout)) {
655 lingo_painter_show_layout(cr, layout);
667 if (pd != xsrc)
lives_memcpy(src + (
int)(top * height) * row, pd, lheight * row);
685 if (!cr)
return layer;
686 layout =
render_text_to_cr(NULL, cr, text, fontname, size, mode, fg_col, bg_col, center, rising, &top, &offsx, width, &height);
687 if (layout && LINGO_IS_LAYOUT(layout)) {
688 lingo_painter_show_layout(cr, layout);
693 if (gamma != WEED_GAMMA_UNKNOWN)
698static const char *cr_str =
"\x0D";
699static const char *lf_str =
"\x0A";
710 if (fd < 0 || !title)
return NULL;
716 poslf = strstr(data, lf_str);
717 if (poslf) *poslf =
'\0';
718 poscr = strstr(data, cr_str);
719 if (poscr) *poscr =
'\0';
721 if (!ret) ret = lives_strdup(data);
723 char *tmp = lives_strconcat(ret,
"\n", data, NULL);
737 char *retmore = NULL;
739 size_t curlen, retlen;
741 if (fd < 0 || !title)
return NULL;
747 poslf = strstr(data, lf_str);
748 if (poslf) *poslf =
'\0';
749 poscr = strstr(data, cr_str);
750 if (poscr) *poscr =
'\0';
754 ret =
subst(data,
"[br]",
"\n");
755 if (!ret)
return NULL;
758 retmore =
subst(data,
"[br]",
"\n");
759 if (!retmore)
return NULL;
762 retlen += curlen + 1;
766 strcat(ret, retmore);
786 char *poslf = NULL, *poscr = NULL;
787 double starttime, endtime;
788 int hstart, mstart, sstart, fstart;
789 int hend, mend, send, fend;
807 poslf = strstr(data, lf_str);
810 poscr = strstr(data, cr_str);
815 i = sscanf(data,
"%d:%d:%d,%d --> %d:%d:%d,%d", \
816 &hstart, &mstart, &sstart, &fstart, \
817 &hend, &mend, &send, &fend);
820 starttime = hstart * 3600 + mstart * 60 + sstart + fstart / 1000.;
821 endtime = hend * 3600 + mend * 60 + send + fend / 1000.;
839 poslf = strstr(data, lf_str);
842 poscr = strstr(data, cr_str);
859 boolean starttext =
FALSE;
862 char *poslf = NULL, *poscr = NULL;
863 int hstart, mstart, sstart, fstart;
864 int hend, mend, send, fend;
866 double starttime, endtime;
868 if (!strncmp(data,
"[SUBTITLE]", 10)) {
873 if (!strncmp(data,
"[DELAY]", 7)) {
883 poslf = strstr(data, lf_str);
886 poscr = strstr(data, cr_str);
891 i = sscanf(data,
"%d:%d:%d.%d,%d:%d:%d.%d", \
892 &hstart, &mstart, &sstart, &fstart, \
893 &hend, &mend, &send, &fend);
896 starttime = hstart * 3600 + mstart * 60 + sstart + fstart / 100.;
897 endtime = hend * 3600 + mend * 60 + send + fend / 100.;
915 poslf = strstr(data, lf_str);
918 poscr = strstr(data, cr_str);
933 if (!sfile || !sfile->
subt)
return FALSE;
941 char *tmp = srt_read_text(sfile->
subt->
tfile, curr);
952 if (xtime < sfile->subt->first->start_time || xtime > sfile->
subt->
last->
end_time) {
960 if (xtime < curr->start_time && xtime <= curr->prev->end_time)
while (curr->
start_time > xtime) curr = curr->
prev;
966 char *tmp = srt_read_text(sfile->
subt->
tfile, curr);
978 if (!sfile->
subt)
return;
1000 if (!sfile)
return FALSE;
1019static void parse_double_time(
double tim,
int *ph,
int *pmin,
int *psec,
int *pmsec,
int fix) {
1020 int ntim = (int)tim;
1024 m = (ntim - h * 3600) / 60;
1025 s = (ntim - h * 3600 - m * 60);
1026 if (fix == 3) ms = (int)((tim - ntim) * 1000.0 + .5);
1027 else ms = (int)((tim - ntim) * 100.0 + .5);
1041 int64_t savepos = 0;
1045 if (!sfile)
return FALSE;
1047 if (!subt)
return FALSE;
1055 if (fd < 0)
return FALSE;
1061 text = srt_read_text(subt->
tfile, ptr);
1069 if (dtim < start_time) dtim = start_time;
1070 dtim += offset_time;
1072 parse_double_time(dtim, &h, &m, &s, &ms, 3);
1076 if (dtim > end_time) dtim = end_time;
1077 dtim += offset_time;
1079 parse_double_time(dtim, &h, &m, &s, &ms, 3);
1085 }
else if (ptr->
start_time >= end_time)
break;
1103 int64_t savepos = 0;
1119 if (fd < 0)
return FALSE;
1135 char *br_text = NULL;
1137 text = sub_read_text(subt->
tfile, ptr);
1142 if (text[ll] ==
'\n') text[ll] = 0;
1144 br_text =
subst(text,
"\n",
"[br]");
1149 if (dtim < start_time) dtim = start_time;
1150 dtim += offset_time;
1152 parse_double_time(dtim, &h, &m, &s, &ms, 2);
1156 if (dtim > end_time) dtim = end_time;
1157 dtim += offset_time;
1159 parse_double_time(dtim, &h, &m, &s, &ms, 2);
1167 }
else if (ptr->
start_time >= end_time)
break;
1183 char **style,
char **weight) {
1184 if (!
string)
return FALSE;
1187 char **array = lives_strsplit(
string,
" ", numtok);
1191 for (
int i = 0; i < numtok - 1; i++) {
1197 }
else *font = lives_strdup(array[i]);
1200 if (size && numtok > 1 && atoi(array[numtok - 1])) *size = atoi(array[numtok - 1]);
1201 if (font && !atoi(array[numtok - 1])) {
1206 }
else *font = lives_strdup(array[numtok - 1]);
1208 lives_strfreev(array);
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_height(weed_layer_t *layer, int height)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_free(weed_layer_t *layer)
frees pixel_data for a layer, then the layer itself
LIVES_GLOBAL_INLINE int weed_layer_get_height(weed_layer_t *layer)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_new(int layer_type)
LIVES_GLOBAL_INLINE uint8_t * weed_layer_get_pixel_data_packed(weed_layer_t *layer)
boolean convert_layer_palette(weed_layer_t *layer, int outpl, int op_clamping)
boolean consider_swapping(int *inpal, int *outpal)
look for shortcuts in palette conversions instead of converting e.g RGB -> BGRA, we may be able to pr...
lives_painter_t * layer_to_lives_painter(weed_layer_t *layer)
convert a weed layer to lives_painter (a.k.a cairo)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_pixel_data_packed(weed_layer_t *layer, void *pixel_data)
LIVES_GLOBAL_INLINE int weed_layer_get_rowstride(weed_layer_t *layer)
for packed palettes
LIVES_GLOBAL_INLINE boolean weed_palette_is_rgb(int pal)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_gamma(weed_layer_t *layer, int gamma_type)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_palette(weed_layer_t *layer, int palette)
functions all return the input layer for convenience; no checking for valid values is done if layer i...
LIVES_GLOBAL_INLINE int weed_layer_get_width(weed_layer_t *layer)
int weed_layer_get_gamma(weed_layer_t *layer)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_nullify_pixel_data(weed_layer_t *layer)
LIVES_GLOBAL_INLINE int weed_layer_get_palette(weed_layer_t *layer)
boolean lives_painter_to_layer(lives_painter_t *cr, weed_layer_t *layer)
convert a lives_painter_t (a.k.a) cairo_t to a weed layer
weed_layer_t * weed_layer_copy(weed_layer_t *dlayer, weed_layer_t *slayer)
copy source layer slayer to dest layer dlayer
LIVES_GLOBAL_INLINE size_t pixel_size(int pal)
#define WEED_LAYER_TYPE_VIDEO
weed_plant_t weed_layer_t
#define LIVES_FLAG_MAINTAIN_VALUE
soft flag, like immutable / deletable for host
#define WEED_LEAF_PREVIOUS
error("LSD_RANDFUNC(ptr, size) must be defined")
LIVES_GLOBAL_INLINE size_t lives_strlen(const char *s)
LIVES_GLOBAL_INLINE int lives_strcmp_ordered(const char *st1, const char *st2)
#define WEED_LEAF_LIVES_MESSAGE_STRING
ssize_t lives_read_buffered(int fd, void *buf, ssize_t count, boolean allow_less)
int lives_close_buffered(int fd)
size_t get_token_count(const char *string, int delim)
#define LIVES_GLOBAL_INLINE
char * subst(const char *string, const char *from, const char *to)
ssize_t lives_write_buffered(int fd, const char *buf, ssize_t count, boolean allow_fail)
#define DEF_FILE_PERMS
non-executable, is modified by the umask
boolean lives_read_buffered_eof(int fd)
int lives_create_buffered(const char *pathname, int mode)
int lives_open_buffered_rdonly(const char *pathname)
ssize_t lives_buffered_write_printf(int fd, boolean allow_fail, const char *fmt,...)
int lives_rm(const char *file)
off_t lives_buffered_offset(int fd)
weed_plant_t * get_nth_info_message(int n)
off_t lives_lseek_buffered_rdonly_absolute(int fd, off_t offset)
boolean lives_freep(void **ptr)
#define MIN_MSGBAR_HEIGHT
weed_plant_t * render_text_to_layer(weed_layer_t *layer, const char *text, const char *fontname, double size, lives_text_mode_t mode, lives_colRGBA64_t *fg_col, lives_colRGBA64_t *bg_col, boolean center, boolean rising, double top)
LingoLayout * layout_nth_message_at_bottom(int n, int width, int height, LiVESWidget *widget, int *linecount)
void subtitles_free(lives_clip_t *sfile)
boolean get_subt_text(lives_clip_t *sfile, double xtime)
boolean subtitles_init(lives_clip_t *sfile, char *fname, lives_subtitle_type_t subtype)
boolean save_srt_subtitles(lives_clip_t *sfile, double start_time, double end_time, double offset_time, const char *filename)
char ** get_font_list(void)
boolean lives_parse_font_string(const char *string, char **font, int *size, char **stretch, char **style, char **weight)
LingoLayout * render_text_to_cr(LiVESWidget *widget, lives_painter_t *cr, const char *text, const char *fontname, double size, lives_text_mode_t mode, lives_colRGBA64_t *fg, lives_colRGBA64_t *bg, boolean center, boolean rising, double *top, int *offs_x, int dwidth, int *dheight)
boolean save_sub_subtitles(lives_clip_t *sfile, double start_time, double end_time, double offset_time, const char *filename)
LIVES_GLOBAL_INLINE weed_plant_t * render_text_overlay(weed_layer_t *layer, const char *text)
void layout_to_lives_painter(LingoLayout *layout, lives_painter_t *cr, lives_text_mode_t mode, lives_colRGBA64_t *fg, lives_colRGBA64_t *bg, int dwidth, int dheight, double x_bg, double y_bg, double x_text, double y_text)
@ LIVES_TEXT_MODE_PRECALCULATE
@ LIVES_TEXT_MODE_BACKGROUND_ONLY
@ LIVES_TEXT_MODE_FOREGROUND_AND_BACKGROUND
#define SRT_DEF_CHARSET
subtitles
#define LIVES_CHARSET_UTF8
corresponds to one clip in the GUI
xlives_subtitle_t * prev
for future use
lives_subtitle_style_t * style
for future use
lives_subtitle_type_t type
lives_subtitle_t * current
pointer to current entry in index
int offset
offset in frames (default 0)
#define lives_strdup_printf(fmt,...)
WEED_GLOBAL_INLINE uint32_t weed_leaf_set_flagbits(weed_plant_t *plant, const char *leaf, uint32_t flagbits)
value ORed with flags
WEED_GLOBAL_INLINE uint32_t weed_leaf_clear_flagbits(weed_plant_t *plant, const char *leaf, uint32_t flagbits)
~value ANDed with flags