Beginning GIF export
Beginning addition of an option to export animated GIFs from the Open -> Slideshow dialog, after choosing the images. Non-operable at this time, but a button has been added (and will provide a hint to select 2 or more images, when clicked).
This commit is contained in:
parent
3ede0b96bf
commit
8c3a07294b
7 changed files with 408 additions and 16 deletions
18
Makefile
18
Makefile
|
|
@ -4,7 +4,7 @@
|
||||||
# Various contributors (see AUTHORS.txt)
|
# Various contributors (see AUTHORS.txt)
|
||||||
# http://www.tuxpaint.org/
|
# http://www.tuxpaint.org/
|
||||||
|
|
||||||
# June 14, 2002 - June 22, 2020
|
# June 14, 2002 - July 24, 2020
|
||||||
|
|
||||||
|
|
||||||
# The version number, for release:
|
# The version number, for release:
|
||||||
|
|
@ -115,10 +115,10 @@ PNG:=$(if $(PNG),$(PNG),$(call linktest,-lpng12,))
|
||||||
FRIBIDI_LIB:=$(shell $(PKG_CONFIG) --libs fribidi)
|
FRIBIDI_LIB:=$(shell $(PKG_CONFIG) --libs fribidi)
|
||||||
FRIBIDI_CFLAGS:=$(shell $(PKG_CONFIG) --cflags fribidi)
|
FRIBIDI_CFLAGS:=$(shell $(PKG_CONFIG) --cflags fribidi)
|
||||||
|
|
||||||
windows_ARCH_LINKS:=-lintl $(PNG) -lzdll -lwinspool -lshlwapi $(FRIBIDI_LIB) -liconv
|
windows_ARCH_LINKS:=-lintl $(PNG) -lzdll -lwinspool -lshlwapi $(FRIBIDI_LIB) -liconv -limagequant
|
||||||
osx_ARCH_LINKS:=$(FRIBIDI_LIB)
|
osx_ARCH_LINKS:=$(FRIBIDI_LIB) -limagequant
|
||||||
beos_ARCH_LINKS:=-lintl $(PNG) -lz -lbe -lnetwork -liconv $(FRIBIDI_LIB) $(PAPER_LIB) $(STDC_LIB)
|
beos_ARCH_LINKS:=-lintl $(PNG) -lz -lbe -lnetwork -liconv $(FRIBIDI_LIB) $(PAPER_LIB) $(STDC_LIB) -limagequant
|
||||||
linux_ARCH_LINKS:=$(PAPER_LIB) $(FRIBIDI_LIB)
|
linux_ARCH_LINKS:=$(PAPER_LIB) $(FRIBIDI_LIB) -limagequant
|
||||||
ARCH_LINKS:=$($(OS)_ARCH_LINKS)
|
ARCH_LINKS:=$($(OS)_ARCH_LINKS)
|
||||||
|
|
||||||
windows_ARCH_HEADERS:=src/win32_print.h
|
windows_ARCH_HEADERS:=src/win32_print.h
|
||||||
|
|
@ -1035,6 +1035,7 @@ TuxPaint.dmg:
|
||||||
tuxpaint: obj/tuxpaint.o obj/i18n.o obj/im.o obj/cursor.o obj/pixels.o \
|
tuxpaint: obj/tuxpaint.o obj/i18n.o obj/im.o obj/cursor.o obj/pixels.o \
|
||||||
obj/rgblinear.o obj/playsound.o obj/fonts.o obj/parse.o obj/fill.o \
|
obj/rgblinear.o obj/playsound.o obj/fonts.o obj/parse.o obj/fill.o \
|
||||||
obj/progressbar.o obj/dirwalk.o obj/get_fname.o obj/onscreen_keyboard.o \
|
obj/progressbar.o obj/dirwalk.o obj/get_fname.o obj/onscreen_keyboard.o \
|
||||||
|
obj/gifenc.o \
|
||||||
$(ARCH_LIBS)
|
$(ARCH_LIBS)
|
||||||
@echo
|
@echo
|
||||||
@echo "...Linking Tux Paint..."
|
@echo "...Linking Tux Paint..."
|
||||||
|
|
@ -1055,6 +1056,7 @@ obj/tuxpaint.o: src/tuxpaint.c \
|
||||||
src/tools.h src/titles.h src/colors.h src/shapes.h \
|
src/tools.h src/titles.h src/colors.h src/shapes.h \
|
||||||
src/sounds.h src/tip_tux.h src/great.h \
|
src/sounds.h src/tip_tux.h src/great.h \
|
||||||
src/tp_magic_api.h src/parse.h src/onscreen_keyboard.h \
|
src/tp_magic_api.h src/parse.h src/onscreen_keyboard.h \
|
||||||
|
src/gifenc.h \
|
||||||
src/$(MOUSEDIR)/arrow.xbm src/$(MOUSEDIR)/arrow-mask.xbm \
|
src/$(MOUSEDIR)/arrow.xbm src/$(MOUSEDIR)/arrow-mask.xbm \
|
||||||
src/$(MOUSEDIR)/hand.xbm src/$(MOUSEDIR)/hand-mask.xbm \
|
src/$(MOUSEDIR)/hand.xbm src/$(MOUSEDIR)/hand-mask.xbm \
|
||||||
src/$(MOUSEDIR)/insertion.xbm \
|
src/$(MOUSEDIR)/insertion.xbm \
|
||||||
|
|
@ -1140,6 +1142,12 @@ obj/pixels.o: src/pixels.c src/pixels.h src/compiler.h src/debug.h
|
||||||
@$(CC) $(CFLAGS) $(DEBUG_FLAGS) $(SDL_CFLAGS) $(DEFS) \
|
@$(CC) $(CFLAGS) $(DEBUG_FLAGS) $(SDL_CFLAGS) $(DEFS) \
|
||||||
-c src/pixels.c -o obj/pixels.o
|
-c src/pixels.c -o obj/pixels.o
|
||||||
|
|
||||||
|
obj/gifenc.o: src/gifenc.c src/gifenc.h
|
||||||
|
@echo
|
||||||
|
@echo "...Compiling animated GIF export libary..."
|
||||||
|
@$(CC) $(CFLAGS) $(DEBUG_FLAGS) $(DEFS) \
|
||||||
|
-c src/gifenc.c -o obj/gifenc.o
|
||||||
|
|
||||||
obj/playsound.o: src/playsound.c src/playsound.h \
|
obj/playsound.o: src/playsound.c src/playsound.h \
|
||||||
src/compiler.h src/debug.h
|
src/compiler.h src/debug.h
|
||||||
@echo
|
@echo
|
||||||
|
|
|
||||||
BIN
data/images/ui/gif_export.png
Normal file
BIN
data/images/ui/gif_export.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -103,6 +103,10 @@ $Id$
|
||||||
which was from "Gimp-gluas" plug-in for The GIMP:
|
which was from "Gimp-gluas" plug-in for The GIMP:
|
||||||
http://pippin.gimp.org/plug-ins/gluas/
|
http://pippin.gimp.org/plug-ins/gluas/
|
||||||
|
|
||||||
|
Animated GIF export from "gifenc",
|
||||||
|
https://github.com/lecram/gifenc,
|
||||||
|
by Marcel Rodrigues <http://lecram.github.io/>
|
||||||
|
|
||||||
Mouse accessibility code and keyboard access
|
Mouse accessibility code and keyboard access
|
||||||
Ankit Choudary <ankit.goaldecided@gmail.com>, as part of GSOC 2010,
|
Ankit Choudary <ankit.goaldecided@gmail.com>, as part of GSOC 2010,
|
||||||
with integration and fixes by Pere Pujal i Carabantes <pere@fornol.no-ip.org>
|
with integration and fixes by Pere Pujal i Carabantes <pere@fornol.no-ip.org>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,16 @@ http://www.tuxpaint.org/
|
||||||
|
|
||||||
$Id$
|
$Id$
|
||||||
|
|
||||||
2020.June.22 (0.9.25)
|
2020.July.24 (0.9.25)
|
||||||
|
* New Features
|
||||||
|
------------
|
||||||
|
* [WIP] GIF export option from Open -> Slideshow dialog.
|
||||||
|
* Utilizes "gifenc", public domain by Marcel Rodrigues:
|
||||||
|
https://github.com/lecram/gifenc
|
||||||
|
* Depends on "libimagequant", from the "pngquant2" project:
|
||||||
|
https://github.com/ImageOptim/libimagequant
|
||||||
|
(GPL v3 or later, for Free/Libre Open Source Software)
|
||||||
|
|
||||||
* Ports & Building
|
* Ports & Building
|
||||||
----------------
|
----------------
|
||||||
* Corrections for Haiku not opening saved files.
|
* Corrections for Haiku not opening saved files.
|
||||||
|
|
|
||||||
287
src/gifenc.c
Normal file
287
src/gifenc.c
Normal file
|
|
@ -0,0 +1,287 @@
|
||||||
|
#include "gifenc.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <io.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* helper to write a little-endian 16-bit number portably */
|
||||||
|
#define write_num(fd, n) write((fd), (uint8_t []) {(n) & 0xFF, (n) >> 8}, 2)
|
||||||
|
|
||||||
|
static uint8_t vga[0x30] = {
|
||||||
|
0x00, 0x00, 0x00,
|
||||||
|
0xAA, 0x00, 0x00,
|
||||||
|
0x00, 0xAA, 0x00,
|
||||||
|
0xAA, 0x55, 0x00,
|
||||||
|
0x00, 0x00, 0xAA,
|
||||||
|
0xAA, 0x00, 0xAA,
|
||||||
|
0x00, 0xAA, 0xAA,
|
||||||
|
0xAA, 0xAA, 0xAA,
|
||||||
|
0x55, 0x55, 0x55,
|
||||||
|
0xFF, 0x55, 0x55,
|
||||||
|
0x55, 0xFF, 0x55,
|
||||||
|
0xFF, 0xFF, 0x55,
|
||||||
|
0x55, 0x55, 0xFF,
|
||||||
|
0xFF, 0x55, 0xFF,
|
||||||
|
0x55, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
uint16_t key;
|
||||||
|
struct Node *children[];
|
||||||
|
};
|
||||||
|
typedef struct Node Node;
|
||||||
|
|
||||||
|
static Node *
|
||||||
|
new_node(uint16_t key, int degree)
|
||||||
|
{
|
||||||
|
Node *node = calloc(1, sizeof(*node) + degree * sizeof(Node *));
|
||||||
|
if (node)
|
||||||
|
node->key = key;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node *
|
||||||
|
new_trie(int degree, int *nkeys)
|
||||||
|
{
|
||||||
|
Node *root = new_node(0, degree);
|
||||||
|
/* Create nodes for single pixels. */
|
||||||
|
for (*nkeys = 0; *nkeys < degree; (*nkeys)++)
|
||||||
|
root->children[*nkeys] = new_node(*nkeys, degree);
|
||||||
|
*nkeys += 2; /* skip clear code and stop code */
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
del_trie(Node *root, int degree)
|
||||||
|
{
|
||||||
|
if (!root)
|
||||||
|
return;
|
||||||
|
for (int i = 0; i < degree; i++)
|
||||||
|
del_trie(root->children[i], degree);
|
||||||
|
free(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_loop(ge_GIF *gif, uint16_t loop);
|
||||||
|
|
||||||
|
ge_GIF *
|
||||||
|
ge_new_gif(
|
||||||
|
const char *fname, uint16_t width, uint16_t height,
|
||||||
|
uint8_t *palette, int depth, int loop
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i, r, g, b, v;
|
||||||
|
ge_GIF *gif = calloc(1, sizeof(*gif) + 2*width*height);
|
||||||
|
if (!gif)
|
||||||
|
goto no_gif;
|
||||||
|
gif->w = width; gif->h = height;
|
||||||
|
gif->depth = depth > 1 ? depth : 2;
|
||||||
|
gif->frame = (uint8_t *) &gif[1];
|
||||||
|
gif->back = &gif->frame[width*height];
|
||||||
|
gif->fd = creat(fname, 0666);
|
||||||
|
if (gif->fd == -1)
|
||||||
|
goto no_fd;
|
||||||
|
#ifdef _WIN32
|
||||||
|
setmode(gif->fd, O_BINARY);
|
||||||
|
#endif
|
||||||
|
write(gif->fd, "GIF89a", 6);
|
||||||
|
write_num(gif->fd, width);
|
||||||
|
write_num(gif->fd, height);
|
||||||
|
write(gif->fd, (uint8_t []) {0xF0 | (depth-1), 0x00, 0x00}, 3);
|
||||||
|
if (palette) {
|
||||||
|
write(gif->fd, palette, 3 << depth);
|
||||||
|
} else if (depth <= 4) {
|
||||||
|
write(gif->fd, vga, 3 << depth);
|
||||||
|
} else {
|
||||||
|
write(gif->fd, vga, sizeof(vga));
|
||||||
|
i = 0x10;
|
||||||
|
for (r = 0; r < 6; r++) {
|
||||||
|
for (g = 0; g < 6; g++) {
|
||||||
|
for (b = 0; b < 6; b++) {
|
||||||
|
write(gif->fd, (uint8_t []) {r*51, g*51, b*51}, 3);
|
||||||
|
if (++i == 1 << depth)
|
||||||
|
goto done_gct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 1; i <= 24; i++) {
|
||||||
|
v = i * 0xFF / 25;
|
||||||
|
write(gif->fd, (uint8_t []) {v, v, v}, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done_gct:
|
||||||
|
if (loop >= 0 && loop <= 0xFFFF)
|
||||||
|
put_loop(gif, (uint16_t) loop);
|
||||||
|
return gif;
|
||||||
|
no_fd:
|
||||||
|
free(gif);
|
||||||
|
no_gif:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
put_loop(ge_GIF *gif, uint16_t loop)
|
||||||
|
{
|
||||||
|
write(gif->fd, (uint8_t []) {'!', 0xFF, 0x0B}, 3);
|
||||||
|
write(gif->fd, "NETSCAPE2.0", 11);
|
||||||
|
write(gif->fd, (uint8_t []) {0x03, 0x01}, 2);
|
||||||
|
write_num(gif->fd, loop);
|
||||||
|
write(gif->fd, "\0", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add packed key to buffer, updating offset and partial.
|
||||||
|
* gif->offset holds position to put next *bit*
|
||||||
|
* gif->partial holds bits to include in next byte */
|
||||||
|
static void
|
||||||
|
put_key(ge_GIF *gif, uint16_t key, int key_size)
|
||||||
|
{
|
||||||
|
int byte_offset, bit_offset, bits_to_write;
|
||||||
|
byte_offset = gif->offset / 8;
|
||||||
|
bit_offset = gif->offset % 8;
|
||||||
|
gif->partial |= ((uint32_t) key) << bit_offset;
|
||||||
|
bits_to_write = bit_offset + key_size;
|
||||||
|
while (bits_to_write >= 8) {
|
||||||
|
gif->buffer[byte_offset++] = gif->partial & 0xFF;
|
||||||
|
if (byte_offset == 0xFF) {
|
||||||
|
write(gif->fd, "\xFF", 1);
|
||||||
|
write(gif->fd, gif->buffer, 0xFF);
|
||||||
|
byte_offset = 0;
|
||||||
|
}
|
||||||
|
gif->partial >>= 8;
|
||||||
|
bits_to_write -= 8;
|
||||||
|
}
|
||||||
|
gif->offset = (gif->offset + key_size) % (0xFF * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
end_key(ge_GIF *gif)
|
||||||
|
{
|
||||||
|
int byte_offset;
|
||||||
|
byte_offset = gif->offset / 8;
|
||||||
|
if (gif->offset % 8)
|
||||||
|
gif->buffer[byte_offset++] = gif->partial & 0xFF;
|
||||||
|
write(gif->fd, (uint8_t []) {byte_offset}, 1);
|
||||||
|
write(gif->fd, gif->buffer, byte_offset);
|
||||||
|
write(gif->fd, "\0", 1);
|
||||||
|
gif->offset = gif->partial = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
put_image(ge_GIF *gif, uint16_t w, uint16_t h, uint16_t x, uint16_t y)
|
||||||
|
{
|
||||||
|
int nkeys, key_size, i, j;
|
||||||
|
Node *node, *child, *root;
|
||||||
|
int degree = 1 << gif->depth;
|
||||||
|
|
||||||
|
write(gif->fd, ",", 1);
|
||||||
|
write_num(gif->fd, x);
|
||||||
|
write_num(gif->fd, y);
|
||||||
|
write_num(gif->fd, w);
|
||||||
|
write_num(gif->fd, h);
|
||||||
|
write(gif->fd, (uint8_t []) {0x00, gif->depth}, 2);
|
||||||
|
root = node = new_trie(degree, &nkeys);
|
||||||
|
key_size = gif->depth + 1;
|
||||||
|
put_key(gif, degree, key_size); /* clear code */
|
||||||
|
for (i = y; i < y+h; i++) {
|
||||||
|
for (j = x; j < x+w; j++) {
|
||||||
|
uint8_t pixel = gif->frame[i*gif->w+j] & (degree - 1);
|
||||||
|
child = node->children[pixel];
|
||||||
|
if (child) {
|
||||||
|
node = child;
|
||||||
|
} else {
|
||||||
|
put_key(gif, node->key, key_size);
|
||||||
|
if (nkeys < 0x1000) {
|
||||||
|
if (nkeys == (1 << key_size))
|
||||||
|
key_size++;
|
||||||
|
node->children[pixel] = new_node(nkeys++, degree);
|
||||||
|
} else {
|
||||||
|
put_key(gif, degree, key_size); /* clear code */
|
||||||
|
del_trie(root, degree);
|
||||||
|
root = node = new_trie(degree, &nkeys);
|
||||||
|
key_size = gif->depth + 1;
|
||||||
|
}
|
||||||
|
node = root->children[pixel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
put_key(gif, node->key, key_size);
|
||||||
|
put_key(gif, degree + 1, key_size); /* stop code */
|
||||||
|
end_key(gif);
|
||||||
|
del_trie(root, degree);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_bbox(ge_GIF *gif, uint16_t *w, uint16_t *h, uint16_t *x, uint16_t *y)
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
int left, right, top, bottom;
|
||||||
|
left = gif->w; right = 0;
|
||||||
|
top = gif->h; bottom = 0;
|
||||||
|
k = 0;
|
||||||
|
for (i = 0; i < gif->h; i++) {
|
||||||
|
for (j = 0; j < gif->w; j++, k++) {
|
||||||
|
if (gif->frame[k] != gif->back[k]) {
|
||||||
|
if (j < left) left = j;
|
||||||
|
if (j > right) right = j;
|
||||||
|
if (i < top) top = i;
|
||||||
|
if (i > bottom) bottom = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (left != gif->w && top != gif->h) {
|
||||||
|
*x = left; *y = top;
|
||||||
|
*w = right - left + 1;
|
||||||
|
*h = bottom - top + 1;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_delay(ge_GIF *gif, uint16_t d)
|
||||||
|
{
|
||||||
|
write(gif->fd, (uint8_t []) {'!', 0xF9, 0x04, 0x04}, 4);
|
||||||
|
write_num(gif->fd, d);
|
||||||
|
write(gif->fd, "\0\0", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ge_add_frame(ge_GIF *gif, uint16_t delay)
|
||||||
|
{
|
||||||
|
uint16_t w, h, x, y;
|
||||||
|
uint8_t *tmp;
|
||||||
|
|
||||||
|
if (delay)
|
||||||
|
set_delay(gif, delay);
|
||||||
|
if (gif->nframes == 0) {
|
||||||
|
w = gif->w;
|
||||||
|
h = gif->h;
|
||||||
|
x = y = 0;
|
||||||
|
} else if (!get_bbox(gif, &w, &h, &x, &y)) {
|
||||||
|
/* image's not changed; save one pixel just to add delay */
|
||||||
|
w = h = 1;
|
||||||
|
x = y = 0;
|
||||||
|
}
|
||||||
|
put_image(gif, w, h, x, y);
|
||||||
|
gif->nframes++;
|
||||||
|
tmp = gif->back;
|
||||||
|
gif->back = gif->frame;
|
||||||
|
gif->frame = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ge_close_gif(ge_GIF* gif)
|
||||||
|
{
|
||||||
|
write(gif->fd, ";", 1);
|
||||||
|
close(gif->fd);
|
||||||
|
free(gif);
|
||||||
|
}
|
||||||
24
src/gifenc.h
Normal file
24
src/gifenc.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef GIFENC_H
|
||||||
|
#define GIFENC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct ge_GIF {
|
||||||
|
uint16_t w, h;
|
||||||
|
int depth;
|
||||||
|
int fd;
|
||||||
|
int offset;
|
||||||
|
int nframes;
|
||||||
|
uint8_t *frame, *back;
|
||||||
|
uint32_t partial;
|
||||||
|
uint8_t buffer[0xFF];
|
||||||
|
} ge_GIF;
|
||||||
|
|
||||||
|
ge_GIF *ge_new_gif(
|
||||||
|
const char *fname, uint16_t width, uint16_t height,
|
||||||
|
uint8_t *palette, int depth, int loop
|
||||||
|
);
|
||||||
|
void ge_add_frame(ge_GIF *gif, uint16_t delay);
|
||||||
|
void ge_close_gif(ge_GIF* gif);
|
||||||
|
|
||||||
|
#endif /* GIFENC_H */
|
||||||
|
|
@ -483,6 +483,8 @@ static void mtw(wchar_t * wtok, char *tok)
|
||||||
#error "---------------------------------------------------"
|
#error "---------------------------------------------------"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "libimagequant.h"
|
||||||
|
|
||||||
#include "SDL_getenv.h"
|
#include "SDL_getenv.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
@ -495,6 +497,7 @@ static void mtw(wchar_t * wtok, char *tok)
|
||||||
#include "dirwalk.h"
|
#include "dirwalk.h"
|
||||||
#include "get_fname.h"
|
#include "get_fname.h"
|
||||||
#include "onscreen_keyboard.h"
|
#include "onscreen_keyboard.h"
|
||||||
|
#include "gifenc.h"
|
||||||
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "titles.h"
|
#include "titles.h"
|
||||||
|
|
@ -1432,7 +1435,7 @@ static SDL_Surface *img_black, *img_grey;
|
||||||
static SDL_Surface *img_yes, *img_no;
|
static SDL_Surface *img_yes, *img_no;
|
||||||
static SDL_Surface *img_sfx, *img_speak;
|
static SDL_Surface *img_sfx, *img_speak;
|
||||||
static SDL_Surface *img_open, *img_erase, *img_back, *img_trash;
|
static SDL_Surface *img_open, *img_erase, *img_back, *img_trash;
|
||||||
static SDL_Surface *img_slideshow, *img_play, *img_select_digits;
|
static SDL_Surface *img_slideshow, *img_play, *img_gif_export, *img_select_digits;
|
||||||
static SDL_Surface *img_printer, *img_printer_wait;
|
static SDL_Surface *img_printer, *img_printer_wait;
|
||||||
static SDL_Surface *img_save_over, *img_popup_arrow;
|
static SDL_Surface *img_save_over, *img_popup_arrow;
|
||||||
static SDL_Surface *img_cursor_up, *img_cursor_down;
|
static SDL_Surface *img_cursor_up, *img_cursor_down;
|
||||||
|
|
@ -1755,7 +1758,8 @@ static short *brushes_directional = NULL;
|
||||||
|
|
||||||
static SDL_Surface *img_shapes[NUM_SHAPES], *img_shape_names[NUM_SHAPES];
|
static SDL_Surface *img_shapes[NUM_SHAPES], *img_shape_names[NUM_SHAPES];
|
||||||
static SDL_Surface *img_openlabels_open, *img_openlabels_erase,
|
static SDL_Surface *img_openlabels_open, *img_openlabels_erase,
|
||||||
*img_openlabels_slideshow, *img_openlabels_back, *img_openlabels_play, *img_openlabels_next;
|
*img_openlabels_slideshow, *img_openlabels_back, *img_openlabels_play,
|
||||||
|
*img_openlabels_gif_export, *img_openlabels_next;
|
||||||
|
|
||||||
static SDL_Surface *img_tux[NUM_TIP_TUX];
|
static SDL_Surface *img_tux[NUM_TIP_TUX];
|
||||||
|
|
||||||
|
|
@ -7861,11 +7865,14 @@ static void create_button_labels(void)
|
||||||
/* Open dialog: 'Back' button, to dismiss Open dialog without opening a picture */
|
/* Open dialog: 'Back' button, to dismiss Open dialog without opening a picture */
|
||||||
img_openlabels_back = do_render_button_label(gettext_noop("Back"));
|
img_openlabels_back = do_render_button_label(gettext_noop("Back"));
|
||||||
|
|
||||||
/* Slideshow: 'Next' button, to load next slide (image) */
|
|
||||||
img_openlabels_next = do_render_button_label(gettext_noop("Next"));
|
|
||||||
|
|
||||||
/* Slideshow: 'Play' button, to begin a slideshow sequence */
|
/* Slideshow: 'Play' button, to begin a slideshow sequence */
|
||||||
img_openlabels_play = do_render_button_label(gettext_noop("Play"));
|
img_openlabels_play = do_render_button_label(gettext_noop("Play"));
|
||||||
|
|
||||||
|
/* Slideshow: 'GIF Export' button, to create an animated GIF */
|
||||||
|
img_openlabels_gif_export = do_render_button_label(gettext_noop("GIF Export"));
|
||||||
|
|
||||||
|
/* Slideshow: 'Next' button, to load next slide (image) */
|
||||||
|
img_openlabels_next = do_render_button_label(gettext_noop("Next"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -15029,7 +15036,7 @@ static int do_slideshow(void)
|
||||||
SDL_Rect dest;
|
SDL_Rect dest;
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
SDLKey key;
|
SDLKey key;
|
||||||
char *freeme;
|
char *freeme, *instructions;
|
||||||
int speeds;
|
int speeds;
|
||||||
float x_per, y_per;
|
float x_per, y_per;
|
||||||
int xx, yy;
|
int xx, yy;
|
||||||
|
|
@ -15278,9 +15285,8 @@ static int do_slideshow(void)
|
||||||
/* Let user choose images: */
|
/* Let user choose images: */
|
||||||
|
|
||||||
/* Instructions for Slideshow file dialog (FIXME: Make a #define) */
|
/* Instructions for Slideshow file dialog (FIXME: Make a #define) */
|
||||||
freeme = textdir(gettext_noop("Choose the pictures you want, " "then click “Play”."));
|
instructions = textdir(gettext_noop("Choose the pictures you want, " "then click “Play”."));
|
||||||
draw_tux_text(TUX_BORED, freeme, 1);
|
draw_tux_text(TUX_BORED, instructions, 1);
|
||||||
free(freeme);
|
|
||||||
|
|
||||||
/* NOTE: cur is now set above; if file_id'th file is found, it's
|
/* NOTE: cur is now set above; if file_id'th file is found, it's
|
||||||
set to that file's index; otherwise, we default to '0' */
|
set to that file's index; otherwise, we default to '0' */
|
||||||
|
|
@ -15386,6 +15392,21 @@ static int do_slideshow(void)
|
||||||
SDL_BlitSurface(img_openlabels_play, NULL, screen, &dest);
|
SDL_BlitSurface(img_openlabels_play, NULL, screen, &dest);
|
||||||
|
|
||||||
|
|
||||||
|
/* "GIF Export" button: */
|
||||||
|
|
||||||
|
dest.x = WINDOW_WIDTH - 96 - 48 * 2;
|
||||||
|
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - 48;
|
||||||
|
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||||||
|
|
||||||
|
dest.x = WINDOW_WIDTH - 96 - 48 * 2 + (48 - img_gif_export->w) / 2;
|
||||||
|
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - 48;
|
||||||
|
SDL_BlitSurface(img_gif_export, NULL, screen, &dest);
|
||||||
|
|
||||||
|
dest.x = WINDOW_WIDTH - 96 - 48 * 2 + (48 - img_openlabels_gif_export->w) / 2;
|
||||||
|
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - img_openlabels_gif_export->h;
|
||||||
|
SDL_BlitSurface(img_openlabels_gif_export, NULL, screen, &dest);
|
||||||
|
|
||||||
|
|
||||||
/* "Back" button: */
|
/* "Back" button: */
|
||||||
|
|
||||||
dest.x = WINDOW_WIDTH - 96 - 48;
|
dest.x = WINDOW_WIDTH - 96 - 48;
|
||||||
|
|
@ -15633,6 +15654,31 @@ static int do_slideshow(void)
|
||||||
update_list = 1;
|
update_list = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (event.button.x >= (WINDOW_WIDTH - 96 - 48 - 48) &&
|
||||||
|
event.button.x < (WINDOW_WIDTH - 96 - 48) &&
|
||||||
|
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||||||
|
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET))
|
||||||
|
{
|
||||||
|
/* GIF Export */
|
||||||
|
|
||||||
|
playsound(screen, 1, SND_CLICK, 1, SNDPOS_RIGHT, SNDDIST_NEAR);
|
||||||
|
|
||||||
|
if (num_selected < 2)
|
||||||
|
{
|
||||||
|
/* None selected? Too dangerous to select all.
|
||||||
|
Only 1 selected? No point in saving as GIF.
|
||||||
|
*/
|
||||||
|
freeme = textdir(gettext_noop("Select 2 or more drawings to turn into an animated GIF."));
|
||||||
|
draw_tux_text(TUX_BORED, freeme, 1);
|
||||||
|
free(freeme);
|
||||||
|
|
||||||
|
control_drawtext_timer(2000, instructions, 0); /* N.B. It will draw instructions, regardless */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* FIXME: Do it */
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (event.button.x >= (WINDOW_WIDTH - 96 - 48) &&
|
else if (event.button.x >= (WINDOW_WIDTH - 96 - 48) &&
|
||||||
event.button.x < (WINDOW_WIDTH - 96) &&
|
event.button.x < (WINDOW_WIDTH - 96) &&
|
||||||
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||||||
|
|
@ -15696,7 +15742,7 @@ static int do_slideshow(void)
|
||||||
do_setcursor(cursor_down);
|
do_setcursor(cursor_down);
|
||||||
}
|
}
|
||||||
else if (((event.button.x >= 96 && event.button.x < 96 + 48 + 96) ||
|
else if (((event.button.x >= 96 && event.button.x < 96 + 48 + 96) ||
|
||||||
(event.button.x >= (WINDOW_WIDTH - 96 - 48) &&
|
(event.button.x >= (WINDOW_WIDTH - 96 - 48 * 2) &&
|
||||||
event.button.x < (WINDOW_WIDTH - 96))) &&
|
event.button.x < (WINDOW_WIDTH - 96))) &&
|
||||||
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||||||
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET))
|
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET))
|
||||||
|
|
@ -15736,6 +15782,17 @@ static int do_slideshow(void)
|
||||||
|
|
||||||
else if (event.type == SDL_JOYBUTTONDOWN || event.type == SDL_JOYBUTTONUP)
|
else if (event.type == SDL_JOYBUTTONDOWN || event.type == SDL_JOYBUTTONUP)
|
||||||
handle_joybuttonupdown(event, oldpos_x, oldpos_y);
|
handle_joybuttonupdown(event, oldpos_x, oldpos_y);
|
||||||
|
|
||||||
|
else if (event.type == SDL_USEREVENT)
|
||||||
|
{
|
||||||
|
if (event.user.code == USEREVENT_TEXT_UPDATE)
|
||||||
|
{
|
||||||
|
if (event.user.data1 != NULL)
|
||||||
|
{
|
||||||
|
draw_tux_text(TUX_BORED, instructions, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (motioner | hatmotioner)
|
if (motioner | hatmotioner)
|
||||||
|
|
@ -15764,6 +15821,8 @@ static int do_slideshow(void)
|
||||||
free(d_exts);
|
free(d_exts);
|
||||||
free(selected);
|
free(selected);
|
||||||
|
|
||||||
|
control_drawtext_timer(0, "", 0);
|
||||||
|
free(instructions);
|
||||||
|
|
||||||
return go_back;
|
return go_back;
|
||||||
}
|
}
|
||||||
|
|
@ -23990,6 +24049,7 @@ static void setup(void)
|
||||||
|
|
||||||
img_slideshow = loadimage(DATA_PREFIX "images/ui/slideshow.png");
|
img_slideshow = loadimage(DATA_PREFIX "images/ui/slideshow.png");
|
||||||
img_play = loadimage(DATA_PREFIX "images/ui/play.png");
|
img_play = loadimage(DATA_PREFIX "images/ui/play.png");
|
||||||
|
img_gif_export = loadimage(DATA_PREFIX "images/ui/gif_export.png");
|
||||||
img_select_digits = loadimage(DATA_PREFIX "images/ui/select_digits.png");
|
img_select_digits = loadimage(DATA_PREFIX "images/ui/select_digits.png");
|
||||||
|
|
||||||
img_popup_arrow = loadimage(DATA_PREFIX "images/ui/popup_arrow.png");
|
img_popup_arrow = loadimage(DATA_PREFIX "images/ui/popup_arrow.png");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue