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
274 bool studio::App::single_threaded=false;
276 bool studio::App::restrict_radius_ducks=false;
277 bool studio::App::resize_imported_images=false;
278 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
279 int studio::App::preferred_x_size=480;
280 int studio::App::preferred_y_size=270;
281 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
282 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
283 float studio::App::preferred_fps=24.0;
284 #ifdef USE_OPEN_FOR_URLS
285 String studio::App::browser_command("open"); // MacOS only
287 String studio::App::browser_command("xdg-open"); // Linux XDG standard
290 static int max_recent_files_=25;
291 int studio::App::get_max_recent_files() { return max_recent_files_; }
292 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
294 static synfig::String app_base_path_;
299 really_delete_widget(Gtk::Widget *widget)
301 // synfig::info("really delete %p", (void*)widget);
306 // nasty workaround - when we've finished with a popup menu, we want to delete it
307 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
308 // so schedule the real delete to happen in 50ms, giving the action a chance to run
310 delete_widget(Gtk::Widget *widget)
312 // synfig::info("delete %p", (void*)widget);
313 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
316 }; // END of namespace studio
317 studio::StateManager* state_manager;
322 class GlobalUIInterface : public synfigapp::UIInterface
326 virtual Response confirmation(const std::string &title,
327 const std::string &primaryText,
328 const std::string &secondaryText,
329 const std::string &confirmPhrase,
330 const std::string &cancelPhrase,
331 Response defaultResponse)
333 Gtk::MessageDialog dialog(
334 primaryText, // Message
336 Gtk::MESSAGE_WARNING, // Type
337 Gtk::BUTTONS_NONE, // Buttons
342 dialog.set_title(title);
343 if (! secondaryText.empty())
344 dialog.set_secondary_text(secondaryText);
346 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
347 dialog.add_button(confirmPhrase, RESPONSE_OK);
348 dialog.set_default_response(defaultResponse);
351 return (Response) dialog.run();
354 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
359 true // use_separator
361 Gtk::Label label(message);
364 dialog.get_vbox()->pack_start(label);
365 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
366 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
368 dialog.set_default_response(dflt);
370 return (Response)dialog.run();
372 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
377 true // use_separator
379 Gtk::Label label(message);
382 dialog.get_vbox()->pack_start(label);
383 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
384 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
385 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
387 dialog.set_default_response(dflt);
389 return (Response)dialog.run();
391 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
396 true // use_separator
398 Gtk::Label label(message);
401 dialog.get_vbox()->pack_start(label);
402 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
403 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
405 dialog.set_default_response(dflt);
407 return (Response)dialog.run();
411 task(const std::string &task)
413 std::cerr<<task<<std::endl;
414 while(studio::App::events_pending())studio::App::iteration(false);
419 error(const std::string &err)
421 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
428 warning(const std::string &err)
430 std::cerr<<"warning: "<<err<<std::endl;
431 while(studio::App::events_pending())studio::App::iteration(false);
436 amount_complete(int /*current*/, int /*total*/)
438 while(studio::App::events_pending())studio::App::iteration(false);
443 /* === P R O C E D U R E S ================================================= */
447 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
449 action_group_list.push_back(action_group);
450 Gtk::UIManager::insert_action_group(action_group, pos);
454 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
456 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
457 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
458 if(*iter==action_group)
460 action_group_list.erase(iter);
461 Gtk::UIManager::remove_action_group(action_group);
464 synfig::error("Unable to find action group");
468 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
470 ui_manager->insert_action_group(group,0);
472 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
473 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
475 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
477 if(*iter && (*iter)->get_name()!="menus")
479 synfig::info("Removing action group "+(*iter)->get_name());
480 ui_manager->remove_action_group(*iter);
483 ui_manager->insert_action_group(group,0);
485 for(;!prev_groups.empty();prev_groups.pop_front())
487 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
488 ui_manager->insert_action_group(prev_groups.front(),1);
492 class Preferences : public synfigapp::Settings
495 virtual bool get_value(const synfig::String& key, synfig::String& value)const
499 value=strprintf("%f %f %f %f",
500 App::gamma.get_gamma_r(),
501 App::gamma.get_gamma_g(),
502 App::gamma.get_gamma_b(),
503 App::gamma.get_black_level()
507 if(key=="time_format")
509 value=strprintf("%i",App::get_time_format());
512 if(key=="file_history.size")
514 value=strprintf("%i",App::get_max_recent_files());
517 if(key=="use_colorspace_gamma")
519 value=strprintf("%i",(int)App::use_colorspace_gamma);
522 if(key=="distance_system")
524 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
527 #ifdef SINGLE_THREADED
528 if(key=="single_threaded")
530 value=strprintf("%i",(int)App::single_threaded);
534 if(key=="auto_recover_backup_interval")
536 value=strprintf("%i",App::auto_recover->get_timeout());
539 if(key=="restrict_radius_ducks")
541 value=strprintf("%i",(int)App::restrict_radius_ducks);
544 if(key=="resize_imported_images")
546 value=strprintf("%i",(int)App::resize_imported_images);
549 if(key=="browser_command")
551 value=App::browser_command;
554 if(key=="custom_filename_prefix")
556 value=App::custom_filename_prefix;
559 if(key=="preferred_x_size")
561 value=strprintf("%i",App::preferred_x_size);
564 if(key=="preferred_y_size")
566 value=strprintf("%i",App::preferred_y_size);
569 if(key=="predefined_size")
571 value=strprintf("%s",App::predefined_size.c_str());
574 if(key=="preferred_fps")
576 value=strprintf("%f",App::preferred_fps);
579 if(key=="predefined_fps")
581 value=strprintf("%s",App::predefined_fps.c_str());
585 return synfigapp::Settings::get_value(key,value);
588 virtual bool set_value(const synfig::String& key,const synfig::String& value)
594 strscanf(value,"%f %f %f %f",
601 App::gamma.set_all(r,g,b,blk);
605 if(key=="time_format")
607 int i(atoi(value.c_str()));
608 App::set_time_format(static_cast<synfig::Time::Format>(i));
611 if(key=="auto_recover_backup_interval")
613 int i(atoi(value.c_str()));
614 App::auto_recover->set_timeout(i);
617 if(key=="file_history.size")
619 int i(atoi(value.c_str()));
620 App::set_max_recent_files(i);
623 if(key=="use_colorspace_gamma")
625 int i(atoi(value.c_str()));
626 App::use_colorspace_gamma=i;
629 if(key=="distance_system")
631 App::distance_system=Distance::ident_system(value);;
634 #ifdef SINGLE_THREADED
635 if(key=="single_threaded")
637 int i(atoi(value.c_str()));
638 App::single_threaded=i;
642 if(key=="restrict_radius_ducks")
644 int i(atoi(value.c_str()));
645 App::restrict_radius_ducks=i;
648 if(key=="resize_imported_images")
650 int i(atoi(value.c_str()));
651 App::resize_imported_images=i;
654 if(key=="browser_command")
656 App::browser_command=value;
659 if(key=="custom_filename_prefix")
661 App::custom_filename_prefix=value;
664 if(key=="preferred_x_size")
666 int i(atoi(value.c_str()));
667 App::preferred_x_size=i;
670 if(key=="preferred_y_size")
672 int i(atoi(value.c_str()));
673 App::preferred_y_size=i;
676 if(key=="predefined_size")
678 App::predefined_size=value;
681 if(key=="preferred_fps")
683 float i(atof(value.c_str()));
684 App::preferred_fps=i;
687 if(key=="predefined_fps")
689 App::predefined_fps=value;
693 return synfigapp::Settings::set_value(key,value);
696 virtual KeyList get_key_list()const
698 KeyList ret(synfigapp::Settings::get_key_list());
699 ret.push_back("gamma");
700 ret.push_back("time_format");
701 ret.push_back("distance_system");
702 ret.push_back("file_history.size");
703 ret.push_back("use_colorspace_gamma");
704 #ifdef SINGLE_THREADED
705 ret.push_back("single_threaded");
707 ret.push_back("auto_recover_backup_interval");
708 ret.push_back("restrict_radius_ducks");
709 ret.push_back("resize_imported_images");
710 ret.push_back("browser_command");
711 ret.push_back("custom_filename_prefix");
712 ret.push_back("preferred_x_size");
713 ret.push_back("preferred_y_size");
714 ret.push_back("predefined_size");
715 ret.push_back("preferred_fps");
716 ret.push_back("predefined_fps");
721 static ::Preferences _preferences;
726 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
728 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
730 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
732 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
733 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
734 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
735 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
736 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
737 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
738 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
739 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
740 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
741 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
742 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
743 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
744 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
746 // Add the synfigapp actions...
747 synfigapp::Action::Book::iterator iter;
748 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
750 actions_action_group->add(Gtk::Action::create(
751 "action-"+iter->second.name,
752 get_action_stock_id(iter->second),
753 iter->second.local_name,iter->second.local_name
757 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); actions_action_group->add(action); }
758 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); actions_action_group->add(action); }
759 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); group->add(action,sig); }
761 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
762 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
763 DEFINE_ACTION("new", Gtk::Stock::NEW);
764 DEFINE_ACTION("open", Gtk::Stock::OPEN);
765 DEFINE_ACTION("save", Gtk::Stock::SAVE);
766 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
767 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
768 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
769 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
770 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
771 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
772 DEFINE_ACTION("import", _("Import"));
773 DEFINE_ACTION("render", _("Render"));
774 DEFINE_ACTION("preview", _("Preview"));
775 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
776 DEFINE_ACTION("sound", _("Sound File"));
777 DEFINE_ACTION("options", _("Options"));
778 DEFINE_ACTION("close", _("Close View"));
779 DEFINE_ACTION("close-document", _("Close Document"));
780 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
783 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
784 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
785 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
786 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
787 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
788 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
789 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
790 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
791 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
792 DEFINE_ACTION("properties", _("Properties"));
794 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
795 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
796 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
797 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
798 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
799 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
800 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
801 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
802 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
803 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
804 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
805 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
806 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
807 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
808 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
809 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
810 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
811 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
812 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
813 DEFINE_ACTION("play", _("Play"));
814 // DEFINE_ACTION("pause", _("Pause"));
815 DEFINE_ACTION("stop", _("Stop"));
816 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
817 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
818 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
819 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
820 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
821 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
822 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
823 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
824 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
825 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
826 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
827 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
828 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
829 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
830 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
831 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
832 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
833 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
834 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
835 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
836 DEFINE_ACTION("seek-end", _("Seek to End"));
838 DEFINE_ACTION("action-group_add", _("Add group"));
840 DEFINE_ACTION("canvas-new", _("New Canvas"));
842 DEFINE_ACTION("amount-inc", _("Increase Amount"));
843 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
846 #undef DEFINE_ACTION_2
847 #undef DEFINE_ACTION_SIG
849 Glib::ustring ui_info =
851 " <popup name='menu-toolbox' action='menu-toolbox'>"
852 " <menu action='menu-file'>"
855 " <popup name='menu-main' action='menu-main'>"
856 " <menu action='menu-file'>"
857 " <menuitem action='new' />"
858 " <menuitem action='open' />"
859 " <menuitem action='save' />"
860 " <menuitem action='save-as' />"
861 " <menuitem action='revert' />"
862 " <separator name='bleh01'/>"
863 " <menuitem action='cvs-add' />"
864 " <menuitem action='cvs-update' />"
865 " <menuitem action='cvs-commit' />"
866 " <menuitem action='cvs-revert' />"
867 " <separator name='bleh02'/>"
868 " <menuitem action='import' />"
869 " <separator name='bleh03'/>"
870 " <menuitem action='render' />"
871 " <menuitem action='preview' />"
872 " <menuitem action='sound' />"
873 " <separator name='bleh04'/>"
874 " <menuitem action='options' />"
875 " <menuitem action='close' />"
876 " <menuitem action='close-document' />"
877 " <menuitem action='quit' />"
879 " <menu action='menu-edit'>"
880 " <menuitem action='undo'/>"
881 " <menuitem action='redo'/>"
882 " <separator name='bleh05'/>"
883 " <menuitem action='cut'/>"
884 " <menuitem action='copy'/>"
885 " <menuitem action='paste'/>"
886 " <separator name='bleh06'/>"
887 " <menuitem action='select-all-layers'/>"
888 " <menuitem action='unselect-all-layers'/>"
889 " <menuitem action='select-all-ducks'/>"
890 " <menuitem action='unselect-all-ducks'/>"
891 " <separator name='bleh07'/>"
892 " <menuitem action='properties'/>"
894 " <menu action='menu-view'>"
895 " <menu action='menu-duck-mask'>"
896 " <menuitem action='mask-position-ducks' />"
897 " <menuitem action='mask-vertex-ducks' />"
898 " <menuitem action='mask-tangent-ducks' />"
899 " <menuitem action='mask-radius-ducks' />"
900 " <menuitem action='mask-width-ducks' />"
901 " <menuitem action='mask-angle-ducks' />"
903 " <menu action='menu-preview-quality'>"
904 " <menuitem action='quality-00' />"
905 " <menuitem action='quality-01' />"
906 " <menuitem action='quality-02' />"
907 " <menuitem action='quality-03' />"
908 " <menuitem action='quality-04' />"
909 " <menuitem action='quality-05' />"
910 " <menuitem action='quality-06' />"
911 " <menuitem action='quality-07' />"
912 " <menuitem action='quality-08' />"
913 " <menuitem action='quality-09' />"
914 " <menuitem action='quality-10' />"
916 " <menu action='menu-lowres-pixel'>"
917 " <menuitem action='decrease-low-res-pixel-size'/>"
918 " <menuitem action='increase-low-res-pixel-size'/>"
919 " <separator name='pixel-size-separator'/>"
922 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
923 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
927 " <separator name='bleh08'/>"
928 " <menuitem action='play'/>"
929 //" <menuitem action='pause'/>"
930 " <menuitem action='stop'/>"
931 " <menuitem action='dialog-flipbook'/>"
932 " <separator name='bleh09'/>"
933 " <menuitem action='toggle-grid-show'/>"
934 " <menuitem action='toggle-grid-snap'/>"
935 " <menuitem action='toggle-guide-show'/>"
936 " <menuitem action='toggle-low-res'/>"
937 " <menuitem action='toggle-onion-skin'/>"
938 " <separator name='bleh10'/>"
939 " <menuitem action='canvas-zoom-in'/>"
940 " <menuitem action='canvas-zoom-out'/>"
941 " <menuitem action='canvas-zoom-fit'/>"
942 " <menuitem action='canvas-zoom-100'/>"
943 " <separator name='bleh11'/>"
944 " <menuitem action='time-zoom-in'/>"
945 " <menuitem action='time-zoom-out'/>"
946 " <separator name='bleh12'/>"
947 " <menuitem action='jump-next-keyframe'/>"
948 " <menuitem action='jump-prev-keyframe'/>"
949 " <menuitem action='seek-next-frame'/>"
950 " <menuitem action='seek-prev-frame'/>"
951 " <menuitem action='seek-next-second'/>"
952 " <menuitem action='seek-prev-second'/>"
953 " <menuitem action='seek-begin'/>"
954 " <menuitem action='seek-end'/>"
956 " <menu action='menu-canvas'>"
957 " <menuitem action='canvas-new'/>"
959 " <menu name='menu-state' action='menu-state'>"
961 " <menu action='menu-group'>"
962 " <menuitem action='action-group_add'/>"
964 " <menu action='menu-layer'>"
965 //" <menuitem action='cut'/>"
966 //" <menuitem action='copy'/>"
967 //" <menuitem action='paste'/>"
968 //" <separator name='bleh06'/>"
969 " <menu action='menu-layer-new'></menu>"
970 " <menuitem action='amount-inc'/>"
971 " <menuitem action='amount-dec'/>"
973 " <menu action='menu-keyframe'>"
974 " <menuitem action='keyframe-properties'/>"
981 " <menubar name='MenuBar'>"
982 " <menu action='MenuFile'>"
983 " <menuitem action='New'/>"
984 " <menuitem action='Open'/>"
986 " <menuitem action='Quit'/>"
988 " <menu action='MenuEdit'>"
989 " <menuitem action='Cut'/>"
990 " <menuitem action='Copy'/>"
991 " <menuitem action='Paste'/>"
994 " <toolbar name='ToolBar'>"
995 " <toolitem action='Open'/>"
996 " <toolitem action='Quit'/>"
1002 actions_action_group->set_sensitive(false);
1003 App::ui_manager()->set_add_tearoffs(true);
1004 App::ui_manager()->insert_action_group(menus_action_group,1);
1005 App::ui_manager()->insert_action_group(actions_action_group,1);
1006 App::ui_manager()->add_ui_from_string(ui_info);
1008 //App::ui_manager()->get_accel_group()->unlock();
1010 catch(const Glib::Error& ex)
1012 synfig::error("building menus and toolbars failed: " + ex.what());
1015 // Add default keyboard accelerators
1016 #define ACCEL(accel,path) \
1018 Gtk::AccelKey accel_key(accel,path); \
1019 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1022 #define ACCEL2(accel) \
1024 Gtk::AccelKey accel_key(accel); \
1025 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1029 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1030 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1031 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1032 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1033 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1034 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1035 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1036 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1037 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1038 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1039 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1040 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1041 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1042 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1043 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1044 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1045 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1046 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1049 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1050 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1051 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1052 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1053 ACCEL("F9", "<Actions>/canvasview/render" );
1054 ACCEL("F11", "<Actions>/canvasview/preview" );
1055 ACCEL("F8", "<Actions>/canvasview/properties" );
1056 ACCEL("F12", "<Actions>/canvasview/options" );
1057 ACCEL("<control>i", "<Actions>/canvasview/import" );
1058 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1059 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1060 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1061 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1062 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1063 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1064 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1065 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1066 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1067 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1068 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1069 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1070 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1071 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1072 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1073 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1074 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1075 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1076 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1077 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1078 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1079 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1080 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1081 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1082 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1083 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1084 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1085 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1086 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1087 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1088 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1089 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1090 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1091 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1092 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1093 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1094 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1095 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1096 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1097 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1098 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1099 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1100 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1101 ACCEL("End", "<Actions>/canvasview/seek-end" );
1108 #define mkdir(x,y) mkdir(x)
1111 /* === M E T H O D S ======================================================= */
1113 App::App(int *argc, char ***argv):
1114 Gtk::Main(argc,argv),
1115 IconController(etl::dirname((*argv)[0]))
1117 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1120 ui_interface_=new GlobalUIInterface();
1124 // don't call thread_init() if threads are already initialized
1125 // on some machines bonobo_init() initialized threads before we get here
1126 if (!g_thread_supported())
1127 Glib::thread_init();
1129 distance_system=Distance::SYSTEM_UNITS;
1131 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1134 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1138 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1144 if(!SYNFIG_CHECK_VERSION())
1146 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1147 dialog_error_blocking("Synfig Studio",
1148 "This copy of Synfig Studio was compiled against a\n"
1149 "different version of libsynfig than what is currently\n"
1150 "installed. Synfig Studio will now abort. Try downloading\n"
1151 "the latest version from the Synfig website at\n"
1152 "http://synfig.org/Download"
1156 Glib::set_application_name(_("Synfig Studio"));
1158 Splash splash_screen;
1159 splash_screen.show();
1161 shutdown_in_progress=false;
1162 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1163 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1165 // Initialize the Synfig library
1166 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1167 catch(std::runtime_error x)
1169 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1174 get_ui_interface()->error(_("Failed to initialize synfig!"));
1178 // add the preferences to the settings
1179 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1183 studio_init_cb.task(_("Init UI Manager..."));
1184 App::ui_manager_=studio::UIManager::create();
1187 studio_init_cb.task(_("Init Dock Manager..."));
1188 dock_manager=new studio::DockManager();
1190 studio_init_cb.task(_("Init State Manager..."));
1191 state_manager=new StateManager();
1193 studio_init_cb.task(_("Init Toolbox..."));
1194 toolbox=new studio::Toolbox();
1196 studio_init_cb.task(_("Init About Dialog..."));
1197 about=new studio::About();
1199 studio_init_cb.task(_("Init Tool Options..."));
1200 dialog_tool_options=new studio::Dialog_ToolOptions();
1201 dock_manager->register_dockable(*dialog_tool_options);
1203 studio_init_cb.task(_("Init History..."));
1204 dock_history=new studio::Dock_History();
1205 dock_manager->register_dockable(*dock_history);
1207 studio_init_cb.task(_("Init Canvases..."));
1208 dock_canvases=new studio::Dock_Canvases();
1209 dock_manager->register_dockable(*dock_canvases);
1211 studio_init_cb.task(_("Init Keyframes..."));
1212 dock_keyframes=new studio::Dock_Keyframes();
1213 dock_manager->register_dockable(*dock_keyframes);
1215 studio_init_cb.task(_("Init Layers..."));
1216 dock_layers=new studio::Dock_Layers();
1217 dock_manager->register_dockable(*dock_layers);
1219 studio_init_cb.task(_("Init Params..."));
1220 dock_params=new studio::Dock_Params();
1221 dock_manager->register_dockable(*dock_params);
1223 studio_init_cb.task(_("Init MetaData..."));
1224 dock_meta_data=new studio::Dock_MetaData();
1225 dock_manager->register_dockable(*dock_meta_data);
1227 studio_init_cb.task(_("Init Children..."));
1228 dock_children=new studio::Dock_Children();
1229 dock_manager->register_dockable(*dock_children);
1231 studio_init_cb.task(_("Init Info..."));
1232 dock_info = new studio::Dock_Info();
1233 dock_manager->register_dockable(*dock_info);
1235 studio_init_cb.task(_("Init Navigator..."));
1236 dock_navigator = new studio::Dock_Navigator();
1237 dock_manager->register_dockable(*dock_navigator);
1239 studio_init_cb.task(_("Init Timetrack..."));
1240 dock_timetrack = new studio::Dock_Timetrack();
1241 dock_manager->register_dockable(*dock_timetrack);
1243 studio_init_cb.task(_("Init Curve Editor..."));
1244 dock_curves = new studio::Dock_Curves();
1245 dock_manager->register_dockable(*dock_curves);
1247 studio_init_cb.task(_("Init Layer Groups..."));
1248 dock_layer_groups = new studio::Dock_LayerGroups();
1249 dock_manager->register_dockable(*dock_layer_groups);
1252 studio_init_cb.task(_("Init Color Dialog..."));
1253 dialog_color=new studio::Dialog_Color();
1255 studio_init_cb.task(_("Init Gradient Dialog..."));
1256 dialog_gradient=new studio::Dialog_Gradient();
1258 studio_init_cb.task(_("Init DeviceTracker..."));
1259 device_tracker=new studio::DeviceTracker();
1261 studio_init_cb.task(_("Init Tools..."));
1264 state_manager->add_state(&state_normal);
1265 state_manager->add_state(&state_smooth_move);
1266 state_manager->add_state(&state_scale);
1267 state_manager->add_state(&state_rotate);
1268 state_manager->add_state(&state_mirror);
1269 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1272 state_manager->add_state(&state_circle);
1273 state_manager->add_state(&state_rectangle);
1274 state_manager->add_state(&state_star);
1275 state_manager->add_state(&state_gradient);
1276 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1277 state_manager->add_state(&state_text);
1278 state_manager->add_state(&state_bline);
1279 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1282 state_manager->add_state(&state_fill);
1283 state_manager->add_state(&state_eyedrop);
1284 state_manager->add_state(&state_zoom);
1285 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1287 studio_init_cb.task(_("Init ModPalette..."));
1288 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1290 studio_init_cb.task(_("Init Setup Dialog..."));
1291 dialog_setup=new studio::Dialog_Setup();
1293 studio_init_cb.task(_("Init Input Dialog..."));
1294 dialog_input=new Gtk::InputDialog();
1295 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1296 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1298 studio_init_cb.task(_("Init auto recovery..."));
1299 auto_recover=new AutoRecover();
1301 studio_init_cb.amount_complete(9250,10000);
1302 studio_init_cb.task(_("Loading Settings..."));
1304 device_tracker->load_preferences();
1306 studio_init_cb.task(_("Checking auto-recover..."));
1308 studio_init_cb.amount_complete(9900,10000);
1310 bool opened_any = false;
1311 if(auto_recover->recovery_needed())
1313 splash_screen.hide();
1314 if (get_ui_interface()->confirmation("Crash Recovery",
1315 _("Auto recovery file found"),
1316 _("Synfig Studio seems to have crashed\n"
1317 "before you could save all your files.\n"
1318 "Recover unsaved changes?"),
1319 _("Recover"), _("Ignore"))
1320 == synfigapp::UIInterface::RESPONSE_OK)
1322 int number_recovered;
1323 if(!auto_recover->recover(number_recovered))
1324 if (number_recovered)
1325 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1327 get_ui_interface()->error(_("Unable to recover from previous crash"));
1329 get_ui_interface()->error(
1330 _("Synfig Studio has attempted to recover\n"
1331 "from a previous crash. The files that it has\n"
1332 "recovered are NOT YET SAVED. It would be a good\n"
1333 "idea to review them and save them now."));
1335 if (number_recovered)
1338 splash_screen.show();
1341 // Look for any files given on the command line,
1342 // and load them if found.
1343 for(;*argc>=1;(*argc)--)
1344 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1346 studio_init_cb.task(_("Loading files..."));
1347 splash_screen.hide();
1348 open((*argv)[*argc]);
1350 splash_screen.show();
1353 // if no file was specified to be opened, create a new document to help new users get started more easily
1354 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1357 studio_init_cb.task(_("Done."));
1358 studio_init_cb.amount_complete(10000,10000);
1364 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1368 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1372 StateManager* App::get_state_manager() { return state_manager; }
1376 shutdown_in_progress=true;
1380 synfigapp::Main::settings().remove_domain("pref");
1382 selected_instance=0;
1384 // Unload all of the modules
1385 for(;!module_list_.empty();module_list_.pop_back())
1388 delete state_manager;
1392 delete auto_recover;
1400 delete dialog_setup;
1402 delete dialog_gradient;
1404 delete dialog_color;
1406 delete dialog_input;
1408 delete dock_manager;
1410 instance_list.clear();
1414 App::get_user_app_directory()
1416 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1418 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1420 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1425 App::get_config_file(const synfig::String& file)
1427 return Glib::build_filename(get_user_app_directory(),file);
1430 #define SCALE_FACTOR (1280)
1431 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1433 App::set_recent_file_window_size(etl::handle<Instance> instance)
1435 int screen_w(Gdk::screen_width());
1436 int screen_h(Gdk::screen_height());
1438 const std::string &canvas_window_size = *recent_files_window_size.begin();
1440 if(canvas_window_size.empty())
1443 synfig::String::size_type current=0;
1444 bool seen_root(false), shown_non_root(false);
1446 while(current != synfig::String::npos)
1448 // find end of first field (canvas) or return
1449 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1450 if(separator == synfig::String::npos) break;
1453 synfig::Canvas::Handle canvas;
1456 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1458 catch(Exception::IDNotFound) {
1459 // can't find the canvas; skip to the next canvas or return
1460 separator = canvas_window_size.find_first_of('\t', current);
1461 if(separator == synfig::String::npos) return;
1462 current = separator+1;
1466 if (canvas->is_root())
1469 shown_non_root = true;
1471 // check that we have the tab character the ends this canvas' data or return
1472 current = separator+1;
1473 separator = canvas_window_size.find_first_of('\t', current);
1474 if(separator == synfig::String::npos) return;
1477 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1479 current = separator+1;
1483 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1484 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1485 x=x*screen_w/SCALE_FACTOR;
1486 y=y*screen_h/SCALE_FACTOR;
1487 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1488 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1489 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1490 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1492 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1493 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1495 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1496 canvasview->move(x,y);
1497 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1498 canvasview->present();
1500 current = separator+1;
1503 if (shown_non_root && !seen_root)
1504 instance->find_canvas_view(instance->get_canvas())->hide();
1508 App::add_recent_file(const etl::handle<Instance> instance)
1510 int screen_w(Gdk::screen_width());
1511 int screen_h(Gdk::screen_height());
1513 std::string canvas_window_size;
1515 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1516 Instance::CanvasViewList::const_iterator iter;
1518 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1520 if( !((*iter)->is_visible()) )
1523 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1524 int x_pos, y_pos, x_size, y_size;
1525 (*iter)->get_position(x_pos,y_pos);
1526 (*iter)->get_size(x_size,y_size);
1528 canvas_window_size += strprintf("%s %d %d %d %d\t",
1529 canvas->get_relative_id(canvas->get_root()).c_str(),
1530 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1531 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1534 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1539 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1541 std::string filename(file_name);
1543 assert(!filename.empty());
1545 if(filename.empty())
1548 // Toss out any "hidden" files
1549 if(basename(filename)[0]=='.')
1552 // If we aren't an absolute path, turn ourselves into one
1553 if(!is_absolute_path(filename))
1554 filename=absolute_path(filename);
1556 std::string old_window_size;
1558 list<string>::iterator iter;
1559 list<string>::iterator iter_wsize;
1560 // Check to see if the file is already on the list.
1561 // If it is, then remove it from the list
1562 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1565 recent_files.erase(iter);
1566 old_window_size = *iter_wsize;
1567 recent_files_window_size.erase(iter_wsize);
1572 // Push the filename to the front of the list
1573 recent_files.push_front(filename);
1574 if(window_size.empty())
1575 recent_files_window_size.push_front(old_window_size);
1577 recent_files_window_size.push_front(window_size);
1579 // Clean out the files at the end of the list.
1580 while(recent_files.size()>(unsigned)get_max_recent_files())
1582 recent_files.pop_back();
1583 recent_files_window_size.pop_back();
1586 signal_recent_files_changed_();
1591 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1594 App::get_time_format()
1596 return _App_time_format;
1600 App::set_time_format(synfig::Time::Format x)
1607 App::save_settings()
1612 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1613 setlocale(LC_NUMERIC, "C");
1615 std::string filename=get_config_file("accelrc");
1616 Gtk::AccelMap::save(filename);
1619 std::string filename=get_config_file("recentfiles");
1621 std::ofstream file(filename.c_str());
1625 synfig::warning("Unable to save %s",filename.c_str());
1629 list<string>::reverse_iterator iter;
1631 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1635 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1637 std::ofstream file(filename.c_str());
1641 synfig::warning("Unable to save %s",filename.c_str());
1645 list<string>::reverse_iterator iter;
1647 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1651 std::string filename=get_config_file("settings");
1652 synfigapp::Main::settings().save_to_file(filename);
1653 setlocale(LC_NUMERIC,old_locale);
1657 synfig::warning("Caught exception when attempting to save settings.");
1662 App::load_settings()
1667 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1668 setlocale(LC_NUMERIC, "C");
1670 std::string filename=get_config_file("accelrc");
1671 Gtk::AccelMap::load(filename);
1674 bool window_size_broken = false;
1676 std::string filename=get_config_file("recentfiles");
1677 std::string filename_window_size=filename+std::string("_window_size");
1679 std::ifstream file(filename.c_str());
1680 std::ifstream file_window_size(filename_window_size.c_str());
1682 if(!file_window_size)
1683 window_size_broken = true;
1687 std::string recent_file;
1688 std::string recent_file_window_size;
1689 getline(file,recent_file);
1690 if(!window_size_broken)
1691 getline(file_window_size,recent_file_window_size);
1692 if(!recent_file.empty())
1694 if(!window_size_broken && !file_window_size)
1695 window_size_broken = true;
1696 if (std::ifstream(recent_file.c_str()))
1698 if(!window_size_broken)
1699 add_recent_file(recent_file,recent_file_window_size);
1701 add_recent_file(recent_file);
1705 if(!window_size_broken && file_window_size)
1706 window_size_broken = true;
1708 if(window_size_broken)
1710 recent_files_window_size.clear();
1711 recent_files_window_size.resize(recent_files.size());
1714 std::string filename=get_config_file("settings");
1715 if(!synfigapp::Main::settings().load_from_file(filename))
1717 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1718 //if(!synfigapp::Main::settings().load_from_file(filename))
1720 gamma.set_gamma(1.0/2.2);
1721 reset_initial_window_configuration();
1724 setlocale(LC_NUMERIC,old_locale);
1728 synfig::warning("Caught exception when attempting to load settings.");
1733 App::reset_initial_window_configuration()
1735 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1736 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1737 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1738 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1739 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1740 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1741 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1742 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1743 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1744 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1745 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1746 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1747 #ifdef SINGLE_THREADED
1748 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1750 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1751 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1752 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1753 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1754 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1755 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1756 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1757 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1758 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1762 App::shutdown_request(GdkEventAny*)
1766 //return !shutdown_in_progress;
1772 if(shutdown_in_progress)return;
1775 get_ui_interface()->task(_("Quit Request"));
1778 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1782 std::list<etl::handle<Instance> >::iterator iter;
1783 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1785 if(!(*iter)->safe_close())
1789 if((*iter)->synfigapp::Instance::get_action_count())
1791 handle<synfigapp::UIInterface> uim;
1792 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1794 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1795 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1797 case synfigapp::UIInterface::RESPONSE_NO:
1799 case synfigapp::UIInterface::RESPONSE_YES:
1802 case synfigapp::UIInterface::RESPONSE_CANCEL:
1811 if((*iter)->synfigapp::Instance::is_modified())
1813 handle<synfigapp::UIInterface> uim;
1814 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1816 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() );
1817 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1819 case synfigapp::UIInterface::RESPONSE_NO:
1821 case synfigapp::UIInterface::RESPONSE_YES:
1822 (*iter)->dialog_cvs_commit();
1824 case synfigapp::UIInterface::RESPONSE_CANCEL:
1833 // This next line causes things to crash for some reason
1837 shutdown_in_progress=true;
1839 instance_list.clear();
1841 while(studio::App::events_pending())studio::App::iteration(false);
1844 auto_recover->normal_shutdown();
1846 get_ui_interface()->task(_("Quit Request sent"));
1852 dialog_setup->refresh();
1853 dialog_setup->show();
1856 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1857 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1860 //#define USE_WIN32_FILE_DIALOGS 1
1863 #ifdef USE_WIN32_FILE_DIALOGS
1864 static OPENFILENAME ofn={};
1868 #include <gdk/gdkwin32.h>
1872 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1874 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1876 #ifdef USE_WIN32_FILE_DIALOGS
1877 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1879 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1880 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1881 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1883 ofn.lStructSize=sizeof(OPENFILENAME);
1884 ofn.hwndOwner = hWnd;
1885 ofn.hInstance = hInstance;
1886 ofn.lpstrFilter = szFilter;
1887 // ofn.lpstrCustomFilter=NULL;
1888 // ofn.nMaxCustFilter=0;
1889 // ofn.nFilterIndex=0;
1890 // ofn.lpstrFile=NULL;
1891 ofn.nMaxFile=MAX_PATH;
1892 // ofn.lpstrFileTitle=NULL;
1893 // ofn.lpstrInitialDir=NULL;
1894 // ofn.lpstrTitle=NULL;
1895 ofn.Flags=OFN_HIDEREADONLY;
1896 // ofn.nFileOffset=0;
1897 // ofn.nFileExtension=0;
1898 ofn.lpstrDefExt=TEXT("sif");
1899 // ofn.lCustData = 0l;
1901 // ofn.lpTemplateName=NULL;
1903 CHAR szFilename[MAX_PATH];
1905 strcpy(szFilename,filename.c_str());
1906 strcpy(szTitle,title.c_str());
1908 ofn.lpstrFile=szFilename;
1909 ofn.lpstrFileTitle=szTitle;
1911 if(GetOpenFileName(&ofn))
1913 filename=szFilename;
1918 #else // not USE_WIN32_FILE_DIALOGS
1919 synfig::String prev_path;
1921 if(!_preferences.get_value(preference, prev_path))
1924 prev_path = absolute_path(prev_path);
1926 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1928 dialog->set_current_folder(prev_path);
1929 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1930 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1932 if (filename.empty())
1933 dialog->set_filename(prev_path);
1934 else if (is_absolute_path(filename))
1935 dialog->set_filename(filename);
1937 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1939 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1940 filename = dialog->get_filename();
1941 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1942 _preferences.set_value(preference, dirname(filename));
1949 #endif // not USE_WIN32_FILE_DIALOGS
1953 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1955 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1957 #if USE_WIN32_FILE_DIALOGS
1958 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1960 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1961 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1962 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1964 ofn.lStructSize=sizeof(OPENFILENAME);
1965 ofn.hwndOwner = hWnd;
1966 ofn.hInstance = hInstance;
1967 ofn.lpstrFilter = szFilter;
1968 // ofn.lpstrCustomFilter=NULL;
1969 // ofn.nMaxCustFilter=0;
1970 // ofn.nFilterIndex=0;
1971 // ofn.lpstrFile=NULL;
1972 ofn.nMaxFile=MAX_PATH;
1973 // ofn.lpstrFileTitle=NULL;
1974 // ofn.lpstrInitialDir=NULL;
1975 // ofn.lpstrTitle=NULL;
1976 ofn.Flags=OFN_OVERWRITEPROMPT;
1977 // ofn.nFileOffset=0;
1978 // ofn.nFileExtension=0;
1979 ofn.lpstrDefExt=TEXT("sif");
1980 // ofn.lCustData = 0l;
1982 // ofn.lpTemplateName=NULL;
1984 CHAR szFilename[MAX_PATH];
1986 strcpy(szFilename,filename.c_str());
1987 strcpy(szTitle,title.c_str());
1989 ofn.lpstrFile=szFilename;
1990 ofn.lpstrFileTitle=szTitle;
1992 if(GetSaveFileName(&ofn))
1994 filename=szFilename;
1995 _preferences.set_value(preference,dirname(filename));
2000 synfig::String prev_path;
2002 if(!_preferences.get_value(preference, prev_path))
2005 prev_path = absolute_path(prev_path);
2007 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2009 dialog->set_current_folder(prev_path);
2010 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2011 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2013 Widget_Enum *file_type_enum = 0;
2014 if (preference == ANIMATION_DIR_PREFERENCE)
2016 file_type_enum = manage(new Widget_Enum());
2017 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2018 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", strprintf("0.62.00 (%s)", _("current")))
2019 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2020 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2021 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2022 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2023 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2025 Gtk::HBox *hbox = manage(new Gtk::HBox);
2026 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2027 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2030 dialog->set_extra_widget(*hbox);
2033 if (filename.empty())
2034 dialog->set_filename(prev_path);
2037 std::string full_path;
2038 if (is_absolute_path(filename))
2039 full_path = filename;
2041 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2043 // select the file if it exists
2044 dialog->set_filename(full_path);
2046 // if the file doesn't exist, put its name into the filename box
2048 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2049 dialog->set_current_name(basename(filename));
2052 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2053 if (preference == ANIMATION_DIR_PREFERENCE)
2054 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2055 filename = dialog->get_filename();
2056 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2057 _preferences.set_value(preference, dirname(filename));
2068 App::dialog_error_blocking(const std::string &title, const std::string &message)
2070 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2071 dialog.set_title(title);
2077 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2079 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2080 dialog.set_title(title);
2086 App::dialog_yes_no(const std::string &title, const std::string &message)
2091 true // use_separator
2093 Gtk::Label label(message);
2096 dialog.get_vbox()->pack_start(label);
2097 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2098 dialog.add_button(Gtk::StockID("gtk-no"),0);
2100 return dialog.run();
2104 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2109 true // use_separator
2111 Gtk::Label label(message);
2114 dialog.get_vbox()->pack_start(label);
2115 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2116 dialog.add_button(Gtk::StockID("gtk-no"),0);
2117 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2119 return dialog.run();
2123 App::dialog_not_implemented()
2125 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2126 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2131 try_open_url(const std::string &url)
2134 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2136 std::vector<std::string> command_line;
2137 std::vector<std::string> browsers;
2138 browsers.reserve(23);
2140 // Browser wrapper scripts
2141 #ifdef USE_OPEN_FOR_URLS
2142 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2144 browsers.push_back("xdg-open"); // XDG wrapper
2145 browsers.push_back("sensible-browser"); // Debian wrapper
2146 browsers.push_back("gnome-open"); // GNOME wrapper
2147 browsers.push_back("kfmclient"); // KDE wrapper
2148 browsers.push_back("exo-open"); // XFCE wrapper
2150 // Alternatives system
2151 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2152 browsers.push_back("x-www-browser"); // Debian GUI alternative
2154 // Individual browsers
2155 browsers.push_back("firefox");
2156 browsers.push_back("epiphany-browser");
2157 browsers.push_back("epiphany");
2158 browsers.push_back("konqueror");
2159 browsers.push_back("iceweasel");
2160 browsers.push_back("mozilla");
2161 browsers.push_back("netscape");
2162 browsers.push_back("icecat");
2163 browsers.push_back("galeon");
2164 browsers.push_back("midori");
2165 browsers.push_back("safari");
2166 browsers.push_back("opera");
2167 browsers.push_back("amaya");
2168 browsers.push_back("netsurf");
2169 browsers.push_back("dillo");
2171 // Try the user-specified browser first
2172 command_line.push_back(App::browser_command);
2173 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2174 command_line.push_back(url);
2176 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2177 catch( Glib::SpawnError& exception ){
2179 while ( !browsers.empty() )
2181 // Skip the browser if we already tried it
2182 if( browsers[0] == App::browser_command )
2185 // Construct the command line
2186 command_line.clear();
2187 command_line.push_back(browsers[0]);
2188 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2189 command_line.push_back(url);
2191 // Remove the browser from the list
2192 browsers.erase(browsers.begin());
2194 // Try to spawn the browser
2195 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2196 // Failed, move on to the next one
2197 catch(Glib::SpawnError& exception){ continue; }
2198 return true; // No exception means we succeeded!
2209 if (!try_open_url("http://synfig.org/Documentation"))
2211 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2212 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2213 dialog.set_title(_("Help"));
2219 App::open_url(const std::string &url)
2221 if(!try_open_url(url))
2223 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2224 dialog.set_secondary_text(url);
2225 dialog.set_title(_("No browser found"));
2231 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2236 true); // use_separator
2238 Gtk::Label label(message);
2240 dialog.get_vbox()->pack_start(label);
2243 entry.set_text(text);
2245 entry.set_activates_default(true);
2247 dialog.get_vbox()->pack_start(entry);
2249 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2250 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2251 dialog.set_default_response(Gtk::RESPONSE_OK);
2253 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2256 if(dialog.run()!=Gtk::RESPONSE_OK)
2259 text=entry.get_text();
2265 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2270 true); // use_separator
2272 Gtk::Label label(message);
2274 dialog.get_vbox()->pack_start(label);
2276 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2277 text_buffer->set_text(text);
2278 Gtk::TextView text_view(text_buffer);
2281 dialog.get_vbox()->pack_start(text_view);
2283 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2284 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2285 dialog.set_default_response(Gtk::RESPONSE_OK);
2287 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2290 if(dialog.run()!=Gtk::RESPONSE_OK)
2293 text=text_buffer->get_text();
2299 App::open(std::string filename)
2301 return open_as(filename,filename);
2304 // this is called from autorecover.cpp:
2305 // App::open_as(get_shadow_file_name(filename),filename)
2306 // other than that, 'filename' and 'as' are the same
2308 App::open_as(std::string filename,std::string as)
2311 char long_name[1024];
2312 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2313 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2314 // don't use it if that's the case
2315 if (long_name[0] != '\0')
2321 OneMoment one_moment;
2322 String errors, warnings;
2324 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2325 if(canvas && get_instance(canvas))
2327 get_instance(canvas)->find_canvas_view(canvas)->present();
2328 info("%s is already open", filename.c_str());
2329 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2334 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2337 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2339 if (as.find(custom_filename_prefix.c_str()) != 0)
2340 add_recent_file(as);
2342 handle<Instance> instance(Instance::create(canvas));
2345 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2347 set_recent_file_window_size(instance);
2351 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)")))
2352 instance->dialog_cvs_update();
2357 dialog_error_blocking(_("Error"), x);
2360 catch(runtime_error x)
2362 dialog_error_blocking(_("Error"), x.what());
2367 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2378 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2380 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2381 canvas->set_name(file_name);
2382 file_name += ".sifz";
2384 canvas->rend_desc().set_frame_rate(preferred_fps);
2385 canvas->rend_desc().set_time_start(0.0);
2386 canvas->rend_desc().set_time_end(5.0);
2387 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2388 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2389 // The top left and botton right positions are expressed in units
2390 // Original convention is that 1 unit = 60 pixels
2391 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2392 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2393 canvas->rend_desc().set_w(preferred_x_size);
2394 canvas->rend_desc().set_h(preferred_y_size);
2395 canvas->rend_desc().set_antialias(1);
2396 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2397 canvas->set_file_name(file_name);
2399 handle<Instance> instance = Instance::create(canvas);
2401 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2402 instance->find_canvas_view(canvas)->canvas_properties.present();
2406 App::dialog_open(string filename)
2408 if (filename.empty())
2411 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2413 // If the filename still has wildcards, then we should
2414 // continue looking for the file we want
2415 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2421 get_ui_interface()->error(_("Unable to open file"));
2426 App::set_selected_instance(etl::loose_handle<Instance> instance)
2428 /* if(get_selected_instance()==instance)
2430 selected_instance=instance;
2431 signal_instance_selected()(instance);
2437 selected_instance=instance;
2438 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2442 instance->focus(instance->get_canvas());
2445 set_selected_canvas_view(0);
2447 signal_instance_selected()(instance);
2451 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2453 selected_canvas_view=canvas_view;
2454 signal_canvas_view_focus()(selected_canvas_view);
2457 selected_instance=canvas_view->get_instance();
2458 signal_instance_selected()(canvas_view->get_instance());
2461 if(get_selected_canvas_view()==canvas_view)
2463 signal_canvas_view_focus()(selected_canvas_view);
2464 signal_instance_selected()(canvas_view->get_instance());
2467 selected_canvas_view=canvas_view;
2468 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2469 set_selected_instance(canvas_view->get_instance());
2470 signal_canvas_view_focus()(selected_canvas_view);
2474 etl::loose_handle<Instance>
2475 App::get_instance(etl::handle<synfig::Canvas> canvas)
2477 if(!canvas) return 0;
2478 canvas=canvas->get_root();
2480 std::list<etl::handle<Instance> >::iterator iter;
2481 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2483 if((*iter)->get_canvas()==canvas)
2499 if(selected_instance)
2500 selected_instance->undo();
2506 if(selected_instance)
2507 selected_instance->redo();
2511 studio::App::get_base_path()
2513 return app_base_path_;