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 SETTINGS_LOCALE_SAFE_AND_BACKUP
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());
591 SETTINGS_LOCALE_RESTORE
595 synfig::warning("Preferences: Caught exception when attempting to get value.");
597 return synfigapp::Settings::get_value(key,value);
600 virtual bool set_value(const synfig::String& key,const synfig::String& value)
604 SETTINGS_LOCALE_SAFE_AND_BACKUP
609 strscanf(value,"%f %f %f %f",
616 App::gamma.set_all(r,g,b,blk);
620 if(key=="time_format")
622 int i(atoi(value.c_str()));
623 App::set_time_format(static_cast<synfig::Time::Format>(i));
626 if(key=="auto_recover_backup_interval")
628 int i(atoi(value.c_str()));
629 App::auto_recover->set_timeout(i);
632 if(key=="file_history.size")
634 int i(atoi(value.c_str()));
635 App::set_max_recent_files(i);
638 if(key=="use_colorspace_gamma")
640 int i(atoi(value.c_str()));
641 App::use_colorspace_gamma=i;
644 if(key=="distance_system")
646 App::distance_system=Distance::ident_system(value);;
649 #ifdef SINGLE_THREADED
650 if(key=="single_threaded")
652 int i(atoi(value.c_str()));
653 App::single_threaded=i;
657 if(key=="restrict_radius_ducks")
659 int i(atoi(value.c_str()));
660 App::restrict_radius_ducks=i;
663 if(key=="resize_imported_images")
665 int i(atoi(value.c_str()));
666 App::resize_imported_images=i;
669 if(key=="browser_command")
671 App::browser_command=value;
674 if(key=="custom_filename_prefix")
676 App::custom_filename_prefix=value;
679 if(key=="preferred_x_size")
681 int i(atoi(value.c_str()));
682 App::preferred_x_size=i;
685 if(key=="preferred_y_size")
687 int i(atoi(value.c_str()));
688 App::preferred_y_size=i;
691 if(key=="predefined_size")
693 App::predefined_size=value;
696 if(key=="preferred_fps")
698 float i(atof(value.c_str()));
699 App::preferred_fps=i;
702 if(key=="predefined_fps")
704 App::predefined_fps=value;
707 SETTINGS_LOCALE_RESTORE
711 synfig::warning("Preferences: Caught exception when attempting to set value.");
713 return synfigapp::Settings::set_value(key,value);
716 virtual KeyList get_key_list()const
718 KeyList ret(synfigapp::Settings::get_key_list());
719 ret.push_back("gamma");
720 ret.push_back("time_format");
721 ret.push_back("distance_system");
722 ret.push_back("file_history.size");
723 ret.push_back("use_colorspace_gamma");
724 #ifdef SINGLE_THREADED
725 ret.push_back("single_threaded");
727 ret.push_back("auto_recover_backup_interval");
728 ret.push_back("restrict_radius_ducks");
729 ret.push_back("resize_imported_images");
730 ret.push_back("browser_command");
731 ret.push_back("custom_filename_prefix");
732 ret.push_back("preferred_x_size");
733 ret.push_back("preferred_y_size");
734 ret.push_back("predefined_size");
735 ret.push_back("preferred_fps");
736 ret.push_back("predefined_fps");
741 static ::Preferences _preferences;
746 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
748 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
750 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
752 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
753 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
754 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
755 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
756 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
757 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
758 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
759 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
760 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
761 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
762 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
763 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
764 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
766 // Add the synfigapp actions...
767 synfigapp::Action::Book::iterator iter;
768 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
770 actions_action_group->add(Gtk::Action::create(
771 "action-"+iter->second.name,
772 get_action_stock_id(iter->second),
773 iter->second.local_name,iter->second.local_name
777 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); actions_action_group->add(action); }
778 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); actions_action_group->add(action); }
779 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); group->add(action,sig); }
781 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
782 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
783 DEFINE_ACTION("new", Gtk::Stock::NEW);
784 DEFINE_ACTION("open", Gtk::Stock::OPEN);
785 DEFINE_ACTION("save", Gtk::Stock::SAVE);
786 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
787 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
788 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
789 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
790 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
791 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
792 DEFINE_ACTION("import", _("Import"));
793 DEFINE_ACTION("render", _("Render"));
794 DEFINE_ACTION("preview", _("Preview"));
795 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
796 DEFINE_ACTION("sound", _("Sound File"));
797 DEFINE_ACTION("options", _("Options"));
798 DEFINE_ACTION("close", _("Close View"));
799 DEFINE_ACTION("close-document", _("Close Document"));
800 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
803 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
804 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
805 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
806 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
807 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
808 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
809 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
810 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
811 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
812 DEFINE_ACTION("properties", _("Properties"));
814 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
815 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
816 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
817 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
818 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
819 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
820 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
821 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
822 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
823 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
824 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
825 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
826 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
827 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
828 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
829 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
830 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
831 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
832 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
833 DEFINE_ACTION("play", _("Play"));
834 // DEFINE_ACTION("pause", _("Pause"));
835 DEFINE_ACTION("stop", _("Stop"));
836 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
837 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
838 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
839 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
840 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
841 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
842 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
843 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
844 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
845 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
846 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
847 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
848 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
849 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
850 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
851 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
852 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
853 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
854 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
855 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
856 DEFINE_ACTION("seek-end", _("Seek to End"));
858 DEFINE_ACTION("action-group_add", _("Add group"));
860 DEFINE_ACTION("canvas-new", _("New Canvas"));
862 DEFINE_ACTION("amount-inc", _("Increase Amount"));
863 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
866 #undef DEFINE_ACTION_2
867 #undef DEFINE_ACTION_SIG
869 Glib::ustring ui_info =
871 " <popup name='menu-toolbox' action='menu-toolbox'>"
872 " <menu action='menu-file'>"
875 " <popup name='menu-main' action='menu-main'>"
876 " <menu action='menu-file'>"
877 " <menuitem action='new' />"
878 " <menuitem action='open' />"
879 " <menuitem action='save' />"
880 " <menuitem action='save-as' />"
881 " <menuitem action='revert' />"
882 " <separator name='bleh01'/>"
883 " <menuitem action='cvs-add' />"
884 " <menuitem action='cvs-update' />"
885 " <menuitem action='cvs-commit' />"
886 " <menuitem action='cvs-revert' />"
887 " <separator name='bleh02'/>"
888 " <menuitem action='import' />"
889 " <separator name='bleh03'/>"
890 " <menuitem action='render' />"
891 " <menuitem action='preview' />"
892 " <menuitem action='sound' />"
893 " <separator name='bleh04'/>"
894 " <menuitem action='options' />"
895 " <menuitem action='close' />"
896 " <menuitem action='close-document' />"
897 " <menuitem action='quit' />"
899 " <menu action='menu-edit'>"
900 " <menuitem action='undo'/>"
901 " <menuitem action='redo'/>"
902 " <separator name='bleh05'/>"
903 " <menuitem action='cut'/>"
904 " <menuitem action='copy'/>"
905 " <menuitem action='paste'/>"
906 " <separator name='bleh06'/>"
907 " <menuitem action='select-all-layers'/>"
908 " <menuitem action='unselect-all-layers'/>"
909 " <menuitem action='select-all-ducks'/>"
910 " <menuitem action='unselect-all-ducks'/>"
911 " <separator name='bleh07'/>"
912 " <menuitem action='properties'/>"
914 " <menu action='menu-view'>"
915 " <menu action='menu-duck-mask'>"
916 " <menuitem action='mask-position-ducks' />"
917 " <menuitem action='mask-vertex-ducks' />"
918 " <menuitem action='mask-tangent-ducks' />"
919 " <menuitem action='mask-radius-ducks' />"
920 " <menuitem action='mask-width-ducks' />"
921 " <menuitem action='mask-angle-ducks' />"
923 " <menu action='menu-preview-quality'>"
924 " <menuitem action='quality-00' />"
925 " <menuitem action='quality-01' />"
926 " <menuitem action='quality-02' />"
927 " <menuitem action='quality-03' />"
928 " <menuitem action='quality-04' />"
929 " <menuitem action='quality-05' />"
930 " <menuitem action='quality-06' />"
931 " <menuitem action='quality-07' />"
932 " <menuitem action='quality-08' />"
933 " <menuitem action='quality-09' />"
934 " <menuitem action='quality-10' />"
936 " <menu action='menu-lowres-pixel'>"
937 " <menuitem action='decrease-low-res-pixel-size'/>"
938 " <menuitem action='increase-low-res-pixel-size'/>"
939 " <separator name='pixel-size-separator'/>"
942 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
943 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
947 " <separator name='bleh08'/>"
948 " <menuitem action='play'/>"
949 //" <menuitem action='pause'/>"
950 " <menuitem action='stop'/>"
951 " <menuitem action='dialog-flipbook'/>"
952 " <separator name='bleh09'/>"
953 " <menuitem action='toggle-grid-show'/>"
954 " <menuitem action='toggle-grid-snap'/>"
955 " <menuitem action='toggle-guide-show'/>"
956 " <menuitem action='toggle-low-res'/>"
957 " <menuitem action='toggle-onion-skin'/>"
958 " <separator name='bleh10'/>"
959 " <menuitem action='canvas-zoom-in'/>"
960 " <menuitem action='canvas-zoom-out'/>"
961 " <menuitem action='canvas-zoom-fit'/>"
962 " <menuitem action='canvas-zoom-100'/>"
963 " <separator name='bleh11'/>"
964 " <menuitem action='time-zoom-in'/>"
965 " <menuitem action='time-zoom-out'/>"
966 " <separator name='bleh12'/>"
967 " <menuitem action='jump-next-keyframe'/>"
968 " <menuitem action='jump-prev-keyframe'/>"
969 " <menuitem action='seek-next-frame'/>"
970 " <menuitem action='seek-prev-frame'/>"
971 " <menuitem action='seek-next-second'/>"
972 " <menuitem action='seek-prev-second'/>"
973 " <menuitem action='seek-begin'/>"
974 " <menuitem action='seek-end'/>"
976 " <menu action='menu-canvas'>"
977 " <menuitem action='canvas-new'/>"
979 " <menu name='menu-state' action='menu-state'>"
981 " <menu action='menu-group'>"
982 " <menuitem action='action-group_add'/>"
984 " <menu action='menu-layer'>"
985 //" <menuitem action='cut'/>"
986 //" <menuitem action='copy'/>"
987 //" <menuitem action='paste'/>"
988 //" <separator name='bleh06'/>"
989 " <menu action='menu-layer-new'></menu>"
990 " <menuitem action='amount-inc'/>"
991 " <menuitem action='amount-dec'/>"
993 " <menu action='menu-keyframe'>"
994 " <menuitem action='keyframe-properties'/>"
1001 " <menubar name='MenuBar'>"
1002 " <menu action='MenuFile'>"
1003 " <menuitem action='New'/>"
1004 " <menuitem action='Open'/>"
1006 " <menuitem action='Quit'/>"
1008 " <menu action='MenuEdit'>"
1009 " <menuitem action='Cut'/>"
1010 " <menuitem action='Copy'/>"
1011 " <menuitem action='Paste'/>"
1014 " <toolbar name='ToolBar'>"
1015 " <toolitem action='Open'/>"
1016 " <toolitem action='Quit'/>"
1022 actions_action_group->set_sensitive(false);
1023 App::ui_manager()->set_add_tearoffs(true);
1024 App::ui_manager()->insert_action_group(menus_action_group,1);
1025 App::ui_manager()->insert_action_group(actions_action_group,1);
1026 App::ui_manager()->add_ui_from_string(ui_info);
1028 //App::ui_manager()->get_accel_group()->unlock();
1030 catch(const Glib::Error& ex)
1032 synfig::error("building menus and toolbars failed: " + ex.what());
1035 // Add default keyboard accelerators
1036 #define ACCEL(accel,path) \
1038 Gtk::AccelKey accel_key(accel,path); \
1039 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1042 #define ACCEL2(accel) \
1044 Gtk::AccelKey accel_key(accel); \
1045 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1049 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1050 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1051 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1052 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1053 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1054 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1055 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1056 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1057 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1058 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1059 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1060 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1061 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1062 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1063 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1064 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1065 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1066 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1069 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1070 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1071 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1072 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1073 ACCEL("F9", "<Actions>/canvasview/render" );
1074 ACCEL("F11", "<Actions>/canvasview/preview" );
1075 ACCEL("F8", "<Actions>/canvasview/properties" );
1076 ACCEL("F12", "<Actions>/canvasview/options" );
1077 ACCEL("<control>i", "<Actions>/canvasview/import" );
1078 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1079 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1080 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1081 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1082 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1083 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1084 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1085 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1086 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1087 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1088 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1089 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1090 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1091 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1092 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1093 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1094 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1095 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1096 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1097 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1098 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1099 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1100 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1101 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1102 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1103 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1104 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1105 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1106 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1107 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1108 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1109 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1110 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1111 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1112 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1113 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1114 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1115 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1116 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1117 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1118 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1119 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1120 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1121 ACCEL("End", "<Actions>/canvasview/seek-end" );
1128 #define mkdir(x,y) mkdir(x)
1131 /* === M E T H O D S ======================================================= */
1133 App::App(int *argc, char ***argv):
1134 Gtk::Main(argc,argv),
1135 IconController(etl::dirname((*argv)[0]))
1137 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1140 ui_interface_=new GlobalUIInterface();
1144 // don't call thread_init() if threads are already initialized
1145 // on some machines bonobo_init() initialized threads before we get here
1146 if (!g_thread_supported())
1147 Glib::thread_init();
1149 distance_system=Distance::SYSTEM_UNITS;
1151 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1154 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1158 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1164 if(!SYNFIG_CHECK_VERSION())
1166 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1167 dialog_error_blocking("Synfig Studio",
1168 "This copy of Synfig Studio was compiled against a\n"
1169 "different version of libsynfig than what is currently\n"
1170 "installed. Synfig Studio will now abort. Try downloading\n"
1171 "the latest version from the Synfig website at\n"
1172 "http://synfig.org/en/current-release"
1176 Glib::set_application_name(_("Synfig Studio"));
1178 Splash splash_screen;
1179 splash_screen.show();
1181 shutdown_in_progress=false;
1182 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1183 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1185 // Initialize the Synfig library
1186 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1187 catch(std::runtime_error x)
1189 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1194 get_ui_interface()->error(_("Failed to initialize synfig!"));
1198 // add the preferences to the settings
1199 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1203 studio_init_cb.task(_("Init UI Manager..."));
1204 App::ui_manager_=studio::UIManager::create();
1207 studio_init_cb.task(_("Init Dock Manager..."));
1208 dock_manager=new studio::DockManager();
1210 studio_init_cb.task(_("Init State Manager..."));
1211 state_manager=new StateManager();
1213 studio_init_cb.task(_("Init Toolbox..."));
1214 toolbox=new studio::Toolbox();
1216 studio_init_cb.task(_("Init About Dialog..."));
1217 about=new studio::About();
1219 studio_init_cb.task(_("Init Tool Options..."));
1220 dialog_tool_options=new studio::Dialog_ToolOptions();
1221 dock_manager->register_dockable(*dialog_tool_options);
1223 studio_init_cb.task(_("Init History..."));
1224 dock_history=new studio::Dock_History();
1225 dock_manager->register_dockable(*dock_history);
1227 studio_init_cb.task(_("Init Canvases..."));
1228 dock_canvases=new studio::Dock_Canvases();
1229 dock_manager->register_dockable(*dock_canvases);
1231 studio_init_cb.task(_("Init Keyframes..."));
1232 dock_keyframes=new studio::Dock_Keyframes();
1233 dock_manager->register_dockable(*dock_keyframes);
1235 studio_init_cb.task(_("Init Layers..."));
1236 dock_layers=new studio::Dock_Layers();
1237 dock_manager->register_dockable(*dock_layers);
1239 studio_init_cb.task(_("Init Params..."));
1240 dock_params=new studio::Dock_Params();
1241 dock_manager->register_dockable(*dock_params);
1243 studio_init_cb.task(_("Init MetaData..."));
1244 dock_meta_data=new studio::Dock_MetaData();
1245 dock_manager->register_dockable(*dock_meta_data);
1247 studio_init_cb.task(_("Init Children..."));
1248 dock_children=new studio::Dock_Children();
1249 dock_manager->register_dockable(*dock_children);
1251 studio_init_cb.task(_("Init Info..."));
1252 dock_info = new studio::Dock_Info();
1253 dock_manager->register_dockable(*dock_info);
1255 studio_init_cb.task(_("Init Navigator..."));
1256 dock_navigator = new studio::Dock_Navigator();
1257 dock_manager->register_dockable(*dock_navigator);
1259 studio_init_cb.task(_("Init Timetrack..."));
1260 dock_timetrack = new studio::Dock_Timetrack();
1261 dock_manager->register_dockable(*dock_timetrack);
1263 studio_init_cb.task(_("Init Curve Editor..."));
1264 dock_curves = new studio::Dock_Curves();
1265 dock_manager->register_dockable(*dock_curves);
1267 studio_init_cb.task(_("Init Layer Groups..."));
1268 dock_layer_groups = new studio::Dock_LayerGroups();
1269 dock_manager->register_dockable(*dock_layer_groups);
1272 studio_init_cb.task(_("Init Color Dialog..."));
1273 dialog_color=new studio::Dialog_Color();
1275 studio_init_cb.task(_("Init Gradient Dialog..."));
1276 dialog_gradient=new studio::Dialog_Gradient();
1278 studio_init_cb.task(_("Init DeviceTracker..."));
1279 device_tracker=new studio::DeviceTracker();
1281 studio_init_cb.task(_("Init Tools..."));
1284 state_manager->add_state(&state_normal);
1285 state_manager->add_state(&state_smooth_move);
1286 state_manager->add_state(&state_scale);
1287 state_manager->add_state(&state_rotate);
1288 state_manager->add_state(&state_mirror);
1291 state_manager->add_state(&state_circle);
1292 state_manager->add_state(&state_rectangle);
1293 state_manager->add_state(&state_star);
1294 state_manager->add_state(&state_gradient);
1295 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1298 state_manager->add_state(&state_bline);
1299 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1300 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1301 state_manager->add_state(&state_fill);
1302 state_manager->add_state(&state_eyedrop);
1305 state_manager->add_state(&state_text);
1306 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1307 state_manager->add_state(&state_zoom);
1309 studio_init_cb.task(_("Init ModPalette..."));
1310 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1312 studio_init_cb.task(_("Init Setup Dialog..."));
1313 dialog_setup=new studio::Dialog_Setup();
1315 studio_init_cb.task(_("Init Input Dialog..."));
1316 dialog_input=new Gtk::InputDialog();
1317 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1318 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1320 studio_init_cb.task(_("Init auto recovery..."));
1321 auto_recover=new AutoRecover();
1323 studio_init_cb.amount_complete(9250,10000);
1324 studio_init_cb.task(_("Loading Settings..."));
1326 device_tracker->load_preferences();
1328 studio_init_cb.task(_("Checking auto-recover..."));
1330 studio_init_cb.amount_complete(9900,10000);
1332 bool opened_any = false;
1333 if(auto_recover->recovery_needed())
1335 splash_screen.hide();
1336 if (get_ui_interface()->confirmation(_("Crash Recovery"),
1337 _("Auto recovery file found"),
1338 _("Synfig Studio seems to have crashed before you could save all your files. "
1339 "Recover unsaved changes?"),
1340 _("Recover"), _("Ignore"))
1341 == synfigapp::UIInterface::RESPONSE_OK)
1343 int number_recovered;
1344 if(!auto_recover->recover(number_recovered))
1345 if (number_recovered)
1346 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1348 get_ui_interface()->error(_("Unable to recover from previous crash"));
1350 dialog_warning_blocking(_("Warning"),
1351 _("Synfig Studio has attempted to recover from a previous crash. "
1352 "The files that it has recovered are NOT YET SAVED. It would be a "
1353 "good idea to review them and save them now."));
1355 if (number_recovered)
1358 splash_screen.show();
1361 // Look for any files given on the command line,
1362 // and load them if found.
1363 for(;*argc>=1;(*argc)--)
1364 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1366 studio_init_cb.task(_("Loading files..."));
1367 splash_screen.hide();
1368 open((*argv)[*argc]);
1370 splash_screen.show();
1373 // if no file was specified to be opened, create a new document to help new users get started more easily
1374 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1377 studio_init_cb.task(_("Done."));
1378 studio_init_cb.amount_complete(10000,10000);
1380 // To avoid problems with some window managers and gtk >= 2.18
1381 // we should show dock dialogs after the settings load.
1382 // If dock dialogs are shown before the settings are loaded,
1383 // the windows manager can act over it.
1384 // See discussions here:
1385 // * http://synfig.org/forums/viewtopic.php?f=1&t=1131&st=0&sk=t&sd=a&start=30
1386 // * http://synfig.org/forums/viewtopic.php?f=15&t=1062
1387 dock_manager->show_all_dock_dialogs();
1393 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1397 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1401 StateManager* App::get_state_manager() { return state_manager; }
1405 shutdown_in_progress=true;
1409 synfigapp::Main::settings().remove_domain("pref");
1411 selected_instance=0;
1413 // Unload all of the modules
1414 for(;!module_list_.empty();module_list_.pop_back())
1417 delete state_manager;
1421 delete auto_recover;
1429 delete dialog_setup;
1431 delete dialog_gradient;
1433 delete dialog_color;
1435 delete dialog_input;
1437 delete dock_manager;
1439 instance_list.clear();
1443 App::get_user_app_directory()
1445 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1447 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1449 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1454 App::get_config_file(const synfig::String& file)
1456 return Glib::build_filename(get_user_app_directory(),file);
1459 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1461 App::set_recent_file_window_size(etl::handle<Instance> instance)
1464 const std::string &canvas_window_size = *recent_files_window_size.begin();
1466 if(canvas_window_size.empty())
1469 synfig::String::size_type current=0;
1470 bool seen_root(false), shown_non_root(false);
1472 while(current != synfig::String::npos)
1474 // find end of first field (canvas) or return
1475 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1476 if(separator == synfig::String::npos) break;
1479 synfig::Canvas::Handle canvas;
1482 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1484 catch(Exception::IDNotFound) {
1485 // can't find the canvas; skip to the next canvas or return
1486 separator = canvas_window_size.find_first_of('\t', current);
1487 if(separator == synfig::String::npos) return;
1488 current = separator+1;
1492 if (canvas->is_root())
1495 shown_non_root = true;
1497 // check that we have the tab character the ends this canvas' data or return
1498 current = separator+1;
1499 separator = canvas_window_size.find_first_of('\t', current);
1500 if(separator == synfig::String::npos) return;
1503 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1505 current = separator+1;
1508 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1509 canvasview->move(x,y);
1510 canvasview->resize(w,h);
1511 canvasview->present();
1513 current = separator+1;
1516 if (shown_non_root && !seen_root)
1517 instance->find_canvas_view(instance->get_canvas())->hide();
1521 App::add_recent_file(const etl::handle<Instance> instance)
1524 std::string canvas_window_size;
1526 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1527 Instance::CanvasViewList::const_iterator iter;
1529 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1531 if( !((*iter)->is_visible()) )
1534 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1535 int x_pos, y_pos, x_size, y_size;
1536 (*iter)->get_position(x_pos,y_pos);
1537 (*iter)->get_size(x_size,y_size);
1539 canvas_window_size += strprintf("%s %d %d %d %d\t",
1540 canvas->get_relative_id(canvas->get_root()).c_str(),
1545 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1549 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1551 std::string filename(file_name);
1553 assert(!filename.empty());
1555 if(filename.empty())
1558 // Toss out any "hidden" files
1559 if(basename(filename)[0]=='.')
1562 // If we aren't an absolute path, turn ourselves into one
1563 if(!is_absolute_path(filename))
1564 filename=absolute_path(filename);
1566 std::string old_window_size;
1568 list<string>::iterator iter;
1569 list<string>::iterator iter_wsize;
1570 // Check to see if the file is already on the list.
1571 // If it is, then remove it from the list
1572 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1575 recent_files.erase(iter);
1576 old_window_size = *iter_wsize;
1577 recent_files_window_size.erase(iter_wsize);
1582 // Push the filename to the front of the list
1583 recent_files.push_front(filename);
1584 if(window_size.empty())
1585 recent_files_window_size.push_front(old_window_size);
1587 recent_files_window_size.push_front(window_size);
1589 // Clean out the files at the end of the list.
1590 while(recent_files.size()>(unsigned)get_max_recent_files())
1592 recent_files.pop_back();
1593 recent_files_window_size.pop_back();
1596 signal_recent_files_changed_();
1601 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1604 App::get_time_format()
1606 return _App_time_format;
1610 App::set_time_format(synfig::Time::Format x)
1617 App::save_settings()
1621 SETTINGS_LOCALE_SAFE_AND_BACKUP
1623 std::string filename=get_config_file("accelrc");
1624 Gtk::AccelMap::save(filename);
1627 std::string filename=get_config_file("recentfiles");
1629 std::ofstream file(filename.c_str());
1633 synfig::warning("Unable to save %s",filename.c_str());
1637 list<string>::reverse_iterator iter;
1639 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1643 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1645 std::ofstream file(filename.c_str());
1649 synfig::warning("Unable to save %s",filename.c_str());
1653 list<string>::reverse_iterator iter;
1655 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1659 std::string filename=get_config_file("settings");
1660 synfigapp::Main::settings().save_to_file(filename);
1661 SETTINGS_LOCALE_RESTORE
1665 synfig::warning("Caught exception when attempting to save settings.");
1670 App::load_settings()
1674 SETTINGS_LOCALE_SAFE_AND_BACKUP
1676 std::string filename=get_config_file("accelrc");
1677 Gtk::AccelMap::load(filename);
1680 bool window_size_broken = false;
1682 std::string filename=get_config_file("recentfiles");
1683 std::string filename_window_size=filename+std::string("_window_size");
1685 std::ifstream file(filename.c_str());
1686 std::ifstream file_window_size(filename_window_size.c_str());
1688 if(!file_window_size)
1689 window_size_broken = true;
1693 std::string recent_file;
1694 std::string recent_file_window_size;
1695 getline(file,recent_file);
1696 if(!window_size_broken)
1697 getline(file_window_size,recent_file_window_size);
1698 if(!recent_file.empty())
1700 if(!window_size_broken && !file_window_size)
1701 window_size_broken = true;
1702 if (std::ifstream(recent_file.c_str()))
1704 if(!window_size_broken)
1705 add_recent_file(recent_file,recent_file_window_size);
1707 add_recent_file(recent_file);
1711 if(!window_size_broken && file_window_size)
1712 window_size_broken = true;
1714 if(window_size_broken)
1716 recent_files_window_size.clear();
1717 recent_files_window_size.resize(recent_files.size());
1720 std::string filename=get_config_file("settings");
1721 if(!synfigapp::Main::settings().load_from_file(filename))
1723 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1724 //if(!synfigapp::Main::settings().load_from_file(filename))
1726 gamma.set_gamma(1.0/2.2);
1727 reset_initial_window_configuration();
1730 SETTINGS_LOCALE_RESTORE
1734 synfig::warning("Caught exception when attempting to load settings.");
1739 App::reset_initial_window_configuration()
1741 Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
1742 Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
1743 Gdk::Rectangle rect;
1744 // A proper way to obtain the primary monitor is to use the
1745 // Gdk::Screen::get_primary_monitor () const member. But as it
1746 // was introduced in gtkmm 2.20 I assume that the monitor 0 is the
1748 screen->get_monitor_geometry(0,rect);
1749 #define hpanel_width 79.0f
1750 #define hpanel_height 25.0f
1751 #define vpanel_width 20.0f
1752 #define vpanel_height 100.0f
1756 /* percentages referred to width or height of the screen
1757 *---------------------------------------------------------------------*
1772 *-----hdock%----------------------------------------------|------------
1777 * --------------------------------------------------------------------*
1780 int v_xpos=rect.get_x() + rect.get_width()*(1.0-vpanel_width/100.0);
1781 int v_xsize=rect.get_width()*vpanel_width/100.0;
1782 int v_ypos=rect.get_y();
1783 int v_ysize=rect.get_height()*vpanel_height/100.0;
1784 std::string v_pos(strprintf("%d %d", v_xpos, v_ypos));
1785 std::string v_size(strprintf("%d %d", v_xsize, v_ysize));
1787 int h_xpos=rect.get_x();
1788 int h_xsize=rect.get_width()*hpanel_width/100.0;
1789 int h_ypos=rect.get_y()+ rect.get_height()*(1.0-hpanel_height/100.0);;
1790 int h_ysize=rect.get_height()*hpanel_height/100.0;
1791 std::string h_pos(strprintf("%d %d", h_xpos, h_ypos));
1792 std::string h_size(strprintf("%d %d", h_xsize, h_ysize));
1793 int v_dock1 = rect.get_height()*vdock*0.8/100.0;
1794 int v_dock2 = rect.get_height()*vdock*0.6/100.0;
1795 int v_dock3 = rect.get_height()*vdock*1.1/100.0;
1796 int h_dock = rect.get_width()*hdock/100.0;
1798 std::string v_contents(strprintf("%d %d %d", v_dock1, v_dock2, v_dock3));
1799 std::string h_contents(strprintf("%d", h_dock));
1800 // Tool Box position
1801 std::string tbox_pos(strprintf("%d %d", rect.get_x(), rect.get_y()));
1803 synfig::info("tool box pos: %s", tbox_pos.c_str());
1804 synfig::info("v_contents sizes: %s", v_contents.c_str());
1805 synfig::info("v_pos: %s", v_pos.c_str());
1806 synfig::info("v_sizes: %s", v_size.c_str());
1807 synfig::info("h_contents sizes: %s", h_contents.c_str());
1808 synfig::info("h_pos: %s", h_pos.c_str());
1809 synfig::info("h_sizes: %s", h_size.c_str());
1811 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1812 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1813 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size",v_contents);
1814 synfigapp::Main::settings().set_value("dock.dialog.1.size",v_size);
1815 synfigapp::Main::settings().set_value("dock.dialog.1.pos",v_pos);
1816 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1817 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1818 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size",h_contents);
1819 synfigapp::Main::settings().set_value("dock.dialog.2.size",h_size);
1820 synfigapp::Main::settings().set_value("dock.dialog.2.pos",h_pos);
1821 synfigapp::Main::settings().set_value("window.toolbox.pos",tbox_pos);
1823 dock_manager->show_all_dock_dialogs();
1827 App::reset_initial_preferences()
1829 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1830 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1831 #ifdef SINGLE_THREADED
1832 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1834 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1835 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1836 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1837 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1838 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1839 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1840 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1841 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1846 App::shutdown_request(GdkEventAny*)
1850 //return !shutdown_in_progress;
1856 if(shutdown_in_progress)return;
1859 get_ui_interface()->task(_("Quit Request"));
1862 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1866 std::list<etl::handle<Instance> >::iterator iter;
1867 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1869 if(!(*iter)->safe_close())
1873 if((*iter)->synfigapp::Instance::get_action_count())
1875 handle<synfigapp::UIInterface> uim;
1876 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1878 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1879 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1881 case synfigapp::UIInterface::RESPONSE_NO:
1883 case synfigapp::UIInterface::RESPONSE_YES:
1886 case synfigapp::UIInterface::RESPONSE_CANCEL:
1895 if((*iter)->synfigapp::Instance::is_modified())
1897 handle<synfigapp::UIInterface> uim;
1898 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1900 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() );
1901 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1903 case synfigapp::UIInterface::RESPONSE_NO:
1905 case synfigapp::UIInterface::RESPONSE_YES:
1906 (*iter)->dialog_cvs_commit();
1908 case synfigapp::UIInterface::RESPONSE_CANCEL:
1917 // This next line causes things to crash for some reason
1921 shutdown_in_progress=true;
1923 instance_list.clear();
1925 while(studio::App::events_pending())studio::App::iteration(false);
1928 auto_recover->normal_shutdown();
1930 get_ui_interface()->task(_("Quit Request sent"));
1936 dialog_setup->refresh();
1937 dialog_setup->show();
1940 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1941 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1944 //#define USE_WIN32_FILE_DIALOGS 1
1947 #ifdef USE_WIN32_FILE_DIALOGS
1948 static OPENFILENAME ofn={};
1952 #include <gdk/gdkwin32.h>
1956 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1958 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1960 #ifdef USE_WIN32_FILE_DIALOGS
1961 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1963 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1964 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1965 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1967 ofn.lStructSize=sizeof(OPENFILENAME);
1968 ofn.hwndOwner = hWnd;
1969 ofn.hInstance = hInstance;
1970 ofn.lpstrFilter = szFilter;
1971 // ofn.lpstrCustomFilter=NULL;
1972 // ofn.nMaxCustFilter=0;
1973 // ofn.nFilterIndex=0;
1974 // ofn.lpstrFile=NULL;
1975 ofn.nMaxFile=MAX_PATH;
1976 // ofn.lpstrFileTitle=NULL;
1977 // ofn.lpstrInitialDir=NULL;
1978 // ofn.lpstrTitle=NULL;
1979 ofn.Flags=OFN_HIDEREADONLY;
1980 // ofn.nFileOffset=0;
1981 // ofn.nFileExtension=0;
1982 ofn.lpstrDefExt=TEXT("sif");
1983 // ofn.lCustData = 0l;
1985 // ofn.lpTemplateName=NULL;
1987 CHAR szFilename[MAX_PATH];
1989 strcpy(szFilename,filename.c_str());
1990 strcpy(szTitle,title.c_str());
1992 ofn.lpstrFile=szFilename;
1993 ofn.lpstrFileTitle=szTitle;
1995 if(GetOpenFileName(&ofn))
1997 filename=szFilename;
2002 #else // not USE_WIN32_FILE_DIALOGS
2003 synfig::String prev_path;
2005 if(!_preferences.get_value(preference, prev_path))
2008 prev_path = absolute_path(prev_path);
2010 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2012 dialog->set_current_folder(prev_path);
2013 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2014 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
2016 if (filename.empty())
2017 dialog->set_filename(prev_path);
2018 else if (is_absolute_path(filename))
2019 dialog->set_filename(filename);
2021 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2023 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2024 filename = dialog->get_filename();
2025 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
2026 _preferences.set_value(preference, dirname(filename));
2033 #endif // not USE_WIN32_FILE_DIALOGS
2037 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2039 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2041 #if USE_WIN32_FILE_DIALOGS
2042 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2044 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2045 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2046 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2048 ofn.lStructSize=sizeof(OPENFILENAME);
2049 ofn.hwndOwner = hWnd;
2050 ofn.hInstance = hInstance;
2051 ofn.lpstrFilter = szFilter;
2052 // ofn.lpstrCustomFilter=NULL;
2053 // ofn.nMaxCustFilter=0;
2054 // ofn.nFilterIndex=0;
2055 // ofn.lpstrFile=NULL;
2056 ofn.nMaxFile=MAX_PATH;
2057 // ofn.lpstrFileTitle=NULL;
2058 // ofn.lpstrInitialDir=NULL;
2059 // ofn.lpstrTitle=NULL;
2060 ofn.Flags=OFN_OVERWRITEPROMPT;
2061 // ofn.nFileOffset=0;
2062 // ofn.nFileExtension=0;
2063 ofn.lpstrDefExt=TEXT("sif");
2064 // ofn.lCustData = 0l;
2066 // ofn.lpTemplateName=NULL;
2068 CHAR szFilename[MAX_PATH];
2070 strcpy(szFilename,filename.c_str());
2071 strcpy(szTitle,title.c_str());
2073 ofn.lpstrFile=szFilename;
2074 ofn.lpstrFileTitle=szTitle;
2076 if(GetSaveFileName(&ofn))
2078 filename=szFilename;
2079 _preferences.set_value(preference,dirname(filename));
2084 synfig::String prev_path;
2086 if(!_preferences.get_value(preference, prev_path))
2089 prev_path = absolute_path(prev_path);
2091 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2093 dialog->set_current_folder(prev_path);
2094 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2095 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2097 Widget_Enum *file_type_enum = 0;
2098 if (preference == ANIMATION_DIR_PREFERENCE)
2100 file_type_enum = manage(new Widget_Enum());
2101 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2102 .add_enum_value(synfig::RELEASE_VERSION_0_62_02, "0.62.02", strprintf("0.62.02 (%s)", _("current")))
2103 .add_enum_value(synfig::RELEASE_VERSION_0_62_01, "0.62.01", "0.62.01")
2104 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", "0.61.00")
2105 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2106 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2107 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2108 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2109 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2111 Gtk::HBox *hbox = manage(new Gtk::HBox);
2112 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2113 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2116 dialog->set_extra_widget(*hbox);
2119 if (filename.empty())
2120 dialog->set_filename(prev_path);
2123 std::string full_path;
2124 if (is_absolute_path(filename))
2125 full_path = filename;
2127 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2129 // select the file if it exists
2130 dialog->set_filename(full_path);
2132 // if the file doesn't exist, put its name into the filename box
2134 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2135 dialog->set_current_name(basename(filename));
2138 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2139 if (preference == ANIMATION_DIR_PREFERENCE)
2140 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2141 filename = dialog->get_filename();
2142 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2143 _preferences.set_value(preference, dirname(filename));
2154 App::dialog_error_blocking(const std::string &title, const std::string &message)
2156 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2157 dialog.set_title(title);
2163 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2165 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2166 dialog.set_title(title);
2172 App::dialog_yes_no(const std::string &title, const std::string &message)
2177 true // use_separator
2179 Gtk::Label label(message);
2182 dialog.get_vbox()->pack_start(label);
2183 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2184 dialog.add_button(Gtk::StockID("gtk-no"),0);
2186 return dialog.run();
2190 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2195 true // use_separator
2197 Gtk::Label label(message);
2200 dialog.get_vbox()->pack_start(label);
2201 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2202 dialog.add_button(Gtk::StockID("gtk-no"),0);
2203 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2205 return dialog.run();
2209 App::dialog_not_implemented()
2211 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2212 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2217 try_open_url(const std::string &url)
2220 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2222 std::vector<std::string> command_line;
2223 std::vector<std::string> browsers;
2224 browsers.reserve(23);
2226 // Browser wrapper scripts
2227 #ifdef USE_OPEN_FOR_URLS
2228 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2230 browsers.push_back("xdg-open"); // XDG wrapper
2231 browsers.push_back("sensible-browser"); // Debian wrapper
2232 browsers.push_back("gnome-open"); // GNOME wrapper
2233 browsers.push_back("kfmclient"); // KDE wrapper
2234 browsers.push_back("exo-open"); // XFCE wrapper
2236 // Alternatives system
2237 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2238 browsers.push_back("x-www-browser"); // Debian GUI alternative
2240 // Individual browsers
2241 browsers.push_back("firefox");
2242 browsers.push_back("epiphany-browser");
2243 browsers.push_back("epiphany");
2244 browsers.push_back("konqueror");
2245 browsers.push_back("iceweasel");
2246 browsers.push_back("mozilla");
2247 browsers.push_back("netscape");
2248 browsers.push_back("icecat");
2249 browsers.push_back("galeon");
2250 browsers.push_back("midori");
2251 browsers.push_back("safari");
2252 browsers.push_back("opera");
2253 browsers.push_back("amaya");
2254 browsers.push_back("netsurf");
2255 browsers.push_back("dillo");
2257 // Try the user-specified browser first
2258 command_line.push_back(App::browser_command);
2259 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2260 command_line.push_back(url);
2262 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2263 catch( Glib::SpawnError& exception ){
2265 while ( !browsers.empty() )
2267 // Skip the browser if we already tried it
2268 if( browsers[0] == App::browser_command )
2271 // Construct the command line
2272 command_line.clear();
2273 command_line.push_back(browsers[0]);
2274 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2275 command_line.push_back(url);
2277 // Remove the browser from the list
2278 browsers.erase(browsers.begin());
2280 // Try to spawn the browser
2281 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2282 // Failed, move on to the next one
2283 catch(Glib::SpawnError& exception){ continue; }
2284 return true; // No exception means we succeeded!
2295 if (!try_open_url("http://synfig.org/wiki/Category:Manual"))
2297 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2298 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://synfig.org/wiki/Category:Manual"));
2299 dialog.set_title(_("Help"));
2305 App::open_url(const std::string &url)
2307 if(!try_open_url(url))
2309 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2310 dialog.set_secondary_text(url);
2311 dialog.set_title(_("No browser found"));
2317 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2322 true); // use_separator
2324 Gtk::Label label(message);
2326 dialog.get_vbox()->pack_start(label);
2329 entry.set_text(text);
2331 entry.set_activates_default(true);
2333 dialog.get_vbox()->pack_start(entry);
2335 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2336 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2337 dialog.set_default_response(Gtk::RESPONSE_OK);
2339 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2342 if(dialog.run()!=Gtk::RESPONSE_OK)
2345 text=entry.get_text();
2351 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2356 true); // use_separator
2358 Gtk::Label label(message);
2360 dialog.get_vbox()->pack_start(label);
2362 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2363 text_buffer->set_text(text);
2364 Gtk::TextView text_view(text_buffer);
2367 dialog.get_vbox()->pack_start(text_view);
2369 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2370 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2371 dialog.set_default_response(Gtk::RESPONSE_OK);
2373 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2376 if(dialog.run()!=Gtk::RESPONSE_OK)
2379 text=text_buffer->get_text();
2385 App::open(std::string filename)
2387 return open_as(filename,filename);
2390 // this is called from autorecover.cpp:
2391 // App::open_as(get_shadow_file_name(filename),filename)
2392 // other than that, 'filename' and 'as' are the same
2394 App::open_as(std::string filename,std::string as)
2397 char long_name[1024];
2398 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2399 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2400 // don't use it if that's the case
2401 if (long_name[0] != '\0')
2407 OneMoment one_moment;
2408 String errors, warnings;
2410 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2411 if(canvas && get_instance(canvas))
2413 get_instance(canvas)->find_canvas_view(canvas)->present();
2414 info("%s is already open", filename.c_str());
2415 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2420 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2423 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2425 if (as.find(custom_filename_prefix.c_str()) != 0)
2426 add_recent_file(as);
2428 handle<Instance> instance(Instance::create(canvas));
2431 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2433 set_recent_file_window_size(instance);
2437 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)")))
2438 instance->dialog_cvs_update();
2443 dialog_error_blocking(_("Error"), x);
2446 catch(runtime_error x)
2448 dialog_error_blocking(_("Error"), x.what());
2453 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2464 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2466 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2467 canvas->set_name(file_name);
2468 file_name += ".sifz";
2470 canvas->rend_desc().set_frame_rate(preferred_fps);
2471 canvas->rend_desc().set_time_start(0.0);
2472 canvas->rend_desc().set_time_end(5.0);
2473 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2474 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2475 // The top left and botton right positions are expressed in units
2476 // Original convention is that 1 unit = 60 pixels
2477 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2478 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2479 canvas->rend_desc().set_w(preferred_x_size);
2480 canvas->rend_desc().set_h(preferred_y_size);
2481 canvas->rend_desc().set_antialias(1);
2482 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2483 canvas->set_file_name(file_name);
2485 handle<Instance> instance = Instance::create(canvas);
2487 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2488 instance->find_canvas_view(canvas)->canvas_properties.present();
2492 App::dialog_open(string filename)
2494 if (filename.empty())
2497 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2499 // If the filename still has wildcards, then we should
2500 // continue looking for the file we want
2501 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2507 get_ui_interface()->error(_("Unable to open file"));
2512 App::set_selected_instance(etl::loose_handle<Instance> instance)
2514 /* if(get_selected_instance()==instance)
2516 selected_instance=instance;
2517 signal_instance_selected()(instance);
2523 selected_instance=instance;
2524 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2528 instance->focus(instance->get_canvas());
2531 set_selected_canvas_view(0);
2533 signal_instance_selected()(instance);
2537 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2539 selected_canvas_view=canvas_view;
2540 signal_canvas_view_focus()(selected_canvas_view);
2543 selected_instance=canvas_view->get_instance();
2544 signal_instance_selected()(canvas_view->get_instance());
2547 if(get_selected_canvas_view()==canvas_view)
2549 signal_canvas_view_focus()(selected_canvas_view);
2550 signal_instance_selected()(canvas_view->get_instance());
2553 selected_canvas_view=canvas_view;
2554 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2555 set_selected_instance(canvas_view->get_instance());
2556 signal_canvas_view_focus()(selected_canvas_view);
2560 etl::loose_handle<Instance>
2561 App::get_instance(etl::handle<synfig::Canvas> canvas)
2563 if(!canvas) return 0;
2564 canvas=canvas->get_root();
2566 std::list<etl::handle<Instance> >::iterator iter;
2567 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2569 if((*iter)->get_canvas()==canvas)
2585 if(selected_instance)
2586 selected_instance->undo();
2592 if(selected_instance)
2593 selected_instance->redo();
2597 studio::App::get_base_path()
2599 return app_base_path_;