diff --git a/synfig-studio/src/gui/app.cpp b/synfig-studio/src/gui/app.cpp index 23e965b..c8f1a6c 100644 --- a/synfig-studio/src/gui/app.cpp +++ b/synfig-studio/src/gui/app.cpp @@ -1,4 +1,4 @@ -// /* === S Y N F I G ========================================================= */ +/* === S Y N F I G ========================================================= */ /*! \file app.cpp ** \brief writeme ** @@ -954,6 +954,7 @@ DEFINE_ACTION("save-as", Gtk::StockID("synfig-save_as")); DEFINE_ACTION("save-all", Gtk::StockID("synfig-save_all")); DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED); DEFINE_ACTION("import", _("Import...")); +DEFINE_ACTION("import-sequence",_("Import Sequence...")); DEFINE_ACTION("render", _("Render...")); DEFINE_ACTION("preview", _("Preview...")); DEFINE_ACTION("close-document", _("Close Document")); @@ -1092,6 +1093,7 @@ DEFINE_ACTION("keyframe-properties", _("Properties")); " " " " " " +" " " " " " " " @@ -2608,7 +2610,6 @@ App::dialog_open_file(const std::string &title, std::string &filename, std::stri #endif // not USE_WIN32_FILE_DIALOGS } - bool App::dialog_open_file_spal(const std::string &title, std::string &filename, std::string preference) { @@ -2816,6 +2817,66 @@ App::dialog_open_file_audio(const std::string &title, std::string &filename, std return false; } +bool +App::dialog_open_file_image_sequence(const std::string &title, std::set &filenames, std::string preference) +{ + synfig::String prev_path; + + if(!_preferences.get_value(preference, prev_path)) + prev_path = Glib::get_home_dir(); + + prev_path = absolute_path(prev_path); + + Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(*App::main_window, + title, Gtk::FILE_CHOOSER_ACTION_OPEN); + + dialog->set_transient_for(*App::main_window); + dialog->set_current_folder(prev_path); + dialog->set_select_multiple(true); + dialog->add_button(_("Cancel"), Gtk::RESPONSE_CANCEL)->set_image_from_icon_name("gtk-cancel", Gtk::ICON_SIZE_BUTTON); + dialog->add_button(_("Load"), Gtk::RESPONSE_ACCEPT)->set_image_from_icon_name("gtk-open", Gtk::ICON_SIZE_BUTTON); + + // show only images + Glib::RefPtr filter_image = Gtk::FileFilter::create(); + filter_image->set_name(_("Images files (*.png, *.jpg, *.jpeg, *.bmp)")); + filter_image->add_mime_type("image/png"); + filter_image->add_mime_type("image/jpeg"); + filter_image->add_mime_type("image/jpg"); + filter_image->add_mime_type("image/bmp"); + filter_image->add_mime_type("image/svg+xml"); + filter_image->add_pattern("*.png"); + filter_image->add_pattern("*.jpeg"); + filter_image->add_pattern("*.jpg"); + filter_image->add_pattern("*.bmp"); + dialog->add_filter(filter_image); + + // Any files + Glib::RefPtr filter_any = Gtk::FileFilter::create(); + filter_any->set_name(_("Any files")); + filter_any->add_pattern("*"); + dialog->add_filter(filter_any); + + std::string filename = filenames.empty() ? std::string() : *filenames.begin(); + if (filename.empty()) + dialog->set_filename(prev_path); + else if (is_absolute_path(filename)) + dialog->set_filename(filename); + else + dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename); + + filenames.clear(); + if(dialog->run() == GTK_RESPONSE_ACCEPT) { + std::vector files = dialog->get_filenames(); + filenames.insert(files.begin(), files.end()); + _preferences.set_value(preference, dirname(dialog->get_filename())); + delete dialog; + return true; + } + + delete dialog; + return false; +} + void on_open_dialog_with_history_selection_changed(Gtk::FileChooserDialog *dialog, Gtk::Button* history_button) { diff --git a/synfig-studio/src/gui/app.h b/synfig-studio/src/gui/app.h index dec1304..44fc661 100644 --- a/synfig-studio/src/gui/app.h +++ b/synfig-studio/src/gui/app.h @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -412,6 +413,7 @@ public: static bool dialog_save_file_spal(const std::string &title, std::string &filename, std::string preference); static bool dialog_save_file_sketch(const std::string &title, std::string &filename, std::string preference); static bool dialog_save_file_render(const std::string &title, std::string &filename, std::string preference); + static bool dialog_open_file_image_sequence(const std::string &title, std::set &filenames, std::string preference); static bool dialog_select_list_item(const std::string &title, const std::string &message, const std::list &list, int &item_index); diff --git a/synfig-studio/src/gui/asyncrenderer.cpp b/synfig-studio/src/gui/asyncrenderer.cpp index f13c38c..e729954 100644 --- a/synfig-studio/src/gui/asyncrenderer.cpp +++ b/synfig-studio/src/gui/asyncrenderer.cpp @@ -124,7 +124,7 @@ public: ContextParams context_params, RectInt rect, RendDesc tile_desc, - ProgressCallback *cb ) + ProgressCallback */*cb*/ ) { if(!alive_flag) return false; diff --git a/synfig-studio/src/gui/canvasview.cpp b/synfig-studio/src/gui/canvasview.cpp index 4b6dc5c..daad0fc 100644 --- a/synfig-studio/src/gui/canvasview.cpp +++ b/synfig-studio/src/gui/canvasview.cpp @@ -1437,6 +1437,9 @@ CanvasView::init_menus() action_group->add( Gtk::Action::create("import", _("Import...")), sigc::hide_return(sigc::mem_fun(*this, &CanvasView::image_import)) ); + action_group->add( Gtk::Action::create("import-sequence", _("Import Sequence...")), + sigc::hide_return(sigc::mem_fun(*this, &CanvasView::squence_import)) + ); action_group->add( Gtk::Action::create("render", Gtk::StockID("synfig-render_options"), _("Render...")), sigc::mem_fun0(render_settings,&RenderSettings::present) ); @@ -3430,7 +3433,36 @@ CanvasView::image_import() if(App::dialog_open_file(_("Please select a file"), filename, IMAGE_DIR_PREFERENCE)) { canvas_interface()->import(filename, errors, warnings, App::resize_imported_images); - if (warnings != "") + if (!errors.empty()) + App::dialog_message_1b( + "ERROR", + etl::strprintf("%s:\n\n%s", _("Error"), errors.c_str()), + "details", + _("Close")); + if (!warnings.empty()) + App::dialog_message_1b( + "WARNING", + etl::strprintf("%s:\n\n%s", _("Warning"), warnings.c_str()), + "details", + _("Close")); + } +} + +void +CanvasView::squence_import() +{ + std::set filenames; + String errors, warnings; + if(App::dialog_open_file_image_sequence(_("Please select a files"), filenames, IMAGE_DIR_PREFERENCE)) + { + canvas_interface()->import_sequence(filenames, errors, warnings, App::resize_imported_images); + if (!errors.empty()) + App::dialog_message_1b( + "ERROR", + etl::strprintf("%s:\n\n%s", _("Error"), errors.c_str()), + "details", + _("Close")); + if (!warnings.empty()) App::dialog_message_1b( "WARNING", etl::strprintf("%s:\n\n%s", _("Warning"), warnings.c_str()), diff --git a/synfig-studio/src/gui/canvasview.h b/synfig-studio/src/gui/canvasview.h index 2451d4b..4196908 100644 --- a/synfig-studio/src/gui/canvasview.h +++ b/synfig-studio/src/gui/canvasview.h @@ -645,6 +645,7 @@ public: void on_keyframe_description_set(); void image_import(); + void squence_import(); void on_waypoint_clicked_canvasview(synfigapp::ValueDesc,std::set >, int button); diff --git a/synfig-studio/src/synfigapp/canvasinterface.cpp b/synfig-studio/src/synfigapp/canvasinterface.cpp index be5f9c5..6a3447b 100644 --- a/synfig-studio/src/synfigapp/canvasinterface.cpp +++ b/synfig-studio/src/synfigapp/canvasinterface.cpp @@ -692,11 +692,15 @@ CanvasInterface::jump_to_prev_keyframe() } bool -CanvasInterface::import(const synfig::String &filename, synfig::String &errors, synfig::String &warnings, bool resize_image) +CanvasInterface::import( + const synfig::String &filename, + synfig::String &errors, + synfig::String &warnings, + bool resize_image ) { Action::PassiveGrouper group(get_instance().get(),_("Import")); - synfig::info("Attempting to import " + filename); + synfig::info("Attempting to import %s", filename.c_str()); String ext(filename_extension(filename)); //if (filename_extension(filename) == "") @@ -939,6 +943,197 @@ CanvasInterface::import(const synfig::String &filename, synfig::String &errors, } +bool +CanvasInterface::import_sequence( + const std::set &filenames, + synfig::String &errors, + synfig::String &/*warnings*/, + bool resize_image ) +{ + Action::PassiveGrouper group(get_instance().get(),_("Import sequence")); + + synfig::info("Attempting to import sequence"); + Layer::Handle layer_switch; + try { + // add imported layers into switch + Action::Handle action(Action::create("LayerEncapsulateSwitch")); + if(!action) + { get_ui_interface()->error(_("Cannot create action")); throw int(); } + action->set_param("canvas",get_canvas()); + action->set_param("canvas_interface",etl::loose_handle(this)); + + Layer::Handle layer; + int layers_count = 0; + for(std::set::const_iterator i = filenames.begin(); i != filenames.end(); ++i) { + const String &filename = *i; + synfig::info("Attempting to import '%s' into sequence", filename.c_str()); + + String ext(filename_extension(filename)); + if (!ext.empty()) ext = ext.substr(1); // skip initial '.' + std::transform(ext.begin(),ext.end(),ext.begin(),&::tolower); + + if (ext.empty()) + { + errors += etl::strprintf(_("Cannot import file witout extension: %s\n"), filename.c_str()); + continue; + } + + if(!Importer::book().count(ext)) + { + errors += etl::strprintf(_("Cannot import file of type '%s': %s\n"), ext.c_str(), filename.c_str()); + continue; + } + + String short_filename = CanvasFileNaming::make_short_filename(get_canvas()->get_file_name(), filename); + + try { + layer = add_layer_to("Import",get_canvas()); + int w, h; + if (!layer) + throw int(); + if (!layer->set_param("filename", ValueBase(short_filename))) + throw int(); + w = layer->get_param("_width").get(int()); + h = layer->get_param("_height").get(int()); + layer->monitor(filename); + if (w && h) { + Vector x, size = get_canvas()->rend_desc().get_br()-get_canvas()->rend_desc().get_tl(); + // vector from top left of canvas to bottom right + if (resize_image) { + if(abs(size[0])set_param("tl",ValueBase(-x/2))) + throw int(); + if(!layer->set_param("br",ValueBase(x/2))) + throw int(); + } else { + if(!layer->set_param("tl",ValueBase(get_canvas()->rend_desc().get_tl()))) + throw int(); + if(!layer->set_param("br",ValueBase(get_canvas()->rend_desc().get_br()))) + throw int(); + } + + String desc = etl::basename(filename); + layer->set_description(desc); + signal_layer_new_description()(layer, desc); + + action->set_param("layer", layer); + if (!layers_count) + action->set_param("description", desc); + ++layers_count; + } catch(...) { + errors += etl::strprintf(_("Unable to import file: %s"), filename.c_str()); + group.cancel(); + return false; + } + } + + if (!layers_count) + { get_ui_interface()->error(_("Nothing imported")); throw int(); } + if(!action->is_ready()) + { get_ui_interface()->error(_("Action Not Ready")); throw int(); } + if(!get_instance()->perform_action(action)) + { get_ui_interface()->error(_("Action Failed.")); throw int(); } + + if (layer) { + Layer::Handle layer_switch = layer->get_parent_paste_canvas_layer(); // get parent layer, because image is incapsulated into action switch + + action = Action::create("ValueDescSet"); + if(!action) + { get_ui_interface()->error(_("Cannot create action")); throw int(); } + action->set_param("canvas", get_canvas()); + action->set_param("canvas_interface", etl::loose_handle(this)); + action->set_param("value_desc", ValueDesc(layer_switch, "layer_name")); + action->set_param("new_value", ValueBase(String())); + if(!action->is_ready()) + { get_ui_interface()->error(_("Action Not Ready")); throw int(); } + if(!get_instance()->perform_action(action)) + { get_ui_interface()->error(_("Action Failed.")); throw int(); } + + action = Action::create("ValueDescSet"); + if(!action) + { get_ui_interface()->error(_("Cannot create action")); throw int(); } + action->set_param("canvas", get_canvas()); + action->set_param("canvas_interface", etl::loose_handle(this)); + action->set_param("value_desc", ValueDesc(layer_switch, "layer_depth")); + action->set_param("new_value", ValueBase(int(0))); + if(!action->is_ready()) + { get_ui_interface()->error(_("Action Not Ready")); throw int(); } + if(!get_instance()->perform_action(action)) + { get_ui_interface()->error(_("Action Failed.")); throw int(); } + + action = Action::create("ValueDescConvert"); + if(!action) + { get_ui_interface()->error(_("Cannot create action")); throw int(); } + action->set_param("canvas", get_canvas()); + action->set_param("canvas_interface", etl::loose_handle(this)); + action->set_param("value_desc", ValueDesc(layer_switch, "layer_depth")); + action->set_param("type", "fromreal"); + action->set_param("time", get_time()); + if(!action->is_ready()) + { get_ui_interface()->error(_("Action Not Ready")); throw int(); } + if(!get_instance()->perform_action(action)) + { get_ui_interface()->error(_("Action Failed.")); throw int(); } + + Layer::DynamicParamList::const_iterator i = layer_switch->dynamic_param_list().find("layer_depth"); + if (i == layer_switch->dynamic_param_list().end()) + { get_ui_interface()->error(_("Dynamic param not found.")); throw int(); } + LinkableValueNode::Handle valuenode_real = LinkableValueNode::Handle::cast_dynamic(i->second); + + action = Action::create("ValueDescConvert"); + if(!action) + { get_ui_interface()->error(_("Cannot create action")); throw int(); } + action->set_param("canvas", get_canvas()); + action->set_param("canvas_interface", etl::loose_handle(this)); + action->set_param("value_desc", ValueDesc(valuenode_real, valuenode_real->get_link_index_from_name("link"))); + action->set_param("type", "linear"); + action->set_param("time", get_time()); + if(!action->is_ready()) + { get_ui_interface()->error(_("Action Not Ready")); throw int(); } + if(!get_instance()->perform_action(action)) + { get_ui_interface()->error(_("Action Failed.")); throw int(); } + + LinkableValueNode::Handle valuenode_linear = LinkableValueNode::Handle::cast_dynamic(valuenode_real->get_link("link")); + + action = Action::create("ValueDescSet"); + if(!action) + { get_ui_interface()->error(_("Cannot create action")); throw int(); } + action->set_param("canvas", get_canvas()); + action->set_param("canvas_interface", etl::loose_handle(this)); + action->set_param("value_desc", ValueDesc(valuenode_linear, valuenode_linear->get_link_index_from_name("slope"))); + action->set_param("new_value", ValueBase(Real(1))); + if(!action->is_ready()) + { get_ui_interface()->error(_("Action Not Ready")); throw int(); } + if(!get_instance()->perform_action(action)) + { get_ui_interface()->error(_("Action Failed.")); throw int(); } + } + } catch(...) { + get_ui_interface()->error("Unable to import sequence"); + group.cancel(); + return false; + } + + get_selection_manager()->clear_selected_layers(); + if (layer_switch) + get_selection_manager()->set_selected_layer(layer_switch); + return true; +} + + void CanvasInterface::waypoint_duplicate(synfigapp::ValueDesc value_desc,synfig::Waypoint waypoint) { diff --git a/synfig-studio/src/synfigapp/canvasinterface.h b/synfig-studio/src/synfigapp/canvasinterface.h index 10e130a..43b5928 100644 --- a/synfig-studio/src/synfigapp/canvasinterface.h +++ b/synfig-studio/src/synfigapp/canvasinterface.h @@ -28,10 +28,14 @@ /* === H E A D E R S ======================================================= */ +#include +#include + +#include + //#include #include -#include -#include + #include "selectionmanager.h" #include "uimanager.h" #include "value_desc.h" @@ -298,7 +302,17 @@ public: void set_rend_desc(const synfig::RendDesc &rend_desc); - bool import(const synfig::String &filename, synfig::String &errors, synfig::String &warnings, bool resize_image=false); + bool import( + const synfig::String &filename, + synfig::String &errors, + synfig::String &warnings, + bool resize_image = false ); + + bool import_sequence( + const std::set &filenames, + synfig::String &errors, + synfig::String &warnings, + bool resize_image = false ); void waypoint_duplicate(synfigapp::ValueDesc value_desc,synfig::Waypoint waypoint);