You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

316 lines
8.6 KiB

  1. /*
  2. * libcucul Unicode canvas library
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the Do What The Fuck You Want To
  8. * Public License, Version 2, as published by Sam Hocevar. See
  9. * http://sam.zoy.org/wtfpl/COPYING for more details.
  10. */
  11. /** \file canvas.c
  12. * \version \$Id$
  13. * \author Sam Hocevar <sam@zoy.org>
  14. * \brief Canvas drawing
  15. *
  16. * This file contains various canvas handling functions such as character
  17. * and string drawing.
  18. */
  19. #include "config.h"
  20. #if !defined(__KERNEL__)
  21. # include <stdio.h> /* BUFSIZ */
  22. # include <string.h>
  23. # include <stdlib.h>
  24. # include <stdarg.h>
  25. # if defined(HAVE_UNISTD_H)
  26. # include <unistd.h>
  27. # endif
  28. # if defined(HAVE_SIGNAL_H)
  29. # include <signal.h>
  30. # endif
  31. # if defined(HAVE_SYS_IOCTL_H)
  32. # include <sys/ioctl.h>
  33. # endif
  34. #endif
  35. #include "cucul.h"
  36. #include "cucul_internals.h"
  37. /** \brief Set the default colour pair.
  38. *
  39. * This function sets the default colour pair. String functions such as
  40. * caca_printf() and graphical primitive functions such as caca_draw_line()
  41. * will use these colour pairs.
  42. *
  43. * \param fgcolor The requested foreground colour.
  44. * \param bgcolor The requested background colour.
  45. */
  46. void cucul_set_color(cucul_t *qq, enum cucul_color fgcolor,
  47. enum cucul_color bgcolor)
  48. {
  49. if(fgcolor < 0 || fgcolor > 15 || bgcolor < 0 || bgcolor > 15)
  50. return;
  51. qq->fgcolor = fgcolor;
  52. qq->bgcolor = bgcolor;
  53. }
  54. /** \brief Get the current foreground colour.
  55. *
  56. * This function returns the current foreground colour that was set with
  57. * cucul_set_color().
  58. *
  59. * \return The current foreground colour.
  60. */
  61. enum cucul_color cucul_get_fg_color(cucul_t const *qq)
  62. {
  63. return qq->fgcolor;
  64. }
  65. /** \brief Get the current background colour.
  66. *
  67. * This function returns the current background colour that was set with
  68. * cucul_set_color().
  69. *
  70. * \return The current background colour.
  71. */
  72. enum cucul_color cucul_get_bg_color(cucul_t const *qq)
  73. {
  74. return qq->bgcolor;
  75. }
  76. /** \brief Print an ASCII character.
  77. *
  78. * This function prints an ASCII character at the given coordinates, using
  79. * the default foreground and background values. If the coordinates are
  80. * outside the screen boundaries, nothing is printed. If the character
  81. * value is a non-printable character or is outside the ASCII range, it is
  82. * replaced with a space. To print a sequence of bytes forming an UTF-8
  83. * character, use cucul_putstr() instead.
  84. *
  85. * \param x X coordinate.
  86. * \param y Y coordinate.
  87. * \param c The character to print.
  88. */
  89. void cucul_putchar(cucul_t *qq, int x, int y, char c)
  90. {
  91. if(x < 0 || x >= (int)qq->width ||
  92. y < 0 || y >= (int)qq->height)
  93. return;
  94. if((unsigned char)c < 0x20 || (unsigned char)c > 0x7f)
  95. c = 0x20;
  96. qq->chars[x + y * qq->width] = c;
  97. qq->attr[x + y * qq->width] = (qq->bgcolor << 4) | qq->fgcolor;
  98. }
  99. /** \brief Print a Unicode character.
  100. *
  101. * FIXME: do we really want this function?
  102. *
  103. * This function prints a Unicode character (native-endian, 32 bits UCS-4,
  104. * also known as UTF-32) at the given coordinates, using the default
  105. * foreground and background values. If the coordinates are outside the
  106. * screen boundaries, nothing is printed. If the character is an invalid
  107. * Unicode character, it is replaced with a space.
  108. *
  109. * \param x X coordinate.
  110. * \param y Y coordinate.
  111. * \param c The character to print.
  112. */
  113. void cucul_putchar32(cucul_t *qq, int x, int y, unsigned long int c)
  114. {
  115. if(x < 0 || x >= (int)qq->width ||
  116. y < 0 || y >= (int)qq->height)
  117. return;
  118. if(c < 0x20 || c > 0x7f)
  119. c = 0x20;
  120. qq->chars[x + y * qq->width] = c;
  121. qq->attr[x + y * qq->width] = (qq->bgcolor << 4) | qq->fgcolor;
  122. }
  123. /** \brief Print a string.
  124. *
  125. * This function prints an UTF-8 string at the given coordinates, using the
  126. * default foreground and background values. The coordinates may be outside
  127. * the screen boundaries (eg. a negative Y coordinate) and the string will
  128. * be cropped accordingly if it is too long.
  129. *
  130. * \param x X coordinate.
  131. * \param y Y coordinate.
  132. * \param s The string to print.
  133. */
  134. void cucul_putstr(cucul_t *qq, int x, int y, char const *s)
  135. {
  136. uint32_t *chars;
  137. uint8_t *attr;
  138. unsigned int len;
  139. if(y < 0 || y >= (int)qq->height || x >= (int)qq->width)
  140. return;
  141. len = _cucul_strlen_utf8(s);
  142. if(x < 0)
  143. {
  144. if(len < (unsigned int)-x)
  145. return;
  146. len -= -x;
  147. s = _cucul_skip_utf8(s, -x);
  148. x = 0;
  149. }
  150. chars = qq->chars + x + y * qq->width;
  151. attr = qq->attr + x + y * qq->width;
  152. if(x + len >= qq->width)
  153. len = qq->width - x;
  154. while(len)
  155. {
  156. *chars++ = _cucul_utf8_to_utf32(s);
  157. *attr++ = (qq->bgcolor << 4) | qq->fgcolor;
  158. s = _cucul_skip_utf8(s, 1);
  159. len--;
  160. }
  161. }
  162. /** \brief Format a string.
  163. *
  164. * This function formats a string at the given coordinates, using the
  165. * default foreground and background values. The coordinates may be outside
  166. * the screen boundaries (eg. a negative Y coordinate) and the string will
  167. * be cropped accordingly if it is too long. The syntax of the format
  168. * string is the same as for the C printf() function.
  169. *
  170. * \param x X coordinate.
  171. * \param y Y coordinate.
  172. * \param format The format string to print.
  173. * \param ... Arguments to the format string.
  174. */
  175. void cucul_printf(cucul_t *qq, int x, int y, char const *format, ...)
  176. {
  177. char tmp[BUFSIZ];
  178. char *buf = tmp;
  179. va_list args;
  180. if(y < 0 || y >= (int)qq->height || x >= (int)qq->width)
  181. return;
  182. if(qq->width - x + 1 > BUFSIZ)
  183. buf = malloc(qq->width - x + 1);
  184. va_start(args, format);
  185. #if defined(HAVE_VSNPRINTF)
  186. vsnprintf(buf, qq->width - x + 1, format, args);
  187. #else
  188. vsprintf(buf, format, args);
  189. #endif
  190. buf[qq->width - x] = '\0';
  191. va_end(args);
  192. cucul_putstr(qq, x, y, buf);
  193. if(buf != tmp)
  194. free(buf);
  195. }
  196. /** \brief Get the screen.
  197. *
  198. * This function fills a byte array with the character values.
  199. */
  200. void cucul_get_screen(cucul_t const *qq, char *buffer)
  201. {
  202. unsigned int x, y;
  203. for(y = 0; y < qq->height; y++)
  204. {
  205. for(x = 0; x < qq->width; x++)
  206. {
  207. *buffer++ = qq->attr[x + y * qq->width];
  208. *buffer++ = qq->chars[x + y * qq->width] & 0x7f; /* FIXME: ASCII */
  209. }
  210. }
  211. }
  212. /** \brief Clear the screen.
  213. *
  214. * This function clears the screen using a black background.
  215. */
  216. void cucul_clear(cucul_t *qq)
  217. {
  218. enum cucul_color oldfg = cucul_get_fg_color(qq);
  219. enum cucul_color oldbg = cucul_get_bg_color(qq);
  220. int y = qq->height;
  221. cucul_set_color(qq, CUCUL_COLOR_LIGHTGRAY, CUCUL_COLOR_BLACK);
  222. /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
  223. while(y--)
  224. cucul_putstr(qq, 0, y, qq->empty_line);
  225. cucul_set_color(qq, oldfg, oldbg);
  226. }
  227. /** \brief Blit a canvas onto another one.
  228. *
  229. * This function blits a canvas onto another one at the given coordinates.
  230. * An optional mask canvas can be used.
  231. *
  232. * \param dst The destination canvas.
  233. * \param x X coordinate.
  234. * \param y Y coordinate.
  235. * \param src The source canvas.
  236. * \param mask The mask canvas.
  237. */
  238. void cucul_blit(cucul_t *dst, int x, int y,
  239. cucul_t const *src, cucul_t const *mask)
  240. {
  241. int i, j, starti, startj, endi, endj;
  242. if(mask && (src->width != mask->width || src->height != mask->height))
  243. return;
  244. starti = x < 0 ? -x : 0;
  245. startj = y < 0 ? -y : 0;
  246. endi = (x + src->width >= dst->width) ? dst->width - x : src->width;
  247. endj = (y + src->height >= dst->height) ? dst->height - y : src->height;
  248. if(starti >= endi || startj >= endj)
  249. return;
  250. for(j = startj; j < endj; j++)
  251. {
  252. if(mask)
  253. {
  254. for(i = starti; i < endi; i++)
  255. {
  256. if(mask->chars[j * src->width + i] == (uint32_t)' ')
  257. continue;
  258. dst->chars[(j + y) * dst->width + (i + x)]
  259. = src->chars[j * src->width + i];
  260. dst->attr[(j + y) * dst->width + (i + x)]
  261. = src->attr[j * src->width + i];
  262. }
  263. }
  264. else
  265. {
  266. memcpy(dst->chars + (j + y) * dst->width + starti + x,
  267. src->chars + j * src->width + starti,
  268. (endi - starti) * 4);
  269. memcpy(dst->attr + (j + y) * dst->width + starti + x,
  270. src->attr + j * src->width + starti,
  271. (endi - starti) * 1);
  272. }
  273. }
  274. }