1 /* === S Y N F I G ========================================================= */
2 /*! \file gtkmm/render.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
35 #include <gtkmm/frame.h>
36 #include <gtkmm/alignment.h>
37 #include <synfig/target_scanline.h>
38 #include <synfig/canvas.h>
39 #include "asyncrenderer.h"
40 #include "dialog_targetparam.h"
48 /* === U S I N G =========================================================== */
52 using namespace synfig;
53 using namespace studio;
55 /* === M A C R O S ========================================================= */
57 /* === G L O B A L S ======================================================= */
59 /* === P R O C E D U R E S ================================================= */
61 /* === M E T H O D S ======================================================= */
63 RenderSettings::RenderSettings(Gtk::Window& parent, etl::handle<synfigapp::CanvasInterface> canvas_interface):
64 Gtk::Dialog(_("Render Settings"),parent,false,true),
65 canvas_interface_(canvas_interface),
66 adjustment_quality(3,0,9),
67 entry_quality(adjustment_quality,1,0),
68 adjustment_antialias(1,1,31),
69 entry_antialias(adjustment_antialias,1,0),
70 toggle_single_frame(_("Use _current frame"), true),
73 widget_rend_desc.show();
74 widget_rend_desc.signal_changed().connect(sigc::mem_fun(*this,&studio::RenderSettings::on_rend_desc_changed));
75 widget_rend_desc.set_rend_desc(canvas_interface_->get_canvas()->rend_desc());
77 canvas_interface->signal_rend_desc_changed().connect(sigc::mem_fun(*this,&RenderSettings::on_rend_desc_changed));
79 menu_target=manage(new class Gtk::Menu());
81 menu_target->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Auto"),
82 sigc::bind(sigc::mem_fun(*this,&RenderSettings::set_target),String())
85 synfig::Target::Book::iterator iter;
86 synfig::Target::Book book(synfig::Target::book());
88 for(iter=book.begin();iter!=book.end();iter++)
90 menu_target->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->first,
91 sigc::bind(sigc::mem_fun(*this,&RenderSettings::set_target),iter->first)
94 optionmenu_target.set_menu(*menu_target);
96 optionmenu_target.set_history(0);
98 Gtk::Alignment *dialogPadding = manage(new Gtk::Alignment(0, 0, 1, 1));
99 dialogPadding->set_padding(12, 12, 12, 12);
100 get_vbox()->pack_start(*dialogPadding, false, false, 0);
102 Gtk::VBox *dialogBox = manage(new Gtk::VBox(false, 12));
103 dialogPadding->add(*dialogBox);
105 Gtk::Button *choose_button(manage(new class Gtk::Button(Gtk::StockID(_("Choose...")))));
106 choose_button->show();
107 choose_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_choose_pressed));
109 Gtk::Button *tparam_button(manage(new class Gtk::Button(Gtk::StockID(_("Parameters...")))));
110 tparam_button->show();
111 tparam_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_targetparam_pressed));
113 Gtk::Frame *target_frame=manage(new Gtk::Frame(_("Target")));
114 target_frame->set_shadow_type(Gtk::SHADOW_NONE);
115 ((Gtk::Label *) target_frame->get_label_widget())->set_markup(_("<b>Target</b>"));
116 dialogBox->pack_start(*target_frame);
117 Gtk::Alignment *targetPadding = manage(new Gtk::Alignment(0, 0, 1, 1));
118 targetPadding->set_padding(6, 0, 24, 0);
119 target_frame->add(*targetPadding);
121 Gtk::Table *target_table = manage(new Gtk::Table(2, 3, false));
122 target_table->set_row_spacings(6);
123 target_table->set_col_spacings(12);
124 targetPadding->add(*target_table);
126 Gtk::Label *filenameLabel = manage(new Gtk::Label(_("_Filename"), true));
127 filenameLabel->set_alignment(0, 0.5);
128 filenameLabel->set_mnemonic_widget(entry_filename);
129 target_table->attach(*filenameLabel, 0, 1, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
130 target_table->attach(entry_filename, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
131 target_table->attach(*choose_button, 2, 3, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
133 Gtk::Label *targetLabel = manage(new Gtk::Label(_("_Target"), true));
134 targetLabel->set_alignment(0, 0.5);
135 targetLabel->set_mnemonic_widget(optionmenu_target);
136 target_table->attach(*targetLabel, 0, 1, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
137 target_table->attach(optionmenu_target, 1, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
138 target_table->attach(*tparam_button, 2, 3, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
140 toggle_single_frame.signal_toggled().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_single_frame_toggle));
142 Gtk::Frame *settings_frame=manage(new Gtk::Frame(_("Settings")));
143 settings_frame->set_shadow_type(Gtk::SHADOW_NONE);
144 ((Gtk::Label *) settings_frame->get_label_widget())->set_markup(_("<b>Settings</b>"));
145 dialogBox->pack_start(*settings_frame);
147 Gtk::Alignment *settingsPadding = manage(new Gtk::Alignment(0, 0, 1, 1));
148 settingsPadding->set_padding(6, 0, 24, 0);
149 settings_frame->add(*settingsPadding);
151 Gtk::Table *settings_table=manage(new Gtk::Table(2,2,false));
152 settings_table->set_row_spacings(6);
153 settings_table->set_col_spacings(12);
154 settingsPadding->add(*settings_table);
156 Gtk::Label *qualityLabel = manage(new Gtk::Label(_("_Quality"), true));
157 qualityLabel->set_alignment(0, 0.5);
158 qualityLabel->set_mnemonic_widget(entry_quality);
159 settings_table->attach(*qualityLabel, 0, 1, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
160 settings_table->attach(entry_quality, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
162 Gtk::Label *antiAliasLabel = manage(new Gtk::Label(_("_Anti-Aliasing"), true));
163 antiAliasLabel->set_alignment(0, 0.5);
164 antiAliasLabel->set_mnemonic_widget(entry_antialias);
165 settings_table->attach(*antiAliasLabel, 0, 1, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
166 settings_table->attach(entry_antialias, 1, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
168 toggle_single_frame.set_alignment(0, 0.5);
169 settings_table->attach(toggle_single_frame, 0, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
171 dialogBox->pack_start(widget_rend_desc);
174 Gtk::Button *render_button(manage(new class Gtk::Button(Gtk::StockID(_("Render")))));
175 render_button->show();
176 add_action_widget(*render_button,1);
177 render_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_render_pressed));
179 Gtk::Button *cancel_button(manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))));
180 cancel_button->show();
181 add_action_widget(*cancel_button,0);
182 cancel_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_cancel_pressed));
184 //set_default_response(1);
186 set_title(_("Render Settings")+String(" - ")+canvas_interface_->get_canvas()->get_name());
188 toggle_single_frame.set_active(false);
189 widget_rend_desc.enable_time_section();
191 set_entry_filename();
193 get_vbox()->show_all();
196 RenderSettings::~RenderSettings()
201 RenderSettings::set_entry_filename()
203 String filename(filename_sans_extension(canvas_interface_->get_canvas()->get_file_name()));
205 // if this isn't the root canvas, append (<canvasname>) to the filename
206 etl::handle<synfig::Canvas> canvas = canvas_interface_->get_canvas();
207 if (!canvas->is_root())
209 if(canvas->get_name().empty())
210 filename+=" ("+canvas->get_id()+')';
212 filename+=" ("+canvas->get_name()+')';
219 entry_filename.set_text((filename));
223 synfig::warning("Averted crash!");
224 entry_filename.set_text("output.png");
229 RenderSettings::on_rend_desc_changed()
231 widget_rend_desc.set_rend_desc(canvas_interface_->get_canvas()->rend_desc());
235 RenderSettings::set_target(synfig::String name)
241 RenderSettings::on_choose_pressed()
243 String filename=entry_filename.get_text();
244 if(App::dialog_save_file("Save Render As", filename, RENDER_DIR_PREFERENCE))
245 entry_filename.set_text(filename);
249 RenderSettings::on_targetparam_pressed()
251 Dialog_TargetParam *dialogtp = new Dialog_TargetParam(tparam);
252 if(dialogtp->run()==Gtk::RESPONSE_OK)
253 tparam=dialogtp->get_tparam();
259 RenderSettings::on_render_pressed()
261 String filename=entry_filename.get_text();
262 synfig::String calculated_target_name(target_name);
266 canvas_interface_->get_ui_interface()->error(_("You must supply a filename!"));
270 // If the target type is not yet defined,
271 // try to figure it out from the outfile.
272 if(calculated_target_name.empty())
276 String ext(filename_extension(filename));
277 if (ext.size()) ext=ext.substr(1); // skip initial '.'
278 synfig::info("render target filename: '%s'; extension: '%s'", filename.c_str(), ext.c_str());
279 if(Target::ext_book().count(ext))
281 calculated_target_name=Target::ext_book()[ext];
282 synfig::info("'%s' is a known extension - using target '%s'", ext.c_str(), calculated_target_name.c_str());
286 calculated_target_name=ext;
287 synfig::info("unknown extension");
290 catch(std::runtime_error x)
292 canvas_interface_->get_ui_interface()->error(_("Unable to determine proper target from filename."));
297 if(filename.empty() && calculated_target_name!="null")
299 canvas_interface_->get_ui_interface()->error(_("A filename is required for this target"));
303 Target::Handle target=Target::create(calculated_target_name,filename, tparam);
306 canvas_interface_->get_ui_interface()->error(_("Unable to create target for ")+filename);
309 // This is the only way I've found to avoid send a non writable
310 // filename path to the renderer.
311 fstream filetest (filename.c_str(), fstream::out);
314 canvas_interface_->get_ui_interface()->error(_("Unable to create file for ")+filename);
320 target->set_canvas(canvas_interface_->get_canvas());
321 RendDesc rend_desc(widget_rend_desc.get_rend_desc());
322 rend_desc.set_antialias((int)adjustment_antialias.get_value());
324 // If we are to only render the current frame
325 if(toggle_single_frame.get_active())
326 rend_desc.set_time(canvas_interface_->get_time());
328 target->set_rend_desc(&rend_desc);
329 target->set_quality((int)adjustment_quality.get_value());
330 if( !target->init() ){
331 canvas_interface_->get_ui_interface()->error(_("Target initialization failure"));
335 canvas_interface_->get_ui_interface()->task(_("Rendering ")+filename);
339 async_renderer->stop();
340 async_renderer.detach();
342 async_renderer=new AsyncRenderer(target);
343 async_renderer->signal_finished().connect( sigc::mem_fun(*this,&RenderSettings::on_finished));
344 async_renderer->start();
346 if(!target->render(canvas_interface_->get_ui_interface().get()))
348 canvas_interface_->get_ui_interface()->error(_("Render Failure"));
349 canvas_interface_->get_ui_interface()->amount_complete(0,10000);
354 canvas_interface_->get_ui_interface()->task(filename+_(" rendered successfully"));
355 canvas_interface_->get_ui_interface()->amount_complete(0,10000);
361 RenderSettings::on_finished()
363 canvas_interface_->get_ui_interface()->task(_("File rendered successfully"));
364 canvas_interface_->get_ui_interface()->amount_complete(0,10000);
368 RenderSettings::on_cancel_pressed()
374 RenderSettings::on_single_frame_toggle()
376 if(toggle_single_frame.get_active())
377 widget_rend_desc.disable_time_section();
379 widget_rend_desc.enable_time_section();