/** \brief Print a string. * * Print an UTF-8 string at the given coordinates, using the default * foreground and background values. The coordinates may be outside the * canvas boundaries (eg. a negative Y coordinate) and the string will * be cropped accordingly if it is too long. * * See caca_put_char() for more information on how fullwidth characters * are handled when overwriting each other or at the canvas' boundaries. * * This function returns the number of cells printed by the string. It is * not the number of characters printed, because fullwidth characters * account for two cells. * * This function never fails. * * \param cv A handle to the libcaca canvas. * \param x X coordinate. * \param y Y coordinate. * \param s The string to print. * \return The number of cells printed. */ int caca_put_str(caca_canvas_t *cv, int x, int y, char const *s) { size_t rd; int len = 0; if (y < 0 || y >= (int)cv->height || x >= (int)cv->width) { while (*s) { len += caca_utf32_is_fullwidth(caca_utf8_to_utf32(s, &rd)) ? 2 : 1; s += rd ? rd : 1; } return len; } while (*s) { uint32_t ch = caca_utf8_to_utf32(s, &rd); if (x + len >= -1 && x + len < (int)cv->width) caca_put_char(cv, x + len, y, ch); len += caca_utf32_is_fullwidth(ch) ? 2 : 1; s += rd ? rd : 1; } return len; }
static void slang_write_utf32(uint32_t ch) { #ifdef HAVE_SLSMG_UTF8_ENABLE char buf[10]; int bytes; #else char ascii; #endif if(ch == CACA_MAGIC_FULLWIDTH) return; #ifdef HAVE_SLSMG_UTF8_ENABLE bytes = caca_utf32_to_utf8(buf, ch); buf[bytes] = '\0'; SLsmg_write_string(buf); #else ascii = caca_utf32_to_ascii(ch); SLsmg_write_char(ascii); if(caca_utf32_is_fullwidth(ch)) SLsmg_write_char(ascii); #endif }
/** \brief Print an ASCII or Unicode character. * * Print an ASCII or Unicode character at the given coordinates, using * the default foreground and background colour values. * * If the coordinates are outside the canvas boundaries, nothing is printed. * If a fullwidth Unicode character gets overwritten, its remaining visible * parts are replaced with spaces. If the canvas' boundaries would split the * fullwidth character in two, a space is printed instead. * * The behaviour when printing non-printable characters or invalid UTF-32 * characters is undefined. To print a sequence of bytes forming an UTF-8 * character instead of an UTF-32 character, use the caca_put_str() function. * * This function returns the width of the printed character. If it is a * fullwidth character, 2 is returned. Otherwise, 1 is returned. * * This function never fails. * * \param cv A handle to the libcaca canvas. * \param x X coordinate. * \param y Y coordinate. * \param ch The character to print. * \return The width of the printed character: 2 for a fullwidth character, * 1 otherwise. */ int caca_put_char(caca_canvas_t *cv, int x, int y, uint32_t ch) { uint32_t *curchar, *curattr, attr; int fullwidth, xmin, xmax, ret; if(ch == CACA_MAGIC_FULLWIDTH) return 1; fullwidth = caca_utf32_is_fullwidth(ch); ret = fullwidth ? 2 : 1; if(x >= (int)cv->width || y < 0 || y >= (int)cv->height) return ret; if(x == -1 && fullwidth) { x = 0; ch = ' '; fullwidth = 0; } else if(x < 0) return ret; curchar = cv->chars + x + y * cv->width; curattr = cv->attrs + x + y * cv->width; attr = cv->curattr; xmin = xmax = x; /* When overwriting the right part of a fullwidth character, * replace its left part with a space. */ if(x && curchar[0] == CACA_MAGIC_FULLWIDTH) { curchar[-1] = ' '; xmin--; } if(fullwidth) { if(x + 1 == (int)cv->width) ch = ' '; else { xmax++; /* When overwriting the left part of a fullwidth character, * replace its right part with a space. */ if(x + 2 < (int)cv->width && curchar[2] == CACA_MAGIC_FULLWIDTH) { curchar[2] = ' '; xmax++; } curchar[1] = CACA_MAGIC_FULLWIDTH; curattr[1] = attr; } } else { /* When overwriting the left part of a fullwidth character, * replace its right part with a space. */ if(x + 1 != (int)cv->width && curchar[1] == CACA_MAGIC_FULLWIDTH) { curchar[1] = ' '; xmax++; } } /* Only add a dirty rectangle if we are pasting a different character * or attribute at that place. This does not account for inconsistencies * in the canvas, ie. if CACA_MAGIC_FULLWIDTH lies at illegal places, * but it's the caller's responsibility not to corrupt the contents. */ if(!cv->dirty_disabled && (curchar[0] != ch || curattr[0] != attr)) caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1); curchar[0] = ch; curattr[0] = attr; return ret; }
static void ncurses_write_utf32(uint32_t ch) { #if defined HAVE_NCURSESW_NCURSES_H char buf[10]; int bytes; #endif if(ch == CACA_MAGIC_FULLWIDTH) return; #if defined HAVE_NCURSESW_NCURSES_H bytes = caca_utf32_to_utf8(buf, ch); buf[bytes] = '\0'; addstr(buf); #else if(ch < 0x80) { addch(ch); } else { chtype cch; chtype cch2; cch = '?'; cch2 = ' '; if ((ch > 0x0000ff00) && (ch < 0x0000ff5f)) { cch = ch - 0x0000ff00 + ' '; } switch (ch) { case 0x000000a0: /* <nbsp> */ case 0x00003000: /* */ cch = ' '; break; case 0x000000a3: /* £ */ cch = ACS_STERLING; break; case 0x000000b0: /* ° */ cch = ACS_DEGREE; break; case 0x000000b1: /* ± */ cch = ACS_PLMINUS; break; case 0x000000b7: /* · */ case 0x00002219: /* ∙ */ case 0x000030fb: /* ・ */ cch = ACS_BULLET; break; case 0x000003c0: /* π */ cch = ACS_PI; break; case 0x00002018: /* ‘ */ case 0x00002019: /* ’ */ cch = '\''; break; case 0x0000201c: /* “ */ case 0x0000201d: /* ” */ cch = '"'; break; case 0x00002190: /* ← */ cch = ACS_LARROW; break; case 0x00002191: /* ↑ */ cch = ACS_UARROW; break; case 0x00002192: /* → */ cch = ACS_RARROW; break; case 0x00002193: /* ↓ */ cch = ACS_DARROW; break; case 0x00002260: /* ≠ */ cch = ACS_NEQUAL; break; case 0x00002261: /* ≡ */ cch = '='; break; case 0x00002264: /* ≤ */ cch = ACS_LEQUAL; break; case 0x00002265: /* ≥ */ cch = ACS_GEQUAL; break; case 0x000023ba: /* ⎺ */ cch = ACS_S1; cch2 = cch; break; case 0x000023bb: /* ⎻ */ cch = ACS_S3; cch2 = cch; break; case 0x000023bc: /* ⎼ */ cch = ACS_S7; cch2 = cch; break; case 0x000023bd: /* ⎽ */ cch = ACS_S9; cch2 = cch; break; case 0x00002500: /* ─ */ case 0x00002550: /* ═ */ cch = ACS_HLINE; cch2 = cch; break; case 0x00002502: /* │ */ case 0x00002551: /* ║ */ cch = ACS_VLINE; break; case 0x0000250c: /* ┌ */ case 0x00002552: /* ╒ */ case 0x00002553: /* ╓ */ case 0x00002554: /* ╔ */ cch = ACS_ULCORNER; cch2 = ACS_HLINE; break; case 0x00002510: /* ┐ */ case 0x00002555: /* ╕ */ case 0x00002556: /* ╖ */ case 0x00002557: /* ╗ */ cch = ACS_URCORNER; break; case 0x00002514: /* └ */ case 0x00002558: /* ╘ */ case 0x00002559: /* ╙ */ case 0x0000255a: /* ╚ */ cch = ACS_LLCORNER; cch2 = ACS_HLINE; break; case 0x00002518: /* ┘ */ case 0x0000255b: /* ╛ */ case 0x0000255c: /* ╜ */ case 0x0000255d: /* ╝ */ cch = ACS_LRCORNER; break; case 0x0000251c: /* ├ */ case 0x0000255e: /* ╞ */ case 0x0000255f: /* ╟ */ case 0x00002560: /* ╠ */ cch = ACS_LTEE; cch2 = ACS_HLINE; break; case 0x00002524: /* ┤ */ case 0x00002561: /* ╡ */ case 0x00002562: /* ╢ */ case 0x00002563: /* ╣ */ cch = ACS_RTEE; break; case 0x0000252c: /* ┬ */ case 0x00002564: /* ╤ */ case 0x00002565: /* ╥ */ case 0x00002566: /* ╦ */ cch = ACS_TTEE; cch2 = ACS_HLINE; break; case 0x00002534: /* ┴ */ case 0x00002567: /* ╧ */ case 0x00002568: /* ╨ */ case 0x00002569: /* ╩ */ cch = ACS_BTEE; cch2 = ACS_HLINE; break; case 0x0000253c: /* ┼ */ case 0x0000256a: /* ╪ */ case 0x0000256b: /* ╫ */ case 0x0000256c: /* ╬ */ cch = ACS_PLUS; cch2 = ACS_HLINE; break; case 0x00002591: /* ░ */ cch = ACS_BOARD; cch2 = cch; break; case 0x00002592: /* ▒ */ case 0x00002593: /* ▓ */ cch = ACS_CKBOARD; cch2 = cch; break; case 0x00002580: /* ▀ */ case 0x00002584: /* ▄ */ case 0x00002588: /* █ */ case 0x0000258c: /* ▌ */ case 0x00002590: /* ▐ */ case 0x000025a0: /* ■ */ case 0x000025ac: /* ▬ */ case 0x000025ae: /* ▮ */ cch = ACS_BLOCK; cch2 = cch; break; case 0x000025c6: /* ◆ */ case 0x00002666: /* ♦ */ cch = ACS_DIAMOND; break; case 0x00002022: /* • */ case 0x000025cb: /* ○ */ case 0x000025cf: /* ● */ case 0x00002603: /* ☃ */ case 0x0000263c: /* ☼ */ cch = ACS_LANTERN; break; case 0x0000301c: /* 〜 */ cch = '~'; break; } addch(cch); if(caca_utf32_is_fullwidth(ch)) { addch(cch2); } } #endif }