commit 7df72cd690fff63c07b79ac54852b4b6802c2528
parent de51f322557a93465ce974f6b2b1223a7cbddc52
Author: nibo <nibo@relim.de>
Date: Mon, 23 Dec 2024 20:21:03 +0100
WIP: toc
Diffstat:
3 files changed, 160 insertions(+), 55 deletions(-)
diff --git a/chordpro.c b/chordpro.c
@@ -3532,6 +3532,9 @@ cho_directive_parse(const char *name)
} /* else if (!strcmp(name, "footerfont")) {
} else if (!strcmp(name, "footersize")) {
} else if (!strcmp(name, "footercolour")) {
+ } else if (!strcmp(name, "labelfont")) {
+ } else if (!strcmp(name, "labelsize")) {
+ } else if (!strcmp(name, "labelcolour")) {
} */
if (!strcmp(name, "transpose")) {
directive->dtype = DT_CHORD;
diff --git a/lorid.c b/lorid.c
@@ -97,8 +97,8 @@ main(int argc, char *argv[])
}
all_songs = erealloc(all_songs, (s+1) * sizeof(struct ChoSong *));
all_songs[s] = NULL;
+ qsort(all_songs, cho_song_count(all_songs), sizeof(struct ChoSong *), cho_song_compare);
}
- qsort(all_songs, cho_song_count(all_songs), sizeof(struct ChoSong *), cho_song_compare);
char *pdf_filename = out_pdf_create(chordpro_filepath, output, all_songs, config);
if (!pdf_filename) {
LOG_DEBUG("out_pdf_new failed.");
diff --git a/out_pdf.c b/out_pdf.c
@@ -361,7 +361,12 @@ find_whitespace(const char *str, size_t start)
}
static int
-text_find_fitting(const char *str, struct ChoStyle *style, double x)
+text_find_fitting(
+ const char *str,
+ struct ChoStyle *style,
+ double x,
+ double max_width
+)
{
size_t len = strlen(str);
size_t start = len - 1;
@@ -373,16 +378,16 @@ text_find_fitting(const char *str, struct ChoStyle *style, double x)
i = find_whitespace((const char *)&tmp, start);
if (i == -1) {
util_log(LOG_ERR, "Can't split text because no whitespace was found.");
- return ERROR;
+ return -1;
}
tmp[i] = 0;
width = text_width((const char *)&tmp, style);
if (width == ERROR) {
LOG_DEBUG("text_width failed.");
- return ERROR;
+ return -1;
}
start = i - 1;
- } while (x + width > LINE_WIDTH);
+ } while (x + width > max_width);
return i;
}
@@ -506,7 +511,51 @@ out_pdf_text_show(pdfio_stream_t *stream, struct PDFText *text)
}
static bool
-annot_add(struct PDFContext *ctx, struct ChoStyle *style, double width)
+annot_page_link_add(
+ struct PDFContext *ctx,
+ struct TocEntry *entry,
+ double font_size
+)
+{
+ pdfio_rect_t rect;
+ pdfio_dict_t *annot;
+ pdfio_array_t *destination;
+ rect.x1 = MARGIN_HORIZONTAL;
+ rect.x2 = MARGIN_HORIZONTAL + LINE_WIDTH;
+ rect.y1 = ctx->y - 2.0;
+ rect.y2 = ctx->y + font_size * 0.8;
+ annot = pdfioDictCreate(g_pdf_file);
+ if (!pdfioDictSetName(annot, "Subtype", "Link")) {
+ LOG_DEBUG("pdfioDictSetName failed.");
+ return false;
+ }
+ if (!pdfioDictSetRect(annot, "Rect", &rect)) {
+ LOG_DEBUG("pdfioDictSetRect failed.");
+ return false;
+ }
+ destination = pdfioArrayCreate(g_pdf_file);
+ printf("page index '%d'\n", entry->page_index);
+ if (!pdfioArrayAppendNumber(destination, entry->page_index)) {
+ LOG_DEBUG("pdfioArrayAppendNumber failed.");
+ return false;
+ }
+ if (!pdfioArrayAppendName(destination, "Fit")) {
+ LOG_DEBUG("pdfioArrayAppendName failed.");
+ return false;
+ }
+ if (!pdfioDictSetArray(annot, "Dest", destination)) {
+ LOG_DEBUG("pdfioDictSetArray failed.");
+ return false;
+ }
+ if (!pdfioArrayAppendDict(ctx->content->pages[ctx->page]->annots, annot)) {
+ LOG_DEBUG("pdfioArrayAppendDict failed.");
+ return false;
+ }
+ return true;
+}
+
+static bool
+annot_url_link_add(struct PDFContext *ctx, struct ChoStyle *style, double width)
{
pdfio_rect_t rect;
pdfio_dict_t *annot, *action;
@@ -1186,7 +1235,8 @@ items_find_position_to_break_line(
pos->text_index = text_find_fitting(
it[i]->u.text->text,
it[i]->u.text->style,
- width
+ width,
+ LINE_WIDTH
);
if (pos->text_index == EMPTY_INT) {
LOG_DEBUG("text_find_fitting failed.");
@@ -1315,8 +1365,8 @@ pdf_texts_add_lyrics(
return false;
}
if (item->u.text->style->href) {
- if (!annot_add(ctx, item->u.text->style, width)) {
- LOG_DEBUG("annot_add failed.");
+ if (!annot_url_link_add(ctx, item->u.text->style, width)) {
+ LOG_DEBUG("annot_url_link_add failed.");
return false;
}
}
@@ -1335,6 +1385,7 @@ pdf_texts_add_lyrics(
sp = ctx->spaces;
while (*sp) {
if ((*sp)->line_item_index == i && (*sp)->text_index == c) {
+ // TODO: This code splits multibyte characters which leads to invalid UTF-8
(*texts)[ctx->text]->text = erealloc((*texts)[ctx->text]->text, (t+1) * sizeof(char));
(*texts)[ctx->text]->text[t] = 0;
(*texts)[ctx->text]->style = cho_style_copy(item->u.text->style);
@@ -1346,8 +1397,8 @@ pdf_texts_add_lyrics(
return false;
}
if (item->u.text->style->href) {
- if (!annot_add(ctx, item->u.text->style, width)) {
- LOG_DEBUG("annot_add failed.");
+ if (!annot_url_link_add(ctx, item->u.text->style, width)) {
+ LOG_DEBUG("annot_url_link_add failed.");
return false;
}
}
@@ -1373,8 +1424,8 @@ pdf_texts_add_lyrics(
return false;
}
if (item->u.text->style->href) {
- if (!annot_add(ctx, item->u.text->style, width)) {
- LOG_DEBUG("annot_add failed.");
+ if (!annot_url_link_add(ctx, item->u.text->style, width)) {
+ LOG_DEBUG("annot_url_link_add failed.");
return false;
}
}
@@ -1418,8 +1469,8 @@ pdf_texts_add_text(
if (width > LINE_WIDTH) {
char *t = (char *)&str;
while (width > LINE_WIDTH) {
- index = text_find_fitting(t, style, 0.0);
- if (index == ERROR) {
+ index = text_find_fitting(t, style, 0.0, LINE_WIDTH);
+ if (index == EMPTY_INT) {
LOG_DEBUG("text_find_fitting failed.");
return false;
}
@@ -1437,8 +1488,8 @@ pdf_texts_add_text(
(*texts)[ctx->text]->x = ctx->x;
(*texts)[ctx->text]->y = ctx->y;
if (style->href) {
- if (!annot_add(ctx, style, width)) {
- LOG_DEBUG("annot_add failed.");
+ if (!annot_url_link_add(ctx, style, width)) {
+ LOG_DEBUG("annot_url_link_add failed.");
return false;
}
}
@@ -1464,8 +1515,8 @@ pdf_texts_add_text(
(*texts)[ctx->text]->x = ctx->x;
(*texts)[ctx->text]->y = ctx->y;
if (style->href) {
- if (!annot_add(ctx, style, width)) {
- LOG_DEBUG("annot_add failed.");
+ if (!annot_url_link_add(ctx, style, width)) {
+ LOG_DEBUG("annot_url_link_add failed.");
return false;
}
}
@@ -1480,8 +1531,8 @@ pdf_texts_add_text(
(*texts)[ctx->text]->x = ctx->x;
(*texts)[ctx->text]->y = ctx->y;
if (style->href) {
- if (!annot_add(ctx, style, width)) {
- LOG_DEBUG("annot_add failed.");
+ if (!annot_url_link_add(ctx, style, width)) {
+ LOG_DEBUG("annot_url_link_add failed.");
return false;
}
}
@@ -1491,39 +1542,47 @@ pdf_texts_add_text(
return true;
}
-/* static pdfio_dict_t *
-annot_within_document_create(struct TocEntry *toc)
+static bool
+pdf_texts_add_toc_entry(
+ struct PDFContext *ctx,
+ struct TocEntry *entry,
+ struct ChoStyle *style,
+ double max_title_width
+)
{
- pdfio_rect_t rect;
- pdfio_dict_t *annot, *action;
- rect.x1 = ctx->x;
- rect.x2 = ctx->x + width;
- rect.y1 = ctx->y - 2.0;
- rect.y2 = ctx->y + style->font->size * 0.8;
- annot = pdfioDictCreate(g_pdf_file);
- if (!pdfioDictSetName(annot, "Subtype", "Link")) {
- LOG_DEBUG("pdfioDictSetName failed.");
- return false;
- }
- if (!pdfioDictSetRect(annot, "Rect", &rect)) {
- LOG_DEBUG("pdfioDictSetRect failed.");
- return false;
- }
- action = pdfioDictCreate(g_pdf_file);
- if (!pdfioDictSetName(action, "S", "GoTo")) {
- LOG_DEBUG("pdfioDictSetName failed.");
+ double width;
+ int index;
+ char tmp[strlen(entry->title)+1];
+ strcpy((char *)&tmp, entry->title);
+ width = text_width(entry->title, style);
+ if (width == ERROR) {
+ LOG_DEBUG("text_width failed.");
return false;
}
- if (!pdfioDictSetName(action, "D", destination)) {
- LOG_DEBUG("pdfioDictSetName failed.");
- return false;
+ width += MARGIN_HORIZONTAL;
+ if (width > max_title_width) {
+ char *t = (char *)&tmp;
+ while (width > max_title_width) {
+ index = text_find_fitting(t, style, MARGIN_HORIZONTAL, max_title_width);
+ if (index == EMPTY_INT) {
+ LOG_DEBUG("text_find_fitting failed.");
+ return false;
+ }
+ t[index] = 0;
+ printf("part '%s'\n", t);
+ t += index + 1;
+ width = text_width(t, style);
+ if (width == ERROR) {
+ LOG_DEBUG("text_width failed.");
+ return false;
+ }
+ }
+ printf("last part '%s'\n", t);
+ } else {
+ printf("title '%s'\n", entry->title);
}
- // if (!pdfioArrayAppendDict(ctx->content->pages[ctx->page]->annots, annot)) {
- // LOG_DEBUG("pdfioArrayAppendDict failed.");
- // return false;
- // }
return true;
-} */
+}
static bool
pdf_toc_create(
@@ -1533,6 +1592,7 @@ pdf_toc_create(
struct Config *config
)
{
+ double width, space_for_dots, max_title_width;
struct PDFContext ctx;
struct PDFText ***texts;
ctx.text = 0;
@@ -1546,13 +1606,55 @@ pdf_toc_create(
struct OutputStyle *toc_style = config_output_style_get(config->output->styles, "toc");
struct TocEntry **toc;
toc = pdf_content->toc;
+ max_title_width = LINE_WIDTH * 0.85 + MARGIN_HORIZONTAL;
+ // TODO: First find out how many pages the toc will have
while (*toc) {
- // annot_within_document_create(*toc);
- if (!pdf_texts_add_text(&ctx, (*toc)->title, toc_style->style, A_LEFT)) {
- LOG_DEBUG("pdf_texts_add_text failed.");
+ if (!pdf_texts_add_toc_entry(&ctx, *toc, toc_style->style, max_title_width)) {
+ LOG_DEBUG("pdf_texts_add_toc_entry failed.");
return false;
}
- printf("%s\n", (*toc)->title);
+ if (ctx.y < MARGIN_BOTTOM) {
+ *texts = erealloc(*texts, (ctx.text+1) * sizeof(struct PDFText *));
+ (*texts)[ctx.text] = NULL;
+ ctx.text = 0;
+ ctx.y = MEDIABOX_HEIGHT - MARGIN_TOP;
+ ctx.page++;
+ ctx.content->pages = erealloc(ctx.content->pages, (ctx.page+1) * sizeof(struct PDFPage *));
+ ctx.content->pages[ctx.page] = pdf_page_new();
+ texts = &ctx.content->pages[ctx.page]->texts;
+ }
+ // pdf_text_count_vertical_space((*toc)->title, toc_style->style);
+ /* if (!annot_page_link_add(&ctx, *toc, toc_style->style->font->size)) {
+ LOG_DEBUG("annot_page_link_add");
+ return false;
+ } */
+ // TODO: create (multi)line with title, dots and the page number
+ space_for_dots = LINE_WIDTH;
+ char page_no[5+1];
+ sprintf((char *)&page_no, "%d", (*toc)->page_index+1);
+ width = text_width(page_no, toc_style->style);
+
+ double most_right_x = MEDIABOX_WIDTH - MARGIN_HORIZONTAL;
+ double page_no_x = most_right_x - width;
+ *texts = erealloc(*texts, (ctx.text+1) * sizeof(struct PDFText *));
+ (*texts)[ctx.text] = pdf_text_new();
+ (*texts)[ctx.text]->text = strdup(page_no);
+ (*texts)[ctx.text]->style = cho_style_copy(toc_style->style);
+ (*texts)[ctx.text]->x = page_no_x;
+ (*texts)[ctx.text]->y = ctx.y;
+ ctx.text++;
+ ctx.y -= 8.0 + toc_style->style->font->size;
+
+ /* space_for_dots -= width;
+ width = text_width((*toc)->title, toc_style->style);
+ space_for_dots -= width;
+ printf("width for dots '%.1f'\n", space_for_dots);
+ char line[4096];
+ sprintf((char *)&line, "%s ........ %d", (*toc)->title, (*toc)->page_index+1);
+ if (!pdf_texts_add_text(&ctx, (char *)&line, toc_style->style, A_LEFT)) {
+ LOG_DEBUG("pdf_texts_add_text failed.");
+ return false;
+ } */
toc++;
}
*texts = erealloc(*texts, (ctx.text+1) * sizeof(struct PDFText *));
@@ -1735,8 +1837,8 @@ pdf_content_create(
LOG_DEBUG("text_width failed.");
return false;
}
- if (!annot_add(&ctx, style, width)) {
- LOG_DEBUG("annot_add failed.");
+ if (!annot_url_link_add(&ctx, style, width)) {
+ LOG_DEBUG("annot_url_link_add failed.");
return false;
}
}