commit 84566db79a88cda5832ace7703ea6f4982e9cff5
parent be6c03f356990e4a791128d878f76bf7c3d1eafd
Author: nibo <nibo@relim.de>
Date: Thu, 25 Jul 2024 18:02:25 +0200
First results with new out_pdf 'engine'
Diffstat:
| M | Makefile | | | 4 | ++-- |
| M | chordpro.c | | | 546 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- |
| M | chordpro.h | | | 54 | +++++++++++++++++++++++++++++++++++++++++++++++++++--- |
| M | config.c | | | 775 | +++++++++++++++++++++++++++++++------------------------------------------------ |
| M | config.h | | | 22 | ++++++++++++---------- |
| M | fontconfig.c | | | 34 | +++++++++++++++++----------------- |
| M | lorid.c | | | 10 | +++++++++- |
| M | out_pdf.c | | | 638 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
| M | out_pdf.h | | | 21 | +++++++++++++++++++++ |
| M | todo | | | 4 | ++++ |
10 files changed, 1401 insertions(+), 707 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
all:
- $(CC) -Wall -Wextra -O2 fontconfig.c config.c chordpro.c out_pdf.c lorid.c -o lorid -lpdfio -ltoml -lfontconfig
+ $(CC) -pedantic -Wall -Wextra -O2 fontconfig.c config.c chordpro.c out_pdf.c lorid.c -o lorid -lpdfio -ltoml -lfontconfig
debug:
- $(CC) -g -Wall -Wextra fontconfig.c config.c chordpro.c out_pdf.c lorid.c -o lorid -I/usr/include/freetype2 -lpdfio -ltoml -lfontconfig
+ $(CC) -g -pedantic -Wall -Wextra fontconfig.c config.c chordpro.c out_pdf.c lorid.c -o lorid -lpdfio -ltoml -lfontconfig
fontconfig:
$(CC) -g chordpro.c fontconfig.c -o fontconfig -lfontconfig
.PHONY: all debug fontconfig
diff --git a/chordpro.c b/chordpro.c
@@ -5,6 +5,7 @@
#include <string.h>
#include <ctype.h>
#include "chordpro.h"
+#include "config.h"
static const char *environment_directives[] = {
"start_of_chorus", "soc", "end_of_chorus", "eoc", "chorus",
@@ -42,6 +43,30 @@ static const char *font_directives[] = {
"tocfont", "tocsize", "toccolour", */
};
+struct StyleProperty default_style_properties[18] = {
+ { SF_CHORD, SPT_FONT, { .font_name = NULL } },
+ { SF_CHORD, SPT_SIZE, { .font_size = EMPTY } },
+ { SF_CHORD, SPT_COLOR, { .foreground_color = NULL } },
+ { SF_CHORUS, SPT_FONT, { .font_name = NULL } },
+ { SF_CHORUS, SPT_SIZE, { .font_size = EMPTY } },
+ { SF_CHORUS, SPT_COLOR, { .foreground_color = NULL } },
+ { SF_GRID, SPT_FONT, { .font_name = NULL } },
+ { SF_GRID, SPT_SIZE, { .font_size = EMPTY } },
+ { SF_GRID, SPT_COLOR, { .foreground_color = NULL } },
+ { SF_TAB, SPT_FONT, { .font_name = NULL } },
+ { SF_TAB, SPT_SIZE, { .font_size = EMPTY } },
+ { SF_TAB, SPT_COLOR, { .foreground_color = NULL } },
+ { SF_TEXT, SPT_FONT, { .font_name = NULL } },
+ { SF_TEXT, SPT_SIZE, { .font_size = EMPTY } },
+ { SF_TEXT, SPT_COLOR, { .foreground_color = NULL } },
+ { SF_TITLE, SPT_FONT, { .font_name = NULL } },
+ { SF_TITLE, SPT_SIZE, { .font_size = EMPTY } },
+ { SF_TITLE, SPT_COLOR, { .foreground_color = NULL } },
+};
+
+static enum SongFragmentType g_current_ftype = SF_TEXT;
+static struct Config *g_config = NULL;
+
static const char *the_state(enum State state)
{
switch (state) {
@@ -72,6 +97,8 @@ static const char *the_state(enum State state)
const char *the_dtype(enum DirectiveType dtype)
{
switch (dtype) {
+ case DT_EMPTY:
+ return "DT_EMPTY";
case DT_ENVIRONMENT:
return "DT_ENVIRONMENT";
case DT_METADATA:
@@ -112,6 +139,8 @@ const char *the_stype(enum SectionType stype)
const char *the_pos(enum Position pos)
{
switch (pos) {
+ case POS_EMPTY:
+ return "POS_EMPTY";
case POS_START:
return "POS_START";
case POS_END:
@@ -167,14 +196,18 @@ const char *the_font_weight(enum FontWeight weight)
const char *the_rgb_color(struct RGBColor *color)
{
- static char str[17];
- sprintf((char *)&str, "rgb(%d,%d,%d)", color->red, color->green, color->blue);
+ static char str[100];
+ sprintf((char *)&str, "rgb(%d,%d,%d) ", color->red, color->green, color->blue);
+ size_t len = strlen((char *)&str);
+ sprintf((char *)&str[len], "\x1b[38;2;%d;%d;%dm🬎\x1b[0m", color->red, color->green, color->blue);
return str;
}
const char *the_line_style(enum LineStyle style)
{
switch (style) {
+ case LS_EMPTY:
+ return "LS_EMPTY";
case LS_SINGLE:
return "LS_SINGLE";
case LS_DOUBLE:
@@ -185,6 +218,76 @@ const char *the_line_style(enum LineStyle style)
return "";
}
+const char *the_song_fragment_type(enum SongFragmentType ftype)
+{
+ switch (ftype) {
+ case SF_EMPTY:
+ return "SF_EMPTY";
+ case SF_CHORD:
+ return "SF_CHORD";
+ case SF_CHORUS:
+ return "SF_CHORUS";
+ case SF_FOOTER:
+ return "SF_FOOTER";
+ case SF_GRID:
+ return "SF_GRID";
+ case SF_TAB:
+ return "SF_TAB";
+ case SF_TOC:
+ return "SF_TOC";
+ case SF_TEXT:
+ return "SF_TEXT";
+ case SF_TITLE:
+ return "SF_TITLE";
+ }
+ return "";
+}
+
+const char *the_style_property_type(enum StylePropertyType type)
+{
+ switch (type) {
+ case SPT_EMPTY:
+ return "SPT_EMPTY";
+ case SPT_FONT:
+ return "SPT_FONT";
+ case SPT_SIZE:
+ return "SPT_SIZE";
+ case SPT_COLOR:
+ return "SPT_COLOR";
+ }
+ return "";
+}
+
+void the_default_style_properties(void)
+{
+ unsigned int i;
+ for (i = 0; i<LENGTH(default_style_properties); i++) {
+ printf(
+ "%s %s ",
+ the_song_fragment_type(default_style_properties[i].ftype),
+ the_style_property_type(default_style_properties[i].type)
+ );
+ switch (default_style_properties[i].type) {
+ case SPT_FONT:
+ if (default_style_properties[i].u.font_name)
+ printf("%s\n", default_style_properties[i].u.font_name);
+ else
+ printf("NULL\n");
+ break;
+ case SPT_SIZE:
+ printf("%.1f\n", default_style_properties[i].u.font_size);
+ break;
+ case SPT_COLOR:
+ if (default_style_properties[i].u.foreground_color)
+ printf("%s\n", the_rgb_color(default_style_properties[i].u.foreground_color));
+ else
+ printf("NULL\n");
+ break;
+ default:
+ }
+ }
+}
+
static char *string_remove_leading_whitespace(const char *str)
{
int i = 0;
@@ -225,6 +328,14 @@ struct RGBColor *cho_rgbcolor_duplicate(struct RGBColor *color)
return copy;
}
+const char *cho_rgbcolor_to_string(struct RGBColor *color)
+{
+ static char str[8];
+ str[7] = 0;
+ sprintf((char *)&str, "#%02X%02X%02X", color->red, color->green, color->blue);
+ return (const char *)&str;
+}
+
struct RGBColor *cho_rgbcolor_parse(const char *str)
{
struct RGBColor *color = malloc(sizeof(struct RGBColor));
@@ -305,9 +416,9 @@ struct RGBColor *cho_color_parse(const char *str)
color->green = 48;
color->blue = 48;
} else if (strcmp(str, "green") == 0) {
- color->red = 193;
- color->green = 223;
- color->blue = 193;
+ color->red = 0;
+ color->green = 126;
+ color->blue = 0;
} else if (strcmp(str, "blue") == 0) {
color->red = 0;
color->green = 0;
@@ -489,7 +600,7 @@ const char *cho_font_weight_to_string(enum FontWeight weight)
void cho_font_print_as_toml(struct Font *font, const char *section)
{
- printf("[fonts.%s]\n", section);
+ printf("[styles.%s.font]\n", section);
printf("\n");
printf("name = \"%s\"\n", font->name);
printf("family = \"%s\"\n", cho_font_family_to_string(font->family));
@@ -499,6 +610,92 @@ void cho_font_print_as_toml(struct Font *font, const char *section)
printf("\n");
}
+enum LineStyle cho_linestyle_parse(const char *str)
+{
+ if (strcmp(str, "single") == 0) {
+ return LS_SINGLE;
+ } else if (strcmp(str, "double") == 0) {
+ return LS_DOUBLE;
+ } else if (strcmp(str, "none") == 0) {
+ return LS_NONE;
+ } else {
+ return LS_EMPTY;
+ }
+}
+
+const char *cho_linestyle_to_string(enum LineStyle linestyle)
+{
+ switch (linestyle) {
+ case LS_SINGLE:
+ return "single";
+ case LS_DOUBLE:
+ return "double";
+ default:
+ return "none";
+ }
+}
+
+static bool cho_style_property_apply_default(enum SongFragmentType current_ftype, enum StylePropertyType ptype, struct Style *style)
+{
+ unsigned int i;
+ for (i = 0; i<LENGTH(default_style_properties); i++) {
+ if (
+ default_style_properties[i].ftype == current_ftype &&
+ default_style_properties[i].type == ptype
+ ) {
+ switch (ptype) {
+ case SPT_FONT:
+ if (default_style_properties[i].u.font_name) {
+ free(style->font->name);
+ style->font->name = strdup(default_style_properties[i].u.font_name);
+ return true;
+ } else {
+ return false;
+ }
+ break;
+ case SPT_SIZE:
+ if (default_style_properties[i].u.font_size != EMPTY) {
+ style->font->size = default_style_properties[i].u.font_size;
+ return true;
+ } else {
+ return false;
+ }
+ break;
+ case SPT_COLOR:
+ if (default_style_properties[i].u.foreground_color) {
+ free(style->foreground_color);
+ style->foreground_color = cho_rgbcolor_duplicate(default_style_properties[i].u.foreground_color);
+ return true;
+ } else {
+ return false;
+ }
+ break;
+ default:
+ }
+ }
+ }
+ return false;
+}
+
+static void cho_style_apply_default(enum SongFragmentType current_ftype, struct Style *style)
+{
+ if (current_ftype == SF_CHORUS) {
+ if (!cho_style_property_apply_default(SF_CHORUS, SPT_FONT, style)) {
+ cho_style_property_apply_default(SF_TEXT, SPT_FONT, style);
+ }
+ if (!cho_style_property_apply_default(SF_CHORUS, SPT_SIZE, style)) {
+ cho_style_property_apply_default(SF_TEXT, SPT_SIZE, style);
+ }
+ if (!cho_style_property_apply_default(SF_CHORUS, SPT_COLOR, style)) {
+ cho_style_property_apply_default(SF_TEXT, SPT_COLOR, style);
+ }
+ } else {
+ cho_style_property_apply_default(current_ftype, SPT_FONT, style);
+ cho_style_property_apply_default(current_ftype, SPT_SIZE, style);
+ cho_style_property_apply_default(current_ftype, SPT_COLOR, style);
+ }
+}
+
struct Style *cho_style_new(void)
{
struct Style *style = malloc(sizeof(struct Style));
@@ -518,19 +715,6 @@ struct Style *cho_style_new(void)
return style;
}
-void cho_style_free(struct Style *style)
-{
- cho_font_free(style->font);
- free(style->foreground_color);
- free(style->background_color);
- free(style->underline_color);
- free(style->overline_color);
- free(style->strikethrough_color);
- free(style->boxed_color);
- free(style->href);
- free(style);
-}
-
struct Style *cho_style_duplicate(struct Style *style)
{
struct Style *copy = malloc(sizeof(struct Style));
@@ -550,10 +734,49 @@ struct Style *cho_style_duplicate(struct Style *style)
return copy;
}
+struct Style *cho_style_new_from_config(void)
+{
+ struct PrintableItem *printable_item;
+ switch (g_current_ftype) {
+ /* case SF_CHORD:
+ printable_item = config_printable_item_get(g_config->printable_items, "chord");
+ return cho_style_duplicate(printable_item->style); */
+ case SF_GRID:
+ printable_item = config_printable_item_get(g_config->printable_items, "grid");
+ return cho_style_duplicate(printable_item->style);
+ case SF_TAB:
+ printable_item = config_printable_item_get(g_config->printable_items, "tab");
+ return cho_style_duplicate(printable_item->style);
+ default:
+ printable_item = config_printable_item_get(g_config->printable_items, "text");
+ return cho_style_duplicate(printable_item->style);
+ }
+}
+
+struct Style *cho_style_new_default(void)
+{
+ struct Style *style = cho_style_new_from_config();
+ cho_style_apply_default(g_current_ftype, style);
+ return style;
+}
+
+void cho_style_free(struct Style *style)
+{
+ cho_font_free(style->font);
+ free(style->foreground_color);
+ free(style->background_color);
+ free(style->underline_color);
+ free(style->overline_color);
+ free(style->strikethrough_color);
+ free(style->boxed_color);
+ free(style->href);
+ free(style);
+}
+
struct Font *cho_style_font_desc_parse(const char *str)
{
struct Font *font = cho_font_new();
- float size = -1.0;
+ double size = -1.0;
char **words = malloc(sizeof(char *));
int w = 0;
words[w] = NULL;
@@ -621,7 +844,7 @@ struct Font *cho_style_font_desc_parse(const char *str)
if (stop_at == -1)
stop_at = w;
} else {
- size = strtof(words[w], NULL);
+ size = strtod(words[w], NULL);
if (size == 0.0)
goto SKIP;
font->size = size;
@@ -665,7 +888,7 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St
if (inherited_style)
style = cho_style_duplicate(inherited_style);
else
- style = cho_style_new();
+ style = cho_style_new_default();
if (strcmp(tag_name, "span") == 0) {
int a = 0;
while (attrs[a] != NULL) {
@@ -890,12 +1113,10 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St
style->strikethrough = true;
} else if (strcmp(tag_name, "sub") == 0) {
style->font->size *= 0.8;
- style->rise = (style->font->size / 2) * 0.3;
+ style->rise = -style->font->size * 0.3;
} else if (strcmp(tag_name, "sup") == 0) {
style->font->size *= 0.8;
- float thirty_percent = (style->font->size / 2) * 0.3;
- // TODO: Is that right?
- style->rise = thirty_percent - thirty_percent * 2;
+ style->rise = style->font->size * 0.3;
} else if (strcmp(tag_name, "small") == 0) {
style->font->size *= 0.8;
} else if (strcmp(tag_name, "tt") == 0) {
@@ -929,10 +1150,56 @@ void cho_style_print(struct Style *style)
printf("href: %s\n", style->href);
else
printf("href: NULL\n");
- printf("---- END STYLE ------\n");
+ printf("---- END STYLE ------\n\n");
+}
+
+void cho_style_print_as_toml(struct Style *style, const char *section)
+{
+ printf("foreground_color = \"%s\"\n", cho_rgbcolor_to_string(style->foreground_color));
+ printf("background_color = \"%s\"\n", cho_rgbcolor_to_string(style->background_color));
+ printf("underline_style = \"%s\"\n", cho_linestyle_to_string(style->underline_style));
+ printf("underline_color = \"%s\"\n", cho_rgbcolor_to_string(style->underline_color));
+ printf("overline_style = \"%s\"\n", cho_linestyle_to_string(style->overline_style));
+ printf("overline_color = \"%s\"\n", cho_rgbcolor_to_string(style->overline_color));
+ printf("strikethrough = %s\n", style->strikethrough ? "true" : "false");
+ printf("strikethrough_color = \"%s\"\n", cho_rgbcolor_to_string(style->strikethrough_color));
+ printf("boxed = %s\n", style->boxed ? "true" : "false");
+ printf("boxed_color = \"%s\"\n", cho_rgbcolor_to_string(style->boxed_color));
+ printf("rise = %.1f\n", style->rise);
+ printf("href = \"%s\"\n", style->href ? style->href : "");
+ printf("\n");
+ cho_font_print_as_toml(style->font, section);
}
-struct Attr *cho_tag_attr_new(void)
+static void cho_style_change_default(struct StyleProperty sprop)
+{
+ if (sprop.type == SPT_EMPTY)
+ return;
+ unsigned int i;
+ for (i = 0; i<LENGTH(default_style_properties); i++) {
+ if (
+ default_style_properties[i].ftype == sprop.ftype &&
+ default_style_properties[i].type == sprop.type
+ ) {
+ switch (sprop.type) {
+ case SPT_FONT:
+ free(default_style_properties[i].u.font_name);
+ default_style_properties[i].u.font_name = strdup(sprop.u.font_name);
+ break;
+ case SPT_SIZE:
+ default_style_properties[i].u.font_size = sprop.u.font_size;
+ break;
+ case SPT_COLOR:
+ free(default_style_properties[i].u.foreground_color);
+ default_style_properties[i].u.foreground_color = cho_rgbcolor_duplicate(sprop.u.foreground_color);
+ break;
+ default:
+ }
+ }
+ }
+}
+
+static struct Attr *cho_tag_attr_new(void)
{
struct Attr *attr = malloc(sizeof(struct Attr));
attr->name = NULL;
@@ -940,14 +1207,14 @@ struct Attr *cho_tag_attr_new(void)
return attr;
}
-void cho_tag_attr_free(struct Attr *attr)
+static void cho_tag_attr_free(struct Attr *attr)
{
free(attr->name);
free(attr->value);
free(attr);
}
-void cho_tag_attrs_free(struct Attr **attrs)
+static void cho_tag_attrs_free(struct Attr **attrs)
{
int a = 0;
while (attrs[a] != NULL) {
@@ -957,7 +1224,7 @@ void cho_tag_attrs_free(struct Attr **attrs)
free(attrs);
}
-struct Tag *cho_tag_new(void)
+static struct Tag *cho_tag_new(void)
{
struct Tag *tag = malloc(sizeof(struct Tag));
tag->name = NULL;
@@ -967,7 +1234,7 @@ struct Tag *cho_tag_new(void)
return tag;
}
-void cho_tag_free(struct Tag *tag)
+static void cho_tag_free(struct Tag *tag)
{
free(tag->name);
cho_style_free(tag->style);
@@ -976,7 +1243,7 @@ void cho_tag_free(struct Tag *tag)
free(tag);
}
-void cho_tag_close_last_unclosed(const char *tag_name, struct Tag **tags, int last_index)
+static void cho_tag_close_last_unclosed(const char *tag_name, struct Tag **tags, int last_index)
{
int i = last_index;
while (i >= 0) {
@@ -989,7 +1256,7 @@ void cho_tag_close_last_unclosed(const char *tag_name, struct Tag **tags, int la
fprintf(stderr, "INFO: Didn't find a start tag for the end tag '%s'.\n", tag_name);
}
-struct Style *cho_tag_style_inherit(struct Tag **tags, int prev_index)
+static struct Style *cho_tag_style_inherit(struct Tag **tags, int prev_index)
{
int i = prev_index;
while (i >= 0) {
@@ -1006,13 +1273,13 @@ struct Style *cho_tag_style_inherit(struct Tag **tags, int prev_index)
return NULL;
}
-void cho_directive_free(struct ChoDirective *directive)
+static void cho_directive_free(struct ChoDirective *directive)
{
cho_style_free(directive->style);
free(directive);
}
-struct ChoMetadata *cho_metadata_new(void)
+static struct ChoMetadata *cho_metadata_new(void)
{
struct ChoMetadata *meta = malloc(sizeof(struct ChoMetadata));
meta->name = NULL;
@@ -1020,7 +1287,7 @@ struct ChoMetadata *cho_metadata_new(void)
return meta;
}
-struct ChoMetadata *cho_metadata_split(const char *directive_value)
+static struct ChoMetadata *cho_metadata_split(const char *directive_value)
{
struct ChoMetadata *meta = cho_metadata_new();
char *value = string_remove_leading_whitespace(directive_value);
@@ -1060,7 +1327,7 @@ struct ChoMetadata *cho_metadata_split(const char *directive_value)
}
}
-struct ChoChord *cho_chord_new(void)
+static struct ChoChord *cho_chord_new(void)
{
struct ChoChord *chord = malloc(sizeof(struct ChoChord));
chord->position = -1;
@@ -1076,7 +1343,7 @@ int cho_chord_count(struct ChoChord **chords)
return i;
}
-struct ChoLine *cho_line_new(void)
+static struct ChoLine *cho_line_new(void)
{
struct ChoLine *line = malloc(sizeof(struct ChoLine));
line->chords = NULL;
@@ -1084,7 +1351,7 @@ struct ChoLine *cho_line_new(void)
return line;
}
-int cho_line_compute_chord_position(struct ChoLine *line, int ly, int te)
+static int cho_line_compute_chord_position(struct ChoLine *line, int ly, int te)
{
if (ly == 0)
return te;
@@ -1097,15 +1364,15 @@ int cho_line_compute_chord_position(struct ChoLine *line, int ly, int te)
return lyrics_len + te;
}
-struct ChoLineItem *cho_line_item_new(void)
+static struct ChoLineItem *cho_line_item_new(void)
{
struct ChoLineItem *item = malloc(sizeof(struct ChoLineItem));
- item->style = cho_style_new();
+ item->style = cho_style_new_default();
item->text = NULL;
return item;
}
-void cho_line_item_free(struct ChoLineItem *item)
+static void cho_line_item_free(struct ChoLineItem *item)
{
cho_style_free(item->style);
free(item->text);
@@ -1120,7 +1387,7 @@ int cho_line_item_count(struct ChoLineItem **items)
return i;
}
-struct ChoSection *cho_section_new(void)
+static struct ChoSection *cho_section_new(void)
{
struct ChoSection *section = malloc(sizeof(struct ChoSection));
section->type = ST_EMPTY;
@@ -1129,7 +1396,7 @@ struct ChoSection *cho_section_new(void)
return section;
}
-struct ChoSong *cho_song_new(void)
+static struct ChoSong *cho_song_new(void)
{
struct ChoSong *song = malloc(sizeof(struct ChoSong));
song->metadata = NULL;
@@ -1137,7 +1404,7 @@ struct ChoSong *cho_song_new(void)
return song;
}
-void cho_song_free(struct ChoSong *song)
+static void cho_song_free(struct ChoSong *song)
{
int i = 0;
int k = 0;
@@ -1191,10 +1458,21 @@ void cho_songs_free(struct ChoSong **songs)
free(songs);
}
-struct ChoDirective *directive_parse(const char *name)
+static struct ChoDirective *cho_directive_new(void)
{
struct ChoDirective *directive = malloc(sizeof(struct ChoDirective));
- directive->style = cho_style_new();
+ directive->dtype = DT_EMPTY;
+ directive->stype = ST_EMPTY;
+ directive->position = POS_EMPTY;
+ directive->sprop = SPT_EMPTY;
+ directive->ftype = SF_EMPTY;
+ directive->style = cho_style_new_default();
+ return directive;
+}
+
+static struct ChoDirective *cho_directive_parse(const char *name)
+{
+ struct ChoDirective *directive = cho_directive_new();
int i = 0;
if (
strcmp(name, environment_directives[0]) == 0 ||
@@ -1203,6 +1481,7 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_START;
directive->stype = ST_CHORUS;
+ directive->ftype = SF_CHORUS;
goto END;
} else if (
strcmp(name, environment_directives[2]) == 0 ||
@@ -1211,6 +1490,7 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_END;
directive->stype = ST_CHORUS;
+ directive->ftype = SF_TEXT;
goto END;
} else if (
strcmp(name, environment_directives[5]) == 0 ||
@@ -1219,6 +1499,7 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_START;
directive->stype = ST_VERSE;
+ directive->ftype = SF_TEXT;
goto END;
} else if (
strcmp(name, environment_directives[7]) == 0 ||
@@ -1227,6 +1508,7 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_END;
directive->stype = ST_VERSE;
+ directive->ftype = SF_TEXT;
goto END;
} else if (
strcmp(name, environment_directives[9]) == 0 ||
@@ -1235,6 +1517,7 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_START;
directive->stype = ST_BRIDGE;
+ directive->ftype = SF_TEXT;
goto END;
} else if (
strcmp(name, environment_directives[11]) == 0 ||
@@ -1243,6 +1526,7 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_END;
directive->stype = ST_BRIDGE;
+ directive->ftype = SF_TEXT;
goto END;
} else if (
strcmp(name, environment_directives[13]) == 0 ||
@@ -1251,6 +1535,7 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_START;
directive->stype = ST_TAB;
+ directive->ftype = SF_TAB;
goto END;
} else if (
strcmp(name, environment_directives[15]) == 0 ||
@@ -1259,6 +1544,7 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_END;
directive->stype = ST_TAB;
+ directive->ftype = SF_TEXT;
goto END;
} else if (
strcmp(name, environment_directives[17]) == 0 ||
@@ -1267,6 +1553,7 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_START;
directive->stype = ST_GRID;
+ directive->ftype = SF_GRID;
goto END;
} else if (
strcmp(name, environment_directives[19]) == 0 ||
@@ -1275,13 +1562,12 @@ struct ChoDirective *directive_parse(const char *name)
directive->dtype = DT_ENVIRONMENT;
directive->position = POS_END;
directive->stype = ST_GRID;
+ directive->ftype = SF_TEXT;
goto END;
}
while (metadata_directives[i] != NULL) {
if (strcmp(metadata_directives[i], name) == 0) {
directive->dtype = DT_METADATA;
- directive->stype = ST_EMPTY;
- directive->position = -1;
goto END;
}
i++;
@@ -1294,8 +1580,6 @@ struct ChoDirective *directive_parse(const char *name)
) {
directive->style->background_color = cho_rgbcolor_new(228, 228, 228);
directive->dtype = DT_FORMATTING;
- directive->stype = ST_EMPTY;
- directive->position = -1;
goto END;
} else if (
strcmp(formatting_directives[3], name) == 0 ||
@@ -1303,8 +1587,6 @@ struct ChoDirective *directive_parse(const char *name)
) {
directive->style->font->style = FS_ITALIC;
directive->dtype = DT_FORMATTING;
- directive->stype = ST_EMPTY;
- directive->position = -1;
goto END;
} else if (
strcmp(formatting_directives[5], name) == 0 ||
@@ -1312,15 +1594,12 @@ struct ChoDirective *directive_parse(const char *name)
) {
directive->style->boxed = true;
directive->dtype = DT_FORMATTING;
- directive->stype = ST_EMPTY;
- directive->position = -1;
goto END;
}
while (preamble_directives[i] != NULL) {
if (strcmp(preamble_directives[i], name) == 0) {
directive->dtype = DT_PREAMBLE;
directive->stype = ST_NEWSONG;
- directive->position = -1;
goto END;
}
i++;
@@ -1330,16 +1609,112 @@ struct ChoDirective *directive_parse(const char *name)
strcmp(font_directives[1], name) == 0
) {
directive->dtype = DT_FONT;
+ directive->sprop = SPT_FONT;
+ directive->ftype = SF_CHORD;
+ goto END;
+ } else if (
+ strcmp(font_directives[2], name) == 0 ||
+ strcmp(font_directives[3], name) == 0
+ ) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_SIZE;
+ directive->ftype = SF_CHORD;
+ goto END;
+ } else if (strcmp(font_directives[4], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_COLOR;
+ directive->ftype = SF_CHORD;
+ goto END;
+ } else if (strcmp(font_directives[5], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_FONT;
+ directive->ftype = SF_CHORUS;
+ goto END;
+ } else if (strcmp(font_directives[6], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_SIZE;
+ directive->ftype = SF_CHORUS;
+ goto END;
+ } else if (strcmp(font_directives[7], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_COLOR;
+ directive->ftype = SF_CHORUS;
+ goto END;
+ } else if (strcmp(font_directives[8], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_FONT;
+ directive->ftype = SF_GRID;
+ goto END;
+ } else if (strcmp(font_directives[9], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_SIZE;
+ directive->ftype = SF_GRID;
+ goto END;
+ } else if (strcmp(font_directives[10], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_COLOR;
+ directive->ftype = SF_GRID;
+ goto END;
+ } else if (strcmp(font_directives[11], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_FONT;
+ directive->ftype = SF_TAB;
+ goto END;
+ } else if (strcmp(font_directives[12], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_SIZE;
+ directive->ftype = SF_TAB;
+ goto END;
+ } else if (strcmp(font_directives[13], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_COLOR;
+ directive->ftype = SF_TAB;
+ goto END;
+ } else if (
+ strcmp(font_directives[14], name) == 0 ||
+ strcmp(font_directives[15], name) == 0
+ ) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_FONT;
+ directive->ftype = SF_TEXT;
+ goto END;
+ } else if (
+ strcmp(font_directives[16], name) == 0 ||
+ strcmp(font_directives[17], name) == 0
+ ) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_SIZE;
+ directive->ftype = SF_TEXT;
+ goto END;
+ } else if (strcmp(font_directives[18], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_COLOR;
+ directive->ftype = SF_TEXT;
+ goto END;
+ } else if (strcmp(font_directives[19], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_FONT;
+ directive->ftype = SF_TITLE;
+ goto END;
+ } else if (strcmp(font_directives[20], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_SIZE;
+ directive->ftype = SF_TITLE;
+ goto END;
+ } else if (strcmp(font_directives[21], name) == 0) {
+ directive->dtype = DT_FONT;
+ directive->sprop = SPT_COLOR;
+ directive->ftype = SF_TITLE;
+ goto END;
}
directive->dtype = DT_CUSTOM;
- directive->stype = ST_EMPTY;
- directive->position = -1;
END:
return directive;
}
-struct ChoSong **cho_parse(FILE *fp)
+struct ChoSong **cho_parse(FILE *fp, struct Config *config)
{
+ g_config = config;
char buf = 0;
char prev_buf = '\n';
char directive_name[16];
@@ -1454,13 +1829,14 @@ struct ChoSong **cho_parse(FILE *fp)
if (buf == '}') {
directive_name[dn] = 0;
dn = 0;
- directive = directive_parse(directive_name);
+ directive = cho_directive_parse(directive_name);
/* printf(
"directive: '%s'\ndtype: %s, stype: %s, position: %s\n",
directive_name, dtype(directive->dtype), the_stype(directive->stype), pos(directive->position)
); */
switch (directive->dtype) {
case DT_ENVIRONMENT:
+ g_current_ftype = directive->ftype;
switch (directive->position) {
case POS_START:
cho_line_item_free(songs[so]->sections[se]->lines[li]->lyrics[ly]);
@@ -1495,6 +1871,7 @@ struct ChoSong **cho_parse(FILE *fp)
songs[so]->sections[se]->lines[li]->lyrics[ly] = cho_line_item_new();
}
break;
+ default:
}
break;
case DT_METADATA:
@@ -1529,10 +1906,12 @@ struct ChoSong **cho_parse(FILE *fp)
songs[so]->sections[se]->lines[li] = cho_line_new();
break;
case DT_FONT:
- // Reset diretive value to default
+ // Reset directive value to default
break;
case DT_CUSTOM:
+ fprintf(stderr, "INFO: Ignoring custom directive '%s'.\n", directive_name);
break;
+ default:
}
cho_directive_free(directive);
directive = NULL;
@@ -1552,13 +1931,14 @@ struct ChoSong **cho_parse(FILE *fp)
if (buf == '}') {
directive_value[dv] = 0;
dv = 0;
- directive = directive_parse(directive_name);
+ directive = cho_directive_parse(directive_name);
/* printf(
"directive: '%s'\ndtype: %s, stype: %s, position: %s\n",
directive_name, dtype(directive->dtype), the_stype(directive->stype), pos(directive->position)
); */
switch (directive->dtype) {
case DT_ENVIRONMENT:
+ g_current_ftype = directive->ftype;
switch (directive->position) {
case POS_START:
cho_line_item_free(songs[so]->sections[se]->lines[li]->lyrics[ly]);
@@ -1594,6 +1974,7 @@ struct ChoSong **cho_parse(FILE *fp)
songs[so]->sections[se]->lines[li]->lyrics[ly] = cho_line_item_new();
}
break;
+ default:
}
break;
case DT_METADATA:
@@ -1632,10 +2013,47 @@ struct ChoSong **cho_parse(FILE *fp)
fprintf(stderr, "INFO: Preamble directive '%s' can't have a value.\n", directive_name);
break;
case DT_FONT:
- // Set directive value globally
+ struct StyleProperty sprop;
+ sprop.ftype = directive->ftype;
+ char *dir_value = string_remove_leading_whitespace(directive_value);
+ switch (directive->sprop) {
+ case SPT_FONT:
+ sprop.u.font_name = malloc((strlen(dir_value)+1) * sizeof(char));
+ strcpy(sprop.u.font_name, dir_value);
+ sprop.type = SPT_FONT;
+ break;
+ case SPT_SIZE:
+ sprop.u.font_size = strtod(dir_value, NULL);
+ if (sprop.u.font_size == 0.0) {
+ fprintf(stderr, "INFO: Font directive '%s' has an invalid value. Ignoring directive.\n", directive_name);
+ sprop.type = SPT_EMPTY;
+ break;
+ }
+ sprop.type = SPT_SIZE;
+ break;
+ case SPT_COLOR:
+ sprop.u.foreground_color = cho_color_parse(dir_value);
+ if (sprop.u.foreground_color == NULL) {
+ fprintf(stderr, "INFO: Font directive '%s' has an invalid value. Ignoring directive.\n", directive_name);
+ sprop.type = SPT_EMPTY;
+ break;
+ }
+ sprop.type = SPT_COLOR;
+ break;
+ default:
+ }
+ cho_style_change_default(sprop);
+ if (sprop.type == SPT_FONT) {
+ free(sprop.u.font_name);
+ } else if (sprop.type == SPT_COLOR) {
+ free(sprop.u.foreground_color);
+ }
+ free(dir_value);
break;
case DT_CUSTOM:
+ fprintf(stderr, "INFO: Ignoring custom directive '%s'.\n", directive_name);
break;
+ default:
}
memset(directive_value, 0, strlen(directive_value));
cho_directive_free(directive);
diff --git a/chordpro.h b/chordpro.h
@@ -1,12 +1,18 @@
+#include "config.h"
/* ChordPro markup language <https://chordpro.org/chordpro/chordpro_markup> */
#ifndef _CHORDPRO_H_
#define _CHORDPRO_H_
-#define RISE_MAX
+#define LENGTH(x) (sizeof x / sizeof x[0])
+
+// #define RISE_MAX
+#define EMPTY -1.0
#define DEFAULT_FONT_SIZE 14.0
+#define DEFAULT_TITLE_FONT_SIZE 18.0
// Based on https://stackoverflow.com/a/417184
#define URL_MAX_LEN 2000
+#define FONT_NAME_MAX 100
enum FontFamily {
FF_EMPTY = -1,
@@ -36,9 +42,9 @@ struct Font {
enum FontWeight weight;
double size;
};
-// "Inter-monospace-regular-regular-12.0"
enum LineStyle {
+ LS_EMPTY = -1,
LS_SINGLE,
LS_DOUBLE,
LS_NONE
@@ -98,7 +104,40 @@ enum State {
STATE_COMMENT
};
+/* Similar to SectionType but different enough for a separate type */
+enum SongFragmentType {
+ SF_EMPTY = -1,
+ SF_CHORD,
+ SF_CHORUS,
+ SF_FOOTER,
+ SF_GRID,
+ SF_TAB,
+ SF_TOC,
+ SF_TEXT,
+ SF_TITLE
+};
+
+enum StylePropertyType {
+ SPT_EMPTY = -1,
+ SPT_FONT,
+ SPT_SIZE,
+ SPT_COLOR
+};
+
+union StylePropertyValue {
+ char *font_name;
+ double font_size;
+ struct RGBColor *foreground_color;
+};
+
+struct StyleProperty {
+ enum SongFragmentType ftype;
+ enum StylePropertyType type;
+ union StylePropertyValue u;
+};
+
enum DirectiveType {
+ DT_EMPTY = -1,
DT_ENVIRONMENT,
DT_METADATA,
DT_FORMATTING,
@@ -118,6 +157,7 @@ enum SectionType {
};
enum Position {
+ POS_EMPTY = -1,
POS_START,
POS_END
};
@@ -126,6 +166,8 @@ struct ChoDirective {
enum DirectiveType dtype;
enum SectionType stype;
enum Position position;
+ enum StylePropertyType sprop;
+ enum SongFragmentType ftype;
struct Style *style;
};
@@ -161,12 +203,18 @@ struct ChoSong {
struct ChoSection **sections;
};
-struct ChoSong **cho_parse(FILE *fp);
+struct ChoSong **cho_parse(FILE *fp, struct Config *config);
void cho_songs_free(struct ChoSong **song);
int cho_line_item_count(struct ChoLineItem **items);
int cho_chord_count(struct ChoChord **chords);
+struct Style *cho_style_new(void);
+void cho_style_free(struct Style *style);
+struct Style *cho_style_duplicate(struct Style *style);
struct Font *cho_style_font_desc_parse(const char *str);
+void cho_style_print_as_toml(struct Style *style, const char *section);
+struct RGBColor *cho_color_parse(const char *str);
+enum LineStyle cho_linestyle_parse(const char *str);
struct Font *cho_font_new(void);
void cho_font_free(struct Font *font);
struct Font *cho_font_duplicate(struct Font *font);
diff --git a/config.c b/config.c
@@ -5,89 +5,295 @@
#include "chordpro.h"
#include "config.h"
-struct Config *config_load_default(void)
+static const char *g_valid_styles[] = {
+ "title",
+ "subtitle",
+ "footer",
+ "text",
+ "chorus",
+ "chord",
+ "annotation",
+ "comment",
+ "comment_italic",
+ "comment_boxed",
+ "tab",
+ "label",
+ "toc",
+ "grid",
+ "grid_margin",
+ "empty",
+ "diagram",
+ "diagram_base",
+ "chordfingers"
+};
+
+static struct PrintableItem *config_printable_item_new(const char *name)
+{
+ struct PrintableItem *item = malloc(sizeof(struct PrintableItem));
+ item->name = strdup(name);
+ item->style = cho_style_new();
+ return item;
+}
+
+static void config_printable_item_free(struct PrintableItem *item)
+{
+ free(item->name);
+ cho_style_free(item->style);
+ free(item);
+}
+
+struct PrintableItem *config_printable_item_get(struct PrintableItem **items, const char *name)
+{
+ int i = 0;
+ while (items[i] != NULL) {
+ if (strcmp(items[i]->name, name) == 0) {
+ return items[i];
+ }
+ i++;
+ }
+ return NULL;
+}
+
+static struct Config *config_load_default(void)
{
struct Config *config = malloc(sizeof(struct Config));
- config->title_font = malloc(sizeof(struct Font));
- config->title_font->family = FF_NORMAL;
- config->title_font->name = strdup("Inter");
- config->title_font->style = FS_ROMAN;
- config->title_font->weight = FW_BOLD;
- config->title_font->size = 18.0;
- config->subtitle_font = malloc(sizeof(struct Font));
- config->subtitle_font->family = FF_NORMAL;
- config->subtitle_font->name = strdup("Inter");
- config->subtitle_font->style = FS_ROMAN;
- config->subtitle_font->weight = FW_REGULAR;
- config->subtitle_font->size = 12.0;
- config->text_font = malloc(sizeof(struct Font));
- config->text_font->name = strdup("Inter");
- config->text_font->family = FF_NORMAL;
- config->text_font->style = FS_ROMAN;
- config->text_font->weight = FW_REGULAR;
- config->text_font->size = 14.0;
- config->chord_font = malloc(sizeof(struct Font));
- config->chord_font->name = strdup("Inter");
- config->chord_font->family = FF_NORMAL;
- config->chord_font->style = FS_ROMAN;
- config->chord_font->weight = FW_BOLD;
- config->chord_font->size = 14.0;
- config->comment_font = malloc(sizeof(struct Font));
- config->comment_font->name = strdup("Inter");
- config->comment_font->family = FF_NORMAL;
- config->comment_font->style = FS_ROMAN;
- config->comment_font->weight = FW_REGULAR;
- config->comment_font->size = 14.0;
- config->comment_italic_font = malloc(sizeof(struct Font));
- config->comment_italic_font->name = strdup("Inter");
- config->comment_italic_font->family = FF_NORMAL;
- config->comment_italic_font->style = FS_ITALIC;
- config->comment_italic_font->weight = FW_BOLD;
- config->comment_italic_font->size = 14.0;
- config->comment_box_font = malloc(sizeof(struct Font));
- config->comment_box_font->name = strdup("Inter");
- config->comment_box_font->family = FF_NORMAL;
- config->comment_box_font->style = FS_ROMAN;
- config->comment_box_font->weight = FW_REGULAR;
- config->comment_box_font->size = 14.0;
- config->tab_font = malloc(sizeof(struct Font));
- config->tab_font->name = strdup("Inter");
- config->tab_font->family = FF_NORMAL;
- config->tab_font->style = FS_ROMAN;
- config->tab_font->weight = FW_REGULAR;
- config->tab_font->size = 14.0;
- config->grid_font = malloc(sizeof(struct Font));
- config->grid_font->name = strdup("Inter");
- config->grid_font->family = FF_NORMAL;
- config->grid_font->style = FS_ROMAN;
- config->grid_font->weight = FW_BOLD;
- config->grid_font->size = 14.0;
- config->label_font = malloc(sizeof(struct Font));
- config->label_font->name = strdup("Inter");
- config->label_font->family = FF_NORMAL;
- config->label_font->style = FS_ITALIC;
- config->label_font->weight = FW_REGULAR;
- config->label_font->size = 14.0;
+ config->printable_items = malloc(11 * sizeof(struct PrintableItem *));
+ config->printable_items[0] = config_printable_item_new("title");
+ config->printable_items[0]->style->font->name = strdup("Inter");
+ config->printable_items[0]->style->font->weight = FW_BOLD;
+ config->printable_items[0]->style->font->size = 18.0;
+ config->printable_items[1] = config_printable_item_new("subtitle");
+ config->printable_items[1]->style->font->name = strdup("Inter");
+ config->printable_items[1]->style->font->size = 12.0;
+ config->printable_items[2] = config_printable_item_new("text");
+ config->printable_items[2]->style->font->name = strdup("Inter");
+ config->printable_items[3] = config_printable_item_new("chord");
+ config->printable_items[3]->style->font->name = strdup("Inter");
+ config->printable_items[3]->style->font->weight = FW_BOLD;
+ config->printable_items[4] = config_printable_item_new("comment");
+ config->printable_items[4]->style->font->name = strdup("Inter");
+ config->printable_items[5] = config_printable_item_new("comment_italic");
+ config->printable_items[5]->style->font->name = strdup("Inter");
+ config->printable_items[5]->style->font->style = FS_ITALIC;
+ config->printable_items[6] = config_printable_item_new("comment_box");
+ config->printable_items[6]->style->font->name = strdup("Inter");
+ config->printable_items[7] = config_printable_item_new("tab");
+ config->printable_items[7]->style->font->name = strdup("Inter");
+ config->printable_items[8] = config_printable_item_new("grid");
+ config->printable_items[8]->style->font->name = strdup("Inter");
+ config->printable_items[8]->style->font->weight = FW_BOLD;
+ config->printable_items[9] = config_printable_item_new("label");
+ config->printable_items[9]->style->font->name = strdup("Inter");
+ config->printable_items[9]->style->font->style = FS_ITALIC;
+ config->printable_items[10] = NULL;
return config;
}
+static void config_printable_item_print_as_toml(struct PrintableItem *item)
+{
+ printf("[styles.%s]\n\n", item->name);
+ cho_style_print_as_toml(item->style, item->name);
+}
+
void config_print_default(void)
{
struct Config *config = config_load_default();
- printf("[fonts]\n\n");
- cho_font_print_as_toml(config->title_font, "title");
- cho_font_print_as_toml(config->subtitle_font, "subtitle");
- cho_font_print_as_toml(config->text_font, "text");
- cho_font_print_as_toml(config->chord_font, "chord");
- cho_font_print_as_toml(config->comment_font, "comment");
- cho_font_print_as_toml(config->comment_italic_font, "comment_italic");
- cho_font_print_as_toml(config->comment_box_font, "comment_box");
- cho_font_print_as_toml(config->tab_font, "tab");
- cho_font_print_as_toml(config->grid_font, "grid");
- cho_font_print_as_toml(config->label_font, "label");
+ int i = 0;
+ printf("[styles]\n");
+ while (config->printable_items[i] != NULL) {
+ config_printable_item_print_as_toml(config->printable_items[i]);
+ i++;
+ }
config_free(config);
}
+static bool config_load_font(struct Font *font, toml_table_t *table, const char *key_name)
+{
+ enum FontFamily family;
+ enum FontStyle style;
+ enum FontWeight weight;
+ toml_value_t value;
+ value = toml_table_string(table, "name");
+ if (value.ok) {
+ free(font->name);
+ font->name = value.u.s;
+ }
+ value = toml_table_string(table, "family");
+ if (value.ok) {
+ family = cho_font_family_parse(value.u.s);
+ if (family != FF_EMPTY) {
+ font->family = family;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s.font] family value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_string(table, "style");
+ if (value.ok) {
+ style = cho_font_style_parse(value.u.s);
+ if (style != FS_EMPTY) {
+ font->style = style;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s.font] style value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_string(table, "weight");
+ if (value.ok) {
+ weight = cho_font_weight_parse(value.u.s);
+ if (weight != FW_EMPTY) {
+ font->weight = weight;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s.font] weight value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_int(table, "size");
+ if (value.ok) {
+ font->size = value.u.i;
+ }
+ return true;
+}
+
+static bool config_load_style(struct Style *style, toml_table_t *table, const char *key_name)
+{
+ toml_value_t value;
+ struct RGBColor *color;
+ enum LineStyle line_style;
+ toml_table_t *font_section = toml_table_table(table, "font");
+ if (font_section) {
+ if (!config_load_font(style->font, font_section, key_name)) {
+ fprintf(stderr, "config_load_font failed.\n");
+ return false;
+ }
+ }
+ value = toml_table_string(table, "foreground_color");
+ if (value.ok) {
+ color = cho_color_parse(value.u.s);
+ if (color) {
+ free(style->foreground_color);
+ style->foreground_color = color;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s] foreground color value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_string(table, "background_color");
+ if (value.ok) {
+ color = cho_color_parse(value.u.s);
+ if (color) {
+ free(style->background_color);
+ style->background_color = color;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s] background color value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_string(table, "underline_style");
+ if (value.ok) {
+ line_style = cho_linestyle_parse(value.u.s);
+ if (line_style != LS_EMPTY) {
+ style->underline_style = line_style;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s] underline style value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_string(table, "underline_color");
+ if (value.ok) {
+ color = cho_color_parse(value.u.s);
+ if (color) {
+ free(style->underline_color);
+ style->underline_color = color;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s] underline color value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_string(table, "overline_style");
+ if (value.ok) {
+ line_style = cho_linestyle_parse(value.u.s);
+ if (line_style != LS_EMPTY) {
+ style->overline_style = line_style;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s] overline style value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_string(table, "overline_color");
+ if (value.ok) {
+ color = cho_color_parse(value.u.s);
+ if (color) {
+ free(style->overline_color);
+ style->overline_color = color;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s] overline color value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_bool(table, "strikethrough");
+ if (value.ok) {
+ style->strikethrough = value.u.b;
+ }
+ value = toml_table_string(table, "strikethrough_color");
+ if (value.ok) {
+ color = cho_color_parse(value.u.s);
+ if (color) {
+ free(style->strikethrough_color);
+ style->strikethrough_color = color;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s] strikethrough color value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_bool(table, "boxed");
+ if (value.ok) {
+ style->boxed = value.u.b;
+ }
+ value = toml_table_string(table, "boxed_color");
+ if (value.ok) {
+ color = cho_color_parse(value.u.s);
+ if (color) {
+ free(style->boxed_color);
+ style->boxed_color = color;
+ } else {
+ fprintf(stderr, "INFO: Config section [styles.%s] boxed color value is invalid.\n", key_name);
+ return false;
+ }
+ free(value.u.s);
+ }
+ value = toml_table_double(table, "rise");
+ if (value.ok) {
+ style->rise = value.u.d;
+ }
+ value = toml_table_string(table, "href");
+ if (value.ok) {
+ style->href = value.u.s;
+ }
+ return true;
+}
+
+static bool config_is_style(const char *str)
+{
+ int i = 0;
+ while (g_valid_styles[i] != NULL) {
+ if (strcmp(g_valid_styles[i], str) == 0)
+ return true;
+ i++;
+ }
+ return false;
+}
+
struct Config *config_load(const char *filepath)
{
struct Config *config = config_load_default();
@@ -104,399 +310,34 @@ struct Config *config_load(const char *filepath)
}
char errbuf[200];
toml_table_t *table = toml_parse_file(fp, (char *)&errbuf, sizeof(errbuf));
- toml_table_t *fonts = toml_table_table(table, "fonts");
- toml_table_t *section;
- toml_value_t name, family, style, weight, size;
- enum FontFamily font_family;
- enum FontStyle font_style;
- enum FontWeight font_weight;
+ if (!table) {
+ fprintf(stderr, "toml_parse_file failed.\n");
+ fprintf(stderr, "INFO: Config file is not a valid toml file.\n");
+ return NULL;
+ }
+ toml_table_t *styles = toml_table_table(table, "styles");
+ if (!styles)
+ goto END;
int unused;
const char *key_name;
- for (int i=0; i<toml_table_len(fonts); i++) {
- key_name = toml_table_key(fonts, i, &unused);
- section = toml_table_table(fonts, key_name);
- name = toml_table_string(section, "name");
- family = toml_table_string(section, "family");
- style = toml_table_string(section, "style");
- weight = toml_table_string(section, "weight");
- size = toml_table_int(section, "size");
- if (strcmp(key_name, "title") == 0) {
- if (name.ok) {
- free(config->title_font->name);
- config->title_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config title section font family value.\n");
- return NULL;
- } else {
- config->title_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config title section font style value.\n");
- return NULL;
- } else {
- config->title_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config title section font weight value.\n");
- return NULL;
- } else {
- config->title_font->weight = font_weight;
+ toml_table_t *key;
+ struct PrintableItem *item;
+ for (int i=0; i<toml_table_len(styles); i++) {
+ key_name = toml_table_key(styles, i, &unused);
+ if (config_is_style(key_name)) {
+ key = toml_table_table(styles, key_name);
+ if (key) {
+ item = config_printable_item_get(config->printable_items, key_name);
+ if (item) {
+ if (!config_load_style(item->style, key, key_name)) {
+ fprintf(stderr, "config_load_style failed.\n");
+ return NULL;
+ }
}
- free(weight.u.s);
}
- if (size.ok)
- config->title_font->size = size.u.i;
- } else if (strcmp(key_name, "subtitle") == 0) {
- if (name.ok) {
- free(config->subtitle_font->name);
- config->subtitle_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config subtitle section font family value.\n");
- return NULL;
- } else {
- config->subtitle_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config subtitle section font style value.\n");
- return NULL;
- } else {
- config->subtitle_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config subtitle section font weight value.\n");
- return NULL;
- } else {
- config->subtitle_font->weight = font_weight;
- }
- free(weight.u.s);
- }
- if (size.ok)
- config->subtitle_font->size = size.u.i;
- } else if (strcmp(key_name, "text") == 0) {
- if (name.ok) {
- free(config->text_font->name);
- config->text_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config text section font family value.\n");
- return NULL;
- } else {
- config->text_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config text section font style value.\n");
- return NULL;
- } else {
- config->text_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config text section font weight value.\n");
- return NULL;
- } else {
- config->text_font->weight = font_weight;
- }
- free(weight.u.s);
- }
- if (size.ok)
- config->text_font->size = size.u.i;
- } else if (strcmp(key_name, "chord") == 0) {
- if (name.ok) {
- free(config->chord_font->name);
- config->chord_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config chord section font family value.\n");
- return NULL;
- } else {
- config->chord_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config chord section font style value.\n");
- return NULL;
- } else {
- config->chord_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config chord section font weight value.\n");
- return NULL;
- } else {
- config->chord_font->weight = font_weight;
- }
- free(weight.u.s);
- }
- if (size.ok) {
- config->chord_font->size = size.u.i;
- }
- } else if (strcmp(key_name, "comment") == 0) {
- if (name.ok) {
- free(config->comment_font->name);
- config->comment_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config comment section font family value.\n");
- return NULL;
- } else {
- config->comment_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config comment section font style value.\n");
- return NULL;
- } else {
- config->comment_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config comment section font weight value.\n");
- return NULL;
- } else {
- config->comment_font->weight = font_weight;
- }
- free(weight.u.s);
- }
- if (size.ok) {
- config->comment_font->size = size.u.i;
- }
- } else if (strcmp(key_name, "comment_italic") == 0) {
- if (name.ok) {
- free(config->comment_italic_font->name);
- config->comment_italic_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config comment_italic section font family value.\n");
- return NULL;
- } else {
- config->comment_italic_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config comment_italic section font style value.\n");
- return NULL;
- } else {
- config->comment_italic_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config comment_italic section font weight value.\n");
- return NULL;
- } else {
- config->comment_italic_font->weight = font_weight;
- }
- free(weight.u.s);
- }
- if (size.ok) {
- config->comment_italic_font->size = size.u.i;
- }
- } else if (strcmp(key_name, "comment_box") == 0) {
- if (name.ok) {
- free(config->comment_box_font->name);
- config->comment_box_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config comment_box section font family value.\n");
- return NULL;
- } else {
- config->comment_box_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config comment_box section font style value.\n");
- return NULL;
- } else {
- config->comment_box_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config comment_box section font weight value.\n");
- return NULL;
- } else {
- config->comment_box_font->weight = font_weight;
- }
- free(weight.u.s);
- }
- if (size.ok) {
- config->comment_box_font->size = size.u.i;
- }
- } else if (strcmp(key_name, "tab") == 0) {
- if (name.ok) {
- free(config->tab_font->name);
- config->tab_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config tab section font family value.\n");
- return NULL;
- } else {
- config->tab_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config tab section font style value.\n");
- return NULL;
- } else {
- config->tab_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config tab section font weight value.\n");
- return NULL;
- } else {
- config->tab_font->weight = font_weight;
- }
- free(weight.u.s);
- }
- if (size.ok) {
- config->tab_font->size = size.u.i;
- }
- } else if (strcmp(key_name, "grid") == 0) {
- if (name.ok) {
- free(config->grid_font->name);
- config->grid_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config grid section font family value.\n");
- return NULL;
- } else {
- config->grid_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config grid section font style value.\n");
- return NULL;
- } else {
- config->grid_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config grid section font weight value.\n");
- return NULL;
- } else {
- config->grid_font->weight = font_weight;
- }
- free(weight.u.s);
- }
- if (size.ok) {
- config->grid_font->size = size.u.i;
- }
- } else if (strcmp(key_name, "label") == 0) {
- if (name.ok) {
- free(config->label_font->name);
- config->label_font->name = name.u.s;
- }
- if (family.ok) {
- font_family = cho_font_family_parse(family.u.s);
- if (font_family == FF_EMPTY) {
- fprintf(stderr, "INFO: Invalid config label section font family value.\n");
- return NULL;
- } else {
- config->label_font->family = font_family;
- }
- }
- if (style.ok) {
- font_style = cho_font_style_parse(style.u.s);
- if (font_style == FS_EMPTY) {
- fprintf(stderr, "INFO: Invalid config label section font style value.\n");
- return NULL;
- } else {
- config->label_font->style = font_style;
- }
- free(style.u.s);
- }
- if (weight.ok) {
- font_weight = cho_font_weight_parse(weight.u.s);
- if (font_weight == FW_EMPTY) {
- fprintf(stderr, "INFO: Invalid config label section font weight value.\n");
- return NULL;
- } else {
- config->label_font->weight = font_weight;
- }
- free(weight.u.s);
- }
- if (size.ok) {
- config->label_font->size = size.u.i;
- }
- } else {
- fprintf(stderr, "INFO: Ignoring [fonts.%s] section in config file.\n", key_name);
- if (name.ok)
- free(name.u.s);
- if (style.ok)
- free(style.u.s);
- if (weight.ok)
- free(weight.u.s);
}
}
+ END:
toml_free(table);
fclose(fp);
return config;
@@ -504,15 +345,11 @@ struct Config *config_load(const char *filepath)
void config_free(struct Config *config)
{
- cho_font_free(config->title_font);
- cho_font_free(config->subtitle_font);
- cho_font_free(config->text_font);
- cho_font_free(config->chord_font);
- cho_font_free(config->comment_font);
- cho_font_free(config->comment_italic_font);
- cho_font_free(config->comment_box_font);
- cho_font_free(config->tab_font);
- cho_font_free(config->grid_font);
- cho_font_free(config->label_font);
+ int i = 0;
+ while (config->printable_items[i] != NULL) {
+ config_printable_item_free(config->printable_items[i]);
+ i++;
+ }
+ free(config->printable_items);
free(config);
}
diff --git a/config.h b/config.h
@@ -1,16 +1,18 @@
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+struct PrintableItem {
+ char *name;
+ struct Style *style;
+};
+
struct Config {
- struct Font *title_font;
- struct Font *subtitle_font;
- struct Font *text_font;
- struct Font *chord_font;
- struct Font *comment_font;
- struct Font *comment_italic_font;
- struct Font *comment_box_font;
- struct Font *tab_font;
- struct Font *grid_font;
- struct Font *label_font;
+ struct PrintableItem **printable_items;
};
struct Config *config_load(const char *filepath);
void config_free(struct Config *config);
void config_print_default(void);
+struct PrintableItem *config_printable_item_get(struct PrintableItem **items, const char *name);
+
+#endif /* _CONFIG_H_ */
diff --git a/fontconfig.c b/fontconfig.c
@@ -2,8 +2,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
-// #include <ft2build.h>
-// #include <freetype/freetype.h>
#include <fontconfig/fontconfig.h>
#include "fontconfig.h"
@@ -46,26 +44,28 @@ char *fontconfig_fontpath_find(struct Font *font, enum FontType font_type)
FcValue style;
style.type = FcTypeInteger;
switch (font->style) {
- case FS_ROMAN:
- style.u.i = FC_SLANT_ROMAN;
- break;
- case FS_OBLIQUE:
- style.u.i = FC_SLANT_OBLIQUE;
- break;
- case FS_ITALIC:
- style.u.i = FC_SLANT_ITALIC;
- break;
+ case FS_ROMAN:
+ style.u.i = FC_SLANT_ROMAN;
+ break;
+ case FS_OBLIQUE:
+ style.u.i = FC_SLANT_OBLIQUE;
+ break;
+ case FS_ITALIC:
+ style.u.i = FC_SLANT_ITALIC;
+ break;
+ default:
}
FcPatternAdd(pattern, FC_SLANT, style, FcFalse);
FcValue weight;
weight.type = FcTypeInteger;
switch (font->weight) {
- case FW_REGULAR:
- weight.u.i = FC_WEIGHT_REGULAR;
- break;
- case FW_BOLD:
- weight.u.i = FC_WEIGHT_BOLD;
- break;
+ case FW_REGULAR:
+ weight.u.i = FC_WEIGHT_REGULAR;
+ break;
+ case FW_BOLD:
+ weight.u.i = FC_WEIGHT_BOLD;
+ break;
+ default:
}
FcPatternAdd(pattern, FC_WEIGHT, weight, FcFalse);
FcFontSet *set = FcFontList(NULL, pattern, obj);
diff --git a/lorid.c b/lorid.c
@@ -34,6 +34,14 @@ int main(int argc, char *argv[])
fprintf(stderr, "config_load failed.\n");
return 1;
}
+ /* int u = 0;
+ while (config->printable_items[u] != NULL) {
+ printf("---- BEGIN PRINTABLE ITEM ----\n");
+ printf("name: %s\n", config->printable_items[u]->name);
+ cho_style_print(config->printable_items[u]->style);
+ printf("---- END PRINTABLE ITEM ------\n");
+ u++;
+ } */
free(config_filepath);
if (argc == optind) {
fp = stdin;
@@ -47,7 +55,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "Provide only one file.\n");
return 1;
}
- struct ChoSong **songs = cho_parse(fp);
+ struct ChoSong **songs = cho_parse(fp, config);
if (songs == NULL) {
fprintf(stderr, "cho_parse failed.\n");
return 1;
diff --git a/out_pdf.c b/out_pdf.c
@@ -10,10 +10,10 @@
static struct Fnt **g_fonts = NULL;
-static char current_font[200];
-static double current_font_size;
-static double current_y = MEDIABOX_HEIGHT - 25.0;
-static pdfio_obj_t *current_font_obj = NULL;
+static char g_current_font_name[200];
+static double g_current_font_size;
+static double g_current_y = MEDIABOX_HEIGHT - 25.0;
+static pdfio_obj_t *g_current_font_obj = NULL;
static pdfio_obj_t *out_pdf_fnt_obj_get_by_name(const char *name)
{
@@ -175,72 +175,19 @@ static void out_pdf_add_fonts(struct Font *font, struct Font ***fonts)
cho_font_free(new_font);
}
-/* static void out_pdf_fonts_add_default(struct Font ***fonts)
-{
- struct Font *font_regular = cho_font_new();
- font_regular->name = strdup("Inter");
- out_pdf_font_add(font_regular, fonts);
- struct Font *font_bold = cho_font_new();
- font_bold->name = strdup("Inter");
- font_bold->weight = FW_BOLD;
- out_pdf_font_add(font_bold, fonts);
- struct Font *font_italic = cho_font_new();
- font_italic->name = strdup("Inter");
- font_italic->style = FS_ITALIC;
- out_pdf_font_add(font_italic, fonts);
- struct Font *font_italic_bold = cho_font_new();
- font_italic_bold->name = strdup("Inter");
- font_italic_bold->style = FS_ITALIC;
- font_italic_bold->weight = FW_BOLD;
- out_pdf_font_add(font_italic_bold, fonts);
-} */
-
static struct Font **out_pdf_font_get_all(struct ChoSong **songs, struct Config *config)
{
struct Font **fonts = NULL;
struct Font *font;
- // out_pdf_fonts_add_default(&fonts);
bool added = false;
- font = cho_font_duplicate(config->title_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
- font = cho_font_duplicate(config->subtitle_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
- font = cho_font_duplicate(config->text_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
- font = cho_font_duplicate(config->chord_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
- font = cho_font_duplicate(config->comment_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
- font = cho_font_duplicate(config->comment_italic_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
- font = cho_font_duplicate(config->comment_box_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
- font = cho_font_duplicate(config->tab_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
- font = cho_font_duplicate(config->grid_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
- font = cho_font_duplicate(config->label_font);
- added = out_pdf_font_add_if_not_in(font, &fonts);
- if (!added)
- cho_font_free(font);
+ int i = 0;
+ while (config->printable_items[i] != NULL) {
+ font = cho_font_duplicate(config->printable_items[i]->style->font);
+ added = out_pdf_font_add_if_not_in(font, &fonts);
+ if (!added)
+ cho_font_free(font);
+ i++;
+ }
int so = 0;
int se = 0;
int li = 0;
@@ -268,18 +215,31 @@ static struct Font **out_pdf_font_get_all(struct ChoSong **songs, struct Config
return fonts;
}
+static void out_pdf_adjust_line(struct ChoLine *line)
+{
+}
+
static bool out_pdf_chord_show(pdfio_stream_t *stream, const char *lyrics_line, struct ChoChord *chord, bool linebreak)
{
- char *line = malloc((strlen(lyrics_line)+1) * sizeof(char));
+ double width;
+ char line[strlen(lyrics_line)+1];
strcpy(line, lyrics_line);
+ // size_t line_len = strlen(line);
line[chord->position] = 0;
- double width = pdfioContentTextMeasure(current_font_obj, line, current_font_size);
- free(line);
+ width = pdfioContentTextMeasure(g_current_font_obj, line, g_current_font_size);
+ /* if (chord->position < line_len) {
+ line[chord->position] = 0;
+ width = pdfioContentTextMeasure(g_current_font_obj, line, g_current_font_size);
+ } else {
+ double space_width = pdfioContentTextMeasure(g_current_font_obj, " ", g_current_font_size);
+ width = pdfioContentTextMeasure(g_current_font_obj, line, g_current_font_size);
+ width += (line_len - chord->position) * space_width;
+ } */
if (!pdfioContentTextBegin(stream)) {
fprintf(stderr, "pdfioContentTextBegin failed.\n");
return false;
}
- if (!pdfioContentTextMoveTo(stream, PADDING + width, current_y)) {
+ if (!pdfioContentTextMoveTo(stream, PADDING + width, g_current_y)) {
fprintf(stderr, "pdfioContentTextMoveTo failed.\n");
return false;
}
@@ -292,43 +252,41 @@ static bool out_pdf_chord_show(pdfio_stream_t *stream, const char *lyrics_line,
return false;
}
if (linebreak) {
- current_y -= current_font_size + 2.0;
+ g_current_y -= g_current_font_size + 2.0;
}
return true;
}
-static bool out_pdf_text_show(pdfio_stream_t *stream, const char *str, enum Alignment align, bool linebreak)
+size_t out_pdf_text_find_fitting_length(const char *str, size_t len)
{
- static double x_continue = PADDING;
- double x;
- double width = pdfioContentTextMeasure(current_font_obj, str, current_font_size);
- // printf("text '%s' has width: '%f'\n", str, width);
- if (LINE_LEN < width)
- return false;
- switch (align) {
- case CENTER:
- x_continue = PADDING;
- x = PADDING + (LINE_LEN - width) / 2;
- break;
- case LEFT:
- x_continue = PADDING;
- x = PADDING;
- break;
- case CONTINUE:
- x = x_continue;
- x_continue += width;
- break;
+ char tmp[512];
+ strncpy((char *)&tmp, str, len);
+ tmp[len] = 0;
+
+ double width;
+ width = pdfioContentTextMeasure(g_current_font_obj, tmp, g_current_font_size);
+
+ while (width > LINE_LEN) {
+ if (tmp[len] == ' ' || tmp[len] == '\t') {
+ tmp[len] = 0;
+ width = pdfioContentTextMeasure(g_current_font_obj, tmp, g_current_font_size);
+ }
+ len--;
}
- // printf("x: %f, y: %f\n", x, current_y);
+ return len;
+}
+
+static bool out_pdf_text_show(pdfio_stream_t *stream, struct TextLineItem *item, double y)
+{
if (!pdfioContentTextBegin(stream)) {
fprintf(stderr, "pdfioContentTextBegin failed.\n");
return false;
}
- if (!pdfioContentTextMoveTo(stream, x, current_y)) {
+ if (!pdfioContentTextMoveTo(stream, item->x, y)) {
fprintf(stderr, "pdfioContentTextMoveTo failed.\n");
return false;
}
- if (!pdfioContentTextShow(stream, true, str)) {
+ if (!pdfioContentTextShow(stream, true, item->text)) {
fprintf(stderr, "pdfioContentTextShow failed.\n");
return false;
}
@@ -336,17 +294,9 @@ static bool out_pdf_text_show(pdfio_stream_t *stream, const char *str, enum Alig
fprintf(stderr, "pdfioContentTextEnd failed.\n");
return false;
}
- if (linebreak) {
- current_y -= current_font_size + 8.0;
- x_continue = PADDING;
- }
return true;
}
-/* void out_pdf_style_set(pdfio_stream_t *stream, struct Style *style)
-{
-} */
-
static char *out_pdf_filename_create(const char *old)
{
char *new = NULL;
@@ -471,7 +421,10 @@ static void out_pdf_fnt_add(struct Fnt *fnt, struct Fnt ***array)
static bool out_pdf_font_set(pdfio_stream_t *stream, struct Font *font)
{
char *name = out_pdf_fnt_name_create(font);
- printf("setting font '%s'\n", name);
+ if (strcmp(name, g_current_font_name) == 0 && font->size == g_current_font_size) {
+ free(name);
+ return true;
+ }
if (!pdfioContentSetTextFont(stream, name, font->size)) {
fprintf(stderr, "pdfioContentSetTextFont failed.\n");
return false;
@@ -481,18 +434,369 @@ static bool out_pdf_font_set(pdfio_stream_t *stream, struct Font *font)
fprintf(stderr, "out_pdf_fnt_obj_get_by_name failed.\n");
return false;
}
- strcpy(current_font, name);
- current_font_obj = font_obj;
- current_font_size = font->size;
+ strcpy(g_current_font_name, name);
+ g_current_font_obj = font_obj;
+ g_current_font_size = font->size;
free(name);
return true;
}
-bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config *config)
+static bool out_pdf_style_apply(pdfio_stream_t *stream, struct Style *style)
{
- if (config->label_font) {
- printf("label_font is not NULL.\n");
+ double red, green, blue;
+ if (!out_pdf_font_set(stream, style->font)) {
+ fprintf(stderr, "out_pdf_font_set failed.\n");
+ return false;
}
+ red = style->foreground_color->red / 255.0;
+ green = style->foreground_color->green / 255.0;
+ blue = style->foreground_color->blue / 255.0;
+ // printf("foreground_color: %s\n", the_rgb_color(style->foreground_color));
+ // printf("%f, %f, %f\n", red, green, blue);
+ if (!pdfioContentSetFillColorRGB(stream, red, green, blue)) {
+ fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n");
+ return false;
+ }
+ // cho_style_print(style);
+ /* printf("name: %s\n", style->font->name);
+ printf("size: %.1f\n", style->font->size);
+ printf(
+ "\x1b[38;2;%d;%d;%dmRGBCOLOR\x1b[0m\n",
+ style->foreground_color->red,
+ style->foreground_color->green,
+ style->foreground_color->blue
+ ); */
+ return true;
+}
+
+static double text_width(struct TextLineItem *item)
+{
+ char *name = out_pdf_fnt_name_create(item->style->font);
+ pdfio_obj_t *font_obj = out_pdf_fnt_obj_get_by_name(name);
+ free(name);
+ return pdfioContentTextMeasure(font_obj, item->text, item->style->font->size);
+}
+
+static double line_width_until_chord(struct ChoLine *line, struct ChoChord *chord, struct SpaceNeeded *space)
+{
+ int ly, i, last_ly, last_i;
+ int pos = 0;
+ char *name;
+ double width = 0.0;
+ pdfio_obj_t *font_obj;
+ for (ly = 0; line->lyrics[ly]; ly++) {
+ for (i = 0; line->lyrics[ly]->text[i]; i++) {
+ if (pos == chord->position) {
+ last_ly = ly;
+ last_i = i;
+ goto FOUND;
+ }
+ pos++;
+ }
+ }
+ /* If the chord is the last thing in the line */
+ last_ly = ly;
+ last_i = i;
+ FOUND:
+ if (space) {
+ space->line_item_index = last_ly;
+ space->text_index = last_i;
+ }
+ for (ly = 0; line->lyrics[ly] && ly <= last_ly; ly++) {
+ name = out_pdf_fnt_name_create(line->lyrics[ly]->style->font);
+ font_obj = out_pdf_fnt_obj_get_by_name(name);
+ if (ly == last_ly) {
+ char tmp[strlen(line->lyrics[ly]->text)+1];
+ strcpy((char *)&tmp, line->lyrics[ly]->text);
+ tmp[last_i] = 0;
+ width += pdfioContentTextMeasure(font_obj, (const char *)&tmp, line->lyrics[ly]->style->font->size);
+ } else {
+ width += pdfioContentTextMeasure(font_obj, line->lyrics[ly]->text, line->lyrics[ly]->style->font->size);
+ }
+ free(name);
+ }
+ return width;
+}
+
+static bool out_pdf_chord_is_enough_space(struct ChoLine *line, struct ChoChord *prev_chord, struct ChoChord *chord, struct Font *chord_font, struct SpaceNeeded *space)
+{
+ double width_between_chords = line_width_until_chord(line, chord, NULL) - line_width_until_chord(line, prev_chord, space);
+ char *name = out_pdf_fnt_name_create(chord_font);
+ pdfio_obj_t *font_obj = out_pdf_fnt_obj_get_by_name(name);
+ free(name);
+ double prev_chord_width = pdfioContentTextMeasure(font_obj, prev_chord->chord, chord_font->size);
+ if (prev_chord_width > width_between_chords) {
+ space->amount = prev_chord_width - width_between_chords;
+ return false;
+ }
+ return true;
+}
+
+static struct SpaceNeeded *needs_space(struct SpaceNeeded **spaces, int ly, int i) {
+ int sn;
+ for (sn = 0; spaces[sn]; sn++) {
+ if (spaces[sn]->line_item_index == ly && spaces[sn]->text_index == i) {
+ return spaces[sn];
+ }
+ }
+ return NULL;
+}
+
+static void text_line_set_lineheight(struct TextLine *line, enum SongFragmentType ftype)
+{
+ double biggest_font_size = 0.0;
+ int tli;
+ for (tli = 0; line->items[tli]; tli++) {
+ // TODO: Implement chord style
+ if (line->items[tli]->style) {
+ if (line->items[tli]->style->font->size > biggest_font_size) {
+ biggest_font_size = line->items[tli]->style->font->size;
+ }
+ } else {
+ if (14.0 > biggest_font_size) {
+ biggest_font_size = 14.0;
+ }
+ }
+ }
+ switch (ftype) {
+ case SF_CHORD:
+ line->height = 8.0 + biggest_font_size;
+ break;
+ default:
+ line->height = 2.0 + biggest_font_size;
+ }
+}
+
+static struct Text **text_create(struct ChoSong **songs, struct Config *config)
+{
+ struct PrintableItem *printable_item;
+ int so, se, li, ly, ch;
+ double width;
+ bool add_space_to_next_chord = false;
+ struct ChoLine **lines;
+ struct ChoChord **chords;
+ struct SpaceNeeded space;
+ struct SpaceNeeded **spaces = NULL;
+ int sn = 0;
+ int t = 0;
+ int tl = 0;
+ int tli = 0;
+ int m;
+ struct Text **text = NULL;
+ for (so = 0; songs[so]; so++, t++) {
+ text = realloc(text, (t+1) * sizeof(struct Text *));
+ text[t] = malloc(sizeof(struct Text));
+ text[t]->lines = NULL;
+ for (m = 0; songs[so]->metadata[m]; m++) {
+ if (strcmp(songs[so]->metadata[m]->name, "title") == 0) {
+ printable_item = config_printable_item_get(config->printable_items, "title");
+ if (!printable_item) {
+ fprintf(stderr, "config_printable_item_get failed.\n");
+ return NULL;
+ }
+ text[t]->lines = realloc(text[t]->lines, (tl+1) * sizeof(struct TextLine *));
+ text[t]->lines[tl] = malloc(sizeof(struct TextLine));
+ text[t]->lines[tl]->items = malloc(2 * sizeof(struct TextLineItem *));
+ text[t]->lines[tl]->items[0] = malloc(sizeof(struct TextLineItem));
+ text[t]->lines[tl]->items[0]->text = strdup(songs[so]->metadata[m]->value);
+ text[t]->lines[tl]->items[0]->style = cho_style_duplicate(printable_item->style);
+ width = text_width(text[t]->lines[tl]->items[0]);
+ text[t]->lines[tl]->items[0]->x = PADDING + (LINE_LEN - width) / 2;
+ text[t]->lines[tl]->items[1] = NULL;
+ text_line_set_lineheight(text[t]->lines[tl], SF_TEXT);
+ tl++;
+ }
+ }
+ for (m = 0; songs[so]->metadata[m]; m++) {
+ if (strcmp(songs[so]->metadata[m]->name, "subtitle") == 0) {
+ printable_item = config_printable_item_get(config->printable_items, "subtitle");
+ if (!printable_item) {
+ fprintf(stderr, "config_printable_item_get failed.\n");
+ return NULL;
+ }
+ text[t]->lines = realloc(text[t]->lines, (tl+1) * sizeof(struct TextLine *));
+ text[t]->lines[tl] = malloc(sizeof(struct TextLine));
+ text[t]->lines[tl]->items = malloc(2 * sizeof(struct TextLineItem *));
+ text[t]->lines[tl]->items[0] = malloc(sizeof(struct TextLineItem));
+ text[t]->lines[tl]->items[0]->text = strdup(songs[so]->metadata[m]->value);
+ text[t]->lines[tl]->items[0]->style = cho_style_duplicate(printable_item->style);
+ width = text_width(text[t]->lines[tl]->items[0]);
+ text[t]->lines[tl]->items[0]->x = PADDING + (LINE_LEN - width) / 2;
+ text[t]->lines[tl]->items[1] = NULL;
+ text_line_set_lineheight(text[t]->lines[tl], SF_TEXT);
+ tl++;
+ }
+ }
+ text[t]->lines = realloc(text[t]->lines, (tl+1) * sizeof(struct TextLine *));
+ text[t]->lines[tl] = malloc(sizeof(struct TextLine));
+ text[t]->lines[tl]->items = NULL;
+ text[t]->lines[tl]->height = 30.0;
+ tl++;
+ for (se = 0; songs[so]->sections[se]; se++) {
+ if (songs[so]->sections[se]->name) {
+ text[t]->lines = realloc(text[t]->lines, (tl+1) * sizeof(struct TextLine *));
+ text[t]->lines[tl] = malloc(sizeof(struct TextLine));
+ text[t]->lines[tl]->items = malloc(2 * sizeof(struct TextLineItem *));
+ text[t]->lines[tl]->items[0] = malloc(sizeof(struct TextLineItem));
+ text[t]->lines[tl]->items[0]->text = strdup(songs[so]->sections[se]->name);
+ printable_item = config_printable_item_get(config->printable_items, "label");
+ if (!printable_item) {
+ fprintf(stderr, "config_printable_item_get failed.\n");
+ return NULL;
+ }
+ text[t]->lines[tl]->items[0]->style = cho_style_duplicate(printable_item->style);
+ text[t]->lines[tl]->items[0]->x = PADDING;
+ text[t]->lines[tl]->items[1] = NULL;
+ text_line_set_lineheight(text[t]->lines[tl], SF_TEXT);
+ tl++;
+ }
+ lines = songs[so]->sections[se]->lines;
+ for (li = 0; lines[li]; li++, tl++) {
+ text[t]->lines = realloc(text[t]->lines, (tl+1) * sizeof(struct TextLine *));
+ text[t]->lines[tl] = malloc(sizeof(struct TextLine));
+ text[t]->lines[tl]->items = NULL;
+ chords = songs[so]->sections[se]->lines[li]->chords;
+ int chords_len = cho_chord_count(chords);
+ printable_item = config_printable_item_get(config->printable_items, "chord");
+ if (!printable_item) {
+ fprintf(stderr, "config_printable_item_get failed.\n");
+ return NULL;
+ }
+ double added_space = 0.0;
+ for (ch = 0; chords[ch]; ch++, tli++) {
+ text[t]->lines[tl]->items = realloc(text[t]->lines[tl]->items, (tli+1) * sizeof(struct TextLineItem *));
+ text[t]->lines[tl]->items[tli] = malloc(sizeof(struct TextLineItem));
+ if (tli == 0) {
+ text[t]->lines[tl]->items[tli]->x = PADDING + line_width_until_chord(lines[li], chords[ch], NULL);
+ } else {
+ text[t]->lines[tl]->items[tli]->x = PADDING + line_width_until_chord(lines[li], chords[ch], NULL) + added_space;
+ }
+ if (add_space_to_next_chord) {
+ added_space += space.amount;
+ text[t]->lines[tl]->items[tli]->x += space.amount;
+ add_space_to_next_chord = false;
+ }
+ // TODO: implement chord style
+ text[t]->lines[tl]->items[tli]->style = cho_style_duplicate(printable_item->style);
+ text[t]->lines[tl]->items[tli]->text = strdup(chords[ch]->chord);
+ if (chords_len == ch+1) {
+ break;
+ }
+ if (!out_pdf_chord_is_enough_space(
+ songs[so]->sections[se]->lines[li],
+ chords[ch],
+ chords[ch+1],
+ printable_item->style->font,
+ &space
+ )) {
+ spaces = realloc(spaces, (sn+1) * sizeof(struct SpaceNeeded *));
+ spaces[sn] = malloc(sizeof(struct SpaceNeeded));
+ spaces[sn]->line_item_index = space.line_item_index;
+ spaces[sn]->text_index = space.text_index;
+ spaces[sn]->amount = space.amount;
+ sn++;
+ add_space_to_next_chord = true;
+ }
+ }
+ spaces = realloc(spaces, (sn+1) * sizeof(struct SpaceNeeded *));
+ spaces[sn] = NULL;
+ tli++;
+ text[t]->lines[tl]->items = realloc(text[t]->lines[tl]->items, (tli+1) * sizeof(struct TextLineItem *));
+ text[t]->lines[tl]->items[tli] = NULL;
+ text_line_set_lineheight(text[t]->lines[tl], SF_CHORD);
+ tli = 0;
+ tl++;
+ text[t]->lines = realloc(text[t]->lines, (tl+1) * sizeof(struct TextLine *));
+ text[t]->lines[tl] = malloc(sizeof(struct TextLine));
+ text[t]->lines[tl]->items = NULL;
+ for (ly = 0; lines[li]->lyrics[ly]; ly++) {
+ int ii;
+ double last_text_line_item_width;
+ struct SpaceNeeded *sp;
+ text[t]->lines[tl]->items = realloc(text[t]->lines[tl]->items, (tli+1) * sizeof(struct TextLineItem *));
+ text[t]->lines[tl]->items[tli] = malloc(sizeof(struct TextLineItem));
+ text[t]->lines[tl]->items[tli]->text = NULL;
+ text[t]->lines[tl]->items[tli]->style = cho_style_duplicate(lines[li]->lyrics[ly]->style);
+ if (ly == 0) {
+ text[t]->lines[tl]->items[tli]->x = PADDING;
+ } else {
+ last_text_line_item_width = text_width(text[t]->lines[tl]->items[tli-1]);
+ text[t]->lines[tl]->items[tli]->x = text[t]->lines[tl]->items[tli-1]->x + last_text_line_item_width;
+ }
+ int tlii = 0;
+ for (ii = 0; lines[li]->lyrics[ly]->text[ii] != 0; ii++) {
+ if (sp = needs_space(spaces, ly, ii)) {
+ text[t]->lines[tl]->items[tli]->text = realloc(text[t]->lines[tl]->items[tli]->text, (tlii+1) * sizeof(char));
+ text[t]->lines[tl]->items[tli]->text[tlii] = lines[li]->lyrics[ly]->text[ii];
+ tlii++;
+ text[t]->lines[tl]->items[tli]->text = realloc(text[t]->lines[tl]->items[tli]->text, (tlii+1) * sizeof(char));
+ text[t]->lines[tl]->items[tli]->text[tlii] = 0;
+ tlii = 0;
+ tli++;
+ text[t]->lines[tl]->items = realloc(text[t]->lines[tl]->items, (tli+1) * sizeof(struct TextLineItem *));
+ text[t]->lines[tl]->items[tli] = malloc(sizeof(struct TextLineItem));
+ text[t]->lines[tl]->items[tli]->text = NULL;
+ text[t]->lines[tl]->items[tli]->style = cho_style_duplicate(lines[li]->lyrics[ly]->style);
+ last_text_line_item_width = text_width(text[t]->lines[tl]->items[tli-1]);
+ text[t]->lines[tl]->items[tli]->x = text[t]->lines[tl]->items[tli-1]->x + last_text_line_item_width + sp->amount;
+ } else {
+ text[t]->lines[tl]->items[tli]->text = realloc(text[t]->lines[tl]->items[tli]->text, (tlii+1) * sizeof(char));
+ text[t]->lines[tl]->items[tli]->text[tlii] = lines[li]->lyrics[ly]->text[ii];
+ tlii++;
+ }
+ }
+ text[t]->lines[tl]->items[tli]->text = realloc(text[t]->lines[tl]->items[tli]->text, (tlii+1) * sizeof(char));
+ text[t]->lines[tl]->items[tli]->text[tlii] = 0;
+ }
+ tli++;
+ text[t]->lines[tl]->items = realloc(text[t]->lines[tl]->items, (tli+1) * sizeof(struct TextLineItem *));
+ text[t]->lines[tl]->items[tli] = NULL;
+ text_line_set_lineheight(text[t]->lines[tl], SF_TEXT);
+ tli = 0;
+ for (sn = 0; spaces[sn]; sn++) {
+ free(spaces[sn]);
+ }
+ free(spaces);
+ spaces = NULL;
+ sn = 0;
+ }
+ text[t]->lines = realloc(text[t]->lines, (tl+1) * sizeof(struct TextLine *));
+ text[t]->lines[tl] = NULL;
+ tl = 0;
+ }
+ }
+ text = realloc(text, (t+1) * sizeof(struct Text *));
+ text[t] = NULL;
+ return text;
+}
+
+static void text_free(struct Text **text)
+{
+ int t, tl, tli;
+ for (t = 0; text[t]; t++) {
+ for (tl = 0; text[t]->lines[tl]; tl++) {
+ if (text[t]->lines[tl]->items) {
+ for (tli = 0; text[t]->lines[tl]->items[tli]; tli++) {
+ free(text[t]->lines[tl]->items[tli]->text);
+ // NULL check because chord style is not yet implemented
+ if (text[t]->lines[tl]->items[tli]->style) {
+ cho_style_free(text[t]->lines[tl]->items[tli]->style);
+ }
+ free(text[t]->lines[tl]->items[tli]);
+ }
+ free(text[t]->lines[tl]->items);
+ }
+ free(text[t]->lines[tl]);
+ }
+ free(text[t]->lines);
+ free(text[t]);
+ }
+ free(text);
+}
+
+bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config *config)
+{
+ memset(&g_current_font_name, 0, sizeof(g_current_font_name));
char *pdf_filename = out_pdf_filename_create(cho_filename);
pdfio_rect_t media_box_a4 = { 0.0, 0.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT };
pdfio_rect_t crop_box = { 36.0, 36.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT };
@@ -506,7 +810,6 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
while (needed_fonts[f] != NULL) {
fontpath = fontconfig_fontpath_find(needed_fonts[f], FT_TTF);
if (fontpath) {
- printf("ttf fontpath: %s\n", fontpath);
fnt = out_pdf_fnt_new();
fnt->name = out_pdf_fnt_name_create(needed_fonts[f]);
fnt->font = pdfioFileCreateFontObjFromFile(pdf, fontpath, true);
@@ -519,7 +822,6 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
} else {
fontpath = fontconfig_fontpath_find(needed_fonts[f], FT_OTF);
if (fontpath) {
- printf("otf fontpath: %s\n", fontpath);
fnt = out_pdf_fnt_new();
fnt->name = out_pdf_fnt_name_create(needed_fonts[f]);
fnt->font = pdfioFileCreateFontObjFromFile(pdf, fontpath, true);
@@ -538,33 +840,53 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
f++;
}
cho_fonts_free(needed_fonts);
- f = 0;
+ /* f = 0;
while (g_fonts[f] != NULL) {
printf("name: %s\n", g_fonts[f]->name);
f++;
+ } */
+ struct Text **text = text_create(songs, config);
+ if (!text) {
+ fprintf(stderr, "text_create failed.\n");
+ return false;
+ }
+ pdfio_array_t *color_array = pdfioArrayCreateColorFromStandard(pdf, 3, PDFIO_CS_ADOBE);
+ if (!pdfioPageDictAddColorSpace(page1_dict, "rgbcolorspace", color_array)) {
+ fprintf(stderr, "pdfioPageDictAddColorSpace failed.\n");
+ return 1;
}
pdfio_stream_t *page1_stream = pdfioFileCreatePage(pdf, page1_dict);
- if (!out_pdf_font_set(page1_stream, config->text_font)) {
- fprintf(stderr, "out_pdf_font_set failed.\n");
- return false;
+ if (!pdfioContentSetFillColorSpace(page1_stream, "rgbcolorspace")) {
+ fprintf(stderr, "pdfioContentSetFillColorSpace failed.\n");
+ return 1;
}
- if (!pdfioContentSetFillColorRGB(page1_stream, 0.0, 0.0, 0.0)) {
- fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n");
- return false;
+ double y = MEDIABOX_HEIGHT - 25.0;
+ int t, tl, tli;
+ for (t = 0; text[t]; t++) {
+ for (tl = 0; text[t]->lines[tl]; tl++) {
+ if (text[t]->lines[tl]->items) {
+ for (tli = 0; text[t]->lines[tl]->items[tli]; tli++) {
+ // NULL check because chord style is not yet implemented
+ if (text[t]->lines[tl]->items[tli]->style) {
+ out_pdf_style_apply(page1_stream, text[t]->lines[tl]->items[tli]->style);
+ }
+ out_pdf_text_show(page1_stream, text[t]->lines[tl]->items[tli], y);
+ }
+ }
+ y -= text[t]->lines[tl]->height;
+ }
+ }
+ text_free(text);
+ /* pdfio_array_t *color_array = pdfioArrayCreateColorFromStandard(pdf, 3, PDFIO_CS_ADOBE);
+ if (!pdfioPageDictAddColorSpace(page1_dict, "rgbcolorspace", color_array)) {
+ fprintf(stderr, "pdfioPageDictAddColorSpace failed.\n");
+ return 1;
+ }
+ pdfio_stream_t *page1_stream = pdfioFileCreatePage(pdf, page1_dict);
+ if (!pdfioContentSetFillColorSpace(page1_stream, "rgbcolorspace")) {
+ fprintf(stderr, "pdfioContentSetFillColorSpace failed.\n");
+ return 1;
}
- // Setting character spacing destroys pdfioContentTextMeasure() results
- /* if (!pdfioContentSetTextCharacterSpacing(page1_stream, 1.0)) {
- fprintf(stderr, "pdfioContentSetTextCharacterSpacing failed.\n");
- return false;
- } */
- /* if (!pdfioContentSetTextLeading(page1_stream, 1.5)) {
- fprintf(stderr, "pdfioContentSetTextLeading failed.\n");
- return false;
- } */
- /* if (!pdfioContentSetLineWidth(page1_stream, LINE_LEN)) {
- fprintf(stderr, "pdfioContentSetLineWidth failed.\n");
- return false;
- } */
int so = 0;
int se = 0;
int m = 0;
@@ -572,12 +894,22 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
int ly = 0;
int ch = 0;
struct ChoChord **chords;
+ struct PrintableItem *printable_item;
+ if (!pdfioContentTextBegin(page1_stream)) {
+ fprintf(stderr, "pdfioContentTextBegin failed.\n");
+ return false;
+ }
while (songs[so] != NULL) {
while (songs[so]->metadata[m] != NULL) {
if (strcmp(songs[so]->metadata[m]->name, "title") == 0) {
const char *title = songs[so]->metadata[m]->value;
pdfioFileSetTitle(pdf, title);
- if (!out_pdf_font_set(page1_stream, config->title_font)) {
+ printable_item = config_printable_item_get(config->printable_items, "title");
+ if (!printable_item) {
+ fprintf(stderr, "config_printable_item_get failed.\n");
+ return false;
+ }
+ if (!out_pdf_font_set(page1_stream, printable_item->style->font)) {
fprintf(stderr, "out_pdf_font_set failed.\n");
return false;
}
@@ -592,7 +924,12 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
while (songs[so]->metadata[m] != NULL) {
if (strcmp(songs[so]->metadata[m]->name, "subtitle") == 0) {
const char *subtitle = songs[so]->metadata[m]->value;
- if (!out_pdf_font_set(page1_stream, config->subtitle_font)) {
+ printable_item = config_printable_item_get(config->printable_items, "subtitle");
+ if (!printable_item) {
+ fprintf(stderr, "config_printable_item_get failed.\n");
+ return false;
+ }
+ if (!out_pdf_font_set(page1_stream, printable_item->style->font)) {
fprintf(stderr, "out_pdf_font_set failed.\n");
return false;
}
@@ -611,7 +948,12 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
while (songs[so]->sections[se] != NULL) {
if (songs[so]->sections[se]->name) {
const char *section_name = songs[so]->sections[se]->name;
- if (!out_pdf_font_set(page1_stream, config->label_font)) {
+ printable_item = config_printable_item_get(config->printable_items, "label");
+ if (!printable_item) {
+ fprintf(stderr, "config_printable_item_get failed.\n");
+ return false;
+ }
+ if (!out_pdf_font_set(page1_stream, printable_item->style->font)) {
fprintf(stderr, "out_pdf_font_set failed.\n");
return false;
}
@@ -621,21 +963,29 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
}
}
while (songs[so]->sections[se]->lines[li] != NULL) {
+ out_pdf_adjust_line(songs[so]->sections[se]->lines[li]);
chords = songs[so]->sections[se]->lines[li]->chords;
int count = cho_chord_count(chords);
if (count > 0) {
- if (!out_pdf_font_set(page1_stream, config->chord_font)) {
+ printable_item = config_printable_item_get(config->printable_items, "chord");
+ if (!printable_item) {
+ fprintf(stderr, "config_printable_item_get failed.\n");
+ return false;
+ }
+ if (!out_pdf_font_set(page1_stream, printable_item->style->font)) {
fprintf(stderr, "out_pdf_font_set failed.\n");
return false;
}
char *lyrics_line = out_pdf_concat_line_items(songs[so]->sections[se]->lines[li]->lyrics);
while (ch < count - 1) {
+ my_helper(lyrics_line, ch == 0 ? NULL : chords[ch-1], chords[ch]);
if (!out_pdf_chord_show(page1_stream, lyrics_line, chords[ch], false)) {
fprintf(stderr, "out_pdf_chord_show failed.\n");
return false;
}
ch++;
}
+ my_helper(lyrics_line, ch == 0 ? NULL : chords[ch-1], chords[ch]);
if (!out_pdf_chord_show(page1_stream, lyrics_line, chords[ch], true)) {
fprintf(stderr, "out_pdf_chord_show failed.\n");
return false;
@@ -644,14 +994,15 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
free(lyrics_line);
}
char *text;
+ struct Style *style;
int items_count = cho_line_item_count(songs[so]->sections[se]->lines[li]->lyrics);
- if (!out_pdf_font_set(page1_stream, config->text_font)) {
- fprintf(stderr, "out_pdf_font_set failed.\n");
- return false;
- }
while (ly < items_count - 1) {
- // out_pdf_style_set(page1_stream, songs[so]->sections[se]->lines[li]->lyrics[ly]->style);
text = songs[so]->sections[se]->lines[li]->lyrics[ly]->text;
+ if (!out_pdf_style_apply(page1_stream, songs[so]->sections[se]->lines[li]->lyrics[ly]->style)) {
+ fprintf(stderr, "out_pdf_style_apply failed.\n");
+ return false;
+ }
+ style = songs[so]->sections[se]->lines[li]->lyrics[ly]->style;
if (!out_pdf_text_show(page1_stream, text, CONTINUE, false)) {
fprintf(stderr, "out_pdf_text_show failed.\n");
return false;
@@ -659,6 +1010,11 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
ly++;
}
text = songs[so]->sections[se]->lines[li]->lyrics[ly]->text;
+ if (!out_pdf_style_apply(page1_stream, songs[so]->sections[se]->lines[li]->lyrics[ly]->style)) {
+ fprintf(stderr, "out_pdf_style_apply failed.\n");
+ return false;
+ }
+ style = songs[so]->sections[se]->lines[li]->lyrics[ly]->style;
if (!out_pdf_text_show(page1_stream, text, CONTINUE, true)) {
fprintf(stderr, "out_pdf_text_show failed.\n");
return false;
@@ -666,13 +1022,13 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config
ly = 0;
li++;
}
- current_y -= 10.0;
+ g_current_y -= 10.0;
li = 0;
se++;
}
se = 0;
so++;
- }
+ } */
if (!pdfioStreamClose(page1_stream)) {
fprintf(stderr, "pdfioStreamClose failed.\n");
return false;
diff --git a/out_pdf.h b/out_pdf.h
@@ -18,4 +18,25 @@ struct Fnt {
pdfio_obj_t *font;
};
+struct SpaceNeeded {
+ int line_item_index;
+ int text_index;
+ double amount;
+};
+
+struct TextLineItem {
+ char *text;
+ struct Style *style;
+ double x;
+};
+
+struct TextLine {
+ struct TextLineItem **items;
+ double height;
+};
+
+struct Text {
+ struct TextLine **lines;
+};
+
bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config *config);
diff --git a/todo b/todo
@@ -1,3 +1,4 @@
+apply config is cho_parse() instead of out_pdf_new()
'chorus' directive
decide how to implement
metadata directives
@@ -11,3 +12,6 @@ the whole chords advanced stuff
transpose
define chords
chord diagrams
+introduce parse errors
+ still very unclear to me when the parser should warn
+ and continue execution and when it should fail