diff --git a/README.md b/README.md index a689af3..0ae51e2 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,8 @@ List of currently supported elements: * Subscripts and superscripts (`_` and `^`) * Grouping parentheses, brackets and braces (`\left` and `\right`) * Grouping angle brackets, vertical lines, and dots (invisible) -* Summation symbols +* Sums, products and integrals (`\sum`, `\prod` and `\int`) +* Vectors (`\vec`) and limits (`\lim`) Features that are partially implemented (and what is left to finish them): @@ -40,7 +41,7 @@ See the `TODO.md` file for more features to come. First specify the platform you want to use : * `cli` is for command-line tests, with no visualization (PC) -* `sdl2` is an SDL interface with visualization (font support coming) (PC) +* `sdl2` is an SDL interface with visualization (PC) * `fx9860g` builds the library for fx-9860G targets (calculator) * `fxcg50` builds the library for fx-CG 50 targets (calculator) diff --git a/TODO.md b/TODO.md index b661a82..680f717 100644 --- a/TODO.md +++ b/TODO.md @@ -1,11 +1,22 @@ -* Write real error messages * Support Unicode symbols (probably requires help from the font side, urgh) + Available blocks: + -> U+0020 .. U+007F (128) ASCII + -> U+00A0 .. U+00FF (96) Latin-1 Supplement + -> U+0390 .. U+03CF (64) Greek + -> U+2010 .. U+215F (80) General punctuation + -> U+2070 .. U+209F (48) Subscripts and superscripts + -> U+2160 .. U+217F (32) Roman numerals + -> U+2190 .. U+21FF (112) Arrows + Blocks to come: + -> U+2200 .. ? Mathematical operators + -> U+25A0 .. U+25FF (96) Geometric shapes + * Don't use TEX_LAYOUT_SPACING for everything, just make it the default * Add a parameter to resolve as inline style or display style -* Support character-level spacing +* Parametrize character-level and word-level spacing * Be more generic in what nodes have display mode by default +* Reduce horizontal spacing by using a proportional font +* Have a decent variable-height font system in gint * Add square roots, and honor TEX_SQRT_SLANTED and TEX_SQRT_BAR_LENGTH -* Add vectors -* Add limits * Add matrices diff --git a/include/TeX/TeX.h b/include/TeX/TeX.h index e7def82..9ff16fe 100644 --- a/include/TeX/TeX.h +++ b/include/TeX/TeX.h @@ -34,6 +34,15 @@ /* Whether to place bounds above and below integrals (display mode) */ #define TEX_INT_DISPLAY 0 +/* Height of the integral symbol */ +#define TEX_INT_HEIGHT 21 + +/* Length of arrow extensions from the tip of a vector */ +#define TEX_VEC_ARROW_LENGTH 2 +/* Horizontal margin around vector */ +#define TEX_VEC_MARGIN 0 +/* Extra height between argument and vector */ +#define TEX_VEC_SPACING TEX_LAYOUT_SPACING /* Make the vertical part of the square root symbol slanted at low heights */ #define TEX_SQRT_SLANTED 1 diff --git a/src/classes.c b/src/classes.c index cec4ab4..bf154ce 100644 --- a/src/classes.c +++ b/src/classes.c @@ -243,11 +243,9 @@ void supsubscript_render(struct TeX_Node const * node, int x, int y, //--- // Summation symbol. // * args: 0 (ignored) -// * flow: default +// * flow: display mode when available // // Summation symbols are just nodes with a constant size and function. -// They are automatically placed in display mode except if the user asked -// for inline mode. //--- void sum_size(struct TeX_Node *node) @@ -271,9 +269,7 @@ void sum_render(__attribute__((unused)) struct TeX_Node const * node, int x, //--- // Product symbol. // * args: 0 (ignored) -// * flow: default -// -// Just like summation symbols, uses display mode by default. +// * flow: display mode when available //--- void prod_size(struct TeX_Node *node) @@ -302,8 +298,8 @@ void prod_render(__attribute__((unused)) struct TeX_Node const * node, int x, void int_size(struct TeX_Node *node) { node->width = 5; - node->height = 19; - node->line = 9; + node->height = TEX_INT_HEIGHT; + node->line = TEX_INT_HEIGHT >> 1; } void int_render(struct TeX_Node const * node, int x, int y, int color) @@ -317,6 +313,79 @@ void int_render(struct TeX_Node const * node, int x, int y, int color) TeX_pixel(x + 1, y + h - 1, color); } +//--- +// Vectors +// * args: 1 (<1 invalidate, >1 ignore) +// * flow: normal +// +// This "\vec" command is an equivalent of "\overrightarrow" in LaTeX, it +// covers its argument and extends. +// +// Graphical parameters: +// +// TEX_VEC_ARROW_LENGTH: +// Number of pixels that extend diagonally from the tip of the arrow. +// TEX_VEC_SPACING: +// Number of pixels of spacing between argument and vector +// TEX_VEC_MARGIN: +// Horizontal margin around the argument. +// +// ------> ] related to TEX_VEC_ARROW_LENGTH +// ] TEX_VEC_SPACING +// 1 +// |_| |_| +// TEX_VEC_MARGIN +//--- + +void vec_size(struct TeX_Node *node) +{ + int arrow_height = 2 * TEX_VEC_ARROW_LENGTH + 1; + + node->width = w(0) + 2 * TEX_VEC_MARGIN; + node->height = h(0) + TEX_VEC_SPACING + arrow_height; + node->line = l(0) + TEX_VEC_SPACING + arrow_height; +} + +void vec_render(struct TeX_Node const * node, int x, int y, int color) +{ + int length = TEX_VEC_ARROW_LENGTH; + int arrow_height = 2 * length + 1; + int w = node->width; + + /* Draw arrow */ + TeX_line(x, y + length, x + w - 1, y + length, color); + TeX_line(x + w - 1, y + length, x + w - 1 - length, y, color); + TeX_line(x + w - 1, y + length, x + w - 1 - length, y + 2 * length, + color); + + /* First argument */ + render_flow(args[0], + x + TEX_VEC_MARGIN, + y + TEX_VEC_SPACING + arrow_height, + color); +} + +//--- +// Limit notation +// * args: 0 (ignored) +// * flow: display mode when available +//--- + +void lim_size(struct TeX_Node *node) +{ + int w, h; + TeX_size("lim", &w, &h); + node->width = w; + node->height = h; + node->line = node->height >> 1; +} + +void lim_render(__attribute__((unused)) struct TeX_Node const * node, int x, + int y, int color) +{ + TeX_text("lim", x, y, color); +} + //--- // The class table and lookup functions //--- @@ -335,13 +404,15 @@ struct TeX_Class TeX_table[] = { { "\\sup", supsubscript_size, supsubscript_render }, { "\\sub", supsubscript_size, supsubscript_render }, - /* Large operator symbols */ + /* Large operator symbols, integral */ { "sum", sum_size, sum_render }, { "prod", prod_size, prod_render }, - - /* Integral */ { "int", int_size, int_render }, + /* Vectors, limits */ + { "vec", vec_size, vec_render }, + { "lim", lim_size, lim_render }, + /* NULL terminator */ { NULL }, }; diff --git a/src/flow.c b/src/flow.c index 4adb9f1..6b5bbf2 100644 --- a/src/flow.c +++ b/src/flow.c @@ -221,11 +221,11 @@ void group_open(struct group *group, struct TeX_Node *left) } /* group_update(): Update a group with a new node */ -void group_update(struct group *group, struct TeX_Node *node) +void group_update(struct group *group, struct chunk *chunk) { /* Account for node displacement around baseline */ - group->above = max(node->line - node->l, group->above); - group->below = max(node->height - node->line + node->l, group->below); + group->above = max(chunk->line, group->above); + group->below = max(chunk->height - chunk->line, group->below); } /* group_close(): Close a group with its right node */ @@ -259,10 +259,12 @@ void group_close(struct group *group, struct TeX_Node *right) // Laying out flows //--- -static void update(struct chunk *c, int *x, int *above, int *below) +static void update(struct chunk *c, struct group *g, int *x, int *above, + int *below) { if(!chunk_set(c)) return; chunk_compute(c); + group_update(g, c); *x += c->width + TEX_LAYOUT_SPACING; *above = max(*above, c->line - c->base->l); @@ -290,7 +292,6 @@ void size_flow(struct TeX_Flow *flow) { char const *class = ""; size_node(node); - group_update(g, node); if(node->type != TEX_NODECLASS_TEXT) class = TeX_table[node->type - 1].name; @@ -305,11 +306,13 @@ void size_flow(struct TeX_Flow *flow) chunk_set_subscript(&c, node); continue; } + /* Leave the last chunk and make a new one */ + update(&c, g, &x, &above, &below); + if(!strcmp(class, "left") && g-groups < TEX_LEFTRIGHT_NESTING) { g++; group_open(g, node); - group_update(g, node); } if(!strcmp(class, "right") && g - groups > 0) { @@ -317,13 +320,12 @@ void size_flow(struct TeX_Flow *flow) g--; } - /* Leave the last chunk and make a new one */ - update(&c, &x, &above, &below); - int mode = TEX_CHUNK_INLINE; - if(!strcmp(class, "sum") || !strcmp(class, "prod") + if(!strcmp(class, "sum") + || !strcmp(class, "prod") + || !strcmp(class, "lim") #if TEX_INT_DISPLAY - || !strcmp(class, "int") + || !strcmp(class, "int") #endif ) { @@ -335,7 +337,7 @@ void size_flow(struct TeX_Flow *flow) } /* Finish the last chunk */ - update(&c, &x, &above, &below); + update(&c, g, &x, &above, &below); flow->height = above + below; flow->line = above; diff --git a/src/platform/sdl2.c b/src/platform/sdl2.c index 2722c27..dd4a66d 100644 --- a/src/platform/sdl2.c +++ b/src/platform/sdl2.c @@ -104,10 +104,6 @@ void intf_text(char const *str, int x, int y, int color) SDL_RenderCopy(r, font, &src, &dst); x += FONT_WIDTH + 1; } - -// SDL_Rect rect = { .x = x, .y = y }; -// intf_size(str, &rect.w, &rect.h); -// SDL_RenderDrawRect(r, &rect); } //--- @@ -170,9 +166,9 @@ int main(void) { char const * formula = "\\frac{x^7\\left[X,Y\\right]+3\\left|\\frac{A}{B}\\right>}" - "{\\prod_{k=1}^n\\left\\{\\frac{a_k+b_k}{k!}\\right\\}^5}" - " + \\sum_{k=1}^n\\frac{(b-a)^k}{k!}" - "+\\int_a^b\\frac{(b-t)^{n+1}}{n!}dt"; + "{\\lim_{x->0}\\left\\{\\frac{a_k+b_k}{k!}\\right\\}^5}" + " + \\int_a^b\\frac{\\left(b-t\\right)^{n+1}}{n!}dt" + " + \\vec{A}.\\vec{B}"; struct TeX_Flow *flow = TeX_parse(formula); if(!flow) { puts("parsing error!"); return 1; }