File: frame.c

package info (click to toggle)
libcaca 0.99.beta20-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 5,264 kB
  • sloc: ansic: 25,091; php: 2,763; python: 2,637; cs: 1,213; cpp: 1,127; java: 916; objc: 836; makefile: 543; perl: 505; sh: 472; asm: 297; ruby: 215; xml: 33
file content (267 lines) | stat: -rw-r--r-- 7,434 bytes parent folder | download | duplicates (3)
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;
}