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();
1325 // If the default bline width is modified before focus a canvas
1326 // window, the Distance widget doesn't understand the given value
1327 // and produces this message:
1328 // Distance::ident_system(): Unknown distance system ".00pt"
1329 // setting the default bline width to 1 unit.
1330 // This line fixes that.
1331 synfigapp::Main::set_bline_width(synfigapp::Main::get_selected_input_device()->get_bline_width());
1333 studio_init_cb.task(_("Checking auto-recover..."));
1335 studio_init_cb.amount_complete(9900,10000);
1337 bool opened_any = false;
1338 if(auto_recover->recovery_needed())
1340 splash_screen.hide();
1341 if (get_ui_interface()->confirmation(_("Crash Recovery"),
1342 _("Auto recovery file found"),
1343 _("Synfig Studio seems to have crashed before you could save all your files. "
1344 "Recover unsaved changes?"),
1345 _("Recover"), _("Ignore"))
1346 == synfigapp::UIInterface::RESPONSE_OK)
1348 int number_recovered;
1349 if(!auto_recover->recover(number_recovered))
1350 if (number_recovered)
1351 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1353 get_ui_interface()->error(_("Unable to recover from previous crash"));
1355 dialog_warning_blocking(_("Warning"),
1356 _("Synfig Studio has attempted to recover from a previous crash. "
1357 "The files that it has recovered are NOT YET SAVED. It would be a "
1358 "good idea to review them and save them now."));
1360 if (number_recovered)
1363 splash_screen.show();
1366 // Look for any files given on the command line,
1367 // and load them if found.
1368 for(;*argc>=1;(*argc)--)
1369 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1371 studio_init_cb.task(_("Loading files..."));
1372 splash_screen.hide();
1373 open((*argv)[*argc]);
1375 splash_screen.show();
1378 // if no file was specified to be opened, create a new document to help new users get started more easily
1379 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1382 studio_init_cb.task(_("Done."));
1383 studio_init_cb.amount_complete(10000,10000);
1385 // To avoid problems with some window managers and gtk >= 2.18
1386 // we should show dock dialogs after the settings load.
1387 // If dock dialogs are shown before the settings are loaded,
1388 // the windows manager can act over it.
1389 // See discussions here:
1390 // * http://synfig.org/forums/viewtopic.php?f=1&t=1131&st=0&sk=t&sd=a&start=30
1391 // * http://synfig.org/forums/viewtopic.php?f=15&t=1062
1392 dock_manager->show_all_dock_dialogs();
1398 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1402 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1406 StateManager* App::get_state_manager() { return state_manager; }
1410 shutdown_in_progress=true;
1414 synfigapp::Main::settings().remove_domain("pref");
1416 selected_instance=0;
1418 // Unload all of the modules
1419 for(;!module_list_.empty();module_list_.pop_back())
1422 delete state_manager;
1426 delete auto_recover;
1434 delete dialog_setup;
1436 delete dialog_gradient;
1438 delete dialog_color;
1440 delete dialog_input;
1442 delete dock_manager;
1444 instance_list.clear();
1448 App::get_user_app_directory()
1450 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1452 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1454 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1459 App::get_config_file(const synfig::String& file)
1461 return Glib::build_filename(get_user_app_directory(),file);
1464 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1466 App::set_recent_file_window_size(etl::handle<Instance> instance)
1469 const std::string &canvas_window_size = *recent_files_window_size.begin();
1471 if(canvas_window_size.empty())
1474 synfig::String::size_type current=0;
1475 bool seen_root(false), shown_non_root(false);
1477 while(current != synfig::String::npos)
1479 // find end of first field (canvas) or return
1480 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1481 if(separator == synfig::String::npos) break;
1484 synfig::Canvas::Handle canvas;
1487 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1489 catch(Exception::IDNotFound) {
1490 // can't find the canvas; skip to the next canvas or return
1491 separator = canvas_window_size.find_first_of('\t', current);
1492 if(separator == synfig::String::npos) return;
1493 current = separator+1;
1497 if (canvas->is_root())
1500 shown_non_root = true;
1502 // check that we have the tab character the ends this canvas' data or return
1503 current = separator+1;
1504 separator = canvas_window_size.find_first_of('\t', current);
1505 if(separator == synfig::String::npos) return;
1508 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1510 current = separator+1;
1513 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1514 canvasview->move(x,y);
1515 canvasview->resize(w,h);
1516 canvasview->present();
1518 current = separator+1;
1521 if (shown_non_root && !seen_root)
1522 instance->find_canvas_view(instance->get_canvas())->hide();
1526 App::add_recent_file(const etl::handle<Instance> instance)
1529 std::string canvas_window_size;
1531 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1532 Instance::CanvasViewList::const_iterator iter;
1534 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1536 if( !((*iter)->is_visible()) )
1539 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1540 int x_pos, y_pos, x_size, y_size;
1541 (*iter)->get_position(x_pos,y_pos);
1542 (*iter)->get_size(x_size,y_size);
1544 canvas_window_size += strprintf("%s %d %d %d %d\t",
1545 canvas->get_relative_id(canvas->get_root()).c_str(),
1550 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1554 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1556 std::string filename(file_name);
1558 assert(!filename.empty());
1560 if(filename.empty())
1563 // Toss out any "hidden" files
1564 if(basename(filename)[0]=='.')
1567 // If we aren't an absolute path, turn ourselves into one
1568 if(!is_absolute_path(filename))
1569 filename=absolute_path(filename);
1571 std::string old_window_size;
1573 list<string>::iterator iter;
1574 list<string>::iterator iter_wsize;
1575 // Check to see if the file is already on the list.
1576 // If it is, then remove it from the list
1577 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1580 recent_files.erase(iter);
1581 old_window_size = *iter_wsize;
1582 recent_files_window_size.erase(iter_wsize);
1587 // Push the filename to the front of the list
1588 recent_files.push_front(filename);
1589 if(window_size.empty())
1590 recent_files_window_size.push_front(old_window_size);
1592 recent_files_window_size.push_front(window_size);
1594 // Clean out the files at the end of the list.
1595 while(recent_files.size()>(unsigned)get_max_recent_files())
1597 recent_files.pop_back();
1598 recent_files_window_size.pop_back();
1601 signal_recent_files_changed_();
1606 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1609 App::get_time_format()
1611 return _App_time_format;
1615 App::set_time_format(synfig::Time::Format x)
1622 App::save_settings()
1626 synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
1628 std::string filename=get_config_file("accelrc");
1629 Gtk::AccelMap::save(filename);
1632 std::string filename=get_config_file("recentfiles");
1634 std::ofstream file(filename.c_str());
1638 synfig::warning("Unable to save %s",filename.c_str());
1642 list<string>::reverse_iterator iter;
1644 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1648 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1650 std::ofstream file(filename.c_str());
1654 synfig::warning("Unable to save %s",filename.c_str());
1658 list<string>::reverse_iterator iter;
1660 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1664 std::string filename=get_config_file("settings");
1665 synfigapp::Main::settings().save_to_file(filename);
1670 synfig::warning("Caught exception when attempting to save settings.");
1675 App::load_settings()
1679 synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
1681 std::string filename=get_config_file("accelrc");
1682 Gtk::AccelMap::load(filename);
1685 bool window_size_broken = false;
1687 std::string filename=get_config_file("recentfiles");
1688 std::string filename_window_size=filename+std::string("_window_size");
1690 std::ifstream file(filename.c_str());
1691 std::ifstream file_window_size(filename_window_size.c_str());
1693 if(!file_window_size)
1694 window_size_broken = true;
1698 std::string recent_file;
1699 std::string recent_file_window_size;
1700 getline(file,recent_file);
1701 if(!window_size_broken)
1702 getline(file_window_size,recent_file_window_size);
1703 if(!recent_file.empty())
1705 if(!window_size_broken && !file_window_size)
1706 window_size_broken = true;
1707 if (std::ifstream(recent_file.c_str()))
1709 if(!window_size_broken)
1710 add_recent_file(recent_file,recent_file_window_size);
1712 add_recent_file(recent_file);
1716 if(!window_size_broken && file_window_size)
1717 window_size_broken = true;
1719 if(window_size_broken)
1721 recent_files_window_size.clear();
1722 recent_files_window_size.resize(recent_files.size());
1725 std::string filename=get_config_file("settings");
1726 if(!synfigapp::Main::settings().load_from_file(filename))
1728 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1729 //if(!synfigapp::Main::settings().load_from_file(filename))
1731 gamma.set_gamma(1.0/2.2);
1732 reset_initial_window_configuration();
1739 synfig::warning("Caught exception when attempting to load settings.");
1744 App::reset_initial_window_configuration()
1746 Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
1747 Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
1748 Gdk::Rectangle rect;
1749 // A proper way to obtain the primary monitor is to use the
1750 // Gdk::Screen::get_primary_monitor () const member. But as it
1751 // was introduced in gtkmm 2.20 I assume that the monitor 0 is the
1753 screen->get_monitor_geometry(0,rect);
1754 #define hpanel_width 79.0f
1755 #define hpanel_height 25.0f
1756 #define vpanel_width 20.0f
1757 #define vpanel_height 100.0f
1761 /* percentages referred to width or height of the screen
1762 *---------------------------------------------------------------------*
1777 *-----hdock%----------------------------------------------|------------
1782 * --------------------------------------------------------------------*
1785 int v_xpos=rect.get_x() + rect.get_width()*(1.0-vpanel_width/100.0);
1786 int v_xsize=rect.get_width()*vpanel_width/100.0;
1787 int v_ypos=rect.get_y();
1788 int v_ysize=rect.get_height()*vpanel_height/100.0;
1789 std::string v_pos(strprintf("%d %d", v_xpos, v_ypos));
1790 std::string v_size(strprintf("%d %d", v_xsize, v_ysize));
1792 int h_xpos=rect.get_x();
1793 int h_xsize=rect.get_width()*hpanel_width/100.0;
1794 int h_ypos=rect.get_y()+ rect.get_height()*(1.0-hpanel_height/100.0);;
1795 int h_ysize=rect.get_height()*hpanel_height/100.0;
1796 std::string h_pos(strprintf("%d %d", h_xpos, h_ypos));
1797 std::string h_size(strprintf("%d %d", h_xsize, h_ysize));
1798 int v_dock1 = rect.get_height()*vdock*0.8/100.0;
1799 int v_dock2 = rect.get_height()*vdock*0.6/100.0;
1800 int v_dock3 = rect.get_height()*vdock*1.1/100.0;
1801 int h_dock = rect.get_width()*hdock/100.0;
1803 std::string v_contents(strprintf("%d %d %d", v_dock1, v_dock2, v_dock3));
1804 std::string h_contents(strprintf("%d", h_dock));
1805 // Tool Box position
1806 std::string tbox_pos(strprintf("%d %d", rect.get_x(), rect.get_y()));
1808 synfig::info("tool box pos: %s", tbox_pos.c_str());
1809 synfig::info("v_contents sizes: %s", v_contents.c_str());
1810 synfig::info("v_pos: %s", v_pos.c_str());
1811 synfig::info("v_sizes: %s", v_size.c_str());
1812 synfig::info("h_contents sizes: %s", h_contents.c_str());
1813 synfig::info("h_pos: %s", h_pos.c_str());
1814 synfig::info("h_sizes: %s", h_size.c_str());
1816 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1817 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1818 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size",v_contents);
1819 synfigapp::Main::settings().set_value("dock.dialog.1.size",v_size);
1820 synfigapp::Main::settings().set_value("dock.dialog.1.pos",v_pos);
1821 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1822 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1823 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size",h_contents);
1824 synfigapp::Main::settings().set_value("dock.dialog.2.size",h_size);
1825 synfigapp::Main::settings().set_value("dock.dialog.2.pos",h_pos);
1826 synfigapp::Main::settings().set_value("window.toolbox.pos",tbox_pos);
1828 dock_manager->show_all_dock_dialogs();
1832 App::reset_initial_preferences()
1834 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1835 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1836 #ifdef SINGLE_THREADED
1837 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1839 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1840 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1841 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1842 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1843 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1844 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1845 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1846 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1851 App::shutdown_request(GdkEventAny*)
1855 //return !shutdown_in_progress;
1861 if(shutdown_in_progress)return;
1864 get_ui_interface()->task(_("Quit Request"));
1867 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1871 std::list<etl::handle<Instance> >::iterator iter;
1872 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1874 if(!(*iter)->safe_close())
1878 if((*iter)->synfigapp::Instance::get_action_count())
1880 handle<synfigapp::UIInterface> uim;
1881 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1883 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1884 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1886 case synfigapp::UIInterface::RESPONSE_NO:
1888 case synfigapp::UIInterface::RESPONSE_YES:
1891 case synfigapp::UIInterface::RESPONSE_CANCEL:
1900 if((*iter)->synfigapp::Instance::is_modified())
1902 handle<synfigapp::UIInterface> uim;
1903 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1905 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() );
1906 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1908 case synfigapp::UIInterface::RESPONSE_NO:
1910 case synfigapp::UIInterface::RESPONSE_YES:
1911 (*iter)->dialog_cvs_commit();
1913 case synfigapp::UIInterface::RESPONSE_CANCEL:
1922 // This next line causes things to crash for some reason
1926 shutdown_in_progress=true;
1928 instance_list.clear();
1930 while(studio::App::events_pending())studio::App::iteration(false);
1933 auto_recover->normal_shutdown();
1935 get_ui_interface()->task(_("Quit Request sent"));
1941 dialog_setup->refresh();
1942 dialog_setup->show();
1945 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1946 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1949 //#define USE_WIN32_FILE_DIALOGS 1
1952 #ifdef USE_WIN32_FILE_DIALOGS
1953 static OPENFILENAME ofn={};
1957 #include <gdk/gdkwin32.h>
1961 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1963 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1965 #ifdef USE_WIN32_FILE_DIALOGS
1966 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1968 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1969 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1970 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1972 ofn.lStructSize=sizeof(OPENFILENAME);
1973 ofn.hwndOwner = hWnd;
1974 ofn.hInstance = hInstance;
1975 ofn.lpstrFilter = szFilter;
1976 // ofn.lpstrCustomFilter=NULL;
1977 // ofn.nMaxCustFilter=0;
1978 // ofn.nFilterIndex=0;
1979 // ofn.lpstrFile=NULL;
1980 ofn.nMaxFile=MAX_PATH;
1981 // ofn.lpstrFileTitle=NULL;
1982 // ofn.lpstrInitialDir=NULL;
1983 // ofn.lpstrTitle=NULL;
1984 ofn.Flags=OFN_HIDEREADONLY;
1985 // ofn.nFileOffset=0;
1986 // ofn.nFileExtension=0;
1987 ofn.lpstrDefExt=TEXT("sif");
1988 // ofn.lCustData = 0l;
1990 // ofn.lpTemplateName=NULL;
1992 CHAR szFilename[MAX_PATH];
1994 strcpy(szFilename,filename.c_str());
1995 strcpy(szTitle,title.c_str());
1997 ofn.lpstrFile=szFilename;
1998 ofn.lpstrFileTitle=szTitle;
2000 if(GetOpenFileName(&ofn))
2002 filename=szFilename;
2007 #else // not USE_WIN32_FILE_DIALOGS
2008 synfig::String prev_path;
2010 if(!_preferences.get_value(preference, prev_path))
2013 prev_path = absolute_path(prev_path);
2015 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2017 dialog->set_current_folder(prev_path);
2018 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2019 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
2021 if (filename.empty())
2022 dialog->set_filename(prev_path);
2023 else if (is_absolute_path(filename))
2024 dialog->set_filename(filename);
2026 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2028 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2029 filename = dialog->get_filename();
2030 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
2031 _preferences.set_value(preference, dirname(filename));
2038 #endif // not USE_WIN32_FILE_DIALOGS
2042 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2044 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2046 #if USE_WIN32_FILE_DIALOGS
2047 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2049 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2050 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2051 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2053 ofn.lStructSize=sizeof(OPENFILENAME);
2054 ofn.hwndOwner = hWnd;
2055 ofn.hInstance = hInstance;
2056 ofn.lpstrFilter = szFilter;
2057 // ofn.lpstrCustomFilter=NULL;
2058 // ofn.nMaxCustFilter=0;
2059 // ofn.nFilterIndex=0;
2060 // ofn.lpstrFile=NULL;
2061 ofn.nMaxFile=MAX_PATH;
2062 // ofn.lpstrFileTitle=NULL;
2063 // ofn.lpstrInitialDir=NULL;
2064 // ofn.lpstrTitle=NULL;
2065 ofn.Flags=OFN_OVERWRITEPROMPT;
2066 // ofn.nFileOffset=0;
2067 // ofn.nFileExtension=0;
2068 ofn.lpstrDefExt=TEXT("sif");
2069 // ofn.lCustData = 0l;
2071 // ofn.lpTemplateName=NULL;
2073 CHAR szFilename[MAX_PATH];
2075 strcpy(szFilename,filename.c_str());
2076 strcpy(szTitle,title.c_str());
2078 ofn.lpstrFile=szFilename;
2079 ofn.lpstrFileTitle=szTitle;
2081 if(GetSaveFileName(&ofn))
2083 filename=szFilename;
2084 _preferences.set_value(preference,dirname(filename));
2089 synfig::String prev_path;
2091 if(!_preferences.get_value(preference, prev_path))
2094 prev_path = absolute_path(prev_path);
2096 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2098 dialog->set_current_folder(prev_path);
2099 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2100 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2102 Widget_Enum *file_type_enum = 0;
2103 if (preference == ANIMATION_DIR_PREFERENCE)
2105 file_type_enum = manage(new Widget_Enum());
2106 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2107 .add_enum_value(synfig::RELEASE_VERSION_0_62_02, "0.62.02", strprintf("0.62.02 (%s)", _("current")))
2108 .add_enum_value(synfig::RELEASE_VERSION_0_62_01, "0.62.01", "0.62.01")
2109 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", "0.61.00")
2110 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2111 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2112 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2113 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2114 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2116 Gtk::HBox *hbox = manage(new Gtk::HBox);
2117 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2118 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2121 dialog->set_extra_widget(*hbox);
2124 if (filename.empty())
2125 dialog->set_filename(prev_path);
2128 std::string full_path;
2129 if (is_absolute_path(filename))
2130 full_path = filename;
2132 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2134 // select the file if it exists
2135 dialog->set_filename(full_path);
2137 // if the file doesn't exist, put its name into the filename box
2139 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2140 dialog->set_current_name(basename(filename));
2143 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2144 if (preference == ANIMATION_DIR_PREFERENCE)
2145 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2146 filename = dialog->get_filename();
2147 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2148 _preferences.set_value(preference, dirname(filename));
2159 App::dialog_error_blocking(const std::string &title, const std::string &message)
2161 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2162 dialog.set_title(title);
2168 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2170 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2171 dialog.set_title(title);
2177 App::dialog_yes_no(const std::string &title, const std::string &message)
2182 true // use_separator
2184 Gtk::Label label(message);
2187 dialog.get_vbox()->pack_start(label);
2188 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2189 dialog.add_button(Gtk::StockID("gtk-no"),0);
2191 return dialog.run();
2195 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2200 true // use_separator
2202 Gtk::Label label(message);
2205 dialog.get_vbox()->pack_start(label);
2206 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2207 dialog.add_button(Gtk::StockID("gtk-no"),0);
2208 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2210 return dialog.run();
2214 App::dialog_not_implemented()
2216 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2217 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2222 try_open_url(const std::string &url)
2225 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2227 std::vector<std::string> command_line;
2228 std::vector<std::string> browsers;
2229 browsers.reserve(23);
2231 // Browser wrapper scripts
2232 #ifdef USE_OPEN_FOR_URLS
2233 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2235 browsers.push_back("xdg-open"); // XDG wrapper
2236 browsers.push_back("sensible-browser"); // Debian wrapper
2237 browsers.push_back("gnome-open"); // GNOME wrapper
2238 browsers.push_back("kfmclient"); // KDE wrapper
2239 browsers.push_back("exo-open"); // XFCE wrapper
2241 // Alternatives system
2242 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2243 browsers.push_back("x-www-browser"); // Debian GUI alternative
2245 // Individual browsers
2246 browsers.push_back("firefox");
2247 browsers.push_back("epiphany-browser");
2248 browsers.push_back("epiphany");
2249 browsers.push_back("konqueror");
2250 browsers.push_back("iceweasel");
2251 browsers.push_back("mozilla");
2252 browsers.push_back("netscape");
2253 browsers.push_back("icecat");
2254 browsers.push_back("galeon");
2255 browsers.push_back("midori");
2256 browsers.push_back("safari");
2257 browsers.push_back("opera");
2258 browsers.push_back("amaya");
2259 browsers.push_back("netsurf");
2260 browsers.push_back("dillo");
2262 // Try the user-specified browser first
2263 command_line.push_back(App::browser_command);
2264 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2265 command_line.push_back(url);
2267 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2268 catch( Glib::SpawnError& exception ){
2270 while ( !browsers.empty() )
2272 // Skip the browser if we already tried it
2273 if( browsers[0] == App::browser_command )
2276 // Construct the command line
2277 command_line.clear();
2278 command_line.push_back(browsers[0]);
2279 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2280 command_line.push_back(url);
2282 // Remove the browser from the list
2283 browsers.erase(browsers.begin());
2285 // Try to spawn the browser
2286 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2287 // Failed, move on to the next one
2288 catch(Glib::SpawnError& exception){ continue; }
2289 return true; // No exception means we succeeded!
2300 if (!try_open_url("http://synfig.org/wiki/Category:Manual"))
2302 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2303 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://synfig.org/wiki/Category:Manual"));
2304 dialog.set_title(_("Help"));
2310 App::open_url(const std::string &url)
2312 if(!try_open_url(url))
2314 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2315 dialog.set_secondary_text(url);
2316 dialog.set_title(_("No browser found"));
2322 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2327 true); // use_separator
2329 Gtk::Label label(message);
2331 dialog.get_vbox()->pack_start(label);
2334 entry.set_text(text);
2336 entry.set_activates_default(true);
2338 dialog.get_vbox()->pack_start(entry);
2340 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2341 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2342 dialog.set_default_response(Gtk::RESPONSE_OK);
2344 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2347 if(dialog.run()!=Gtk::RESPONSE_OK)
2350 text=entry.get_text();
2356 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2361 true); // use_separator
2363 Gtk::Label label(message);
2365 dialog.get_vbox()->pack_start(label);
2367 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2368 text_buffer->set_text(text);
2369 Gtk::TextView text_view(text_buffer);
2372 dialog.get_vbox()->pack_start(text_view);
2374 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2375 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2376 dialog.set_default_response(Gtk::RESPONSE_OK);
2378 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2381 if(dialog.run()!=Gtk::RESPONSE_OK)
2384 text=text_buffer->get_text();
2390 App::open(std::string filename)
2392 return open_as(filename,filename);
2395 // this is called from autorecover.cpp:
2396 // App::open_as(get_shadow_file_name(filename),filename)
2397 // other than that, 'filename' and 'as' are the same
2399 App::open_as(std::string filename,std::string as)
2402 char long_name[1024];
2403 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2404 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2405 // don't use it if that's the case
2406 if (long_name[0] != '\0')
2412 OneMoment one_moment;
2413 String errors, warnings;
2415 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2416 if(canvas && get_instance(canvas))
2418 get_instance(canvas)->find_canvas_view(canvas)->present();
2419 info("%s is already open", filename.c_str());
2420 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2425 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2428 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2430 if (as.find(custom_filename_prefix.c_str()) != 0)
2431 add_recent_file(as);
2433 handle<Instance> instance(Instance::create(canvas));
2436 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2438 set_recent_file_window_size(instance);
2442 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)")))
2443 instance->dialog_cvs_update();
2448 dialog_error_blocking(_("Error"), x);
2451 catch(runtime_error x)
2453 dialog_error_blocking(_("Error"), x.what());
2458 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2469 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2471 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2472 canvas->set_name(file_name);
2473 file_name += ".sifz";
2475 canvas->rend_desc().set_frame_rate(preferred_fps);
2476 canvas->rend_desc().set_time_start(0.0);
2477 canvas->rend_desc().set_time_end(5.0);
2478 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2479 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2480 // The top left and botton right positions are expressed in units
2481 // Original convention is that 1 unit = 60 pixels
2482 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2483 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2484 canvas->rend_desc().set_w(preferred_x_size);
2485 canvas->rend_desc().set_h(preferred_y_size);
2486 canvas->rend_desc().set_antialias(1);
2487 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2488 canvas->set_file_name(file_name);
2490 handle<Instance> instance = Instance::create(canvas);
2492 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2493 instance->find_canvas_view(canvas)->canvas_properties.present();
2497 App::dialog_open(string filename)
2499 if (filename.empty())
2502 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2504 // If the filename still has wildcards, then we should
2505 // continue looking for the file we want
2506 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2512 get_ui_interface()->error(_("Unable to open file"));
2517 App::set_selected_instance(etl::loose_handle<Instance> instance)
2519 /* if(get_selected_instance()==instance)
2521 selected_instance=instance;
2522 signal_instance_selected()(instance);
2528 selected_instance=instance;
2529 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2533 instance->focus(instance->get_canvas());
2536 set_selected_canvas_view(0);
2538 signal_instance_selected()(instance);
2542 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2544 selected_canvas_view=canvas_view;
2545 signal_canvas_view_focus()(selected_canvas_view);
2548 selected_instance=canvas_view->get_instance();
2549 signal_instance_selected()(canvas_view->get_instance());
2552 if(get_selected_canvas_view()==canvas_view)
2554 signal_canvas_view_focus()(selected_canvas_view);
2555 signal_instance_selected()(canvas_view->get_instance());
2558 selected_canvas_view=canvas_view;
2559 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2560 set_selected_instance(canvas_view->get_instance());
2561 signal_canvas_view_focus()(selected_canvas_view);
2565 etl::loose_handle<Instance>
2566 App::get_instance(etl::handle<synfig::Canvas> canvas)
2568 if(!canvas) return 0;
2569 canvas=canvas->get_root();
2571 std::list<etl::handle<Instance> >::iterator iter;
2572 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2574 if((*iter)->get_canvas()==canvas)
2590 if(selected_instance)
2591 selected_instance->undo();
2597 if(selected_instance)
2598 selected_instance->redo();
2602 studio::App::get_base_path()
2604 return app_base_path_;