/*
* TilEm II
*
* Copyright (c) 2010-2011 Thibault Duponchelle
* Copyright (c) 2011 Benjamin Moody
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include
#include "gui.h"
#include "files.h"
#include "filedlg.h"
#include "msgbox.h"
#define DEFAULT_WIDTH_96 192
#define DEFAULT_HEIGHT_96 128
#define DEFAULT_WIDTH_128 256
#define DEFAULT_HEIGHT_128 128
#define DEFAULT_FORMAT "png"
struct imgsize {
int width;
int height;
};
static const struct imgsize normal_sizes[] =
{ { 96, 64 }, { 192, 128 }, { 288, 192 } };
static const struct imgsize wide_sizes[] =
/* actual aspect ratio is 92:55 or 1.673:1 */
{ { 128, 64 }, { 128, 77 },
{ 214, 128 }, { 256, 128 }, { 256, 153 },
{ 321, 192 }, { 384, 192 } };
static void grab_screen(GtkButton *btn, TilemScreenshotDialog *ssdlg);
static void begin_animation(GtkButton *btn, TilemScreenshotDialog *ssdlg);
static void end_animation(GtkButton *btn, TilemScreenshotDialog *ssdlg);
static gboolean save_output(TilemScreenshotDialog *ssdlg);
static char* find_free_filename(const char* directory,
const char* filename,
const char* extension);
/* Test if the calc has a wide screen (ti86) */
static gboolean is_wide_screen(TilemCalcEmulator *emu)
{
g_return_val_if_fail(emu != NULL, FALSE);
g_return_val_if_fail(emu->calc != NULL, FALSE);
return (emu->calc->hw.lcdwidth == 128);
}
/* Quick screenshot: save a screenshot with predefined settings,
without prompting the user */
void quick_screenshot(TilemEmulatorWindow *ewin)
{
char *folder, *filename, *format;
int grayscale, w96, h96, w128, h128, width, height;
TilemAnimation *anim;
GError *err = NULL;
GdkColor fg, bg;
tilem_config_get("screenshot",
"directory/f", &folder,
"format/s", &format,
"grayscale/b=1", &grayscale,
"width_96x64/i", &w96,
"height_96x64/i", &h96,
"width_128x64/i", &w128,
"height_128x64/i", &h128,
"foreground/c=#000", &fg,
"background/c=#fff", &bg,
NULL);
anim = tilem_calc_emulator_get_screenshot(ewin->emu, grayscale);
if (!anim) {
g_free(folder);
g_free(format);
return;
}
if (is_wide_screen(ewin->emu)) {
width = (w128 > 0 ? w128 : DEFAULT_WIDTH_128);
height = (h128 > 0 ? h128 : DEFAULT_HEIGHT_128);
}
else {
width = (w96 > 0 ? w96 : DEFAULT_WIDTH_96);
height = (h96 > 0 ? h96 : DEFAULT_HEIGHT_96);
}
tilem_animation_set_size(anim, width, height);
tilem_animation_set_colors(anim, &fg, &bg);
if (!folder)
folder = get_config_file_path("screenshots", NULL);
if (!format)
format = g_strdup(DEFAULT_FORMAT);
g_mkdir_with_parents(folder, 0755);
filename = find_free_filename(folder, "screenshot", format);
if (!filename) {
g_free(folder);
g_free(format);
g_object_unref(anim);
return;
}
printf("screenshot saved : %s\n", filename);
if (!tilem_animation_save(anim, filename, format, NULL, NULL, &err)) {
messagebox01(ewin->window, GTK_MESSAGE_ERROR,
"Unable to save screenshot",
"%s", err->message);
g_error_free(err);
}
g_object_unref(anim);
g_free(filename);
g_free(folder);
g_free(format);
}
/* Look for a free filename by testing [folder]/[basename]000.[extension] to [folder]/[basename]999.[extension]
Return a newly allocated string if success
Return null if no filename found */
static char* find_free_filename(const char* folder,
const char* basename,
const char* extension)
{
int i;
char *filename, *prefix;
if(folder)
prefix = g_build_filename(folder, basename, NULL);
else
prefix = g_build_filename(basename, NULL);
/* I do not use a while and limit number to 1000 because for any reason, if there's a problem in this scope
I don't want to freeze tilem (if tilem don't find a free filename and never return anything)
Limit to 1000 prevent this problem but if you prefer we could use a while wich wait a valid filename... */
for(i=0; i<999; i++) {
filename = g_strdup_printf("%s%03d.%s", prefix, i, extension);
if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
g_free(prefix);
return filename;
}
g_free(filename);
}
g_free(prefix);
return NULL;
}
/* Change the review image to set the current animation */
static void set_current_animation(TilemScreenshotDialog *ssdlg,
TilemAnimation *anim)
{
GtkImage *img = GTK_IMAGE(ssdlg->screenshot_preview_image);
int width, height;
GdkColor fg, bg;
gdouble speed;
if (anim)
g_object_ref(anim);
if (ssdlg->current_anim)
g_object_unref(ssdlg->current_anim);
ssdlg->current_anim = anim;
if (!anim) {
gtk_image_set_from_animation(img, NULL);
gtk_dialog_set_response_sensitive(GTK_DIALOG(ssdlg->window),
GTK_RESPONSE_ACCEPT, FALSE);
}
else {
width = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ssdlg->width_spin));
height = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ssdlg->height_spin));
tilem_animation_set_size(anim, width, height);
gtk_color_button_get_color
(GTK_COLOR_BUTTON(ssdlg->foreground_color), &fg);
gtk_color_button_get_color
(GTK_COLOR_BUTTON(ssdlg->background_color), &bg);
tilem_animation_set_colors(anim, &fg, &bg);
speed = gtk_spin_button_get_value
(GTK_SPIN_BUTTON(ssdlg->animation_speed));
tilem_animation_set_speed(anim, speed);
gtk_image_set_from_animation(img, GDK_PIXBUF_ANIMATION(anim));
/* Need to call gtk_widget_show because we hide it
while recording */
gtk_widget_show(ssdlg->screenshot_preview_image);
gtk_dialog_set_response_sensitive(GTK_DIALOG(ssdlg->window),
GTK_RESPONSE_ACCEPT, TRUE);
}
}
static void dialog_response(G_GNUC_UNUSED GtkDialog *dialog, gint response, gpointer data)
{
TilemScreenshotDialog *ssdlg = data;
if (response == GTK_RESPONSE_ACCEPT) {
if (!save_output(ssdlg))
return;
}
gtk_widget_hide(GTK_WIDGET(dialog));
end_animation(NULL, ssdlg);
set_current_animation(ssdlg, NULL);
}
static void set_size_spin_buttons(TilemScreenshotDialog *ssdlg,
int width, int height)
{
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ssdlg->width_spin), width);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ssdlg->height_spin), height);
}
enum {
COL_TEXT,
COL_WIDTH,
COL_HEIGHT
};
static void animation_speed_changed(GtkSpinButton *animation_speed,
gpointer data)
{
TilemScreenshotDialog *ssdlg = data;
TilemAnimation * anim = ssdlg->current_anim;
gdouble value = gtk_spin_button_get_value(animation_speed);
tilem_animation_set_speed(anim, value);
}
/* Combo box changed. Update spin buttons accordingly. */
static void size_combo_changed(GtkComboBox *combo,
TilemScreenshotDialog *ssdlg)
{
GtkTreeModel *model;
GtkTreeIter iter;
int width, height;
if (gtk_combo_box_get_active_iter(combo, &iter)) {
model = gtk_combo_box_get_model(combo);
gtk_tree_model_get(model, &iter,
COL_WIDTH, &width,
COL_HEIGHT, &height,
-1);
if (width && height)
set_size_spin_buttons(ssdlg, width, height);
}
}
static void size_spin_changed(G_GNUC_UNUSED GtkSpinButton *sb,
TilemScreenshotDialog *ssdlg)
{
GtkComboBox *combo = GTK_COMBO_BOX(ssdlg->ss_size_combo);
GtkTreeModel *model;
GtkTreeIter iter;
int width, height, w, h;
model = gtk_combo_box_get_model(combo);
if (!model || !gtk_tree_model_get_iter_first(model, &iter))
return;
width = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ssdlg->width_spin));
height = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ssdlg->height_spin));
do {
gtk_tree_model_get(model, &iter,
COL_WIDTH, &w,
COL_HEIGHT, &h,
-1);
if ((w == 0 && h == 0) || (w == width && h == height)) {
gtk_combo_box_set_active_iter(combo, &iter);
break;
}
} while (gtk_tree_model_iter_next(model, &iter));
set_current_animation(ssdlg, ssdlg->current_anim);
}
static void fill_size_combobox(GtkComboBox *combo,
const struct imgsize *sizes,
int nsizes)
{
GtkListStore *store;
GtkTreeIter iter;
int i;
char *s;
store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
for (i = 0; i < nsizes; i++) {
s = g_strdup_printf("%d \303\227 %d",
sizes[i].width,
sizes[i].height);
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
COL_TEXT, s,
COL_WIDTH, sizes[i].width,
COL_HEIGHT, sizes[i].height,
-1);
g_free(s);
}
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
COL_TEXT, "Custom",
COL_WIDTH, 0,
COL_HEIGHT, 0,
-1);
gtk_combo_box_set_model(GTK_COMBO_BOX(combo), GTK_TREE_MODEL(store));
}
/* This method is called when a color is set (foreground or background)
* It set a new palette based on new custom colors
* It refresh the screen to print new colors
*/
static void color_changed(G_GNUC_UNUSED GtkSpinButton *sb,
TilemScreenshotDialog *ssdlg)
{
set_current_animation(ssdlg, ssdlg->current_anim);
}
/* Create the screenshot menu */
static TilemScreenshotDialog * create_screenshot_window(TilemCalcEmulator *emu)
{
TilemScreenshotDialog *ssdlg = g_slice_new0(TilemScreenshotDialog);
GtkWidget *main_table, *vbox, *frame, *config_expander,
*tbl, *lbl, *align;
GtkCellRenderer *cell;
ssdlg->emu = emu;
ssdlg->window = gtk_dialog_new_with_buttons
("Screenshot",
(emu->ewin ? GTK_WINDOW(emu->ewin->window) : NULL),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
NULL);
gtk_window_set_resizable(GTK_WINDOW(ssdlg->window), FALSE);
gtk_dialog_set_alternative_button_order(GTK_DIALOG(ssdlg->window),
GTK_RESPONSE_ACCEPT,
GTK_RESPONSE_CANCEL,
-1);
gtk_dialog_set_default_response(GTK_DIALOG(ssdlg->window),
GTK_RESPONSE_ACCEPT);
g_signal_connect(ssdlg->window, "response",
G_CALLBACK(dialog_response), ssdlg);
g_signal_connect(ssdlg->window, "delete-event",
G_CALLBACK(gtk_widget_hide_on_delete), NULL);
main_table = gtk_table_new(2, 2, FALSE);
gtk_table_set_row_spacings(GTK_TABLE(main_table), 6);
gtk_table_set_col_spacings(GTK_TABLE(main_table), 12);
gtk_container_set_border_width(GTK_CONTAINER(main_table), 6);
/* Preview */
frame = gtk_frame_new("Preview");
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
ssdlg->screenshot_preview_image = gtk_image_new();
align = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);
gtk_container_add(GTK_CONTAINER(align), ssdlg->screenshot_preview_image);
gtk_container_add(GTK_CONTAINER(frame), align);
gtk_table_attach(GTK_TABLE(main_table), frame, 0, 1, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
/* Buttons */
vbox = gtk_vbutton_box_new();
gtk_button_box_set_layout(GTK_BUTTON_BOX(vbox), GTK_BUTTONBOX_START);
gtk_box_set_spacing(GTK_BOX(vbox), 6);
ssdlg->screenshot = gtk_button_new_with_mnemonic("_Grab");
gtk_box_pack_start(GTK_BOX(vbox), ssdlg->screenshot, FALSE, FALSE, 0);
ssdlg->record = gtk_button_new_with_mnemonic("_Record");
gtk_box_pack_start(GTK_BOX(vbox), ssdlg->record, FALSE, FALSE, 0);
ssdlg->stop = gtk_button_new_with_mnemonic("_Stop");
gtk_box_pack_start(GTK_BOX(vbox), ssdlg->stop, FALSE, FALSE, 0);
gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->stop), FALSE);
gtk_table_attach(GTK_TABLE(main_table), vbox, 1, 2, 0, 2,
GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
/* Options */
config_expander = gtk_expander_new("Options");
tbl = gtk_table_new(7, 2, FALSE);
gtk_table_set_row_spacings(GTK_TABLE(tbl), 6);
gtk_table_set_col_spacings(GTK_TABLE(tbl), 6);
ssdlg->grayscale_tb = gtk_check_button_new_with_mnemonic("Gra_yscale");
gtk_table_attach(GTK_TABLE(tbl), ssdlg->grayscale_tb,
0, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
lbl = gtk_label_new_with_mnemonic("Image si_ze:");
gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5);
gtk_table_attach(GTK_TABLE(tbl), lbl,
0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
ssdlg->ss_size_combo = gtk_combo_box_new();
cell = gtk_cell_renderer_text_new();
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(ssdlg->ss_size_combo),
cell, TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(ssdlg->ss_size_combo),
cell, "text", COL_TEXT, NULL);
gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->ss_size_combo);
gtk_table_attach(GTK_TABLE(tbl), ssdlg->ss_size_combo,
1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
lbl = gtk_label_new_with_mnemonic("_Width:");
gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5);
gtk_table_attach(GTK_TABLE(tbl), lbl,
0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
ssdlg->width_spin = gtk_spin_button_new_with_range(1, 750, 1);
gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->width_spin);
align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0);
gtk_container_add(GTK_CONTAINER(align), ssdlg->width_spin);
gtk_table_attach(GTK_TABLE(tbl), align,
1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
lbl = gtk_label_new_with_mnemonic("_Height:");
gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5);
gtk_table_attach(GTK_TABLE(tbl), lbl,
0, 1, 3, 4, GTK_FILL, GTK_FILL, 0, 0);
ssdlg->height_spin = gtk_spin_button_new_with_range(1, 500, 1);
gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->height_spin);
align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0);
gtk_container_add(GTK_CONTAINER(align), ssdlg->height_spin);
gtk_table_attach(GTK_TABLE(tbl), align,
1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0);
lbl = gtk_label_new_with_mnemonic("Animation s_peed:");
gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5);
gtk_table_attach(GTK_TABLE(tbl), lbl,
0, 1, 4, 5, GTK_FILL, GTK_FILL, 0, 0);
ssdlg->animation_speed = gtk_spin_button_new_with_range(0.1, 100.0, 0.1);
gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->animation_speed);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ssdlg->animation_speed), 1.0);
align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0);
gtk_container_add(GTK_CONTAINER(align), ssdlg->animation_speed);
gtk_table_attach(GTK_TABLE(tbl), align,
1, 2, 4, 5, GTK_FILL, GTK_FILL, 0, 0);
/* Foreground color and background color */
lbl = gtk_label_new_with_mnemonic("_Foreground:");
gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5);
gtk_table_attach(GTK_TABLE(tbl), lbl,
0, 1, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
ssdlg->foreground_color = gtk_color_button_new();
gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->foreground_color);
align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0);
gtk_container_add(GTK_CONTAINER(align), ssdlg->foreground_color);
gtk_table_attach(GTK_TABLE(tbl), align,
1, 2, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
lbl = gtk_label_new_with_mnemonic("_Background:");
gtk_misc_set_alignment(GTK_MISC(lbl), LABEL_X_ALIGN, 0.5);
gtk_table_attach(GTK_TABLE(tbl), lbl,
0, 1, 6, 7, GTK_FILL, GTK_FILL, 0, 0);
ssdlg->background_color = gtk_color_button_new();
gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), ssdlg->background_color);
align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0);
gtk_container_add(GTK_CONTAINER(align), ssdlg->background_color);
gtk_table_attach(GTK_TABLE(tbl), align,
1, 2, 6, 7, GTK_FILL, GTK_FILL, 0, 0);
align = gtk_alignment_new(0.5, 0.5, 1.0, 1.0);
gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);
gtk_container_add(GTK_CONTAINER(align), tbl);
gtk_container_add(GTK_CONTAINER(config_expander), align);
gtk_table_attach(GTK_TABLE(main_table), config_expander, 0, 1, 1, 2,
GTK_FILL, GTK_FILL, 0, 0);
g_signal_connect(ssdlg->screenshot, "clicked",
G_CALLBACK(grab_screen), ssdlg);
g_signal_connect(ssdlg->record, "clicked",
G_CALLBACK(begin_animation), ssdlg);
g_signal_connect(ssdlg->stop, "clicked",
G_CALLBACK(end_animation), ssdlg);
g_signal_connect(ssdlg->ss_size_combo, "changed",
G_CALLBACK(size_combo_changed), ssdlg);
g_signal_connect(ssdlg->width_spin, "value-changed",
G_CALLBACK(size_spin_changed), ssdlg);
g_signal_connect(ssdlg->height_spin, "value-changed",
G_CALLBACK(size_spin_changed), ssdlg);
g_signal_connect(ssdlg->animation_speed, "value-changed",
G_CALLBACK(animation_speed_changed), ssdlg);
g_signal_connect(ssdlg->foreground_color, "color-set",
G_CALLBACK(color_changed), ssdlg);
g_signal_connect(ssdlg->background_color, "color-set",
G_CALLBACK(color_changed), ssdlg);
/*g_signal_connect(config_expander, "activate",
G_CALLBACK(on_config_expander_activate), ssdlg);
*/
vbox = gtk_dialog_get_content_area(GTK_DIALOG(ssdlg->window));
gtk_container_add(GTK_CONTAINER(vbox), main_table);
gtk_widget_show_all(main_table);
return ssdlg;
}
/* Popup the screenshot window */
void popup_screenshot_window(TilemEmulatorWindow *ewin)
{
TilemScreenshotDialog *ssdlg;
int w96, h96, w128, h128, width, height, grayscale;
GdkColor fg, bg;
g_return_if_fail(ewin != NULL);
g_return_if_fail(ewin->emu != NULL);
if (!ewin->emu->ssdlg)
ewin->emu->ssdlg = create_screenshot_window(ewin->emu);
ssdlg = ewin->emu->ssdlg;
tilem_config_get("screenshot",
"grayscale/b=1", &grayscale,
"width_96x64/i", &w96,
"height_96x64/i", &h96,
"width_128x64/i", &w128,
"height_128x64/i", &h128,
"foreground/c=#000", &fg,
"background/c=#fff", &bg,
NULL);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssdlg->grayscale_tb),
grayscale);
if (is_wide_screen(ewin->emu)) {
fill_size_combobox(GTK_COMBO_BOX(ssdlg->ss_size_combo),
wide_sizes, G_N_ELEMENTS(wide_sizes));
width = (w128 > 0 ? w128 : DEFAULT_WIDTH_128);
height = (h128 > 0 ? h128 : DEFAULT_HEIGHT_128);
}
else {
fill_size_combobox(GTK_COMBO_BOX(ssdlg->ss_size_combo),
normal_sizes, G_N_ELEMENTS(normal_sizes));
width = (w96 > 0 ? w96 : DEFAULT_WIDTH_96);
height = (h96 > 0 ? h96 : DEFAULT_HEIGHT_96);
}
set_size_spin_buttons(ssdlg, width, height);
size_spin_changed(NULL, ssdlg);
gtk_color_button_set_color(GTK_COLOR_BUTTON(ssdlg->foreground_color), &fg);
gtk_color_button_set_color(GTK_COLOR_BUTTON(ssdlg->background_color), &bg);
grab_screen(NULL, ssdlg);
gtk_window_present(GTK_WINDOW(ssdlg->window));
}
/* Save the current (static) output */
static gboolean save_output(TilemScreenshotDialog *ssdlg)
{
char *dir, *format, *filename, *basename;
TilemAnimation *anim = ssdlg->current_anim;
GdkPixbufAnimation *ganim = GDK_PIXBUF_ANIMATION(anim);
const char *format_opt, *width_opt, *height_opt;
gboolean is_static;
int width, height;
GdkColor fg, bg;
GError *err = NULL;
g_return_val_if_fail(anim != NULL, FALSE);
is_static = gdk_pixbuf_animation_is_static_image(ganim);
width = gdk_pixbuf_animation_get_width(ganim);
height = gdk_pixbuf_animation_get_height(ganim);
gtk_color_button_get_color
(GTK_COLOR_BUTTON(ssdlg->foreground_color), &fg);
gtk_color_button_get_color
(GTK_COLOR_BUTTON(ssdlg->background_color), &bg);
tilem_config_get("screenshot",
"directory/f", &dir,
"static_format/s", &format,
NULL);
if (!dir)
dir = g_get_current_dir();
if (!is_static) {
g_free(format);
format = g_strdup("gif");
}
else if (!format) {
format = g_strdup(DEFAULT_FORMAT);
}
filename = find_free_filename(dir, "screenshot", format);
basename = (filename ? g_filename_display_basename(filename) : NULL);
g_free(filename);
g_free(format);
if (!is_static) {
filename = prompt_save_file("Save Screenshot",
GTK_WINDOW(ssdlg->window),
basename, dir,
"GIF images", "*.gif",
"All files", "*",
NULL);
}
else {
/* FIXME: perhaps check the list of supported output
formats (gdk_pixbuf_get_formats()) - e.g., tiff is
usually supported, although it requires libtiff
installed (png and jpeg also require external
libraries, but we need those libraries anyway for
other reasons) */
filename = prompt_save_file("Save Screenshot",
GTK_WINDOW(ssdlg->window),
basename, dir,
"PNG images", "*.png",
"GIF images", "*.gif",
"BMP images", "*.bmp",
"JPEG images", "*.jpg;*.jpe;*.jpeg",
"All files", "*",
NULL);
}
g_free(basename);
g_free(dir);
if (!filename)
return FALSE;
if (!is_static) {
format = g_strdup("gif");
}
else {
basename = g_path_get_basename(filename);
format = strrchr(basename, '.');
if (!format) {
messagebox00(ssdlg->window, GTK_MESSAGE_ERROR,
"Unable to save screenshot",
"File name does not have a"
" recognized suffix");
g_free(filename);
g_free(basename);
return FALSE;
}
else {
format = g_strdup(format + 1);
}
}
tilem_animation_save(anim, filename, format, NULL, NULL, &err);
dir = g_path_get_dirname(filename);
if (err) {
messagebox01(ssdlg->window, GTK_MESSAGE_ERROR,
"Unable to save screenshot",
"%s", err->message);
g_error_free(err);
g_free(dir);
g_free(filename);
g_free(format);
return FALSE;
}
if (is_static)
format_opt = "static_format/s";
else
format_opt = NULL;
if (is_wide_screen(ssdlg->emu)) {
width_opt = "width_128x64/i";
height_opt = "height_128x64/i";
}
else {
width_opt = "width_96x64/i";
height_opt = "height_96x64/i";
}
tilem_config_set("screenshot",
"directory/f", dir,
"grayscale/b", ssdlg->current_anim_grayscale,
"foreground/c", &fg,
"background/c", &bg,
width_opt, width,
height_opt, height,
format_opt, format,
NULL);
g_free(dir);
g_free(filename);
g_free(format);
return TRUE;
}
/* Callback for record button */
static void begin_animation(G_GNUC_UNUSED GtkButton *btn,
TilemScreenshotDialog *ssdlg)
{
gboolean grayscale = gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON(ssdlg->grayscale_tb));
gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->animation_speed), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->screenshot), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->record), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->stop), TRUE);
gtk_dialog_set_response_sensitive(GTK_DIALOG(ssdlg->window),
GTK_RESPONSE_ACCEPT, FALSE);
tilem_calc_emulator_begin_animation(ssdlg->emu, grayscale);
ssdlg->current_anim_grayscale = grayscale;
/* You can choose to hide current animation while recording or not
It's as you prefer... For the moment I hide it */
/*gtk_widget_hide(GTK_WIDGET(ssdlg->screenshot_preview_image)); */
//set_current_animation(ssdlg, NULL);
}
/* Callback for stop button (stop the recording) */
static void end_animation(G_GNUC_UNUSED GtkButton *btn,
TilemScreenshotDialog *ssdlg)
{
TilemAnimation *anim;
if (ssdlg->emu->anim) {
anim = tilem_calc_emulator_end_animation(ssdlg->emu);
set_current_animation(ssdlg, anim);
g_object_unref(anim);
}
else {
set_current_animation(ssdlg, NULL);
}
gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->animation_speed), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->screenshot), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->record), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(ssdlg->stop), FALSE);
}
/* Callback for screenshot button (take a screenshot) */
static void grab_screen(G_GNUC_UNUSED GtkButton *btn,
TilemScreenshotDialog *ssdlg)
{
TilemAnimation *anim;
gboolean grayscale = gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON(ssdlg->grayscale_tb));
anim = tilem_calc_emulator_get_screenshot(ssdlg->emu, grayscale);
ssdlg->current_anim_grayscale = grayscale;
set_current_animation(ssdlg, anim);
g_object_unref(anim);
}