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
12 ** Copyright (c) 2009 Nikita Kitaev
14 ** This package is free software; you can redistribute it and/or
15 ** modify it under the terms of the GNU General Public License as
16 ** published by the Free Software Foundation; either version 2 of
17 ** the License, or (at your option) any later version.
19 ** This package is distributed in the hope that it will be useful,
20 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 ** General Public License for more details.
25 /* ========================================================================= */
27 /* === H E A D E R S ======================================================= */
46 #ifdef HAVE_SYS_ERRNO_H
47 #include <sys/errno.h>
49 #include <gtkmm/fileselection.h>
50 #include <gtkmm/dialog.h>
51 #include <gtkmm/messagedialog.h>
52 #include <gtkmm/label.h>
53 #include <gtkmm/stock.h>
54 #include <gtkmm/stockitem.h>
55 #include <gtkmm/iconsource.h>
56 #include <gtkmm/inputdialog.h>
57 #include <gtkmm/accelmap.h>
58 #include <gtkmm/uimanager.h>
59 #include <gtkmm/textview.h>
63 #include <gdkmm/general.h>
65 #include <synfig/loadcanvas.h>
66 #include <synfig/savecanvas.h>
69 #include "dialogs/about.h"
72 #include "canvasview.h"
73 #include "dialogs/dialog_setup.h"
74 #include "dialogs/dialog_gradient.h"
75 #include "dialogs/dialog_color.h"
77 #include "onemoment.h"
79 #include "docks/dockmanager.h"
81 #include "states/state_eyedrop.h"
82 #include "states/state_normal.h"
83 #include "states/state_mirror.h"
84 #include "states/state_draw.h"
85 #include "states/state_fill.h"
86 #include "states/state_bline.h"
87 #include "states/state_polygon.h"
88 #include "states/state_sketch.h"
89 #include "states/state_gradient.h"
90 #include "states/state_circle.h"
91 #include "states/state_rectangle.h"
92 #include "states/state_smoothmove.h"
93 #include "states/state_scale.h"
94 #include "states/state_star.h"
95 #include "states/state_text.h"
96 #include "states/state_width.h"
97 #include "states/state_rotate.h"
98 #include "states/state_zoom.h"
100 #include "devicetracker.h"
101 #include "docks/dialog_tooloptions.h"
102 #include "widgets/widget_enum.h"
104 #include "autorecover.h"
106 #include <synfigapp/settings.h>
107 #include "docks/dock_history.h"
108 #include "docks/dock_canvases.h"
109 #include "docks/dock_keyframes.h"
110 #include "docks/dock_layers.h"
111 #include "docks/dock_params.h"
112 #include "docks/dock_metadata.h"
113 #include "docks/dock_children.h"
114 #include "docks/dock_info.h"
115 #include "docks/dock_navigator.h"
116 #include "docks/dock_layergroups.h"
117 #include "docks/dock_timetrack.h"
118 #include "docks/dock_curves.h"
120 #include "modules/module.h"
121 #include "modules/mod_palette/mod_palette.h"
123 #include <sys/stat.h>
127 #include "statemanager.h"
133 #include <gtkmm/accelmap.h>
134 #include <gtkmm/filechooser.h>
135 #include <gtkmm/filechooserdialog.h>
141 /* === U S I N G =========================================================== */
145 using namespace synfig;
146 using namespace studio;
148 /* === M A C R O S ========================================================= */
150 #ifndef SYNFIG_USER_APP_DIR
152 #define SYNFIG_USER_APP_DIR "Library/Synfig"
153 #elif defined(_WIN32)
154 #define SYNFIG_USER_APP_DIR "Synfig"
156 #define SYNFIG_USER_APP_DIR ".synfig"
161 #define DPM2DPI(x) (float(x)/39.3700787402f)
162 #define DPI2DPM(x) (float(x)*39.3700787402f)
168 # define IMAGE_DIR "share\\pixmaps"
173 # define IMAGE_DIR "/usr/local/share/pixmaps"
177 # define IMAGE_EXT "tif"
180 #include <synfigapp/main.h>
182 /* === S I G N A L S ======================================================= */
184 static sigc::signal<void> signal_present_all_;
186 App::signal_present_all() { return signal_present_all_; }
188 static sigc::signal<void> signal_recent_files_changed_;
190 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
192 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
193 sigc::signal<void,etl::loose_handle<CanvasView> >&
194 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
196 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
197 sigc::signal<void,etl::handle<Instance> >&
198 App::signal_instance_selected() { return signal_instance_selected_; }
200 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
201 sigc::signal<void,etl::handle<Instance> >&
202 App::signal_instance_created() { return signal_instance_created_; }
204 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
205 sigc::signal<void,etl::handle<Instance> >&
206 App::signal_instance_deleted() { return signal_instance_deleted_; }
208 /* === G L O B A L S ======================================================= */
210 static std::list<std::string> recent_files;
211 const std::list<std::string>& App::get_recent_files() { return recent_files; }
213 static std::list<std::string> recent_files_window_size;
215 int App::Busy::count;
216 bool App::shutdown_in_progress;
218 synfig::Gamma App::gamma;
220 Glib::RefPtr<studio::UIManager> App::ui_manager_;
222 synfig::Distance::System App::distance_system;
224 studio::Dialog_Setup* App::dialog_setup;
226 etl::handle< studio::ModPalette > mod_palette_;
227 //studio::Dialog_Palette* App::dialog_palette;
229 std::list<etl::handle<Instance> > App::instance_list;
231 static etl::handle<synfigapp::UIInterface> ui_interface_;
232 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
234 etl::handle<Instance> App::selected_instance;
235 etl::handle<CanvasView> App::selected_canvas_view;
237 studio::About *studio::App::about=NULL;
239 studio::Toolbox *studio::App::toolbox=NULL;
241 studio::AutoRecover *studio::App::auto_recover=NULL;
243 studio::IPC *ipc=NULL;
245 studio::DockManager* studio::App::dock_manager=0;
247 studio::DeviceTracker* studio::App::device_tracker=0;
249 studio::Dialog_Gradient* studio::App::dialog_gradient;
251 studio::Dialog_Color* studio::App::dialog_color;
253 Gtk::InputDialog* studio::App::dialog_input;
255 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
257 studio::Dock_History* dock_history;
258 studio::Dock_Canvases* dock_canvases;
259 studio::Dock_Keyframes* dock_keyframes;
260 studio::Dock_Layers* dock_layers;
261 studio::Dock_Params* dock_params;
262 studio::Dock_MetaData* dock_meta_data;
263 studio::Dock_Children* dock_children;
264 studio::Dock_Info* dock_info;
265 studio::Dock_LayerGroups* dock_layer_groups;
266 studio::Dock_Navigator* dock_navigator;
267 studio::Dock_Timetrack* dock_timetrack;
268 studio::Dock_Curves* dock_curves;
270 std::list< etl::handle< studio::Module > > module_list_;
272 bool studio::App::use_colorspace_gamma=true;
273 #ifdef SINGLE_THREADED
275 bool studio::App::single_threaded=true;
277 bool studio::App::single_threaded=false;
279 #endif // SINGLE THREADED
280 bool studio::App::restrict_radius_ducks=false;
281 bool studio::App::resize_imported_images=false;
282 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
283 int studio::App::preferred_x_size=480;
284 int studio::App::preferred_y_size=270;
285 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
286 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
287 float studio::App::preferred_fps=24.0;
288 #ifdef USE_OPEN_FOR_URLS
289 String studio::App::browser_command("open"); // MacOS only
291 String studio::App::browser_command("xdg-open"); // Linux XDG standard
294 static int max_recent_files_=25;
295 int studio::App::get_max_recent_files() { return max_recent_files_; }
296 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
298 static synfig::String app_base_path_;
303 really_delete_widget(Gtk::Widget *widget)
305 // synfig::info("really delete %p", (void*)widget);
310 // nasty workaround - when we've finished with a popup menu, we want to delete it
311 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
312 // so schedule the real delete to happen in 50ms, giving the action a chance to run
314 delete_widget(Gtk::Widget *widget)
316 // synfig::info("delete %p", (void*)widget);
317 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
320 }; // END of namespace studio
321 studio::StateManager* state_manager;
326 class GlobalUIInterface : public synfigapp::UIInterface
330 virtual Response confirmation(const std::string &title,
331 const std::string &primaryText,
332 const std::string &secondaryText,
333 const std::string &confirmPhrase,
334 const std::string &cancelPhrase,
335 Response defaultResponse)
337 Gtk::MessageDialog dialog(
338 primaryText, // Message
340 Gtk::MESSAGE_WARNING, // Type
341 Gtk::BUTTONS_NONE, // Buttons
346 dialog.set_title(title);
347 if (! secondaryText.empty())
348 dialog.set_secondary_text(secondaryText);
350 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
351 dialog.add_button(confirmPhrase, RESPONSE_OK);
352 dialog.set_default_response(defaultResponse);
355 return (Response) dialog.run();
358 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
363 true // use_separator
365 Gtk::Label label(message);
368 dialog.get_vbox()->pack_start(label);
369 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
370 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
372 dialog.set_default_response(dflt);
374 return (Response)dialog.run();
376 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
381 true // use_separator
383 Gtk::Label label(message);
386 dialog.get_vbox()->pack_start(label);
387 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
388 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
389 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
391 dialog.set_default_response(dflt);
393 return (Response)dialog.run();
395 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
400 true // use_separator
402 Gtk::Label label(message);
405 dialog.get_vbox()->pack_start(label);
406 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
407 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
409 dialog.set_default_response(dflt);
411 return (Response)dialog.run();
415 task(const std::string &task)
417 std::cerr<<task<<std::endl;
418 while(studio::App::events_pending())studio::App::iteration(false);
423 error(const std::string &err)
425 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
432 warning(const std::string &err)
434 std::cerr<<"warning: "<<err<<std::endl;
435 while(studio::App::events_pending())studio::App::iteration(false);
440 amount_complete(int /*current*/, int /*total*/)
442 while(studio::App::events_pending())studio::App::iteration(false);
447 /* === P R O C E D U R E S ================================================= */
451 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
453 action_group_list.push_back(action_group);
454 Gtk::UIManager::insert_action_group(action_group, pos);
458 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
460 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
461 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
462 if(*iter==action_group)
464 action_group_list.erase(iter);
465 Gtk::UIManager::remove_action_group(action_group);
468 synfig::error("Unable to find action group");
472 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
474 ui_manager->insert_action_group(group,0);
476 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
477 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
479 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
481 if(*iter && (*iter)->get_name()!="menus")
483 synfig::info("Removing action group "+(*iter)->get_name());
484 ui_manager->remove_action_group(*iter);
487 ui_manager->insert_action_group(group,0);
489 for(;!prev_groups.empty();prev_groups.pop_front())
491 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
492 ui_manager->insert_action_group(prev_groups.front(),1);
496 class Preferences : public synfigapp::Settings
499 virtual bool get_value(const synfig::String& key, synfig::String& value)const
503 synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
506 value=strprintf("%f %f %f %f",
507 App::gamma.get_gamma_r(),
508 App::gamma.get_gamma_g(),
509 App::gamma.get_gamma_b(),
510 App::gamma.get_black_level()
514 if(key=="time_format")
516 value=strprintf("%i",App::get_time_format());
519 if(key=="file_history.size")
521 value=strprintf("%i",App::get_max_recent_files());
524 if(key=="use_colorspace_gamma")
526 value=strprintf("%i",(int)App::use_colorspace_gamma);
529 if(key=="distance_system")
531 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
534 #ifdef SINGLE_THREADED
535 if(key=="single_threaded")
537 value=strprintf("%i",(int)App::single_threaded);
541 if(key=="auto_recover_backup_interval")
543 value=strprintf("%i",App::auto_recover->get_timeout());
546 if(key=="restrict_radius_ducks")
548 value=strprintf("%i",(int)App::restrict_radius_ducks);
551 if(key=="resize_imported_images")
553 value=strprintf("%i",(int)App::resize_imported_images);
556 if(key=="browser_command")
558 value=App::browser_command;
561 if(key=="custom_filename_prefix")
563 value=App::custom_filename_prefix;
566 if(key=="preferred_x_size")
568 value=strprintf("%i",App::preferred_x_size);
571 if(key=="preferred_y_size")
573 value=strprintf("%i",App::preferred_y_size);
576 if(key=="predefined_size")
578 value=strprintf("%s",App::predefined_size.c_str());
581 if(key=="preferred_fps")
583 value=strprintf("%f",App::preferred_fps);
586 if(key=="predefined_fps")
588 value=strprintf("%s",App::predefined_fps.c_str());
594 synfig::warning("Preferences: Caught exception when attempting to get value.");
596 return synfigapp::Settings::get_value(key,value);
599 virtual bool set_value(const synfig::String& key,const synfig::String& value)
603 synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
608 strscanf(value,"%f %f %f %f",
615 App::gamma.set_all(r,g,b,blk);
619 if(key=="time_format")
621 int i(atoi(value.c_str()));
622 App::set_time_format(static_cast<synfig::Time::Format>(i));
625 if(key=="auto_recover_backup_interval")
627 int i(atoi(value.c_str()));
628 App::auto_recover->set_timeout(i);
631 if(key=="file_history.size")
633 int i(atoi(value.c_str()));
634 App::set_max_recent_files(i);
637 if(key=="use_colorspace_gamma")
639 int i(atoi(value.c_str()));
640 App::use_colorspace_gamma=i;
643 if(key=="distance_system")
645 App::distance_system=Distance::ident_system(value);;
648 #ifdef SINGLE_THREADED
649 if(key=="single_threaded")
651 int i(atoi(value.c_str()));
652 App::single_threaded=i;
656 if(key=="restrict_radius_ducks")
658 int i(atoi(value.c_str()));
659 App::restrict_radius_ducks=i;
662 if(key=="resize_imported_images")
664 int i(atoi(value.c_str()));
665 App::resize_imported_images=i;
668 if(key=="browser_command")
670 App::browser_command=value;
673 if(key=="custom_filename_prefix")
675 App::custom_filename_prefix=value;
678 if(key=="preferred_x_size")
680 int i(atoi(value.c_str()));
681 App::preferred_x_size=i;
684 if(key=="preferred_y_size")
686 int i(atoi(value.c_str()));
687 App::preferred_y_size=i;
690 if(key=="predefined_size")
692 App::predefined_size=value;
695 if(key=="preferred_fps")
697 float i(atof(value.c_str()));
698 App::preferred_fps=i;
701 if(key=="predefined_fps")
703 App::predefined_fps=value;
709 synfig::warning("Preferences: Caught exception when attempting to set value.");
711 return synfigapp::Settings::set_value(key,value);
714 virtual KeyList get_key_list()const
716 KeyList ret(synfigapp::Settings::get_key_list());
717 ret.push_back("gamma");
718 ret.push_back("time_format");
719 ret.push_back("distance_system");
720 ret.push_back("file_history.size");
721 ret.push_back("use_colorspace_gamma");
722 #ifdef SINGLE_THREADED
723 ret.push_back("single_threaded");
725 ret.push_back("auto_recover_backup_interval");
726 ret.push_back("restrict_radius_ducks");
727 ret.push_back("resize_imported_images");
728 ret.push_back("browser_command");
729 ret.push_back("custom_filename_prefix");
730 ret.push_back("preferred_x_size");
731 ret.push_back("preferred_y_size");
732 ret.push_back("predefined_size");
733 ret.push_back("preferred_fps");
734 ret.push_back("predefined_fps");
739 static ::Preferences _preferences;
744 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
746 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
748 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
750 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
751 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
752 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
753 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
754 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
755 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
756 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
757 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
758 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
759 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
760 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
761 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
762 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
764 // Add the synfigapp actions...
765 synfigapp::Action::Book::iterator iter;
766 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
768 actions_action_group->add(Gtk::Action::create(
769 "action-"+iter->second.name,
770 get_action_stock_id(iter->second),
771 iter->second.local_name,iter->second.local_name
775 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); actions_action_group->add(action); }
776 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); actions_action_group->add(action); }
777 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); group->add(action,sig); }
779 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
780 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
781 DEFINE_ACTION("new", Gtk::Stock::NEW);
782 DEFINE_ACTION("open", Gtk::Stock::OPEN);
783 DEFINE_ACTION("save", Gtk::Stock::SAVE);
784 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
785 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
786 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
787 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
788 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
789 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
790 DEFINE_ACTION("import", _("Import"));
791 DEFINE_ACTION("render", _("Render"));
792 DEFINE_ACTION("preview", _("Preview"));
793 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
794 DEFINE_ACTION("sound", _("Sound File"));
795 DEFINE_ACTION("options", _("Options"));
796 DEFINE_ACTION("close", _("Close View"));
797 DEFINE_ACTION("close-document", _("Close Document"));
798 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
801 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
802 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
803 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
804 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
805 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
806 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
807 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
808 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
809 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
810 DEFINE_ACTION("properties", _("Properties"));
812 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
813 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
814 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
815 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
816 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
817 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
818 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
819 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
820 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
821 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
822 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
823 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
824 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
825 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
826 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
827 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
828 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
829 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
830 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
831 DEFINE_ACTION("play", _("Play"));
832 // DEFINE_ACTION("pause", _("Pause"));
833 DEFINE_ACTION("stop", _("Stop"));
834 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
835 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
836 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
837 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
838 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
839 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
840 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
841 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
842 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
843 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
844 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
845 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
846 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
847 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
848 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
849 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
850 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
851 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
852 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
853 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
854 DEFINE_ACTION("seek-end", _("Seek to End"));
856 DEFINE_ACTION("action-group_add", _("Add group"));
858 DEFINE_ACTION("canvas-new", _("New Canvas"));
860 DEFINE_ACTION("amount-inc", _("Increase Amount"));
861 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
864 #undef DEFINE_ACTION_2
865 #undef DEFINE_ACTION_SIG
867 Glib::ustring ui_info =
869 " <popup name='menu-toolbox' action='menu-toolbox'>"
870 " <menu action='menu-file'>"
873 " <popup name='menu-main' action='menu-main'>"
874 " <menu action='menu-file'>"
875 " <menuitem action='new' />"
876 " <menuitem action='open' />"
877 " <menuitem action='save' />"
878 " <menuitem action='save-as' />"
879 " <menuitem action='revert' />"
880 " <separator name='bleh01'/>"
881 " <menuitem action='cvs-add' />"
882 " <menuitem action='cvs-update' />"
883 " <menuitem action='cvs-commit' />"
884 " <menuitem action='cvs-revert' />"
885 " <separator name='bleh02'/>"
886 " <menuitem action='import' />"
887 " <separator name='bleh03'/>"
888 " <menuitem action='render' />"
889 " <menuitem action='preview' />"
890 " <menuitem action='sound' />"
891 " <separator name='bleh04'/>"
892 " <menuitem action='options' />"
893 " <menuitem action='close' />"
894 " <menuitem action='close-document' />"
895 " <menuitem action='quit' />"
897 " <menu action='menu-edit'>"
898 " <menuitem action='undo'/>"
899 " <menuitem action='redo'/>"
900 " <separator name='bleh05'/>"
901 " <menuitem action='cut'/>"
902 " <menuitem action='copy'/>"
903 " <menuitem action='paste'/>"
904 " <separator name='bleh06'/>"
905 " <menuitem action='select-all-layers'/>"
906 " <menuitem action='unselect-all-layers'/>"
907 " <menuitem action='select-all-ducks'/>"
908 " <menuitem action='unselect-all-ducks'/>"
909 " <separator name='bleh07'/>"
910 " <menuitem action='properties'/>"
912 " <menu action='menu-view'>"
913 " <menu action='menu-duck-mask'>"
914 " <menuitem action='mask-position-ducks' />"
915 " <menuitem action='mask-vertex-ducks' />"
916 " <menuitem action='mask-tangent-ducks' />"
917 " <menuitem action='mask-radius-ducks' />"
918 " <menuitem action='mask-width-ducks' />"
919 " <menuitem action='mask-angle-ducks' />"
921 " <menu action='menu-preview-quality'>"
922 " <menuitem action='quality-00' />"
923 " <menuitem action='quality-01' />"
924 " <menuitem action='quality-02' />"
925 " <menuitem action='quality-03' />"
926 " <menuitem action='quality-04' />"
927 " <menuitem action='quality-05' />"
928 " <menuitem action='quality-06' />"
929 " <menuitem action='quality-07' />"
930 " <menuitem action='quality-08' />"
931 " <menuitem action='quality-09' />"
932 " <menuitem action='quality-10' />"
934 " <menu action='menu-lowres-pixel'>"
935 " <menuitem action='decrease-low-res-pixel-size'/>"
936 " <menuitem action='increase-low-res-pixel-size'/>"
937 " <separator name='pixel-size-separator'/>"
940 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
941 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
945 " <separator name='bleh08'/>"
946 " <menuitem action='play'/>"
947 //" <menuitem action='pause'/>"
948 " <menuitem action='stop'/>"
949 " <menuitem action='dialog-flipbook'/>"
950 " <separator name='bleh09'/>"
951 " <menuitem action='toggle-grid-show'/>"
952 " <menuitem action='toggle-grid-snap'/>"
953 " <menuitem action='toggle-guide-show'/>"
954 " <menuitem action='toggle-low-res'/>"
955 " <menuitem action='toggle-onion-skin'/>"
956 " <separator name='bleh10'/>"
957 " <menuitem action='canvas-zoom-in'/>"
958 " <menuitem action='canvas-zoom-out'/>"
959 " <menuitem action='canvas-zoom-fit'/>"
960 " <menuitem action='canvas-zoom-100'/>"
961 " <separator name='bleh11'/>"
962 " <menuitem action='time-zoom-in'/>"
963 " <menuitem action='time-zoom-out'/>"
964 " <separator name='bleh12'/>"
965 " <menuitem action='jump-next-keyframe'/>"
966 " <menuitem action='jump-prev-keyframe'/>"
967 " <menuitem action='seek-next-frame'/>"
968 " <menuitem action='seek-prev-frame'/>"
969 " <menuitem action='seek-next-second'/>"
970 " <menuitem action='seek-prev-second'/>"
971 " <menuitem action='seek-begin'/>"
972 " <menuitem action='seek-end'/>"
974 " <menu action='menu-canvas'>"
975 " <menuitem action='canvas-new'/>"
977 " <menu name='menu-state' action='menu-state'>"
979 " <menu action='menu-group'>"
980 " <menuitem action='action-group_add'/>"
982 " <menu action='menu-layer'>"
983 //" <menuitem action='cut'/>"
984 //" <menuitem action='copy'/>"
985 //" <menuitem action='paste'/>"
986 //" <separator name='bleh06'/>"
987 " <menu action='menu-layer-new'></menu>"
988 " <menuitem action='amount-inc'/>"
989 " <menuitem action='amount-dec'/>"
991 " <menu action='menu-keyframe'>"
992 " <menuitem action='keyframe-properties'/>"
999 " <menubar name='MenuBar'>"
1000 " <menu action='MenuFile'>"
1001 " <menuitem action='New'/>"
1002 " <menuitem action='Open'/>"
1004 " <menuitem action='Quit'/>"
1006 " <menu action='MenuEdit'>"
1007 " <menuitem action='Cut'/>"
1008 " <menuitem action='Copy'/>"
1009 " <menuitem action='Paste'/>"
1012 " <toolbar name='ToolBar'>"
1013 " <toolitem action='Open'/>"
1014 " <toolitem action='Quit'/>"
1020 actions_action_group->set_sensitive(false);
1021 App::ui_manager()->set_add_tearoffs(true);
1022 App::ui_manager()->insert_action_group(menus_action_group,1);
1023 App::ui_manager()->insert_action_group(actions_action_group,1);
1024 App::ui_manager()->add_ui_from_string(ui_info);
1026 //App::ui_manager()->get_accel_group()->unlock();
1028 catch(const Glib::Error& ex)
1030 synfig::error("building menus and toolbars failed: " + ex.what());
1033 // Add default keyboard accelerators
1034 #define ACCEL(accel,path) \
1036 Gtk::AccelKey accel_key(accel,path); \
1037 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1040 #define ACCEL2(accel) \
1042 Gtk::AccelKey accel_key(accel); \
1043 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1047 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1048 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1049 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1050 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1051 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1052 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1053 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1054 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1055 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1056 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1057 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1058 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1059 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1060 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1061 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1062 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1063 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1064 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1067 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1068 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1069 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1070 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1071 ACCEL("F9", "<Actions>/canvasview/render" );
1072 ACCEL("F11", "<Actions>/canvasview/preview" );
1073 ACCEL("F8", "<Actions>/canvasview/properties" );
1074 ACCEL("F12", "<Actions>/canvasview/options" );
1075 ACCEL("<control>i", "<Actions>/canvasview/import" );
1076 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1077 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1078 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1079 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1080 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1081 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1082 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1083 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1084 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1085 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1086 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1087 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1088 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1089 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1090 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1091 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1092 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1093 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1094 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1095 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1096 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1097 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1098 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1099 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1100 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1101 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1102 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1103 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1104 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1105 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1106 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1107 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1108 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1109 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1110 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1111 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1112 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1113 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1114 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1115 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1116 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1117 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1118 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1119 ACCEL("End", "<Actions>/canvasview/seek-end" );
1126 #define mkdir(x,y) mkdir(x)
1129 /* === M E T H O D S ======================================================= */
1131 App::App(int *argc, char ***argv):
1132 Gtk::Main(argc,argv),
1133 IconController(etl::dirname((*argv)[0]))
1135 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1138 ui_interface_=new GlobalUIInterface();
1142 // don't call thread_init() if threads are already initialized
1143 // on some machines bonobo_init() initialized threads before we get here
1144 if (!g_thread_supported())
1145 Glib::thread_init();
1147 distance_system=Distance::SYSTEM_UNITS;
1149 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1152 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1156 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1162 if(!SYNFIG_CHECK_VERSION())
1164 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1165 dialog_error_blocking("Synfig Studio",
1166 "This copy of Synfig Studio was compiled against a\n"
1167 "different version of libsynfig than what is currently\n"
1168 "installed. Synfig Studio will now abort. Try downloading\n"
1169 "the latest version from the Synfig website at\n"
1170 "http://synfig.org/en/current-release"
1174 Glib::set_application_name(_("Synfig Studio"));
1176 Splash splash_screen;
1177 splash_screen.show();
1179 shutdown_in_progress=false;
1180 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1181 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1183 // Initialize the Synfig library
1184 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1185 catch(std::runtime_error x)
1187 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1192 get_ui_interface()->error(_("Failed to initialize synfig!"));
1196 // add the preferences to the settings
1197 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1201 studio_init_cb.task(_("Init UI Manager..."));
1202 App::ui_manager_=studio::UIManager::create();
1205 studio_init_cb.task(_("Init Dock Manager..."));
1206 dock_manager=new studio::DockManager();
1208 studio_init_cb.task(_("Init State Manager..."));
1209 state_manager=new StateManager();
1211 studio_init_cb.task(_("Init Toolbox..."));
1212 toolbox=new studio::Toolbox();
1214 studio_init_cb.task(_("Init About Dialog..."));
1215 about=new studio::About();
1217 studio_init_cb.task(_("Init Tool Options..."));
1218 dialog_tool_options=new studio::Dialog_ToolOptions();
1219 dock_manager->register_dockable(*dialog_tool_options);
1221 studio_init_cb.task(_("Init History..."));
1222 dock_history=new studio::Dock_History();
1223 dock_manager->register_dockable(*dock_history);
1225 studio_init_cb.task(_("Init Canvases..."));
1226 dock_canvases=new studio::Dock_Canvases();
1227 dock_manager->register_dockable(*dock_canvases);
1229 studio_init_cb.task(_("Init Keyframes..."));
1230 dock_keyframes=new studio::Dock_Keyframes();
1231 dock_manager->register_dockable(*dock_keyframes);
1233 studio_init_cb.task(_("Init Layers..."));
1234 dock_layers=new studio::Dock_Layers();
1235 dock_manager->register_dockable(*dock_layers);
1237 studio_init_cb.task(_("Init Params..."));
1238 dock_params=new studio::Dock_Params();
1239 dock_manager->register_dockable(*dock_params);
1241 studio_init_cb.task(_("Init MetaData..."));
1242 dock_meta_data=new studio::Dock_MetaData();
1243 dock_manager->register_dockable(*dock_meta_data);
1245 studio_init_cb.task(_("Init Children..."));
1246 dock_children=new studio::Dock_Children();
1247 dock_manager->register_dockable(*dock_children);
1249 studio_init_cb.task(_("Init Info..."));
1250 dock_info = new studio::Dock_Info();
1251 dock_manager->register_dockable(*dock_info);
1253 studio_init_cb.task(_("Init Navigator..."));
1254 dock_navigator = new studio::Dock_Navigator();
1255 dock_manager->register_dockable(*dock_navigator);
1257 studio_init_cb.task(_("Init Timetrack..."));
1258 dock_timetrack = new studio::Dock_Timetrack();
1259 dock_manager->register_dockable(*dock_timetrack);
1261 studio_init_cb.task(_("Init Curve Editor..."));
1262 dock_curves = new studio::Dock_Curves();
1263 dock_manager->register_dockable(*dock_curves);
1265 studio_init_cb.task(_("Init Layer Groups..."));
1266 dock_layer_groups = new studio::Dock_LayerGroups();
1267 dock_manager->register_dockable(*dock_layer_groups);
1270 studio_init_cb.task(_("Init Color Dialog..."));
1271 dialog_color=new studio::Dialog_Color();
1273 studio_init_cb.task(_("Init Gradient Dialog..."));
1274 dialog_gradient=new studio::Dialog_Gradient();
1276 studio_init_cb.task(_("Init DeviceTracker..."));
1277 device_tracker=new studio::DeviceTracker();
1279 studio_init_cb.task(_("Init Tools..."));
1282 state_manager->add_state(&state_normal);
1283 state_manager->add_state(&state_smooth_move);
1284 state_manager->add_state(&state_scale);
1285 state_manager->add_state(&state_rotate);
1286 state_manager->add_state(&state_mirror);
1289 state_manager->add_state(&state_circle);
1290 state_manager->add_state(&state_rectangle);
1291 state_manager->add_state(&state_star);
1292 state_manager->add_state(&state_gradient);
1293 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1296 state_manager->add_state(&state_bline);
1297 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1298 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1299 state_manager->add_state(&state_fill);
1300 state_manager->add_state(&state_eyedrop);
1303 state_manager->add_state(&state_text);
1304 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1305 state_manager->add_state(&state_zoom);
1307 studio_init_cb.task(_("Init ModPalette..."));
1308 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1310 studio_init_cb.task(_("Init Setup Dialog..."));
1311 dialog_setup=new studio::Dialog_Setup();
1313 studio_init_cb.task(_("Init Input Dialog..."));
1314 dialog_input=new Gtk::InputDialog();
1315 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1316 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1318 studio_init_cb.task(_("Init auto recovery..."));
1319 auto_recover=new AutoRecover();
1321 studio_init_cb.amount_complete(9250,10000);
1322 studio_init_cb.task(_("Loading Settings..."));
1324 device_tracker->load_preferences();
1326 studio_init_cb.task(_("Checking auto-recover..."));
1328 studio_init_cb.amount_complete(9900,10000);
1330 bool opened_any = false;
1331 if(auto_recover->recovery_needed())
1333 splash_screen.hide();
1334 if (get_ui_interface()->confirmation(_("Crash Recovery"),
1335 _("Auto recovery file found"),
1336 _("Synfig Studio seems to have crashed before you could save all your files. "
1337 "Recover unsaved changes?"),
1338 _("Recover"), _("Ignore"))
1339 == synfigapp::UIInterface::RESPONSE_OK)
1341 int number_recovered;
1342 if(!auto_recover->recover(number_recovered))
1343 if (number_recovered)
1344 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1346 get_ui_interface()->error(_("Unable to recover from previous crash"));
1348 dialog_warning_blocking(_("Warning"),
1349 _("Synfig Studio has attempted to recover from a previous crash. "
1350 "The files that it has recovered are NOT YET SAVED. It would be a "
1351 "good idea to review them and save them now."));
1353 if (number_recovered)
1356 splash_screen.show();
1359 // Look for any files given on the command line,
1360 // and load them if found.
1361 for(;*argc>=1;(*argc)--)
1362 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1364 studio_init_cb.task(_("Loading files..."));
1365 splash_screen.hide();
1366 open((*argv)[*argc]);
1368 splash_screen.show();
1371 // if no file was specified to be opened, create a new document to help new users get started more easily
1372 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1375 studio_init_cb.task(_("Done."));
1376 studio_init_cb.amount_complete(10000,10000);
1378 // To avoid problems with some window managers and gtk >= 2.18
1379 // we should show dock dialogs after the settings load.
1380 // If dock dialogs are shown before the settings are loaded,
1381 // the windows manager can act over it.
1382 // See discussions here:
1383 // * http://synfig.org/forums/viewtopic.php?f=1&t=1131&st=0&sk=t&sd=a&start=30
1384 // * http://synfig.org/forums/viewtopic.php?f=15&t=1062
1385 dock_manager->show_all_dock_dialogs();
1391 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1395 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1399 StateManager* App::get_state_manager() { return state_manager; }
1403 shutdown_in_progress=true;
1407 synfigapp::Main::settings().remove_domain("pref");
1409 selected_instance=0;
1411 // Unload all of the modules
1412 for(;!module_list_.empty();module_list_.pop_back())
1415 delete state_manager;
1419 delete auto_recover;
1427 delete dialog_setup;
1429 delete dialog_gradient;
1431 delete dialog_color;
1433 delete dialog_input;
1435 delete dock_manager;
1437 instance_list.clear();
1441 App::get_user_app_directory()
1443 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1445 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1447 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1452 App::get_config_file(const synfig::String& file)
1454 return Glib::build_filename(get_user_app_directory(),file);
1457 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1459 App::set_recent_file_window_size(etl::handle<Instance> instance)
1462 const std::string &canvas_window_size = *recent_files_window_size.begin();
1464 if(canvas_window_size.empty())
1467 synfig::String::size_type current=0;
1468 bool seen_root(false), shown_non_root(false);
1470 while(current != synfig::String::npos)
1472 // find end of first field (canvas) or return
1473 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1474 if(separator == synfig::String::npos) break;
1477 synfig::Canvas::Handle canvas;
1480 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1482 catch(Exception::IDNotFound) {
1483 // can't find the canvas; skip to the next canvas or return
1484 separator = canvas_window_size.find_first_of('\t', current);
1485 if(separator == synfig::String::npos) return;
1486 current = separator+1;
1490 if (canvas->is_root())
1493 shown_non_root = true;
1495 // check that we have the tab character the ends this canvas' data or return
1496 current = separator+1;
1497 separator = canvas_window_size.find_first_of('\t', current);
1498 if(separator == synfig::String::npos) return;
1501 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1503 current = separator+1;
1506 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1507 canvasview->move(x,y);
1508 canvasview->resize(w,h);
1509 canvasview->present();
1511 current = separator+1;
1514 if (shown_non_root && !seen_root)
1515 instance->find_canvas_view(instance->get_canvas())->hide();
1519 App::add_recent_file(const etl::handle<Instance> instance)
1522 std::string canvas_window_size;
1524 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1525 Instance::CanvasViewList::const_iterator iter;
1527 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1529 if( !((*iter)->is_visible()) )
1532 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1533 int x_pos, y_pos, x_size, y_size;
1534 (*iter)->get_position(x_pos,y_pos);
1535 (*iter)->get_size(x_size,y_size);
1537 canvas_window_size += strprintf("%s %d %d %d %d\t",
1538 canvas->get_relative_id(canvas->get_root()).c_str(),
1543 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1547 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1549 std::string filename(file_name);
1551 assert(!filename.empty());
1553 if(filename.empty())
1556 // Toss out any "hidden" files
1557 if(basename(filename)[0]=='.')
1560 // If we aren't an absolute path, turn ourselves into one
1561 if(!is_absolute_path(filename))
1562 filename=absolute_path(filename);
1564 std::string old_window_size;
1566 list<string>::iterator iter;
1567 list<string>::iterator iter_wsize;
1568 // Check to see if the file is already on the list.
1569 // If it is, then remove it from the list
1570 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1573 recent_files.erase(iter);
1574 old_window_size = *iter_wsize;
1575 recent_files_window_size.erase(iter_wsize);
1580 // Push the filename to the front of the list
1581 recent_files.push_front(filename);
1582 if(window_size.empty())
1583 recent_files_window_size.push_front(old_window_size);
1585 recent_files_window_size.push_front(window_size);
1587 // Clean out the files at the end of the list.
1588 while(recent_files.size()>(unsigned)get_max_recent_files())
1590 recent_files.pop_back();
1591 recent_files_window_size.pop_back();
1594 signal_recent_files_changed_();
1599 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1602 App::get_time_format()
1604 return _App_time_format;
1608 App::set_time_format(synfig::Time::Format x)
1615 App::save_settings()
1619 synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
1621 std::string filename=get_config_file("accelrc");
1622 Gtk::AccelMap::save(filename);
1625 std::string filename=get_config_file("recentfiles");
1627 std::ofstream file(filename.c_str());
1631 synfig::warning("Unable to save %s",filename.c_str());
1635 list<string>::reverse_iterator iter;
1637 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1641 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1643 std::ofstream file(filename.c_str());
1647 synfig::warning("Unable to save %s",filename.c_str());
1651 list<string>::reverse_iterator iter;
1653 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1657 std::string filename=get_config_file("settings");
1658 synfigapp::Main::settings().save_to_file(filename);
1663 synfig::warning("Caught exception when attempting to save settings.");
1668 App::load_settings()
1672 synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
1674 std::string filename=get_config_file("accelrc");
1675 Gtk::AccelMap::load(filename);
1678 bool window_size_broken = false;
1680 std::string filename=get_config_file("recentfiles");
1681 std::string filename_window_size=filename+std::string("_window_size");
1683 std::ifstream file(filename.c_str());
1684 std::ifstream file_window_size(filename_window_size.c_str());
1686 if(!file_window_size)
1687 window_size_broken = true;
1691 std::string recent_file;
1692 std::string recent_file_window_size;
1693 getline(file,recent_file);
1694 if(!window_size_broken)
1695 getline(file_window_size,recent_file_window_size);
1696 if(!recent_file.empty())
1698 if(!window_size_broken && !file_window_size)
1699 window_size_broken = true;
1700 if (std::ifstream(recent_file.c_str()))
1702 if(!window_size_broken)
1703 add_recent_file(recent_file,recent_file_window_size);
1705 add_recent_file(recent_file);
1709 if(!window_size_broken && file_window_size)
1710 window_size_broken = true;
1712 if(window_size_broken)
1714 recent_files_window_size.clear();
1715 recent_files_window_size.resize(recent_files.size());
1718 std::string filename=get_config_file("settings");
1719 if(!synfigapp::Main::settings().load_from_file(filename))
1721 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1722 //if(!synfigapp::Main::settings().load_from_file(filename))
1724 gamma.set_gamma(1.0/2.2);
1725 reset_initial_window_configuration();
1732 synfig::warning("Caught exception when attempting to load settings.");
1737 App::reset_initial_window_configuration()
1739 Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
1740 Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
1741 Gdk::Rectangle rect;
1742 // A proper way to obtain the primary monitor is to use the
1743 // Gdk::Screen::get_primary_monitor () const member. But as it
1744 // was introduced in gtkmm 2.20 I assume that the monitor 0 is the
1746 screen->get_monitor_geometry(0,rect);
1747 #define hpanel_width 79.0f
1748 #define hpanel_height 25.0f
1749 #define vpanel_width 20.0f
1750 #define vpanel_height 100.0f
1754 /* percentages referred to width or height of the screen
1755 *---------------------------------------------------------------------*
1770 *-----hdock%----------------------------------------------|------------
1775 * --------------------------------------------------------------------*
1778 int v_xpos=rect.get_x() + rect.get_width()*(1.0-vpanel_width/100.0);
1779 int v_xsize=rect.get_width()*vpanel_width/100.0;
1780 int v_ypos=rect.get_y();
1781 int v_ysize=rect.get_height()*vpanel_height/100.0;
1782 std::string v_pos(strprintf("%d %d", v_xpos, v_ypos));
1783 std::string v_size(strprintf("%d %d", v_xsize, v_ysize));
1785 int h_xpos=rect.get_x();
1786 int h_xsize=rect.get_width()*hpanel_width/100.0;
1787 int h_ypos=rect.get_y()+ rect.get_height()*(1.0-hpanel_height/100.0);;
1788 int h_ysize=rect.get_height()*hpanel_height/100.0;
1789 std::string h_pos(strprintf("%d %d", h_xpos, h_ypos));
1790 std::string h_size(strprintf("%d %d", h_xsize, h_ysize));
1791 int v_dock1 = rect.get_height()*vdock*0.8/100.0;
1792 int v_dock2 = rect.get_height()*vdock*0.6/100.0;
1793 int v_dock3 = rect.get_height()*vdock*1.1/100.0;
1794 int h_dock = rect.get_width()*hdock/100.0;
1796 std::string v_contents(strprintf("%d %d %d", v_dock1, v_dock2, v_dock3));
1797 std::string h_contents(strprintf("%d", h_dock));
1798 // Tool Box position
1799 std::string tbox_pos(strprintf("%d %d", rect.get_x(), rect.get_y()));
1801 synfig::info("tool box pos: %s", tbox_pos.c_str());
1802 synfig::info("v_contents sizes: %s", v_contents.c_str());
1803 synfig::info("v_pos: %s", v_pos.c_str());
1804 synfig::info("v_sizes: %s", v_size.c_str());
1805 synfig::info("h_contents sizes: %s", h_contents.c_str());
1806 synfig::info("h_pos: %s", h_pos.c_str());
1807 synfig::info("h_sizes: %s", h_size.c_str());
1809 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1810 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1811 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size",v_contents);
1812 synfigapp::Main::settings().set_value("dock.dialog.1.size",v_size);
1813 synfigapp::Main::settings().set_value("dock.dialog.1.pos",v_pos);
1814 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1815 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1816 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size",h_contents);
1817 synfigapp::Main::settings().set_value("dock.dialog.2.size",h_size);
1818 synfigapp::Main::settings().set_value("dock.dialog.2.pos",h_pos);
1819 synfigapp::Main::settings().set_value("window.toolbox.pos",tbox_pos);
1821 dock_manager->show_all_dock_dialogs();
1825 App::reset_initial_preferences()
1827 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1828 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1829 #ifdef SINGLE_THREADED
1830 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1832 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1833 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1834 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1835 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1836 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1837 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1838 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1839 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1844 App::shutdown_request(GdkEventAny*)
1848 //return !shutdown_in_progress;
1854 if(shutdown_in_progress)return;
1857 get_ui_interface()->task(_("Quit Request"));
1860 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1864 std::list<etl::handle<Instance> >::iterator iter;
1865 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1867 if(!(*iter)->safe_close())
1871 if((*iter)->synfigapp::Instance::get_action_count())
1873 handle<synfigapp::UIInterface> uim;
1874 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1876 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1877 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1879 case synfigapp::UIInterface::RESPONSE_NO:
1881 case synfigapp::UIInterface::RESPONSE_YES:
1884 case synfigapp::UIInterface::RESPONSE_CANCEL:
1893 if((*iter)->synfigapp::Instance::is_modified())
1895 handle<synfigapp::UIInterface> uim;
1896 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1898 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() );
1899 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1901 case synfigapp::UIInterface::RESPONSE_NO:
1903 case synfigapp::UIInterface::RESPONSE_YES:
1904 (*iter)->dialog_cvs_commit();
1906 case synfigapp::UIInterface::RESPONSE_CANCEL:
1915 // This next line causes things to crash for some reason
1919 shutdown_in_progress=true;
1921 instance_list.clear();
1923 while(studio::App::events_pending())studio::App::iteration(false);
1926 auto_recover->normal_shutdown();
1928 get_ui_interface()->task(_("Quit Request sent"));
1934 dialog_setup->refresh();
1935 dialog_setup->show();
1938 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1939 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1942 //#define USE_WIN32_FILE_DIALOGS 1
1945 #ifdef USE_WIN32_FILE_DIALOGS
1946 static OPENFILENAME ofn={};
1950 #include <gdk/gdkwin32.h>
1954 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1956 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1958 #ifdef USE_WIN32_FILE_DIALOGS
1959 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1961 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1962 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1963 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1965 ofn.lStructSize=sizeof(OPENFILENAME);
1966 ofn.hwndOwner = hWnd;
1967 ofn.hInstance = hInstance;
1968 ofn.lpstrFilter = szFilter;
1969 // ofn.lpstrCustomFilter=NULL;
1970 // ofn.nMaxCustFilter=0;
1971 // ofn.nFilterIndex=0;
1972 // ofn.lpstrFile=NULL;
1973 ofn.nMaxFile=MAX_PATH;
1974 // ofn.lpstrFileTitle=NULL;
1975 // ofn.lpstrInitialDir=NULL;
1976 // ofn.lpstrTitle=NULL;
1977 ofn.Flags=OFN_HIDEREADONLY;
1978 // ofn.nFileOffset=0;
1979 // ofn.nFileExtension=0;
1980 ofn.lpstrDefExt=TEXT("sif");
1981 // ofn.lCustData = 0l;
1983 // ofn.lpTemplateName=NULL;
1985 CHAR szFilename[MAX_PATH];
1987 strcpy(szFilename,filename.c_str());
1988 strcpy(szTitle,title.c_str());
1990 ofn.lpstrFile=szFilename;
1991 ofn.lpstrFileTitle=szTitle;
1993 if(GetOpenFileName(&ofn))
1995 filename=szFilename;
2000 #else // not USE_WIN32_FILE_DIALOGS
2001 synfig::String prev_path;
2003 if(!_preferences.get_value(preference, prev_path))
2006 prev_path = absolute_path(prev_path);
2008 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2010 dialog->set_current_folder(prev_path);
2011 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2012 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
2014 if (filename.empty())
2015 dialog->set_filename(prev_path);
2016 else if (is_absolute_path(filename))
2017 dialog->set_filename(filename);
2019 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2021 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2022 filename = dialog->get_filename();
2023 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
2024 _preferences.set_value(preference, dirname(filename));
2031 #endif // not USE_WIN32_FILE_DIALOGS
2035 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2037 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2039 #if USE_WIN32_FILE_DIALOGS
2040 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2042 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2043 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2044 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2046 ofn.lStructSize=sizeof(OPENFILENAME);
2047 ofn.hwndOwner = hWnd;
2048 ofn.hInstance = hInstance;
2049 ofn.lpstrFilter = szFilter;
2050 // ofn.lpstrCustomFilter=NULL;
2051 // ofn.nMaxCustFilter=0;
2052 // ofn.nFilterIndex=0;
2053 // ofn.lpstrFile=NULL;
2054 ofn.nMaxFile=MAX_PATH;
2055 // ofn.lpstrFileTitle=NULL;
2056 // ofn.lpstrInitialDir=NULL;
2057 // ofn.lpstrTitle=NULL;
2058 ofn.Flags=OFN_OVERWRITEPROMPT;
2059 // ofn.nFileOffset=0;
2060 // ofn.nFileExtension=0;
2061 ofn.lpstrDefExt=TEXT("sif");
2062 // ofn.lCustData = 0l;
2064 // ofn.lpTemplateName=NULL;
2066 CHAR szFilename[MAX_PATH];
2068 strcpy(szFilename,filename.c_str());
2069 strcpy(szTitle,title.c_str());
2071 ofn.lpstrFile=szFilename;
2072 ofn.lpstrFileTitle=szTitle;
2074 if(GetSaveFileName(&ofn))
2076 filename=szFilename;
2077 _preferences.set_value(preference,dirname(filename));
2082 synfig::String prev_path;
2084 if(!_preferences.get_value(preference, prev_path))
2087 prev_path = absolute_path(prev_path);
2089 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2091 dialog->set_current_folder(prev_path);
2092 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2093 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2095 Widget_Enum *file_type_enum = 0;
2096 if (preference == ANIMATION_DIR_PREFERENCE)
2098 file_type_enum = manage(new Widget_Enum());
2099 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2100 .add_enum_value(synfig::RELEASE_VERSION_0_62_02, "0.62.02", strprintf("0.62.02 (%s)", _("current")))
2101 .add_enum_value(synfig::RELEASE_VERSION_0_62_01, "0.62.01", "0.62.01")
2102 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", "0.61.00")
2103 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2104 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2105 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2106 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2107 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2109 Gtk::HBox *hbox = manage(new Gtk::HBox);
2110 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2111 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2114 dialog->set_extra_widget(*hbox);
2117 if (filename.empty())
2118 dialog->set_filename(prev_path);
2121 std::string full_path;
2122 if (is_absolute_path(filename))
2123 full_path = filename;
2125 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2127 // select the file if it exists
2128 dialog->set_filename(full_path);
2130 // if the file doesn't exist, put its name into the filename box
2132 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2133 dialog->set_current_name(basename(filename));
2136 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2137 if (preference == ANIMATION_DIR_PREFERENCE)
2138 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2139 filename = dialog->get_filename();
2140 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2141 _preferences.set_value(preference, dirname(filename));
2152 App::dialog_error_blocking(const std::string &title, const std::string &message)
2154 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2155 dialog.set_title(title);
2161 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2163 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2164 dialog.set_title(title);
2170 App::dialog_yes_no(const std::string &title, const std::string &message)
2175 true // use_separator
2177 Gtk::Label label(message);
2180 dialog.get_vbox()->pack_start(label);
2181 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2182 dialog.add_button(Gtk::StockID("gtk-no"),0);
2184 return dialog.run();
2188 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2193 true // use_separator
2195 Gtk::Label label(message);
2198 dialog.get_vbox()->pack_start(label);
2199 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2200 dialog.add_button(Gtk::StockID("gtk-no"),0);
2201 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2203 return dialog.run();
2207 App::dialog_not_implemented()
2209 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2210 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2215 try_open_url(const std::string &url)
2218 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2220 std::vector<std::string> command_line;
2221 std::vector<std::string> browsers;
2222 browsers.reserve(23);
2224 // Browser wrapper scripts
2225 #ifdef USE_OPEN_FOR_URLS
2226 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2228 browsers.push_back("xdg-open"); // XDG wrapper
2229 browsers.push_back("sensible-browser"); // Debian wrapper
2230 browsers.push_back("gnome-open"); // GNOME wrapper
2231 browsers.push_back("kfmclient"); // KDE wrapper
2232 browsers.push_back("exo-open"); // XFCE wrapper
2234 // Alternatives system
2235 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2236 browsers.push_back("x-www-browser"); // Debian GUI alternative
2238 // Individual browsers
2239 browsers.push_back("firefox");
2240 browsers.push_back("epiphany-browser");
2241 browsers.push_back("epiphany");
2242 browsers.push_back("konqueror");
2243 browsers.push_back("iceweasel");
2244 browsers.push_back("mozilla");
2245 browsers.push_back("netscape");
2246 browsers.push_back("icecat");
2247 browsers.push_back("galeon");
2248 browsers.push_back("midori");
2249 browsers.push_back("safari");
2250 browsers.push_back("opera");
2251 browsers.push_back("amaya");
2252 browsers.push_back("netsurf");
2253 browsers.push_back("dillo");
2255 // Try the user-specified browser first
2256 command_line.push_back(App::browser_command);
2257 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2258 command_line.push_back(url);
2260 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2261 catch( Glib::SpawnError& exception ){
2263 while ( !browsers.empty() )
2265 // Skip the browser if we already tried it
2266 if( browsers[0] == App::browser_command )
2269 // Construct the command line
2270 command_line.clear();
2271 command_line.push_back(browsers[0]);
2272 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2273 command_line.push_back(url);
2275 // Remove the browser from the list
2276 browsers.erase(browsers.begin());
2278 // Try to spawn the browser
2279 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2280 // Failed, move on to the next one
2281 catch(Glib::SpawnError& exception){ continue; }
2282 return true; // No exception means we succeeded!
2293 if (!try_open_url("http://synfig.org/wiki/Category:Manual"))
2295 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2296 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://synfig.org/wiki/Category:Manual"));
2297 dialog.set_title(_("Help"));
2303 App::open_url(const std::string &url)
2305 if(!try_open_url(url))
2307 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2308 dialog.set_secondary_text(url);
2309 dialog.set_title(_("No browser found"));
2315 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2320 true); // use_separator
2322 Gtk::Label label(message);
2324 dialog.get_vbox()->pack_start(label);
2327 entry.set_text(text);
2329 entry.set_activates_default(true);
2331 dialog.get_vbox()->pack_start(entry);
2333 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2334 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2335 dialog.set_default_response(Gtk::RESPONSE_OK);
2337 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2340 if(dialog.run()!=Gtk::RESPONSE_OK)
2343 text=entry.get_text();
2349 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2354 true); // use_separator
2356 Gtk::Label label(message);
2358 dialog.get_vbox()->pack_start(label);
2360 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2361 text_buffer->set_text(text);
2362 Gtk::TextView text_view(text_buffer);
2365 dialog.get_vbox()->pack_start(text_view);
2367 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2368 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2369 dialog.set_default_response(Gtk::RESPONSE_OK);
2371 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2374 if(dialog.run()!=Gtk::RESPONSE_OK)
2377 text=text_buffer->get_text();
2383 App::open(std::string filename)
2385 return open_as(filename,filename);
2388 // this is called from autorecover.cpp:
2389 // App::open_as(get_shadow_file_name(filename),filename)
2390 // other than that, 'filename' and 'as' are the same
2392 App::open_as(std::string filename,std::string as)
2395 char long_name[1024];
2396 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2397 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2398 // don't use it if that's the case
2399 if (long_name[0] != '\0')
2405 OneMoment one_moment;
2406 String errors, warnings;
2408 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2409 if(canvas && get_instance(canvas))
2411 get_instance(canvas)->find_canvas_view(canvas)->present();
2412 info("%s is already open", filename.c_str());
2413 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2418 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2421 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2423 if (as.find(custom_filename_prefix.c_str()) != 0)
2424 add_recent_file(as);
2426 handle<Instance> instance(Instance::create(canvas));
2429 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2431 set_recent_file_window_size(instance);
2435 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)")))
2436 instance->dialog_cvs_update();
2441 dialog_error_blocking(_("Error"), x);
2444 catch(runtime_error x)
2446 dialog_error_blocking(_("Error"), x.what());
2451 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2462 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2464 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2465 canvas->set_name(file_name);
2466 file_name += ".sifz";
2468 canvas->rend_desc().set_frame_rate(preferred_fps);
2469 canvas->rend_desc().set_time_start(0.0);
2470 canvas->rend_desc().set_time_end(5.0);
2471 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2472 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2473 // The top left and botton right positions are expressed in units
2474 // Original convention is that 1 unit = 60 pixels
2475 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2476 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2477 canvas->rend_desc().set_w(preferred_x_size);
2478 canvas->rend_desc().set_h(preferred_y_size);
2479 canvas->rend_desc().set_antialias(1);
2480 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2481 canvas->set_file_name(file_name);
2483 handle<Instance> instance = Instance::create(canvas);
2485 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2486 instance->find_canvas_view(canvas)->canvas_properties.present();
2490 App::dialog_open(string filename)
2492 if (filename.empty())
2495 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2497 // If the filename still has wildcards, then we should
2498 // continue looking for the file we want
2499 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2505 get_ui_interface()->error(_("Unable to open file"));
2510 App::set_selected_instance(etl::loose_handle<Instance> instance)
2512 /* if(get_selected_instance()==instance)
2514 selected_instance=instance;
2515 signal_instance_selected()(instance);
2521 selected_instance=instance;
2522 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2526 instance->focus(instance->get_canvas());
2529 set_selected_canvas_view(0);
2531 signal_instance_selected()(instance);
2535 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2537 selected_canvas_view=canvas_view;
2538 signal_canvas_view_focus()(selected_canvas_view);
2541 selected_instance=canvas_view->get_instance();
2542 signal_instance_selected()(canvas_view->get_instance());
2545 if(get_selected_canvas_view()==canvas_view)
2547 signal_canvas_view_focus()(selected_canvas_view);
2548 signal_instance_selected()(canvas_view->get_instance());
2551 selected_canvas_view=canvas_view;
2552 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2553 set_selected_instance(canvas_view->get_instance());
2554 signal_canvas_view_focus()(selected_canvas_view);
2558 etl::loose_handle<Instance>
2559 App::get_instance(etl::handle<synfig::Canvas> canvas)
2561 if(!canvas) return 0;
2562 canvas=canvas->get_root();
2564 std::list<etl::handle<Instance> >::iterator iter;
2565 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2567 if((*iter)->get_canvas()==canvas)
2583 if(selected_instance)
2584 selected_instance->undo();
2590 if(selected_instance)
2591 selected_instance->redo();
2595 studio::App::get_base_path()
2597 return app_base_path_;