Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

268 рядки
7.3 KiB

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