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