source: libcaca/trunk/caca/frame.c @ 3470

Last change on this file since 3470 was 3470, checked in by Sam Hocevar, 11 years ago

Change the dirty rectangle API so that it can handle several rectangles. The
inner implementation still only handles one dirty rectangle, but this way
we can prepare supporting applictions for the future.

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