25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

282 lines
7.8 KiB

  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * This file contains a small framework for canvas frame management.
  16. */
  17. #include "config.h"
  18. #if !defined(__KERNEL__)
  19. # include <stdio.h>
  20. # include <stdlib.h>
  21. # include <string.h>
  22. #endif
  23. #include "caca.h"
  24. #include "caca_internals.h"
  25. /** \brief Get the number of frames in a canvas.
  26. *
  27. * Return the current canvas' frame count.
  28. *
  29. * This function never fails.
  30. *
  31. * \param cv A libcaca canvas
  32. * \return The frame count
  33. */
  34. int caca_get_frame_count(caca_canvas_t const *cv)
  35. {
  36. return cv->framecount;
  37. }
  38. /** \brief Activate a given canvas frame.
  39. *
  40. * Set the active canvas frame. All subsequent drawing operations will
  41. * be performed on that frame. The current painting context set by
  42. * caca_set_attr() is inherited.
  43. *
  44. * If the frame index is outside the canvas' frame range, nothing happens.
  45. *
  46. * If an error occurs, -1 is returned and \b errno is set accordingly:
  47. * - \c EINVAL Requested frame is out of range.
  48. *
  49. * \param cv A libcaca canvas
  50. * \param id The canvas frame to activate
  51. * \return 0 in case of success, -1 if an error occurred.
  52. */
  53. int caca_set_frame(caca_canvas_t *cv, int id)
  54. {
  55. if(id < 0 || id >= cv->framecount)
  56. {
  57. seterrno(EINVAL);
  58. return -1;
  59. }
  60. /* Bail out if no operation is required */
  61. if(id == cv->frame)
  62. return 0;
  63. _caca_save_frame_info(cv);
  64. cv->frame = id;
  65. _caca_load_frame_info(cv);
  66. caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
  67. return 0;
  68. }
  69. /** \brief Get the current frame's name.
  70. *
  71. * Return the current frame's name. The returned string is valid until
  72. * the frame is deleted or caca_set_frame_name() is called to change
  73. * the frame name again.
  74. *
  75. * This function never fails.
  76. *
  77. * \param cv A libcaca canvas.
  78. * \return The current frame's name.
  79. */
  80. char const *caca_get_frame_name(caca_canvas_t const *cv)
  81. {
  82. return cv->frames[cv->frame].name;
  83. }
  84. /** \brief Set the current frame's name.
  85. *
  86. * Set the current frame's name. Upon creation, a frame has a default name
  87. * of \c "frame#xxxxxxxx" where \c xxxxxxxx is a self-incrementing
  88. * hexadecimal number.
  89. *
  90. * If an error occurs, -1 is returned and \b errno is set accordingly:
  91. * - \c ENOMEM Not enough memory to allocate new frame.
  92. *
  93. * \param cv A libcaca canvas.
  94. * \param name The name to give to the current frame.
  95. * \return 0 in case of success, -1 if an error occurred.
  96. */
  97. int caca_set_frame_name(caca_canvas_t *cv, char const *name)
  98. {
  99. char *newname = strdup(name);
  100. if(!newname)
  101. {
  102. seterrno(ENOMEM);
  103. return -1;
  104. }
  105. free(cv->frames[cv->frame].name);
  106. cv->frames[cv->frame].name = newname;
  107. return 0;
  108. }
  109. /** \brief Add a frame to a canvas.
  110. *
  111. * Create a new frame within the given canvas. Its contents and attributes
  112. * are copied from the currently active frame.
  113. *
  114. * The frame index indicates where the frame should be inserted. Valid
  115. * values range from 0 to the current canvas frame count. If the frame
  116. * index is greater than or equals the current canvas frame count, the new
  117. * frame is appended at the end of the canvas. If the frame index is less
  118. * than zero, the new frame is inserted at index 0.
  119. *
  120. * The active frame does not change, but its index may be renumbered due
  121. * to the insertion.
  122. *
  123. * If an error occurs, -1 is returned and \b errno is set accordingly:
  124. * - \c ENOMEM Not enough memory to allocate new frame.
  125. *
  126. * \param cv A libcaca canvas
  127. * \param id The index where to insert the new frame
  128. * \return 0 in case of success, -1 if an error occurred.
  129. */
  130. int caca_create_frame(caca_canvas_t *cv, int id)
  131. {
  132. int size = cv->width * cv->height;
  133. int f;
  134. if(id < 0)
  135. id = 0;
  136. else if(id > cv->framecount)
  137. id = cv->framecount;
  138. cv->framecount++;
  139. cv->frames = realloc(cv->frames,
  140. sizeof(struct caca_frame) * cv->framecount);
  141. for(f = cv->framecount - 1; f > id; f--)
  142. cv->frames[f] = cv->frames[f - 1];
  143. if(cv->frame >= id)
  144. cv->frame++;
  145. cv->frames[id].width = cv->width;
  146. cv->frames[id].height = cv->height;
  147. cv->frames[id].chars = malloc(size * sizeof(uint32_t));
  148. memcpy(cv->frames[id].chars, cv->chars, size * sizeof(uint32_t));
  149. cv->frames[id].attrs = malloc(size * sizeof(uint32_t));
  150. memcpy(cv->frames[id].attrs, cv->attrs, size * sizeof(uint32_t));
  151. cv->frames[id].curattr = cv->curattr;
  152. cv->frames[id].x = cv->frames[cv->frame].x;
  153. cv->frames[id].y = cv->frames[cv->frame].y;
  154. cv->frames[id].handlex = cv->frames[cv->frame].handlex;
  155. cv->frames[id].handley = cv->frames[cv->frame].handley;
  156. cv->frames[id].name = strdup("frame#--------");
  157. sprintf(cv->frames[id].name + 6, "%.08x", ++cv->autoinc);
  158. return 0;
  159. }
  160. /** \brief Remove a frame from a canvas.
  161. *
  162. * Delete a frame from a given canvas.
  163. *
  164. * The frame index indicates the frame to delete. Valid values range from
  165. * 0 to the current canvas frame count minus 1. If the frame index is
  166. * greater than or equals the current canvas frame count, the last frame
  167. * is deleted.
  168. *
  169. * If the active frame is deleted, frame 0 becomes the new active frame.
  170. * Otherwise, the active frame does not change, but its index may be
  171. * renumbered due to the deletion.
  172. *
  173. * If an error occurs, -1 is returned and \b errno is set accordingly:
  174. * - \c EINVAL Requested frame is out of range, or attempt to delete the
  175. * last frame of the canvas.
  176. *
  177. * \param cv A libcaca canvas
  178. * \param id The index of the frame to delete
  179. * \return 0 in case of success, -1 if an error occurred.
  180. */
  181. int caca_free_frame(caca_canvas_t *cv, int id)
  182. {
  183. int f;
  184. if(id < 0 || id >= cv->framecount)
  185. {
  186. seterrno(EINVAL);
  187. return -1;
  188. }
  189. if(cv->framecount == 1)
  190. {
  191. seterrno(EINVAL);
  192. return -1;
  193. }
  194. free(cv->frames[id].chars);
  195. free(cv->frames[id].attrs);
  196. free(cv->frames[id].name);
  197. for(f = id + 1; f < cv->framecount; f++)
  198. cv->frames[f - 1] = cv->frames[f];
  199. cv->framecount--;
  200. cv->frames = realloc(cv->frames,
  201. sizeof(struct caca_frame) * cv->framecount);
  202. if(cv->frame > id)
  203. cv->frame--;
  204. else if(cv->frame == id)
  205. {
  206. cv->frame = 0;
  207. _caca_load_frame_info(cv);
  208. caca_add_dirty_rectangle(cv, 0, 0, cv->width - 1, cv->height - 1);
  209. }
  210. return 0;
  211. }
  212. /*
  213. * XXX: the following functions are local.
  214. */
  215. void _caca_save_frame_info(caca_canvas_t *cv)
  216. {
  217. cv->frames[cv->frame].width = cv->width;
  218. cv->frames[cv->frame].height = cv->height;
  219. cv->frames[cv->frame].curattr = cv->curattr;
  220. }
  221. void _caca_load_frame_info(caca_canvas_t *cv)
  222. {
  223. cv->width = cv->frames[cv->frame].width;
  224. cv->height = cv->frames[cv->frame].height;
  225. cv->chars = cv->frames[cv->frame].chars;
  226. cv->attrs = cv->frames[cv->frame].attrs;
  227. cv->curattr = cv->frames[cv->frame].curattr;
  228. }
  229. /*
  230. * XXX: The following functions are aliases.
  231. */
  232. int cucul_get_frame_count(cucul_canvas_t const *)
  233. CACA_ALIAS(caca_get_frame_count);
  234. int cucul_set_frame(cucul_canvas_t *, int) CACA_ALIAS(caca_set_frame);
  235. char const *cucul_get_frame_name(cucul_canvas_t const *)
  236. CACA_ALIAS(caca_get_frame_name);
  237. int cucul_set_frame_name(cucul_canvas_t *, char const *)
  238. CACA_ALIAS(caca_set_frame_name);
  239. int cucul_create_frame(cucul_canvas_t *, int) CACA_ALIAS(caca_create_frame);
  240. int cucul_free_frame(cucul_canvas_t *, int) CACA_ALIAS(caca_free_frame);