Fixed 1799250: Add a function to update the render filename from the document filenam...
[synfig.git] / synfig-studio / trunk / src / gtkmm / render.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file gtkmm/render.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "render.h"
33 #include "app.h"
34 #include <gtkmm/frame.h>
35 #include <gtkmm/alignment.h>
36 #include <synfig/target_scanline.h>
37 #include <synfig/canvas.h>
38 #include "asyncrenderer.h"
39
40 #endif
41
42 /* === U S I N G =========================================================== */
43
44 using namespace std;
45 using namespace etl;
46 using namespace synfig;
47 using namespace studio;
48
49 /* === M A C R O S ========================================================= */
50
51 /* === G L O B A L S ======================================================= */
52
53 /* === P R O C E D U R E S ================================================= */
54
55 /* === M E T H O D S ======================================================= */
56
57 RenderSettings::RenderSettings(Gtk::Window& parent,handle<synfigapp::CanvasInterface> canvas_interface):
58         Gtk::Dialog(_("Render Settings"),parent,false,true),
59         canvas_interface_(canvas_interface),
60         adjustment_quality(3,0,9),
61         entry_quality(adjustment_quality,1,0),
62         adjustment_antialias(1,1,31),
63         entry_antialias(adjustment_antialias,1,0),
64         toggle_single_frame(_("Use _current frame"), true)
65 {
66         widget_rend_desc.show();
67         widget_rend_desc.signal_changed().connect(sigc::mem_fun(*this,&studio::RenderSettings::on_rend_desc_changed));
68         widget_rend_desc.set_rend_desc(canvas_interface_->get_canvas()->rend_desc());
69
70         canvas_interface->signal_rend_desc_changed().connect(sigc::mem_fun(*this,&RenderSettings::on_rend_desc_changed));
71
72         menu_target=manage(new class Gtk::Menu());
73
74         menu_target->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Auto"),
75                         sigc::bind(sigc::mem_fun(*this,&RenderSettings::set_target),String())
76                 ));
77
78         synfig::Target::Book::iterator iter;
79         synfig::Target::Book book(synfig::Target::book());
80
81         for(iter=book.begin();iter!=book.end();iter++)
82         {
83                 menu_target->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->first,
84                         sigc::bind(sigc::mem_fun(*this,&RenderSettings::set_target),iter->first)
85                 ));
86         }
87         optionmenu_target.set_menu(*menu_target);
88
89         optionmenu_target.set_history(0);
90
91         Gtk::Alignment *dialogPadding = manage(new Gtk::Alignment(0, 0, 1, 1));
92         dialogPadding->set_padding(12, 12, 12, 12);
93         get_vbox()->pack_start(*dialogPadding, false, false, 0);
94
95         Gtk::VBox *dialogBox = manage(new Gtk::VBox(false, 12));
96         dialogPadding->add(*dialogBox);
97
98         Gtk::Button *choose_button(manage(new class Gtk::Button(Gtk::StockID(_("Choose...")))));
99         choose_button->show();
100         choose_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_choose_pressed));
101
102         Gtk::Frame *target_frame=manage(new Gtk::Frame(_("Target")));
103         target_frame->set_shadow_type(Gtk::SHADOW_NONE);
104         ((Gtk::Label *) target_frame->get_label_widget())->set_markup(_("<b>Target</b>"));
105         dialogBox->pack_start(*target_frame);
106         Gtk::Alignment *targetPadding = manage(new Gtk::Alignment(0, 0, 1, 1));
107         targetPadding->set_padding(6, 0, 24, 0);
108         target_frame->add(*targetPadding);
109
110         Gtk::Table *target_table = manage(new Gtk::Table(2, 3, false));
111         target_table->set_row_spacings(6);
112         target_table->set_col_spacings(12);
113         targetPadding->add(*target_table);
114
115         Gtk::Label *filenameLabel = manage(new Gtk::Label(_("_Filename"), true));
116         filenameLabel->set_alignment(0, 0.5);
117         filenameLabel->set_mnemonic_widget(entry_filename);
118         target_table->attach(*filenameLabel, 0, 1, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
119         target_table->attach(entry_filename, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
120         target_table->attach(*choose_button, 2, 3, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
121
122         Gtk::Label *targetLabel = manage(new Gtk::Label(_("_Target"), true));
123         targetLabel->set_alignment(0, 0.5);
124         targetLabel->set_mnemonic_widget(optionmenu_target);
125         target_table->attach(*targetLabel, 0, 1, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
126         target_table->attach(optionmenu_target, 1, 3, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
127
128         toggle_single_frame.signal_toggled().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_single_frame_toggle));
129
130         Gtk::Frame *settings_frame=manage(new Gtk::Frame(_("Settings")));
131         settings_frame->set_shadow_type(Gtk::SHADOW_NONE);
132         ((Gtk::Label *) settings_frame->get_label_widget())->set_markup(_("<b>Settings</b>"));
133         dialogBox->pack_start(*settings_frame);
134
135         Gtk::Alignment *settingsPadding = manage(new Gtk::Alignment(0, 0, 1, 1));
136         settingsPadding->set_padding(6, 0, 24, 0);
137         settings_frame->add(*settingsPadding);
138
139         Gtk::Table *settings_table=manage(new Gtk::Table(2,2,false));
140         settings_table->set_row_spacings(6);
141         settings_table->set_col_spacings(12);
142         settingsPadding->add(*settings_table);
143
144         Gtk::Label *qualityLabel = manage(new Gtk::Label(_("_Quality"), true));
145         qualityLabel->set_alignment(0, 0.5);
146         qualityLabel->set_mnemonic_widget(entry_quality);
147         settings_table->attach(*qualityLabel, 0, 1, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
148         settings_table->attach(entry_quality, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
149
150         Gtk::Label *antiAliasLabel = manage(new Gtk::Label(_("_Anti-Aliasing"), true));
151         antiAliasLabel->set_alignment(0, 0.5);
152         antiAliasLabel->set_mnemonic_widget(entry_antialias);
153         settings_table->attach(*antiAliasLabel, 0, 1, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
154         settings_table->attach(entry_antialias, 1, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
155
156         toggle_single_frame.set_alignment(0, 0.5);
157         settings_table->attach(toggle_single_frame, 0, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
158
159         dialogBox->pack_start(widget_rend_desc);
160
161
162         Gtk::Button *render_button(manage(new class Gtk::Button(Gtk::StockID("Render"))));
163         render_button->show();
164         add_action_widget(*render_button,1);
165         render_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_render_pressed));
166
167         Gtk::Button *cancel_button(manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))));
168         cancel_button->show();
169         add_action_widget(*cancel_button,0);
170         cancel_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_cancel_pressed));
171
172         //set_default_response(1);
173
174         set_title(_("Render Settings")+String(" - ")+canvas_interface_->get_canvas()->get_name());
175
176
177         toggle_single_frame.set_active(true);
178         widget_rend_desc.disable_time_section();
179
180         set_entry_filename();
181
182         get_vbox()->show_all();
183 }
184
185 RenderSettings::~RenderSettings()
186 {
187 }
188
189 void
190 RenderSettings::set_entry_filename()
191 {
192         String filename(canvas_interface_->get_canvas()->get_file_name());
193
194         // if the basename of the filename has an extension, remove it
195         String base = basename(filename);
196         if(find(base.begin(),base.end(),'.')!=base.end())
197                 filename = String(filename.begin(), filename.begin()+filename.find_last_of('.'));
198
199         // if this isn't the root canvas, append (<canvasname>) to the filename
200         etl::handle<synfig::Canvas> canvas = canvas_interface_->get_canvas();
201         if (!canvas->is_root())
202                 if(canvas->get_name().empty())
203                         filename+=" ("+canvas->get_id()+')';
204                 else
205                         filename+=" ("+canvas->get_name()+')';
206
207         filename += ".png";
208
209         try
210         {
211                 entry_filename.set_text((filename));
212         }
213         catch(...)
214         {
215                 synfig::warning("Averted crash!");
216                 entry_filename.set_text("output.png");
217         }
218 }
219
220 void
221 RenderSettings::on_rend_desc_changed()
222 {
223         widget_rend_desc.set_rend_desc(canvas_interface_->get_canvas()->rend_desc());
224 }
225
226 void
227 RenderSettings::set_target(synfig::String name)
228 {
229         target_name=name;
230 }
231
232 void
233 RenderSettings::on_choose_pressed()
234 {
235         String filename=entry_filename.get_text();
236         if(App::dialog_save_file("Save Render As",filename))
237                 entry_filename.set_text(filename);
238 }
239
240 void
241 RenderSettings::on_render_pressed()
242 {
243         String filename=entry_filename.get_text();
244
245         if(filename.empty())
246         {
247                 canvas_interface_->get_ui_interface()->error(_("You must supply a filename!"));
248                 return;
249         }
250
251         // If the target type is not yet defined,
252         // try to figure it out from the outfile.
253         if(target_name.empty())
254         {
255                 try
256                 {
257                         String ext=String(find(filename.begin(),filename.end(),'.')+1,filename.end());
258                         if(Target::ext_book().count(ext))
259                                 target_name=Target::ext_book()[ext];
260                         else
261                                 target_name=ext;
262                 }
263                 catch(std::runtime_error x)
264                 {
265                         canvas_interface_->get_ui_interface()->error(_("Unable to determine proper target from filename."));
266                         return;
267                 }
268         }
269
270         if(filename.empty() && target_name!="null")
271         {
272                 canvas_interface_->get_ui_interface()->error(_("A filename is required for this target"));
273                 return;
274         }
275
276         Target::Handle target=Target::create(target_name,filename);
277         if(!target)
278         {
279                 canvas_interface_->get_ui_interface()->error(_("Unable to create target for ")+filename);
280                 return;
281         }
282
283         hide();
284
285         target->set_canvas(canvas_interface_->get_canvas());
286         RendDesc rend_desc(widget_rend_desc.get_rend_desc());
287         rend_desc.set_antialias((int)adjustment_antialias.get_value());
288
289         // If we are to only render the current frame
290         if(toggle_single_frame.get_active())
291                 rend_desc.set_time(canvas_interface_->get_time());
292
293         target->set_rend_desc(&rend_desc);
294         target->set_quality((int)adjustment_quality.get_value());
295         if( !target->init() ){
296                 canvas_interface_->get_ui_interface()->error(_("Target initialisation failure"));
297                 return;
298         }
299
300         canvas_interface_->get_ui_interface()->task(_("Rendering ")+filename);
301
302         if(async_renderer)
303         {
304                 async_renderer->stop();
305                 async_renderer.detach();
306         }
307         async_renderer=new AsyncRenderer(target);
308         async_renderer->signal_finished().connect( sigc::mem_fun(*this,&RenderSettings::on_finished));
309         async_renderer->start();
310         /*
311         if(!target->render(canvas_interface_->get_ui_interface().get()))
312         {
313                 canvas_interface_->get_ui_interface()->error(_("Render Failure"));
314                 canvas_interface_->get_ui_interface()->amount_complete(0,10000);
315                 return;
316         }
317
318         // Success!
319         canvas_interface_->get_ui_interface()->task(filename+_(" rendered successfully"));
320         canvas_interface_->get_ui_interface()->amount_complete(0,10000);
321         */
322         return;
323 }
324
325 void
326 RenderSettings::on_finished()
327 {
328         canvas_interface_->get_ui_interface()->task(_("File rendered successfully"));
329         canvas_interface_->get_ui_interface()->amount_complete(0,10000);
330 }
331
332 void
333 RenderSettings::on_cancel_pressed()
334 {
335         hide();
336 }
337
338 void
339 RenderSettings::on_single_frame_toggle()
340 {
341         if(toggle_single_frame.get_active())
342                 widget_rend_desc.disable_time_section();
343         else
344                 widget_rend_desc.enable_time_section();
345 }