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

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

Change the dirty rectangle API once again so that calling applications get
a more natural (x,y,w,h) 4-tuple to handle.

  • Property svn:keywords set to Id
File size: 7.8 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2009 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  $Id: frame.c 3494 2009-05-21 20:55:13Z 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_rect(cv, 0, 0, cv->width, cv->height);
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_rect(cv, 0, 0, cv->width, cv->height);
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.