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/en/current-release"
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);
1271 state_manager->add_state(&state_circle);
1272 state_manager->add_state(&state_rectangle);
1273 state_manager->add_state(&state_star);
1274 state_manager->add_state(&state_gradient);
1275 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
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.
1280 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1281 state_manager->add_state(&state_fill);
1282 state_manager->add_state(&state_eyedrop);
1285 state_manager->add_state(&state_text);
1286 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1287 state_manager->add_state(&state_zoom);
1289 studio_init_cb.task(_("Init ModPalette..."));
1290 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1292 studio_init_cb.task(_("Init Setup Dialog..."));
1293 dialog_setup=new studio::Dialog_Setup();
1295 studio_init_cb.task(_("Init Input Dialog..."));
1296 dialog_input=new Gtk::InputDialog();
1297 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1298 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1300 studio_init_cb.task(_("Init auto recovery..."));
1301 auto_recover=new AutoRecover();
1303 studio_init_cb.amount_complete(9250,10000);
1304 studio_init_cb.task(_("Loading Settings..."));
1306 device_tracker->load_preferences();
1308 studio_init_cb.task(_("Checking auto-recover..."));
1310 studio_init_cb.amount_complete(9900,10000);
1312 bool opened_any = false;
1313 if(auto_recover->recovery_needed())
1315 splash_screen.hide();
1316 if (get_ui_interface()->confirmation("Crash Recovery",
1317 _("Auto recovery file found"),
1318 _("Synfig Studio seems to have crashed\n"
1319 "before you could save all your files.\n"
1320 "Recover unsaved changes?"),
1321 _("Recover"), _("Ignore"))
1322 == synfigapp::UIInterface::RESPONSE_OK)
1324 int number_recovered;
1325 if(!auto_recover->recover(number_recovered))
1326 if (number_recovered)
1327 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1329 get_ui_interface()->error(_("Unable to recover from previous crash"));
1331 get_ui_interface()->error(
1332 _("Synfig Studio has attempted to recover\n"
1333 "from a previous crash. The files that it has\n"
1334 "recovered are NOT YET SAVED. It would be a good\n"
1335 "idea to review them and save them now."));
1337 if (number_recovered)
1340 splash_screen.show();
1343 // Look for any files given on the command line,
1344 // and load them if found.
1345 for(;*argc>=1;(*argc)--)
1346 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1348 studio_init_cb.task(_("Loading files..."));
1349 splash_screen.hide();
1350 open((*argv)[*argc]);
1352 splash_screen.show();
1355 // if no file was specified to be opened, create a new document to help new users get started more easily
1356 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1359 studio_init_cb.task(_("Done."));
1360 studio_init_cb.amount_complete(10000,10000);
1362 // To avoid problems with some window managers and gtk >= 2.18
1363 // we should show dock dialogs after the settings load.
1364 // If dock dialogs are shown before the settings are loaded,
1365 // the windows manager can act over it.
1366 // See discussions here:
1367 // * http://synfig.org/forums/viewtopic.php?f=1&t=1131&st=0&sk=t&sd=a&start=30
1368 // * http://synfig.org/forums/viewtopic.php?f=15&t=1062
1369 dock_manager->show_all_dock_dialogs();
1375 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1379 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1383 StateManager* App::get_state_manager() { return state_manager; }
1387 shutdown_in_progress=true;
1391 synfigapp::Main::settings().remove_domain("pref");
1393 selected_instance=0;
1395 // Unload all of the modules
1396 for(;!module_list_.empty();module_list_.pop_back())
1399 delete state_manager;
1403 delete auto_recover;
1411 delete dialog_setup;
1413 delete dialog_gradient;
1415 delete dialog_color;
1417 delete dialog_input;
1419 delete dock_manager;
1421 instance_list.clear();
1425 App::get_user_app_directory()
1427 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1429 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1431 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1436 App::get_config_file(const synfig::String& file)
1438 return Glib::build_filename(get_user_app_directory(),file);
1441 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1443 App::set_recent_file_window_size(etl::handle<Instance> instance)
1446 const std::string &canvas_window_size = *recent_files_window_size.begin();
1448 if(canvas_window_size.empty())
1451 synfig::String::size_type current=0;
1452 bool seen_root(false), shown_non_root(false);
1454 while(current != synfig::String::npos)
1456 // find end of first field (canvas) or return
1457 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1458 if(separator == synfig::String::npos) break;
1461 synfig::Canvas::Handle canvas;
1464 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1466 catch(Exception::IDNotFound) {
1467 // can't find the canvas; skip to the next canvas or return
1468 separator = canvas_window_size.find_first_of('\t', current);
1469 if(separator == synfig::String::npos) return;
1470 current = separator+1;
1474 if (canvas->is_root())
1477 shown_non_root = true;
1479 // check that we have the tab character the ends this canvas' data or return
1480 current = separator+1;
1481 separator = canvas_window_size.find_first_of('\t', current);
1482 if(separator == synfig::String::npos) return;
1485 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1487 current = separator+1;
1490 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1491 canvasview->move(x,y);
1492 canvasview->resize(w,h);
1493 canvasview->present();
1495 current = separator+1;
1498 if (shown_non_root && !seen_root)
1499 instance->find_canvas_view(instance->get_canvas())->hide();
1503 App::add_recent_file(const etl::handle<Instance> instance)
1506 std::string canvas_window_size;
1508 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1509 Instance::CanvasViewList::const_iterator iter;
1511 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1513 if( !((*iter)->is_visible()) )
1516 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1517 int x_pos, y_pos, x_size, y_size;
1518 (*iter)->get_position(x_pos,y_pos);
1519 (*iter)->get_size(x_size,y_size);
1521 canvas_window_size += strprintf("%s %d %d %d %d\t",
1522 canvas->get_relative_id(canvas->get_root()).c_str(),
1527 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1531 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1533 std::string filename(file_name);
1535 assert(!filename.empty());
1537 if(filename.empty())
1540 // Toss out any "hidden" files
1541 if(basename(filename)[0]=='.')
1544 // If we aren't an absolute path, turn ourselves into one
1545 if(!is_absolute_path(filename))
1546 filename=absolute_path(filename);
1548 std::string old_window_size;
1550 list<string>::iterator iter;
1551 list<string>::iterator iter_wsize;
1552 // Check to see if the file is already on the list.
1553 // If it is, then remove it from the list
1554 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1557 recent_files.erase(iter);
1558 old_window_size = *iter_wsize;
1559 recent_files_window_size.erase(iter_wsize);
1564 // Push the filename to the front of the list
1565 recent_files.push_front(filename);
1566 if(window_size.empty())
1567 recent_files_window_size.push_front(old_window_size);
1569 recent_files_window_size.push_front(window_size);
1571 // Clean out the files at the end of the list.
1572 while(recent_files.size()>(unsigned)get_max_recent_files())
1574 recent_files.pop_back();
1575 recent_files_window_size.pop_back();
1578 signal_recent_files_changed_();
1583 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1586 App::get_time_format()
1588 return _App_time_format;
1592 App::set_time_format(synfig::Time::Format x)
1599 App::save_settings()
1604 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1605 setlocale(LC_NUMERIC, "C");
1607 std::string filename=get_config_file("accelrc");
1608 Gtk::AccelMap::save(filename);
1611 std::string filename=get_config_file("recentfiles");
1613 std::ofstream file(filename.c_str());
1617 synfig::warning("Unable to save %s",filename.c_str());
1621 list<string>::reverse_iterator iter;
1623 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1627 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
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_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1643 std::string filename=get_config_file("settings");
1644 synfigapp::Main::settings().save_to_file(filename);
1645 setlocale(LC_NUMERIC,old_locale);
1649 synfig::warning("Caught exception when attempting to save settings.");
1654 App::load_settings()
1659 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1660 setlocale(LC_NUMERIC, "C");
1662 std::string filename=get_config_file("accelrc");
1663 Gtk::AccelMap::load(filename);
1666 bool window_size_broken = false;
1668 std::string filename=get_config_file("recentfiles");
1669 std::string filename_window_size=filename+std::string("_window_size");
1671 std::ifstream file(filename.c_str());
1672 std::ifstream file_window_size(filename_window_size.c_str());
1674 if(!file_window_size)
1675 window_size_broken = true;
1679 std::string recent_file;
1680 std::string recent_file_window_size;
1681 getline(file,recent_file);
1682 if(!window_size_broken)
1683 getline(file_window_size,recent_file_window_size);
1684 if(!recent_file.empty())
1686 if(!window_size_broken && !file_window_size)
1687 window_size_broken = true;
1688 if (std::ifstream(recent_file.c_str()))
1690 if(!window_size_broken)
1691 add_recent_file(recent_file,recent_file_window_size);
1693 add_recent_file(recent_file);
1697 if(!window_size_broken && file_window_size)
1698 window_size_broken = true;
1700 if(window_size_broken)
1702 recent_files_window_size.clear();
1703 recent_files_window_size.resize(recent_files.size());
1706 std::string filename=get_config_file("settings");
1707 if(!synfigapp::Main::settings().load_from_file(filename))
1709 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1710 //if(!synfigapp::Main::settings().load_from_file(filename))
1712 gamma.set_gamma(1.0/2.2);
1713 reset_initial_window_configuration();
1716 setlocale(LC_NUMERIC,old_locale);
1720 synfig::warning("Caught exception when attempting to load settings.");
1725 App::reset_initial_window_configuration()
1727 Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
1728 Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
1729 Gdk::Rectangle rect;
1730 // A proper way to obtain the primary monitor is to use the
1731 // Gdk::Screen::get_primary_monitor () const member. But as it
1732 // was introduced in gtkmm 2.20 I assume that the monitor 0 is the
1734 screen->get_monitor_geometry(0,rect);
1735 #define hpanel_width 79.0f
1736 #define hpanel_height 25.0f
1737 #define vpanel_width 20.0f
1738 #define vpanel_height 100.0f
1742 /* percentages referred to width or height of the screen
1743 *---------------------------------------------------------------------*
1758 *-----hdock%----------------------------------------------|------------
1763 * --------------------------------------------------------------------*
1766 int v_xpos=rect.get_x() + rect.get_width()*(1.0-vpanel_width/100.0);
1767 int v_xsize=rect.get_width()*vpanel_width/100.0;
1768 int v_ypos=rect.get_y();
1769 int v_ysize=rect.get_height()*vpanel_height/100.0;
1770 std::string v_pos(strprintf("%d %d", v_xpos, v_ypos));
1771 std::string v_size(strprintf("%d %d", v_xsize, v_ysize));
1773 int h_xpos=rect.get_x();
1774 int h_xsize=rect.get_width()*hpanel_width/100.0;
1775 int h_ypos=rect.get_y()+ rect.get_height()*(1.0-hpanel_height/100.0);;
1776 int h_ysize=rect.get_height()*hpanel_height/100.0;
1777 std::string h_pos(strprintf("%d %d", h_xpos, h_ypos));
1778 std::string h_size(strprintf("%d %d", h_xsize, h_ysize));
1779 int v_dock1 = rect.get_height()*vdock*0.8/100.0;
1780 int v_dock2 = rect.get_height()*vdock*0.6/100.0;
1781 int v_dock3 = rect.get_height()*vdock*1.1/100.0;
1782 int h_dock = rect.get_width()*hdock/100.0;
1784 std::string v_contents(strprintf("%d %d %d", v_dock1, v_dock2, v_dock3));
1785 std::string h_contents(strprintf("%d", h_dock));
1786 // Tool Box position
1787 std::string tbox_pos(strprintf("%d %d", rect.get_x(), rect.get_y()));
1789 synfig::info("tool box pos: %s", tbox_pos.c_str());
1790 synfig::info("v_contents sizes: %s", v_contents.c_str());
1791 synfig::info("v_pos: %s", v_pos.c_str());
1792 synfig::info("v_sizes: %s", v_size.c_str());
1793 synfig::info("h_contents sizes: %s", h_contents.c_str());
1794 synfig::info("h_pos: %s", h_pos.c_str());
1795 synfig::info("h_sizes: %s", h_size.c_str());
1797 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1798 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1799 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size",v_contents);
1800 synfigapp::Main::settings().set_value("dock.dialog.1.size",v_size);
1801 synfigapp::Main::settings().set_value("dock.dialog.1.pos",v_pos);
1802 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1803 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1804 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size",h_contents);
1805 synfigapp::Main::settings().set_value("dock.dialog.2.size",h_size);
1806 synfigapp::Main::settings().set_value("dock.dialog.2.pos",h_pos);
1807 synfigapp::Main::settings().set_value("window.toolbox.pos",tbox_pos);
1809 dock_manager->show_all_dock_dialogs();
1813 App::reset_initial_preferences()
1815 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1816 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1817 #ifdef SINGLE_THREADED
1818 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1820 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1821 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1822 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1823 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1824 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1825 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1826 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1827 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1832 App::shutdown_request(GdkEventAny*)
1836 //return !shutdown_in_progress;
1842 if(shutdown_in_progress)return;
1845 get_ui_interface()->task(_("Quit Request"));
1848 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1852 std::list<etl::handle<Instance> >::iterator iter;
1853 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1855 if(!(*iter)->safe_close())
1859 if((*iter)->synfigapp::Instance::get_action_count())
1861 handle<synfigapp::UIInterface> uim;
1862 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1864 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1865 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1867 case synfigapp::UIInterface::RESPONSE_NO:
1869 case synfigapp::UIInterface::RESPONSE_YES:
1872 case synfigapp::UIInterface::RESPONSE_CANCEL:
1881 if((*iter)->synfigapp::Instance::is_modified())
1883 handle<synfigapp::UIInterface> uim;
1884 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1886 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() );
1887 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1889 case synfigapp::UIInterface::RESPONSE_NO:
1891 case synfigapp::UIInterface::RESPONSE_YES:
1892 (*iter)->dialog_cvs_commit();
1894 case synfigapp::UIInterface::RESPONSE_CANCEL:
1903 // This next line causes things to crash for some reason
1907 shutdown_in_progress=true;
1909 instance_list.clear();
1911 while(studio::App::events_pending())studio::App::iteration(false);
1914 auto_recover->normal_shutdown();
1916 get_ui_interface()->task(_("Quit Request sent"));
1922 dialog_setup->refresh();
1923 dialog_setup->show();
1926 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1927 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1930 //#define USE_WIN32_FILE_DIALOGS 1
1933 #ifdef USE_WIN32_FILE_DIALOGS
1934 static OPENFILENAME ofn={};
1938 #include <gdk/gdkwin32.h>
1942 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1944 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1946 #ifdef USE_WIN32_FILE_DIALOGS
1947 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1949 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1950 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1951 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1953 ofn.lStructSize=sizeof(OPENFILENAME);
1954 ofn.hwndOwner = hWnd;
1955 ofn.hInstance = hInstance;
1956 ofn.lpstrFilter = szFilter;
1957 // ofn.lpstrCustomFilter=NULL;
1958 // ofn.nMaxCustFilter=0;
1959 // ofn.nFilterIndex=0;
1960 // ofn.lpstrFile=NULL;
1961 ofn.nMaxFile=MAX_PATH;
1962 // ofn.lpstrFileTitle=NULL;
1963 // ofn.lpstrInitialDir=NULL;
1964 // ofn.lpstrTitle=NULL;
1965 ofn.Flags=OFN_HIDEREADONLY;
1966 // ofn.nFileOffset=0;
1967 // ofn.nFileExtension=0;
1968 ofn.lpstrDefExt=TEXT("sif");
1969 // ofn.lCustData = 0l;
1971 // ofn.lpTemplateName=NULL;
1973 CHAR szFilename[MAX_PATH];
1975 strcpy(szFilename,filename.c_str());
1976 strcpy(szTitle,title.c_str());
1978 ofn.lpstrFile=szFilename;
1979 ofn.lpstrFileTitle=szTitle;
1981 if(GetOpenFileName(&ofn))
1983 filename=szFilename;
1988 #else // not USE_WIN32_FILE_DIALOGS
1989 synfig::String prev_path;
1991 if(!_preferences.get_value(preference, prev_path))
1994 prev_path = absolute_path(prev_path);
1996 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1998 dialog->set_current_folder(prev_path);
1999 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2000 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
2002 if (filename.empty())
2003 dialog->set_filename(prev_path);
2004 else if (is_absolute_path(filename))
2005 dialog->set_filename(filename);
2007 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2009 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2010 filename = dialog->get_filename();
2011 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
2012 _preferences.set_value(preference, dirname(filename));
2019 #endif // not USE_WIN32_FILE_DIALOGS
2023 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2025 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2027 #if USE_WIN32_FILE_DIALOGS
2028 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2030 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2031 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2032 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2034 ofn.lStructSize=sizeof(OPENFILENAME);
2035 ofn.hwndOwner = hWnd;
2036 ofn.hInstance = hInstance;
2037 ofn.lpstrFilter = szFilter;
2038 // ofn.lpstrCustomFilter=NULL;
2039 // ofn.nMaxCustFilter=0;
2040 // ofn.nFilterIndex=0;
2041 // ofn.lpstrFile=NULL;
2042 ofn.nMaxFile=MAX_PATH;
2043 // ofn.lpstrFileTitle=NULL;
2044 // ofn.lpstrInitialDir=NULL;
2045 // ofn.lpstrTitle=NULL;
2046 ofn.Flags=OFN_OVERWRITEPROMPT;
2047 // ofn.nFileOffset=0;
2048 // ofn.nFileExtension=0;
2049 ofn.lpstrDefExt=TEXT("sif");
2050 // ofn.lCustData = 0l;
2052 // ofn.lpTemplateName=NULL;
2054 CHAR szFilename[MAX_PATH];
2056 strcpy(szFilename,filename.c_str());
2057 strcpy(szTitle,title.c_str());
2059 ofn.lpstrFile=szFilename;
2060 ofn.lpstrFileTitle=szTitle;
2062 if(GetSaveFileName(&ofn))
2064 filename=szFilename;
2065 _preferences.set_value(preference,dirname(filename));
2070 synfig::String prev_path;
2072 if(!_preferences.get_value(preference, prev_path))
2075 prev_path = absolute_path(prev_path);
2077 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2079 dialog->set_current_folder(prev_path);
2080 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2081 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2083 Widget_Enum *file_type_enum = 0;
2084 if (preference == ANIMATION_DIR_PREFERENCE)
2086 file_type_enum = manage(new Widget_Enum());
2087 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2088 .add_enum_value(synfig::RELEASE_VERSION_0_62_01, "0.62.01", strprintf("0.62.01 (%s)", _("current")))
2089 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", "0.61.00")
2090 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2091 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2092 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2093 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2094 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2096 Gtk::HBox *hbox = manage(new Gtk::HBox);
2097 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2098 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2101 dialog->set_extra_widget(*hbox);
2104 if (filename.empty())
2105 dialog->set_filename(prev_path);
2108 std::string full_path;
2109 if (is_absolute_path(filename))
2110 full_path = filename;
2112 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2114 // select the file if it exists
2115 dialog->set_filename(full_path);
2117 // if the file doesn't exist, put its name into the filename box
2119 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2120 dialog->set_current_name(basename(filename));
2123 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2124 if (preference == ANIMATION_DIR_PREFERENCE)
2125 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2126 filename = dialog->get_filename();
2127 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2128 _preferences.set_value(preference, dirname(filename));
2139 App::dialog_error_blocking(const std::string &title, const std::string &message)
2141 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2142 dialog.set_title(title);
2148 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2150 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2151 dialog.set_title(title);
2157 App::dialog_yes_no(const std::string &title, const std::string &message)
2162 true // use_separator
2164 Gtk::Label label(message);
2167 dialog.get_vbox()->pack_start(label);
2168 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2169 dialog.add_button(Gtk::StockID("gtk-no"),0);
2171 return dialog.run();
2175 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2180 true // use_separator
2182 Gtk::Label label(message);
2185 dialog.get_vbox()->pack_start(label);
2186 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2187 dialog.add_button(Gtk::StockID("gtk-no"),0);
2188 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2190 return dialog.run();
2194 App::dialog_not_implemented()
2196 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2197 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2202 try_open_url(const std::string &url)
2205 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2207 std::vector<std::string> command_line;
2208 std::vector<std::string> browsers;
2209 browsers.reserve(23);
2211 // Browser wrapper scripts
2212 #ifdef USE_OPEN_FOR_URLS
2213 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2215 browsers.push_back("xdg-open"); // XDG wrapper
2216 browsers.push_back("sensible-browser"); // Debian wrapper
2217 browsers.push_back("gnome-open"); // GNOME wrapper
2218 browsers.push_back("kfmclient"); // KDE wrapper
2219 browsers.push_back("exo-open"); // XFCE wrapper
2221 // Alternatives system
2222 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2223 browsers.push_back("x-www-browser"); // Debian GUI alternative
2225 // Individual browsers
2226 browsers.push_back("firefox");
2227 browsers.push_back("epiphany-browser");
2228 browsers.push_back("epiphany");
2229 browsers.push_back("konqueror");
2230 browsers.push_back("iceweasel");
2231 browsers.push_back("mozilla");
2232 browsers.push_back("netscape");
2233 browsers.push_back("icecat");
2234 browsers.push_back("galeon");
2235 browsers.push_back("midori");
2236 browsers.push_back("safari");
2237 browsers.push_back("opera");
2238 browsers.push_back("amaya");
2239 browsers.push_back("netsurf");
2240 browsers.push_back("dillo");
2242 // Try the user-specified browser first
2243 command_line.push_back(App::browser_command);
2244 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2245 command_line.push_back(url);
2247 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2248 catch( Glib::SpawnError& exception ){
2250 while ( !browsers.empty() )
2252 // Skip the browser if we already tried it
2253 if( browsers[0] == App::browser_command )
2256 // Construct the command line
2257 command_line.clear();
2258 command_line.push_back(browsers[0]);
2259 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2260 command_line.push_back(url);
2262 // Remove the browser from the list
2263 browsers.erase(browsers.begin());
2265 // Try to spawn the browser
2266 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2267 // Failed, move on to the next one
2268 catch(Glib::SpawnError& exception){ continue; }
2269 return true; // No exception means we succeeded!
2280 if (!try_open_url("http://synfig.org/wiki/Category:Manual"))
2282 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2283 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://synfig.org/wiki/Category:Manual"));
2284 dialog.set_title(_("Help"));
2290 App::open_url(const std::string &url)
2292 if(!try_open_url(url))
2294 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2295 dialog.set_secondary_text(url);
2296 dialog.set_title(_("No browser found"));
2302 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2307 true); // use_separator
2309 Gtk::Label label(message);
2311 dialog.get_vbox()->pack_start(label);
2314 entry.set_text(text);
2316 entry.set_activates_default(true);
2318 dialog.get_vbox()->pack_start(entry);
2320 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2321 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2322 dialog.set_default_response(Gtk::RESPONSE_OK);
2324 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2327 if(dialog.run()!=Gtk::RESPONSE_OK)
2330 text=entry.get_text();
2336 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2341 true); // use_separator
2343 Gtk::Label label(message);
2345 dialog.get_vbox()->pack_start(label);
2347 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2348 text_buffer->set_text(text);
2349 Gtk::TextView text_view(text_buffer);
2352 dialog.get_vbox()->pack_start(text_view);
2354 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2355 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2356 dialog.set_default_response(Gtk::RESPONSE_OK);
2358 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2361 if(dialog.run()!=Gtk::RESPONSE_OK)
2364 text=text_buffer->get_text();
2370 App::open(std::string filename)
2372 return open_as(filename,filename);
2375 // this is called from autorecover.cpp:
2376 // App::open_as(get_shadow_file_name(filename),filename)
2377 // other than that, 'filename' and 'as' are the same
2379 App::open_as(std::string filename,std::string as)
2382 char long_name[1024];
2383 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2384 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2385 // don't use it if that's the case
2386 if (long_name[0] != '\0')
2392 OneMoment one_moment;
2393 String errors, warnings;
2395 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2396 if(canvas && get_instance(canvas))
2398 get_instance(canvas)->find_canvas_view(canvas)->present();
2399 info("%s is already open", filename.c_str());
2400 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2405 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2408 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2410 if (as.find(custom_filename_prefix.c_str()) != 0)
2411 add_recent_file(as);
2413 handle<Instance> instance(Instance::create(canvas));
2416 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2418 set_recent_file_window_size(instance);
2422 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)")))
2423 instance->dialog_cvs_update();
2428 dialog_error_blocking(_("Error"), x);
2431 catch(runtime_error x)
2433 dialog_error_blocking(_("Error"), x.what());
2438 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2449 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2451 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2452 canvas->set_name(file_name);
2453 file_name += ".sifz";
2455 canvas->rend_desc().set_frame_rate(preferred_fps);
2456 canvas->rend_desc().set_time_start(0.0);
2457 canvas->rend_desc().set_time_end(5.0);
2458 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2459 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2460 // The top left and botton right positions are expressed in units
2461 // Original convention is that 1 unit = 60 pixels
2462 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2463 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2464 canvas->rend_desc().set_w(preferred_x_size);
2465 canvas->rend_desc().set_h(preferred_y_size);
2466 canvas->rend_desc().set_antialias(1);
2467 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2468 canvas->set_file_name(file_name);
2470 handle<Instance> instance = Instance::create(canvas);
2472 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2473 instance->find_canvas_view(canvas)->canvas_properties.present();
2477 App::dialog_open(string filename)
2479 if (filename.empty())
2482 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2484 // If the filename still has wildcards, then we should
2485 // continue looking for the file we want
2486 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2492 get_ui_interface()->error(_("Unable to open file"));
2497 App::set_selected_instance(etl::loose_handle<Instance> instance)
2499 /* if(get_selected_instance()==instance)
2501 selected_instance=instance;
2502 signal_instance_selected()(instance);
2508 selected_instance=instance;
2509 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2513 instance->focus(instance->get_canvas());
2516 set_selected_canvas_view(0);
2518 signal_instance_selected()(instance);
2522 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2524 selected_canvas_view=canvas_view;
2525 signal_canvas_view_focus()(selected_canvas_view);
2528 selected_instance=canvas_view->get_instance();
2529 signal_instance_selected()(canvas_view->get_instance());
2532 if(get_selected_canvas_view()==canvas_view)
2534 signal_canvas_view_focus()(selected_canvas_view);
2535 signal_instance_selected()(canvas_view->get_instance());
2538 selected_canvas_view=canvas_view;
2539 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2540 set_selected_instance(canvas_view->get_instance());
2541 signal_canvas_view_focus()(selected_canvas_view);
2545 etl::loose_handle<Instance>
2546 App::get_instance(etl::handle<synfig::Canvas> canvas)
2548 if(!canvas) return 0;
2549 canvas=canvas->get_root();
2551 std::list<etl::handle<Instance> >::iterator iter;
2552 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2554 if((*iter)->get_canvas()==canvas)
2570 if(selected_instance)
2571 selected_instance->undo();
2577 if(selected_instance)
2578 selected_instance->redo();
2582 studio::App::get_base_path()
2584 return app_base_path_;