811 lines
26 KiB
C
811 lines
26 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <gtk/gtk.h>
|
|
#include <glib/gstdio.h>
|
|
#include <ticalcs.h>
|
|
#include <tilem.h>
|
|
|
|
#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);
|
|
}
|
|
|