1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2008 Gerald Young
11 ** Copyright (c) 2008 Carlos López
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
24 /* ========================================================================= */
26 /* === H E A D E R S ======================================================= */
45 #ifdef HAVE_SYS_ERRNO_H
46 #include <sys/errno.h>
48 #include <gtkmm/fileselection.h>
49 #include <gtkmm/dialog.h>
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/label.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/stockitem.h>
54 #include <gtkmm/iconsource.h>
55 #include <gtkmm/inputdialog.h>
56 #include <gtkmm/accelmap.h>
57 #include <gtkmm/uimanager.h>
58 #include <gtkmm/textview.h>
60 #include <gdkmm/general.h>
62 #include <synfig/loadcanvas.h>
63 #include <synfig/savecanvas.h>
69 #include "canvasview.h"
70 #include "dialog_setup.h"
71 #include "dialog_gradient.h"
72 #include "dialog_color.h"
75 #include "onemoment.h"
77 #include "dockmanager.h"
79 #include "state_eyedrop.h"
80 #include "state_normal.h"
81 #include "state_draw.h"
82 #include "state_fill.h"
83 #include "state_bline.h"
84 #include "state_polygon.h"
85 #include "state_sketch.h"
86 #include "state_gradient.h"
87 #include "state_circle.h"
88 #include "state_rectangle.h"
89 #include "state_smoothmove.h"
90 #include "state_scale.h"
91 #include "state_star.h"
92 #include "state_text.h"
93 #include "state_width.h"
94 #include "state_rotate.h"
95 #include "state_zoom.h"
97 #include "devicetracker.h"
98 #include "dialog_tooloptions.h"
99 #include "widget_enum.h"
101 #include "autorecover.h"
103 #include <synfigapp/settings.h>
104 #include "dock_history.h"
105 #include "dock_canvases.h"
106 #include "dock_keyframes.h"
107 #include "dock_layers.h"
108 #include "dock_params.h"
109 #include "dock_metadata.h"
110 #include "dock_children.h"
111 #include "dock_info.h"
112 #include "dock_navigator.h"
113 #include "dock_layergroups.h"
114 #include "dock_timetrack.h"
115 #include "dock_curves.h"
117 #include "mod_palette/mod_palette.h"
118 #include "mod_mirror/mod_mirror.h"
120 #include <sys/stat.h>
126 #include "statemanager.h"
132 #include <gtkmm/accelmap.h>
133 #include <gtkmm/filechooser.h>
134 #include <gtkmm/filechooserdialog.h>
140 /* === U S I N G =========================================================== */
144 using namespace synfig;
145 using namespace studio;
147 /* === M A C R O S ========================================================= */
149 #ifndef SYNFIG_USER_APP_DIR
151 #define SYNFIG_USER_APP_DIR "Library/Synfig"
152 #elif defined(_WIN32)
153 #define SYNFIG_USER_APP_DIR "Synfig"
155 #define SYNFIG_USER_APP_DIR ".synfig"
160 #define DPM2DPI(x) (float(x)/39.3700787402f)
161 #define DPI2DPM(x) (float(x)*39.3700787402f)
167 # define IMAGE_DIR "share\\pixmaps"
172 # define IMAGE_DIR "/usr/local/share/pixmaps"
176 # define IMAGE_EXT "tif"
179 #include <synfigapp/main.h>
181 /* === S I G N A L S ======================================================= */
183 static sigc::signal<void> signal_present_all_;
185 App::signal_present_all() { return signal_present_all_; }
187 static sigc::signal<void> signal_recent_files_changed_;
189 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
191 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
192 sigc::signal<void,etl::loose_handle<CanvasView> >&
193 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
195 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
196 sigc::signal<void,etl::handle<Instance> >&
197 App::signal_instance_selected() { return signal_instance_selected_; }
199 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
200 sigc::signal<void,etl::handle<Instance> >&
201 App::signal_instance_created() { return signal_instance_created_; }
203 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
204 sigc::signal<void,etl::handle<Instance> >&
205 App::signal_instance_deleted() { return signal_instance_deleted_; }
207 /* === G L O B A L S ======================================================= */
209 static std::list<std::string> recent_files;
210 const std::list<std::string>& App::get_recent_files() { return recent_files; }
212 static std::list<std::string> recent_files_window_size;
214 int App::Busy::count;
215 bool App::shutdown_in_progress;
217 synfig::Gamma App::gamma;
219 Glib::RefPtr<studio::UIManager> App::ui_manager_;
221 synfig::Distance::System App::distance_system;
223 studio::Dialog_Setup* App::dialog_setup;
225 etl::handle< studio::ModPalette > mod_palette_;
226 //studio::Dialog_Palette* App::dialog_palette;
228 std::list<etl::handle<Instance> > App::instance_list;
230 static etl::handle<synfigapp::UIInterface> ui_interface_;
231 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
233 etl::handle<Instance> App::selected_instance;
234 etl::handle<CanvasView> App::selected_canvas_view;
236 studio::About *studio::App::about=NULL;
238 studio::Toolbox *studio::App::toolbox=NULL;
240 studio::AutoRecover *studio::App::auto_recover=NULL;
242 studio::IPC *ipc=NULL;
244 studio::DockManager* studio::App::dock_manager=0;
246 studio::DeviceTracker* studio::App::device_tracker=0;
248 studio::Dialog_Gradient* studio::App::dialog_gradient;
250 studio::Dialog_Color* studio::App::dialog_color;
252 Gtk::InputDialog* studio::App::dialog_input;
254 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
256 studio::Dock_History* dock_history;
257 studio::Dock_Canvases* dock_canvases;
258 studio::Dock_Keyframes* dock_keyframes;
259 studio::Dock_Layers* dock_layers;
260 studio::Dock_Params* dock_params;
261 studio::Dock_MetaData* dock_meta_data;
262 studio::Dock_Children* dock_children;
263 studio::Dock_Info* dock_info;
264 studio::Dock_LayerGroups* dock_layer_groups;
265 studio::Dock_Navigator* dock_navigator;
266 studio::Dock_Timetrack* dock_timetrack;
267 studio::Dock_Curves* dock_curves;
269 std::list< etl::handle< studio::Module > > module_list_;
271 bool studio::App::use_colorspace_gamma=true;
272 #ifdef SINGLE_THREADED
273 bool studio::App::single_threaded=false;
275 bool studio::App::restrict_radius_ducks=false;
276 bool studio::App::resize_imported_images=false;
277 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
278 int studio::App::preferred_x_size=480;
279 int studio::App::preferred_y_size=270;
280 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
281 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
282 float studio::App::preferred_fps=24.0;
283 #ifdef USE_OPEN_FOR_URLS
284 String studio::App::browser_command("open"); // MacOS only
286 String studio::App::browser_command("xdg-open"); // Linux XDG standard
289 static int max_recent_files_=25;
290 int studio::App::get_max_recent_files() { return max_recent_files_; }
291 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
293 static synfig::String app_base_path_;
298 really_delete_widget(Gtk::Widget *widget)
300 // synfig::info("really delete %p", (void*)widget);
305 // nasty workaround - when we've finished with a popup menu, we want to delete it
306 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
307 // so schedule the real delete to happen in 50ms, giving the action a chance to run
309 delete_widget(Gtk::Widget *widget)
311 // synfig::info("delete %p", (void*)widget);
312 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
315 }; // END of namespace studio
316 studio::StateManager* state_manager;
321 class GlobalUIInterface : public synfigapp::UIInterface
325 virtual Response confirmation(const std::string &title,
326 const std::string &primaryText,
327 const std::string &secondaryText,
328 const std::string &confirmPhrase,
329 const std::string &cancelPhrase,
330 Response defaultResponse)
332 Gtk::MessageDialog dialog(
333 primaryText, // Message
335 Gtk::MESSAGE_WARNING, // Type
336 Gtk::BUTTONS_NONE, // Buttons
341 dialog.set_title(title);
342 if (! secondaryText.empty())
343 dialog.set_secondary_text(secondaryText);
345 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
346 dialog.add_button(confirmPhrase, RESPONSE_OK);
347 dialog.set_default_response(defaultResponse);
350 return (Response) dialog.run();
353 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
358 true // use_separator
360 Gtk::Label label(message);
363 dialog.get_vbox()->pack_start(label);
364 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
365 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
367 dialog.set_default_response(dflt);
369 return (Response)dialog.run();
371 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
376 true // use_separator
378 Gtk::Label label(message);
381 dialog.get_vbox()->pack_start(label);
382 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
383 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
384 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
386 dialog.set_default_response(dflt);
388 return (Response)dialog.run();
390 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
395 true // use_separator
397 Gtk::Label label(message);
400 dialog.get_vbox()->pack_start(label);
401 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
402 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
404 dialog.set_default_response(dflt);
406 return (Response)dialog.run();
410 task(const std::string &task)
412 std::cerr<<task<<std::endl;
413 while(studio::App::events_pending())studio::App::iteration(false);
418 error(const std::string &err)
420 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
427 warning(const std::string &err)
429 std::cerr<<"warning: "<<err<<std::endl;
430 while(studio::App::events_pending())studio::App::iteration(false);
435 amount_complete(int /*current*/, int /*total*/)
437 while(studio::App::events_pending())studio::App::iteration(false);
442 /* === P R O C E D U R E S ================================================= */
446 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
448 action_group_list.push_back(action_group);
449 Gtk::UIManager::insert_action_group(action_group, pos);
453 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
455 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
456 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
457 if(*iter==action_group)
459 action_group_list.erase(iter);
460 Gtk::UIManager::remove_action_group(action_group);
463 synfig::error("Unable to find action group");
467 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
469 ui_manager->insert_action_group(group,0);
471 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
472 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
474 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
476 if(*iter && (*iter)->get_name()!="menus")
478 synfig::info("Removing action group "+(*iter)->get_name());
479 ui_manager->remove_action_group(*iter);
482 ui_manager->insert_action_group(group,0);
484 for(;!prev_groups.empty();prev_groups.pop_front())
486 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
487 ui_manager->insert_action_group(prev_groups.front(),1);
491 class Preferences : public synfigapp::Settings
494 virtual bool get_value(const synfig::String& key, synfig::String& value)const
498 value=strprintf("%f %f %f %f",
499 App::gamma.get_gamma_r(),
500 App::gamma.get_gamma_g(),
501 App::gamma.get_gamma_b(),
502 App::gamma.get_black_level()
506 if(key=="time_format")
508 value=strprintf("%i",App::get_time_format());
511 if(key=="file_history.size")
513 value=strprintf("%i",App::get_max_recent_files());
516 if(key=="use_colorspace_gamma")
518 value=strprintf("%i",(int)App::use_colorspace_gamma);
521 if(key=="distance_system")
523 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
526 #ifdef SINGLE_THREADED
527 if(key=="single_threaded")
529 value=strprintf("%i",(int)App::single_threaded);
533 if(key=="auto_recover_backup_interval")
535 value=strprintf("%i",App::auto_recover->get_timeout());
538 if(key=="restrict_radius_ducks")
540 value=strprintf("%i",(int)App::restrict_radius_ducks);
543 if(key=="resize_imported_images")
545 value=strprintf("%i",(int)App::resize_imported_images);
548 if(key=="browser_command")
550 value=App::browser_command;
553 if(key=="custom_filename_prefix")
555 value=App::custom_filename_prefix;
558 if(key=="preferred_x_size")
560 value=strprintf("%i",App::preferred_x_size);
563 if(key=="preferred_y_size")
565 value=strprintf("%i",App::preferred_y_size);
568 if(key=="predefined_size")
570 value=strprintf("%s",App::predefined_size.c_str());
573 if(key=="preferred_fps")
575 value=strprintf("%f",App::preferred_fps);
578 if(key=="predefined_fps")
580 value=strprintf("%s",App::predefined_fps.c_str());
584 return synfigapp::Settings::get_value(key,value);
587 virtual bool set_value(const synfig::String& key,const synfig::String& value)
593 strscanf(value,"%f %f %f %f",
600 App::gamma.set_all(r,g,b,blk);
604 if(key=="time_format")
606 int i(atoi(value.c_str()));
607 App::set_time_format(static_cast<synfig::Time::Format>(i));
610 if(key=="auto_recover_backup_interval")
612 int i(atoi(value.c_str()));
613 App::auto_recover->set_timeout(i);
616 if(key=="file_history.size")
618 int i(atoi(value.c_str()));
619 App::set_max_recent_files(i);
622 if(key=="use_colorspace_gamma")
624 int i(atoi(value.c_str()));
625 App::use_colorspace_gamma=i;
628 if(key=="distance_system")
630 App::distance_system=Distance::ident_system(value);;
633 #ifdef SINGLE_THREADED
634 if(key=="single_threaded")
636 int i(atoi(value.c_str()));
637 App::single_threaded=i;
641 if(key=="restrict_radius_ducks")
643 int i(atoi(value.c_str()));
644 App::restrict_radius_ducks=i;
647 if(key=="resize_imported_images")
649 int i(atoi(value.c_str()));
650 App::resize_imported_images=i;
653 if(key=="browser_command")
655 App::browser_command=value;
658 if(key=="custom_filename_prefix")
660 App::custom_filename_prefix=value;
663 if(key=="preferred_x_size")
665 int i(atoi(value.c_str()));
666 App::preferred_x_size=i;
669 if(key=="preferred_y_size")
671 int i(atoi(value.c_str()));
672 App::preferred_y_size=i;
675 if(key=="predefined_size")
677 App::predefined_size=value;
680 if(key=="preferred_fps")
682 float i(atof(value.c_str()));
683 App::preferred_fps=i;
686 if(key=="predefined_fps")
688 App::predefined_fps=value;
692 return synfigapp::Settings::set_value(key,value);
695 virtual KeyList get_key_list()const
697 KeyList ret(synfigapp::Settings::get_key_list());
698 ret.push_back("gamma");
699 ret.push_back("time_format");
700 ret.push_back("distance_system");
701 ret.push_back("file_history.size");
702 ret.push_back("use_colorspace_gamma");
703 #ifdef SINGLE_THREADED
704 ret.push_back("single_threaded");
706 ret.push_back("auto_recover_backup_interval");
707 ret.push_back("restrict_radius_ducks");
708 ret.push_back("resize_imported_images");
709 ret.push_back("browser_command");
710 ret.push_back("custom_filename_prefix");
711 ret.push_back("preferred_x_size");
712 ret.push_back("preferred_y_size");
713 ret.push_back("predefined_size");
714 ret.push_back("preferred_fps");
715 ret.push_back("predefined_fps");
720 static ::Preferences _preferences;
725 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
727 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
729 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
731 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
732 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
733 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
734 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
735 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
736 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
737 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
738 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
739 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
740 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
741 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
742 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
743 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
745 // Add the synfigapp actions...
746 synfigapp::Action::Book::iterator iter;
747 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
749 actions_action_group->add(Gtk::Action::create(
750 "action-"+iter->second.name,
751 get_action_stock_id(iter->second),
752 iter->second.local_name,iter->second.local_name
756 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
757 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
758 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ group->add(action,sig); }
760 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
761 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
762 DEFINE_ACTION("new", Gtk::Stock::NEW);
763 DEFINE_ACTION("open", Gtk::Stock::OPEN);
764 DEFINE_ACTION("save", Gtk::Stock::SAVE);
765 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
766 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
767 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
768 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
769 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
770 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
771 DEFINE_ACTION("import", _("Import"));
772 DEFINE_ACTION("render", _("Render"));
773 DEFINE_ACTION("preview", _("Preview"));
774 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
775 DEFINE_ACTION("sound", _("Sound File"));
776 DEFINE_ACTION("options", _("Options"));
777 DEFINE_ACTION("close", _("Close View"));
778 DEFINE_ACTION("close-document", _("Close Document"));
779 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
782 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
783 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
784 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
785 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
786 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
787 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
788 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
789 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
790 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
791 DEFINE_ACTION("properties", _("Properties"));
793 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
794 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
795 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
796 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
797 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
798 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
799 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
800 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
801 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
802 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
803 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
804 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
805 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
806 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
807 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
808 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
809 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
810 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
811 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
812 DEFINE_ACTION("play", _("Play"));
813 // DEFINE_ACTION("pause", _("Pause"));
814 DEFINE_ACTION("stop", _("Stop"));
815 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
816 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
817 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
818 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
819 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
820 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
821 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
822 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
823 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
824 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
825 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
826 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
827 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
828 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
829 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
830 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
831 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
832 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
833 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
834 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
835 DEFINE_ACTION("seek-end", _("Seek to End"));
837 DEFINE_ACTION("action-group_add", _("Add group"));
839 DEFINE_ACTION("canvas-new", _("New Canvas"));
841 DEFINE_ACTION("amount-inc", _("Increase Amount"));
842 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
847 // Set up synfigapp actions
849 synfigapp::Action::Book::iterator iter;
851 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
853 Gtk::StockID stock_id;
855 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
857 //Gtk::Image* image(manage(new Gtk::Image()));
858 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
859 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
860 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
861 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
862 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
863 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
864 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
865 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
866 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
867 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
869 actions_action_group->add(Gtk::Action::create(
870 "action-"+iter->second.name,
872 iter->second.local_name,iter->second.local_name
880 Glib::ustring ui_info =
882 " <popup name='menu-toolbox' action='menu-toolbox'>"
883 " <menu action='menu-file'>"
886 " <popup name='menu-main' action='menu-main'>"
887 " <menu action='menu-file'>"
888 " <menuitem action='new' />"
889 " <menuitem action='open' />"
890 " <menuitem action='save' />"
891 " <menuitem action='save-as' />"
892 " <menuitem action='revert' />"
893 " <separator name='bleh01'/>"
894 " <menuitem action='cvs-add' />"
895 " <menuitem action='cvs-update' />"
896 " <menuitem action='cvs-commit' />"
897 " <menuitem action='cvs-revert' />"
898 " <separator name='bleh02'/>"
899 " <menuitem action='import' />"
900 " <separator name='bleh03'/>"
901 " <menuitem action='render' />"
902 " <menuitem action='preview' />"
903 " <menuitem action='sound' />"
904 " <separator name='bleh04'/>"
905 " <menuitem action='options' />"
906 " <menuitem action='close' />"
907 " <menuitem action='close-document' />"
908 " <menuitem action='quit' />"
910 " <menu action='menu-edit'>"
911 " <menuitem action='undo'/>"
912 " <menuitem action='redo'/>"
913 " <separator name='bleh05'/>"
914 " <menuitem action='cut'/>"
915 " <menuitem action='copy'/>"
916 " <menuitem action='paste'/>"
917 " <separator name='bleh06'/>"
918 " <menuitem action='select-all-layers'/>"
919 " <menuitem action='unselect-all-layers'/>"
920 " <menuitem action='select-all-ducks'/>"
921 " <menuitem action='unselect-all-ducks'/>"
922 " <separator name='bleh07'/>"
923 " <menuitem action='properties'/>"
925 " <menu action='menu-view'>"
926 " <menu action='menu-duck-mask'>"
927 " <menuitem action='mask-position-ducks' />"
928 " <menuitem action='mask-vertex-ducks' />"
929 " <menuitem action='mask-tangent-ducks' />"
930 " <menuitem action='mask-radius-ducks' />"
931 " <menuitem action='mask-width-ducks' />"
932 " <menuitem action='mask-angle-ducks' />"
934 " <menu action='menu-preview-quality'>"
935 " <menuitem action='quality-00' />"
936 " <menuitem action='quality-01' />"
937 " <menuitem action='quality-02' />"
938 " <menuitem action='quality-03' />"
939 " <menuitem action='quality-04' />"
940 " <menuitem action='quality-05' />"
941 " <menuitem action='quality-06' />"
942 " <menuitem action='quality-07' />"
943 " <menuitem action='quality-08' />"
944 " <menuitem action='quality-09' />"
945 " <menuitem action='quality-10' />"
947 " <menu action='menu-lowres-pixel'>"
948 " <menuitem action='decrease-low-res-pixel-size'/>"
949 " <menuitem action='increase-low-res-pixel-size'/>"
950 " <separator name='pixel-size-separator'/>"
953 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
954 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
958 " <separator name='bleh08'/>"
959 " <menuitem action='play'/>"
960 //" <menuitem action='pause'/>"
961 " <menuitem action='stop'/>"
962 " <menuitem action='dialog-flipbook'/>"
963 " <separator name='bleh09'/>"
964 " <menuitem action='toggle-grid-show'/>"
965 " <menuitem action='toggle-grid-snap'/>"
966 " <menuitem action='toggle-guide-show'/>"
967 " <menuitem action='toggle-low-res'/>"
968 " <menuitem action='toggle-onion-skin'/>"
969 " <separator name='bleh10'/>"
970 " <menuitem action='canvas-zoom-in'/>"
971 " <menuitem action='canvas-zoom-out'/>"
972 " <menuitem action='canvas-zoom-fit'/>"
973 " <menuitem action='canvas-zoom-100'/>"
974 " <separator name='bleh11'/>"
975 " <menuitem action='time-zoom-in'/>"
976 " <menuitem action='time-zoom-out'/>"
977 " <separator name='bleh12'/>"
978 " <menuitem action='jump-next-keyframe'/>"
979 " <menuitem action='jump-prev-keyframe'/>"
980 " <menuitem action='seek-next-frame'/>"
981 " <menuitem action='seek-prev-frame'/>"
982 " <menuitem action='seek-next-second'/>"
983 " <menuitem action='seek-prev-second'/>"
984 " <menuitem action='seek-begin'/>"
985 " <menuitem action='seek-end'/>"
987 " <menu action='menu-canvas'>"
988 " <menuitem action='canvas-new'/>"
990 " <menu name='menu-state' action='menu-state'>"
992 " <menu action='menu-group'>"
993 " <menuitem action='action-group_add'/>"
995 " <menu action='menu-layer'>"
996 //" <menuitem action='cut'/>"
997 //" <menuitem action='copy'/>"
998 //" <menuitem action='paste'/>"
999 //" <separator name='bleh06'/>"
1000 " <menu action='menu-layer-new'></menu>"
1001 " <menuitem action='amount-inc'/>"
1002 " <menuitem action='amount-dec'/>"
1004 " <menu action='menu-keyframe'>"
1005 " <menuitem action='keyframe-properties'/>"
1012 " <menubar name='MenuBar'>"
1013 " <menu action='MenuFile'>"
1014 " <menuitem action='New'/>"
1015 " <menuitem action='Open'/>"
1017 " <menuitem action='Quit'/>"
1019 " <menu action='MenuEdit'>"
1020 " <menuitem action='Cut'/>"
1021 " <menuitem action='Copy'/>"
1022 " <menuitem action='Paste'/>"
1025 " <toolbar name='ToolBar'>"
1026 " <toolitem action='Open'/>"
1027 " <toolitem action='Quit'/>"
1033 actions_action_group->set_sensitive(false);
1034 App::ui_manager()->set_add_tearoffs(true);
1035 App::ui_manager()->insert_action_group(menus_action_group,1);
1036 App::ui_manager()->insert_action_group(actions_action_group,1);
1037 App::ui_manager()->add_ui_from_string(ui_info);
1039 //App::ui_manager()->get_accel_group()->unlock();
1041 catch(const Glib::Error& ex)
1043 synfig::error("building menus and toolbars failed: " + ex.what());
1046 // Add default keyboard accelerators
1047 #define ACCEL(accel,path) \
1049 Gtk::AccelKey accel_key(accel,path); \
1050 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1053 #define ACCEL2(accel) \
1055 Gtk::AccelKey accel_key(accel); \
1056 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1060 ACCEL("<Mod1>a", "<Actions>//state-normal" );
1061 ACCEL("<Mod1>v", "<Actions>//state-smooth_move" );
1062 ACCEL("<Mod1>s", "<Actions>//state-scale" );
1063 ACCEL("<Mod1>t", "<Actions>//state-rotate" );
1064 ACCEL("<Mod1>m", "<Actions>//state-mirror" );
1065 ACCEL("<Mod1>c", "<Actions>//state-circle" );
1066 ACCEL("<Mod1>r", "<Actions>//state-rectangle" );
1067 ACCEL("<Mod1>q", "<Actions>//state-star" );
1068 ACCEL("<Mod1>g", "<Actions>//state-gradient" );
1069 ACCEL("<Mod1>p", "<Actions>//state-polygon" );
1070 ACCEL("<Mod1>b", "<Actions>//state-bline" );
1071 ACCEL("<Mod1>x", "<Actions>//state-text" );
1072 ACCEL("<Mod1>f", "<Actions>//state-fill" );
1073 ACCEL("<Mod1>e", "<Actions>//state-eyedrop" );
1074 ACCEL("<Mod1>z", "<Actions>//state-zoom" );
1075 ACCEL("<Mod1>d", "<Actions>//state-draw" );
1076 ACCEL("<Mod1>k", "<Actions>//state-sketch" );
1077 ACCEL("<Mod1>w", "<Actions>//state-width" );
1080 ACCEL("<Control>a", "<Actions>//select-all-ducks" );
1081 ACCEL("<Control>d", "<Actions>//unselect-all-ducks" );
1082 ACCEL("<Control><Shift>a", "<Actions>//select-all-layers" );
1083 ACCEL("<Control><Shift>d", "<Actions>//unselect-all-layers" );
1084 ACCEL("F9", "<Actions>//render" );
1085 ACCEL("F11", "<Actions>//preview" );
1086 ACCEL("F8", "<Actions>//properties" );
1087 ACCEL("F12", "<Actions>//options" );
1088 ACCEL("<control>i", "<Actions>//import" );
1089 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>//stop" ));
1090 ACCEL("<Control>g", "<Actions>//toggle-grid-show" );
1091 ACCEL("<Control>l", "<Actions>//toggle-grid-snap" );
1092 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>//toggle-low-res" ));
1093 ACCEL("<Mod1>1", "<Actions>//mask-position-ducks" );
1094 ACCEL("<Mod1>2", "<Actions>//mask-vertex-ducks" );
1095 ACCEL("<Mod1>3", "<Actions>//mask-tangent-ducks" );
1096 ACCEL("<Mod1>4", "<Actions>//mask-radius-ducks" );
1097 ACCEL("<Mod1>5", "<Actions>//mask-width-ducks" );
1098 ACCEL("<Mod1>6", "<Actions>//mask-angle-ducks" );
1099 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>//action-LayerRaise" ));
1100 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>//action-LayerLower" ));
1101 ACCEL("<Control>1", "<Actions>//quality-01" );
1102 ACCEL("<Control>2", "<Actions>//quality-02" );
1103 ACCEL("<Control>3", "<Actions>//quality-03" );
1104 ACCEL("<Control>4", "<Actions>//quality-04" );
1105 ACCEL("<Control>5", "<Actions>//quality-05" );
1106 ACCEL("<Control>6", "<Actions>//quality-06" );
1107 ACCEL("<Control>7", "<Actions>//quality-07" );
1108 ACCEL("<Control>8", "<Actions>//quality-08" );
1109 ACCEL("<Control>9", "<Actions>//quality-09" );
1110 ACCEL("<Control>0", "<Actions>//quality-10" );
1111 ACCEL("<Control>z", "<Actions>//undo" );
1112 ACCEL("<Control>r", "<Actions>//redo" );
1113 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>//action-LayerRemove" ));
1114 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>//decrease-low-res-pixel-size" ));
1115 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>//increase-low-res-pixel-size" ));
1116 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>//amount-dec" ));
1117 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>//amount-inc" ));
1118 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>//jump-next-keyframe" ));
1119 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>//jump-prev-keyframe" ));
1120 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>//canvas-zoom-in" ));
1121 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>//canvas-zoom-out" ));
1122 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>//time-zoom-in" ));
1123 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>//time-zoom-out" ));
1124 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>//seek-next-frame" ));
1125 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>//seek-prev-frame" ));
1126 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>//seek-next-second" ));
1127 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>//seek-prev-second" ));
1128 ACCEL("<Mod1>o", "<Actions>//toggle-onion-skin" );
1129 ACCEL("<Control><Shift>z", "<Actions>//canvas-zoom-fit" );
1130 ACCEL("<Control>p", "<Actions>//play" );
1131 ACCEL("Home", "<Actions>//seek-begin" );
1132 ACCEL("End", "<Actions>//seek-end" );
1138 #define mkdir(x,y) mkdir(x)
1141 /* === M E T H O D S ======================================================= */
1143 App::App(int *argc, char ***argv):
1144 Gtk::Main(argc,argv),
1145 IconController(etl::dirname((*argv)[0]))
1147 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1150 ui_interface_=new GlobalUIInterface();
1154 // don't call thread_init() if threads are already initialized
1155 // on some machines bonobo_init() initialized threads before we get here
1156 if (!g_thread_supported())
1157 Glib::thread_init();
1159 distance_system=Distance::SYSTEM_UNITS;
1161 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1164 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1168 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1174 if(!SYNFIG_CHECK_VERSION())
1176 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1177 dialog_error_blocking("Synfig Studio",
1178 "This copy of Synfig Studio was compiled against a\n"
1179 "different version of libsynfig than what is currently\n"
1180 "installed. Synfig Studio will now abort. Try downloading\n"
1181 "the latest version from the Synfig website at\n"
1182 "http://synfig.org/Download"
1186 Glib::set_application_name(_("Synfig Studio"));
1188 Splash splash_screen;
1189 splash_screen.show();
1191 shutdown_in_progress=false;
1192 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1193 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1195 // Initialize the Synfig library
1196 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1197 catch(std::runtime_error x)
1199 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1204 get_ui_interface()->error(_("Failed to initialize synfig!"));
1208 // add the preferences to the settings
1209 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1213 studio_init_cb.task(_("Init UI Manager..."));
1214 App::ui_manager_=studio::UIManager::create();
1217 studio_init_cb.task(_("Init Dock Manager..."));
1218 dock_manager=new studio::DockManager();
1220 studio_init_cb.task(_("Init State Manager..."));
1221 state_manager=new StateManager();
1223 studio_init_cb.task(_("Init Toolbox..."));
1224 toolbox=new studio::Toolbox();
1226 studio_init_cb.task(_("Init About Dialog..."));
1227 about=new studio::About();
1229 studio_init_cb.task(_("Init Tool Options..."));
1230 dialog_tool_options=new studio::Dialog_ToolOptions();
1231 dock_manager->register_dockable(*dialog_tool_options);
1233 studio_init_cb.task(_("Init History..."));
1234 dock_history=new studio::Dock_History();
1235 dock_manager->register_dockable(*dock_history);
1237 studio_init_cb.task(_("Init Canvases..."));
1238 dock_canvases=new studio::Dock_Canvases();
1239 dock_manager->register_dockable(*dock_canvases);
1241 studio_init_cb.task(_("Init Keyframes..."));
1242 dock_keyframes=new studio::Dock_Keyframes();
1243 dock_manager->register_dockable(*dock_keyframes);
1245 studio_init_cb.task(_("Init Layers..."));
1246 dock_layers=new studio::Dock_Layers();
1247 dock_manager->register_dockable(*dock_layers);
1249 studio_init_cb.task(_("Init Params..."));
1250 dock_params=new studio::Dock_Params();
1251 dock_manager->register_dockable(*dock_params);
1253 studio_init_cb.task(_("Init MetaData..."));
1254 dock_meta_data=new studio::Dock_MetaData();
1255 dock_manager->register_dockable(*dock_meta_data);
1257 studio_init_cb.task(_("Init Children..."));
1258 dock_children=new studio::Dock_Children();
1259 dock_manager->register_dockable(*dock_children);
1261 studio_init_cb.task(_("Init Info..."));
1262 dock_info = new studio::Dock_Info();
1263 dock_manager->register_dockable(*dock_info);
1265 studio_init_cb.task(_("Init Navigator..."));
1266 dock_navigator = new studio::Dock_Navigator();
1267 dock_manager->register_dockable(*dock_navigator);
1269 studio_init_cb.task(_("Init Timetrack..."));
1270 dock_timetrack = new studio::Dock_Timetrack();
1271 dock_manager->register_dockable(*dock_timetrack);
1273 studio_init_cb.task(_("Init Curve Editor..."));
1274 dock_curves = new studio::Dock_Curves();
1275 dock_manager->register_dockable(*dock_curves);
1277 studio_init_cb.task(_("Init Layer Groups..."));
1278 dock_layer_groups = new studio::Dock_LayerGroups();
1279 dock_manager->register_dockable(*dock_layer_groups);
1282 studio_init_cb.task(_("Init Color Dialog..."));
1283 dialog_color=new studio::Dialog_Color();
1285 studio_init_cb.task(_("Init Gradient Dialog..."));
1286 dialog_gradient=new studio::Dialog_Gradient();
1288 studio_init_cb.task(_("Init DeviceTracker..."));
1289 device_tracker=new studio::DeviceTracker();
1291 studio_init_cb.task(_("Init Tools..."));
1294 state_manager->add_state(&state_normal);
1295 state_manager->add_state(&state_smooth_move);
1296 state_manager->add_state(&state_scale);
1297 state_manager->add_state(&state_rotate);
1298 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1301 state_manager->add_state(&state_circle);
1302 state_manager->add_state(&state_rectangle);
1303 state_manager->add_state(&state_star);
1304 state_manager->add_state(&state_gradient);
1305 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1308 state_manager->add_state(&state_bline);
1309 state_manager->add_state(&state_text);
1310 state_manager->add_state(&state_fill);
1311 state_manager->add_state(&state_eyedrop);
1312 state_manager->add_state(&state_zoom);
1314 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1315 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1316 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1318 studio_init_cb.task(_("Init ModPalette..."));
1319 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1321 studio_init_cb.task(_("Init Setup Dialog..."));
1322 dialog_setup=new studio::Dialog_Setup();
1324 studio_init_cb.task(_("Init Input Dialog..."));
1325 dialog_input=new Gtk::InputDialog();
1326 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1327 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1329 studio_init_cb.task(_("Init auto recovery..."));
1330 auto_recover=new AutoRecover();
1332 studio_init_cb.amount_complete(9250,10000);
1333 studio_init_cb.task(_("Loading Settings..."));
1335 device_tracker->load_preferences();
1337 studio_init_cb.task(_("Checking auto-recover..."));
1339 studio_init_cb.amount_complete(9900,10000);
1341 bool opened_any = false;
1342 if(auto_recover->recovery_needed())
1344 splash_screen.hide();
1345 if (get_ui_interface()->confirmation("Crash Recovery",
1346 _("Auto recovery file found"),
1347 _("Synfig Studio seems to have crashed\n"
1348 "before you could save all your files.\n"
1349 "Recover unsaved changes?"),
1350 _("Recover"), _("Ignore"))
1351 == synfigapp::UIInterface::RESPONSE_OK)
1353 int number_recovered;
1354 if(!auto_recover->recover(number_recovered))
1355 if (number_recovered)
1356 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1358 get_ui_interface()->error(_("Unable to recover from previous crash"));
1360 get_ui_interface()->error(
1361 _("Synfig Studio has attempted to recover\n"
1362 "from a previous crash. The files that it has\n"
1363 "recovered are NOT YET SAVED. It would be a good\n"
1364 "idea to review them and save them now."));
1366 if (number_recovered)
1369 splash_screen.show();
1372 // Look for any files given on the command line,
1373 // and load them if found.
1374 for(;*argc>=1;(*argc)--)
1375 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1377 studio_init_cb.task(_("Loading files..."));
1378 splash_screen.hide();
1379 open((*argv)[*argc]);
1381 splash_screen.show();
1384 // if no file was specified to be opened, create a new document to help new users get started more easily
1385 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1388 studio_init_cb.task(_("Done."));
1389 studio_init_cb.amount_complete(10000,10000);
1395 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1399 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1403 StateManager* App::get_state_manager() { return state_manager; }
1407 shutdown_in_progress=true;
1411 synfigapp::Main::settings().remove_domain("pref");
1413 selected_instance=0;
1415 // Unload all of the modules
1416 for(;!module_list_.empty();module_list_.pop_back())
1419 delete state_manager;
1423 delete auto_recover;
1429 // studio::App::iteration(false);
1433 // studio::App::iteration(false);
1435 // studio::App::iteration(false);
1437 delete dialog_setup;
1439 delete dialog_gradient;
1441 delete dialog_color;
1443 delete dialog_input;
1445 delete dock_manager;
1447 instance_list.clear();
1449 // studio::App::iteration(false);
1453 App::get_user_app_directory()
1455 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1457 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1459 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1464 App::get_config_file(const synfig::String& file)
1466 return Glib::build_filename(get_user_app_directory(),file);
1469 #define SCALE_FACTOR (1280)
1470 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1472 App::set_recent_file_window_size(etl::handle<Instance> instance)
1474 int screen_w(Gdk::screen_width());
1475 int screen_h(Gdk::screen_height());
1477 const std::string &canvas_window_size = *recent_files_window_size.begin();
1479 if(canvas_window_size.empty())
1482 synfig::String::size_type current=0;
1483 bool seen_root(false), shown_non_root(false);
1485 while(current != synfig::String::npos)
1487 // find end of first field (canvas) or return
1488 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1489 if(separator == synfig::String::npos) break;
1492 synfig::Canvas::Handle canvas;
1495 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1497 catch(Exception::IDNotFound) {
1498 // can't find the canvas; skip to the next canvas or return
1499 separator = canvas_window_size.find_first_of('\t', current);
1500 if(separator == synfig::String::npos) return;
1501 current = separator+1;
1505 if (canvas->is_root())
1508 shown_non_root = true;
1510 // check that we have the tab character the ends this canvas' data or return
1511 current = separator+1;
1512 separator = canvas_window_size.find_first_of('\t', current);
1513 if(separator == synfig::String::npos) return;
1516 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1518 current = separator+1;
1522 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1523 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1524 x=x*screen_w/SCALE_FACTOR;
1525 y=y*screen_h/SCALE_FACTOR;
1526 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1527 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1528 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1529 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1531 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1532 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1534 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1535 canvasview->move(x,y);
1536 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1537 canvasview->present();
1539 current = separator+1;
1542 if (shown_non_root && !seen_root)
1543 instance->find_canvas_view(instance->get_canvas())->hide();
1547 App::add_recent_file(const etl::handle<Instance> instance)
1549 int screen_w(Gdk::screen_width());
1550 int screen_h(Gdk::screen_height());
1552 std::string canvas_window_size;
1554 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1555 Instance::CanvasViewList::const_iterator iter;
1557 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1559 if( !((*iter)->is_visible()) )
1562 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1563 int x_pos, y_pos, x_size, y_size;
1564 (*iter)->get_position(x_pos,y_pos);
1565 (*iter)->get_size(x_size,y_size);
1567 canvas_window_size += strprintf("%s %d %d %d %d\t",
1568 canvas->get_relative_id(canvas->get_root()).c_str(),
1569 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1570 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1573 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1578 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1580 std::string filename(file_name);
1582 assert(!filename.empty());
1584 if(filename.empty())
1587 // Toss out any "hidden" files
1588 if(basename(filename)[0]=='.')
1591 // If we aren't an absolute path, turn ourselves into one
1592 if(!is_absolute_path(filename))
1593 filename=absolute_path(filename);
1595 std::string old_window_size;
1597 list<string>::iterator iter;
1598 list<string>::iterator iter_wsize;
1599 // Check to see if the file is already on the list.
1600 // If it is, then remove it from the list
1601 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1604 recent_files.erase(iter);
1605 old_window_size = *iter_wsize;
1606 recent_files_window_size.erase(iter_wsize);
1611 // Push the filename to the front of the list
1612 recent_files.push_front(filename);
1613 if(window_size.empty())
1614 recent_files_window_size.push_front(old_window_size);
1616 recent_files_window_size.push_front(window_size);
1618 // Clean out the files at the end of the list.
1619 while(recent_files.size()>(unsigned)get_max_recent_files())
1621 recent_files.pop_back();
1622 recent_files_window_size.pop_back();
1625 signal_recent_files_changed_();
1630 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1633 App::get_time_format()
1635 return _App_time_format;
1639 App::set_time_format(synfig::Time::Format x)
1646 App::save_settings()
1651 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1652 setlocale(LC_NUMERIC, "C");
1654 std::string filename=get_config_file("accelrc");
1655 Gtk::AccelMap::save(filename);
1658 std::string filename=get_config_file("recentfiles");
1660 std::ofstream file(filename.c_str());
1664 synfig::warning("Unable to save %s",filename.c_str());
1668 list<string>::reverse_iterator iter;
1670 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1674 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1676 std::ofstream file(filename.c_str());
1680 synfig::warning("Unable to save %s",filename.c_str());
1684 list<string>::reverse_iterator iter;
1686 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1690 std::string filename=get_config_file("settings");
1691 synfigapp::Main::settings().save_to_file(filename);
1692 setlocale(LC_NUMERIC,old_locale);
1696 synfig::warning("Caught exception when attempting to save settings.");
1701 App::load_settings()
1706 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1707 setlocale(LC_NUMERIC, "C");
1709 std::string filename=get_config_file("accelrc");
1710 Gtk::AccelMap::load(filename);
1713 bool window_size_broken = false;
1715 std::string filename=get_config_file("recentfiles");
1716 std::string filename_window_size=filename+std::string("_window_size");
1718 std::ifstream file(filename.c_str());
1719 std::ifstream file_window_size(filename_window_size.c_str());
1721 if(!file_window_size)
1722 window_size_broken = true;
1726 std::string recent_file;
1727 std::string recent_file_window_size;
1728 getline(file,recent_file);
1729 if(!window_size_broken)
1730 getline(file_window_size,recent_file_window_size);
1731 if(!recent_file.empty())
1733 if(!window_size_broken && !file_window_size)
1734 window_size_broken = true;
1735 if (std::ifstream(recent_file.c_str()))
1737 if(!window_size_broken)
1738 add_recent_file(recent_file,recent_file_window_size);
1740 add_recent_file(recent_file);
1744 if(!window_size_broken && file_window_size)
1745 window_size_broken = true;
1747 if(window_size_broken)
1749 recent_files_window_size.clear();
1750 recent_files_window_size.resize(recent_files.size());
1753 std::string filename=get_config_file("settings");
1754 if(!synfigapp::Main::settings().load_from_file(filename))
1756 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1757 //if(!synfigapp::Main::settings().load_from_file(filename))
1759 gamma.set_gamma(1.0/2.2);
1760 reset_initial_window_configuration();
1763 setlocale(LC_NUMERIC,old_locale);
1767 synfig::warning("Caught exception when attempting to load settings.");
1772 App::reset_initial_window_configuration()
1774 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1775 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1776 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1777 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1778 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1779 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1780 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1781 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1782 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1783 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1784 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1785 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1786 #ifdef SINGLE_THREADED
1787 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1789 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1790 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1791 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1792 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1793 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1794 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1795 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1796 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1797 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1801 App::shutdown_request(GdkEventAny*)
1805 //return !shutdown_in_progress;
1811 if(shutdown_in_progress)return;
1814 get_ui_interface()->task(_("Quit Request"));
1817 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1821 std::list<etl::handle<Instance> >::iterator iter;
1822 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1824 if(!(*iter)->safe_close())
1828 if((*iter)->synfigapp::Instance::get_action_count())
1830 handle<synfigapp::UIInterface> uim;
1831 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1833 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1834 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1836 case synfigapp::UIInterface::RESPONSE_NO:
1838 case synfigapp::UIInterface::RESPONSE_YES:
1841 case synfigapp::UIInterface::RESPONSE_CANCEL:
1850 if((*iter)->synfigapp::Instance::is_modified())
1852 handle<synfigapp::UIInterface> uim;
1853 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1855 string str=strprintf(_("%s has changes not yet on the CVS repository.\nWould you like to commit these changes?"),(*iter)->get_file_name().c_str() );
1856 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1858 case synfigapp::UIInterface::RESPONSE_NO:
1860 case synfigapp::UIInterface::RESPONSE_YES:
1861 (*iter)->dialog_cvs_commit();
1863 case synfigapp::UIInterface::RESPONSE_CANCEL:
1872 // This next line causes things to crash for some reason
1876 shutdown_in_progress=true;
1878 instance_list.clear();
1880 while(studio::App::events_pending())studio::App::iteration(false);
1883 auto_recover->normal_shutdown();
1885 get_ui_interface()->task(_("Quit Request sent"));
1891 dialog_setup->refresh();
1892 dialog_setup->show();
1895 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1896 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1899 //#define USE_WIN32_FILE_DIALOGS 1
1902 #ifdef USE_WIN32_FILE_DIALOGS
1903 static OPENFILENAME ofn={};
1907 #include <gdk/gdkwin32.h>
1911 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1913 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1915 #ifdef USE_WIN32_FILE_DIALOGS
1916 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1918 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1919 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1920 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1922 ofn.lStructSize=sizeof(OPENFILENAME);
1923 ofn.hwndOwner = hWnd;
1924 ofn.hInstance = hInstance;
1925 ofn.lpstrFilter = szFilter;
1926 // ofn.lpstrCustomFilter=NULL;
1927 // ofn.nMaxCustFilter=0;
1928 // ofn.nFilterIndex=0;
1929 // ofn.lpstrFile=NULL;
1930 ofn.nMaxFile=MAX_PATH;
1931 // ofn.lpstrFileTitle=NULL;
1932 // ofn.lpstrInitialDir=NULL;
1933 // ofn.lpstrTitle=NULL;
1934 ofn.Flags=OFN_HIDEREADONLY;
1935 // ofn.nFileOffset=0;
1936 // ofn.nFileExtension=0;
1937 ofn.lpstrDefExt=TEXT("sif");
1938 // ofn.lCustData = 0l;
1940 // ofn.lpTemplateName=NULL;
1942 CHAR szFilename[MAX_PATH];
1944 strcpy(szFilename,filename.c_str());
1945 strcpy(szTitle,title.c_str());
1947 ofn.lpstrFile=szFilename;
1948 ofn.lpstrFileTitle=szTitle;
1950 if(GetOpenFileName(&ofn))
1952 filename=szFilename;
1958 synfig::String prev_path;
1960 if(!_preferences.get_value(preference, prev_path))
1963 prev_path = absolute_path(prev_path);
1965 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1967 dialog->set_current_folder(prev_path);
1968 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1969 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1971 if (filename.empty())
1972 dialog->set_filename(prev_path);
1973 else if (is_absolute_path(filename))
1974 dialog->set_filename(filename);
1976 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1978 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1979 filename = dialog->get_filename();
1980 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1981 _preferences.set_value(preference, dirname(filename));
1995 GtkWidget *fileselection;
1996 fileselection = gtk_file_selection_new(title.c_str());
1999 if(basename(filename)==filename)
2001 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
2004 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
2006 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
2008 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
2009 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
2011 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
2012 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
2014 gtk_widget_show(fileselection);
2022 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
2023 _preferences.set_value(preference,dirname(filename));
2027 gtk_widget_destroy(fileselection);
2030 gtk_widget_destroy(fileselection);
2037 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2039 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2041 #if USE_WIN32_FILE_DIALOGS
2042 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2044 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2045 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2046 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2048 ofn.lStructSize=sizeof(OPENFILENAME);
2049 ofn.hwndOwner = hWnd;
2050 ofn.hInstance = hInstance;
2051 ofn.lpstrFilter = szFilter;
2052 // ofn.lpstrCustomFilter=NULL;
2053 // ofn.nMaxCustFilter=0;
2054 // ofn.nFilterIndex=0;
2055 // ofn.lpstrFile=NULL;
2056 ofn.nMaxFile=MAX_PATH;
2057 // ofn.lpstrFileTitle=NULL;
2058 // ofn.lpstrInitialDir=NULL;
2059 // ofn.lpstrTitle=NULL;
2060 ofn.Flags=OFN_OVERWRITEPROMPT;
2061 // ofn.nFileOffset=0;
2062 // ofn.nFileExtension=0;
2063 ofn.lpstrDefExt=TEXT("sif");
2064 // ofn.lCustData = 0l;
2066 // ofn.lpTemplateName=NULL;
2068 CHAR szFilename[MAX_PATH];
2070 strcpy(szFilename,filename.c_str());
2071 strcpy(szTitle,title.c_str());
2073 ofn.lpstrFile=szFilename;
2074 ofn.lpstrFileTitle=szTitle;
2076 if(GetSaveFileName(&ofn))
2078 filename=szFilename;
2079 _preferences.set_value(preference,dirname(filename));
2084 synfig::String prev_path;
2086 if(!_preferences.get_value(preference, prev_path))
2089 prev_path = absolute_path(prev_path);
2091 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2093 dialog->set_current_folder(prev_path);
2094 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2095 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2097 Widget_Enum *file_type_enum = 0;
2098 if (preference == ANIMATION_DIR_PREFERENCE)
2100 file_type_enum = manage(new Widget_Enum());
2101 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2102 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2103 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2104 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2105 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2106 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2108 Gtk::HBox *hbox = manage(new Gtk::HBox);
2109 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2110 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2113 dialog->set_extra_widget(*hbox);
2116 if (filename.empty())
2117 dialog->set_filename(prev_path);
2120 std::string full_path;
2121 if (is_absolute_path(filename))
2122 full_path = filename;
2124 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2126 // select the file if it exists
2127 dialog->set_filename(full_path);
2129 // if the file doesn't exist, put its name into the filename box
2131 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2132 dialog->set_current_name(basename(filename));
2135 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2136 if (preference == ANIMATION_DIR_PREFERENCE)
2137 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2138 filename = dialog->get_filename();
2139 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2140 _preferences.set_value(preference, dirname(filename));
2151 App::dialog_error_blocking(const std::string &title, const std::string &message)
2153 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2154 dialog.set_title(title);
2160 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2162 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2163 dialog.set_title(title);
2169 App::dialog_yes_no(const std::string &title, const std::string &message)
2174 true // use_separator
2176 Gtk::Label label(message);
2179 dialog.get_vbox()->pack_start(label);
2180 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2181 dialog.add_button(Gtk::StockID("gtk-no"),0);
2183 return dialog.run();
2187 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2192 true // use_separator
2194 Gtk::Label label(message);
2197 dialog.get_vbox()->pack_start(label);
2198 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2199 dialog.add_button(Gtk::StockID("gtk-no"),0);
2200 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2202 return dialog.run();
2206 App::dialog_not_implemented()
2208 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2209 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2214 try_open_url(const std::string &url)
2217 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2219 std::vector<std::string> command_line;
2220 std::vector<std::string> browsers;
2221 browsers.reserve(23);
2223 // Browser wrapper scripts
2224 #ifdef USE_OPEN_FOR_URLS
2225 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2227 browsers.push_back("xdg-open"); // XDG wrapper
2228 browsers.push_back("sensible-browser"); // Debian wrapper
2229 browsers.push_back("gnome-open"); // GNOME wrapper
2230 browsers.push_back("kfmclient"); // KDE wrapper
2231 browsers.push_back("exo-open"); // XFCE wrapper
2233 // Alternatives system
2234 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2235 browsers.push_back("x-www-browser"); // Debian GUI alternative
2237 // Individual browsers
2238 browsers.push_back("firefox");
2239 browsers.push_back("epiphany-browser");
2240 browsers.push_back("epiphany");
2241 browsers.push_back("konqueror");
2242 browsers.push_back("iceweasel");
2243 browsers.push_back("mozilla");
2244 browsers.push_back("netscape");
2245 browsers.push_back("icecat");
2246 browsers.push_back("galeon");
2247 browsers.push_back("midori");
2248 browsers.push_back("safari");
2249 browsers.push_back("opera");
2250 browsers.push_back("amaya");
2251 browsers.push_back("netsurf");
2252 browsers.push_back("dillo");
2254 // Try the user-specified browser first
2255 command_line.push_back(App::browser_command);
2256 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2257 command_line.push_back(url);
2259 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2260 catch( Glib::SpawnError& exception ){
2262 while ( !browsers.empty() )
2264 // Skip the browser if we already tried it
2265 if( browsers[0] == App::browser_command )
2268 // Construct the command line
2269 command_line.clear();
2270 command_line.push_back(browsers[0]);
2271 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2272 command_line.push_back(url);
2274 // Remove the browser from the list
2275 browsers.erase(browsers.begin());
2277 // Try to spawn the browser
2278 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2279 // Failed, move on to the next one
2280 catch(Glib::SpawnError& exception){ continue; }
2281 return true; // No exception means we succeeded!
2292 if (!try_open_url("http://synfig.org/Documentation"))
2294 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2295 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2296 dialog.set_title(_("Help"));
2302 App::open_url(const std::string &url)
2304 if(!try_open_url(url))
2306 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2307 dialog.set_secondary_text(url);
2308 dialog.set_title(_("No browser found"));
2314 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2319 true); // use_separator
2321 Gtk::Label label(message);
2323 dialog.get_vbox()->pack_start(label);
2326 entry.set_text(text);
2328 entry.set_activates_default(true);
2330 dialog.get_vbox()->pack_start(entry);
2332 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2333 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2334 dialog.set_default_response(Gtk::RESPONSE_OK);
2336 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2339 if(dialog.run()!=Gtk::RESPONSE_OK)
2342 text=entry.get_text();
2348 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2353 true); // use_separator
2355 Gtk::Label label(message);
2357 dialog.get_vbox()->pack_start(label);
2359 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2360 text_buffer->set_text(text);
2361 Gtk::TextView text_view(text_buffer);
2364 dialog.get_vbox()->pack_start(text_view);
2366 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2367 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2368 dialog.set_default_response(Gtk::RESPONSE_OK);
2370 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2373 if(dialog.run()!=Gtk::RESPONSE_OK)
2376 text=text_buffer->get_text();
2382 App::open(std::string filename)
2384 return open_as(filename,filename);
2387 // this is called from autorecover.cpp:
2388 // App::open_as(get_shadow_file_name(filename),filename)
2389 // other than that, 'filename' and 'as' are the same
2391 App::open_as(std::string filename,std::string as)
2394 char long_name[1024];
2395 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2396 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2397 // don't use it if that's the case
2398 if (long_name[0] != '\0')
2404 OneMoment one_moment;
2405 String errors, warnings;
2407 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2408 if(canvas && get_instance(canvas))
2410 get_instance(canvas)->find_canvas_view(canvas)->present();
2411 info("%s is already open", filename.c_str());
2412 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2417 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2420 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2422 if (as.find(custom_filename_prefix.c_str()) != 0)
2423 add_recent_file(as);
2425 handle<Instance> instance(Instance::create(canvas));
2428 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2430 set_recent_file_window_size(instance);
2434 if(instance->is_updated() && App::dialog_yes_no(_("CVS Update"), _("There appears to be a newer version of this file available on the CVS repository.\nWould you like to update now? (It would probably be a good idea)")))
2435 instance->dialog_cvs_update();
2440 dialog_error_blocking(_("Error"), x);
2443 catch(runtime_error x)
2445 dialog_error_blocking(_("Error"), x.what());
2450 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2461 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2463 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2464 canvas->set_name(file_name);
2465 file_name += ".sifz";
2467 canvas->rend_desc().set_frame_rate(preferred_fps);
2468 canvas->rend_desc().set_time_start(0.0);
2469 canvas->rend_desc().set_time_end(5.0);
2470 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2471 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2472 // The top left and botton right positions are expressed in units
2473 // Original convention is that 1 unit = 60 pixels
2474 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2475 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2476 canvas->rend_desc().set_w(preferred_x_size);
2477 canvas->rend_desc().set_h(preferred_y_size);
2478 canvas->rend_desc().set_antialias(1);
2479 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2480 canvas->set_file_name(file_name);
2482 handle<Instance> instance = Instance::create(canvas);
2484 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2485 instance->find_canvas_view(canvas)->canvas_properties.present();
2489 App::dialog_open(string filename)
2491 if (filename.empty())
2494 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2496 // If the filename still has wildcards, then we should
2497 // continue looking for the file we want
2498 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2504 get_ui_interface()->error(_("Unable to open file"));
2509 App::set_selected_instance(etl::loose_handle<Instance> instance)
2511 /* if(get_selected_instance()==instance)
2513 selected_instance=instance;
2514 signal_instance_selected()(instance);
2520 selected_instance=instance;
2521 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2525 instance->focus(instance->get_canvas());
2528 set_selected_canvas_view(0);
2530 signal_instance_selected()(instance);
2534 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2536 selected_canvas_view=canvas_view;
2537 signal_canvas_view_focus()(selected_canvas_view);
2540 selected_instance=canvas_view->get_instance();
2541 signal_instance_selected()(canvas_view->get_instance());
2544 if(get_selected_canvas_view()==canvas_view)
2546 signal_canvas_view_focus()(selected_canvas_view);
2547 signal_instance_selected()(canvas_view->get_instance());
2550 selected_canvas_view=canvas_view;
2551 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2552 set_selected_instance(canvas_view->get_instance());
2553 signal_canvas_view_focus()(selected_canvas_view);
2557 etl::loose_handle<Instance>
2558 App::get_instance(etl::handle<synfig::Canvas> canvas)
2560 if(!canvas) return 0;
2561 canvas=canvas->get_root();
2563 std::list<etl::handle<Instance> >::iterator iter;
2564 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2566 if((*iter)->get_canvas()==canvas)
2582 if(selected_instance)
2583 selected_instance->undo();
2589 if(selected_instance)
2590 selected_instance->redo();
2594 studio::App::get_base_path()
2596 return app_base_path_;