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)
|
||||
# http://www.tuxpaint.org/
|
||||
|
||||
# June 14, 2002 - June 22, 2020
|
||||
# June 14, 2002 - July 24, 2020
|
||||
|
||||
|
||||
# The version number, for release:
|
||||
|
|
@ -115,10 +115,10 @@ PNG:=$(if $(PNG),$(PNG),$(call linktest,-lpng12,))
|
|||
FRIBIDI_LIB:=$(shell $(PKG_CONFIG) --libs fribidi)
|
||||
FRIBIDI_CFLAGS:=$(shell $(PKG_CONFIG) --cflags fribidi)
|
||||
|
||||
windows_ARCH_LINKS:=-lintl $(PNG) -lzdll -lwinspool -lshlwapi $(FRIBIDI_LIB) -liconv
|
||||
osx_ARCH_LINKS:=$(FRIBIDI_LIB)
|
||||
beos_ARCH_LINKS:=-lintl $(PNG) -lz -lbe -lnetwork -liconv $(FRIBIDI_LIB) $(PAPER_LIB) $(STDC_LIB)
|
||||
linux_ARCH_LINKS:=$(PAPER_LIB) $(FRIBIDI_LIB)
|
||||
windows_ARCH_LINKS:=-lintl $(PNG) -lzdll -lwinspool -lshlwapi $(FRIBIDI_LIB) -liconv -limagequant
|
||||
osx_ARCH_LINKS:=$(FRIBIDI_LIB) -limagequant
|
||||
beos_ARCH_LINKS:=-lintl $(PNG) -lz -lbe -lnetwork -liconv $(FRIBIDI_LIB) $(PAPER_LIB) $(STDC_LIB) -limagequant
|
||||
linux_ARCH_LINKS:=$(PAPER_LIB) $(FRIBIDI_LIB) -limagequant
|
||||
ARCH_LINKS:=$($(OS)_ARCH_LINKS)
|
||||
|
||||
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 \
|
||||
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/gifenc.o \
|
||||
$(ARCH_LIBS)
|
||||
@echo
|
||||
@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/sounds.h src/tip_tux.h src/great.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)/hand.xbm src/$(MOUSEDIR)/hand-mask.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) \
|
||||
-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 \
|
||||
src/compiler.h src/debug.h
|
||||
@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:
|
||||
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
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,16 @@ http://www.tuxpaint.org/
|
|||
|
||||
$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
|
||||
----------------
|
||||
* 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 "---------------------------------------------------"
|
||||
#endif
|
||||
|
||||
#include "libimagequant.h"
|
||||
|
||||
#include "SDL_getenv.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
|
@ -495,6 +497,7 @@ static void mtw(wchar_t * wtok, char *tok)
|
|||
#include "dirwalk.h"
|
||||
#include "get_fname.h"
|
||||
#include "onscreen_keyboard.h"
|
||||
#include "gifenc.h"
|
||||
|
||||
#include "tools.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_sfx, *img_speak;
|
||||
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_save_over, *img_popup_arrow;
|
||||
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_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];
|
||||
|
||||
|
|
@ -7861,11 +7865,14 @@ static void create_button_labels(void)
|
|||
/* Open dialog: 'Back' button, to dismiss Open dialog without opening a picture */
|
||||
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 */
|
||||
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_Event event;
|
||||
SDLKey key;
|
||||
char *freeme;
|
||||
char *freeme, *instructions;
|
||||
int speeds;
|
||||
float x_per, y_per;
|
||||
int xx, yy;
|
||||
|
|
@ -15278,9 +15285,8 @@ static int do_slideshow(void)
|
|||
/* Let user choose images: */
|
||||
|
||||
/* Instructions for Slideshow file dialog (FIXME: Make a #define) */
|
||||
freeme = textdir(gettext_noop("Choose the pictures you want, " "then click “Play”."));
|
||||
draw_tux_text(TUX_BORED, freeme, 1);
|
||||
free(freeme);
|
||||
instructions = textdir(gettext_noop("Choose the pictures you want, " "then click “Play”."));
|
||||
draw_tux_text(TUX_BORED, instructions, 1);
|
||||
|
||||
/* 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' */
|
||||
|
|
@ -15386,6 +15392,21 @@ static int do_slideshow(void)
|
|||
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: */
|
||||
|
||||
dest.x = WINDOW_WIDTH - 96 - 48;
|
||||
|
|
@ -15633,6 +15654,31 @@ static int do_slideshow(void)
|
|||
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) &&
|
||||
event.button.x < (WINDOW_WIDTH - 96) &&
|
||||
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||||
|
|
@ -15696,7 +15742,7 @@ static int do_slideshow(void)
|
|||
do_setcursor(cursor_down);
|
||||
}
|
||||
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.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||||
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)
|
||||
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)
|
||||
|
|
@ -15764,6 +15821,8 @@ static int do_slideshow(void)
|
|||
free(d_exts);
|
||||
free(selected);
|
||||
|
||||
control_drawtext_timer(0, "", 0);
|
||||
free(instructions);
|
||||
|
||||
return go_back;
|
||||
}
|
||||
|
|
@ -23990,6 +24049,7 @@ static void setup(void)
|
|||
|
||||
img_slideshow = loadimage(DATA_PREFIX "images/ui/slideshow.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_popup_arrow = loadimage(DATA_PREFIX "images/ui/popup_arrow.png");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue