/* * 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); }