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>
72 #include "canvasview.h"
73 #include "dialog_setup.h"
74 #include "dialog_gradient.h"
75 #include "dialog_color.h"
78 #include "onemoment.h"
80 #include "dockmanager.h"
82 #include "state_eyedrop.h"
83 #include "state_normal.h"
84 #include "state_draw.h"
85 #include "state_fill.h"
86 #include "state_bline.h"
87 #include "state_polygon.h"
88 #include "state_sketch.h"
89 #include "state_gradient.h"
90 #include "state_circle.h"
91 #include "state_rectangle.h"
92 #include "state_smoothmove.h"
93 #include "state_scale.h"
94 #include "state_star.h"
95 #include "state_text.h"
96 #include "state_width.h"
97 #include "state_rotate.h"
98 #include "state_zoom.h"
100 #include "devicetracker.h"
101 #include "dialog_tooloptions.h"
102 #include "widget_enum.h"
104 #include "autorecover.h"
106 #include <synfigapp/settings.h>
107 #include "dock_history.h"
108 #include "dock_canvases.h"
109 #include "dock_keyframes.h"
110 #include "dock_layers.h"
111 #include "dock_params.h"
112 #include "dock_metadata.h"
113 #include "dock_children.h"
114 #include "dock_info.h"
115 #include "dock_navigator.h"
116 #include "dock_layergroups.h"
117 #include "dock_timetrack.h"
118 #include "dock_curves.h"
120 #include "mod_palette/mod_palette.h"
121 #include "mod_mirror/mod_mirror.h"
123 #include <sys/stat.h>
129 #include "statemanager.h"
135 #include <gtkmm/accelmap.h>
136 #include <gtkmm/filechooser.h>
137 #include <gtkmm/filechooserdialog.h>
143 /* === U S I N G =========================================================== */
147 using namespace synfig;
148 using namespace studio;
150 /* === M A C R O S ========================================================= */
152 #ifndef SYNFIG_USER_APP_DIR
154 #define SYNFIG_USER_APP_DIR "Library/Synfig"
155 #elif defined(_WIN32)
156 #define SYNFIG_USER_APP_DIR "Synfig"
158 #define SYNFIG_USER_APP_DIR ".synfig"
163 #define DPM2DPI(x) (float(x)/39.3700787402f)
164 #define DPI2DPM(x) (float(x)*39.3700787402f)
170 # define IMAGE_DIR "share\\pixmaps"
175 # define IMAGE_DIR "/usr/local/share/pixmaps"
179 # define IMAGE_EXT "tif"
182 #include <synfigapp/main.h>
184 /* === S I G N A L S ======================================================= */
186 static sigc::signal<void> signal_present_all_;
188 App::signal_present_all() { return signal_present_all_; }
190 static sigc::signal<void> signal_recent_files_changed_;
192 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
194 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
195 sigc::signal<void,etl::loose_handle<CanvasView> >&
196 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
198 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
199 sigc::signal<void,etl::handle<Instance> >&
200 App::signal_instance_selected() { return signal_instance_selected_; }
202 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
203 sigc::signal<void,etl::handle<Instance> >&
204 App::signal_instance_created() { return signal_instance_created_; }
206 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
207 sigc::signal<void,etl::handle<Instance> >&
208 App::signal_instance_deleted() { return signal_instance_deleted_; }
210 /* === G L O B A L S ======================================================= */
212 static std::list<std::string> recent_files;
213 const std::list<std::string>& App::get_recent_files() { return recent_files; }
215 static std::list<std::string> recent_files_window_size;
217 int App::Busy::count;
218 bool App::shutdown_in_progress;
220 synfig::Gamma App::gamma;
222 Glib::RefPtr<studio::UIManager> App::ui_manager_;
224 synfig::Distance::System App::distance_system;
226 studio::Dialog_Setup* App::dialog_setup;
228 etl::handle< studio::ModPalette > mod_palette_;
229 //studio::Dialog_Palette* App::dialog_palette;
231 std::list<etl::handle<Instance> > App::instance_list;
233 static etl::handle<synfigapp::UIInterface> ui_interface_;
234 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
236 etl::handle<Instance> App::selected_instance;
237 etl::handle<CanvasView> App::selected_canvas_view;
239 studio::About *studio::App::about=NULL;
241 studio::Toolbox *studio::App::toolbox=NULL;
243 studio::AutoRecover *studio::App::auto_recover=NULL;
245 studio::IPC *ipc=NULL;
247 studio::DockManager* studio::App::dock_manager=0;
249 studio::DeviceTracker* studio::App::device_tracker=0;
251 studio::Dialog_Gradient* studio::App::dialog_gradient;
253 studio::Dialog_Color* studio::App::dialog_color;
255 Gtk::InputDialog* studio::App::dialog_input;
257 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
259 studio::Dock_History* dock_history;
260 studio::Dock_Canvases* dock_canvases;
261 studio::Dock_Keyframes* dock_keyframes;
262 studio::Dock_Layers* dock_layers;
263 studio::Dock_Params* dock_params;
264 studio::Dock_MetaData* dock_meta_data;
265 studio::Dock_Children* dock_children;
266 studio::Dock_Info* dock_info;
267 studio::Dock_LayerGroups* dock_layer_groups;
268 studio::Dock_Navigator* dock_navigator;
269 studio::Dock_Timetrack* dock_timetrack;
270 studio::Dock_Curves* dock_curves;
272 std::list< etl::handle< studio::Module > > module_list_;
274 bool studio::App::use_colorspace_gamma=true;
275 #ifdef SINGLE_THREADED
276 bool studio::App::single_threaded=false;
278 bool studio::App::restrict_radius_ducks=false;
279 bool studio::App::resize_imported_images=false;
280 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
281 int studio::App::preferred_x_size=480;
282 int studio::App::preferred_y_size=270;
283 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
284 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
285 float studio::App::preferred_fps=24.0;
286 #ifdef USE_OPEN_FOR_URLS
287 String studio::App::browser_command("open"); // MacOS only
289 String studio::App::browser_command("xdg-open"); // Linux XDG standard
292 static int max_recent_files_=25;
293 int studio::App::get_max_recent_files() { return max_recent_files_; }
294 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
296 static synfig::String app_base_path_;
301 really_delete_widget(Gtk::Widget *widget)
303 // synfig::info("really delete %p", (void*)widget);
308 // nasty workaround - when we've finished with a popup menu, we want to delete it
309 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
310 // so schedule the real delete to happen in 50ms, giving the action a chance to run
312 delete_widget(Gtk::Widget *widget)
314 // synfig::info("delete %p", (void*)widget);
315 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
318 }; // END of namespace studio
319 studio::StateManager* state_manager;
324 class GlobalUIInterface : public synfigapp::UIInterface
328 virtual Response confirmation(const std::string &title,
329 const std::string &primaryText,
330 const std::string &secondaryText,
331 const std::string &confirmPhrase,
332 const std::string &cancelPhrase,
333 Response defaultResponse)
335 Gtk::MessageDialog dialog(
336 primaryText, // Message
338 Gtk::MESSAGE_WARNING, // Type
339 Gtk::BUTTONS_NONE, // Buttons
344 dialog.set_title(title);
345 if (! secondaryText.empty())
346 dialog.set_secondary_text(secondaryText);
348 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
349 dialog.add_button(confirmPhrase, RESPONSE_OK);
350 dialog.set_default_response(defaultResponse);
353 return (Response) dialog.run();
356 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
361 true // use_separator
363 Gtk::Label label(message);
366 dialog.get_vbox()->pack_start(label);
367 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
368 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
370 dialog.set_default_response(dflt);
372 return (Response)dialog.run();
374 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
379 true // use_separator
381 Gtk::Label label(message);
384 dialog.get_vbox()->pack_start(label);
385 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
386 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
387 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
389 dialog.set_default_response(dflt);
391 return (Response)dialog.run();
393 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
398 true // use_separator
400 Gtk::Label label(message);
403 dialog.get_vbox()->pack_start(label);
404 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
405 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
407 dialog.set_default_response(dflt);
409 return (Response)dialog.run();
413 task(const std::string &task)
415 std::cerr<<task<<std::endl;
416 while(studio::App::events_pending())studio::App::iteration(false);
421 error(const std::string &err)
423 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
430 warning(const std::string &err)
432 std::cerr<<"warning: "<<err<<std::endl;
433 while(studio::App::events_pending())studio::App::iteration(false);
438 amount_complete(int /*current*/, int /*total*/)
440 while(studio::App::events_pending())studio::App::iteration(false);
445 /* === P R O C E D U R E S ================================================= */
449 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
451 action_group_list.push_back(action_group);
452 Gtk::UIManager::insert_action_group(action_group, pos);
456 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
458 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
459 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
460 if(*iter==action_group)
462 action_group_list.erase(iter);
463 Gtk::UIManager::remove_action_group(action_group);
466 synfig::error("Unable to find action group");
470 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
472 ui_manager->insert_action_group(group,0);
474 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
475 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
477 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
479 if(*iter && (*iter)->get_name()!="menus")
481 synfig::info("Removing action group "+(*iter)->get_name());
482 ui_manager->remove_action_group(*iter);
485 ui_manager->insert_action_group(group,0);
487 for(;!prev_groups.empty();prev_groups.pop_front())
489 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
490 ui_manager->insert_action_group(prev_groups.front(),1);
494 class Preferences : public synfigapp::Settings
497 virtual bool get_value(const synfig::String& key, synfig::String& value)const
501 value=strprintf("%f %f %f %f",
502 App::gamma.get_gamma_r(),
503 App::gamma.get_gamma_g(),
504 App::gamma.get_gamma_b(),
505 App::gamma.get_black_level()
509 if(key=="time_format")
511 value=strprintf("%i",App::get_time_format());
514 if(key=="file_history.size")
516 value=strprintf("%i",App::get_max_recent_files());
519 if(key=="use_colorspace_gamma")
521 value=strprintf("%i",(int)App::use_colorspace_gamma);
524 if(key=="distance_system")
526 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
529 #ifdef SINGLE_THREADED
530 if(key=="single_threaded")
532 value=strprintf("%i",(int)App::single_threaded);
536 if(key=="auto_recover_backup_interval")
538 value=strprintf("%i",App::auto_recover->get_timeout());
541 if(key=="restrict_radius_ducks")
543 value=strprintf("%i",(int)App::restrict_radius_ducks);
546 if(key=="resize_imported_images")
548 value=strprintf("%i",(int)App::resize_imported_images);
551 if(key=="browser_command")
553 value=App::browser_command;
556 if(key=="custom_filename_prefix")
558 value=App::custom_filename_prefix;
561 if(key=="preferred_x_size")
563 value=strprintf("%i",App::preferred_x_size);
566 if(key=="preferred_y_size")
568 value=strprintf("%i",App::preferred_y_size);
571 if(key=="predefined_size")
573 value=strprintf("%s",App::predefined_size.c_str());
576 if(key=="preferred_fps")
578 value=strprintf("%f",App::preferred_fps);
581 if(key=="predefined_fps")
583 value=strprintf("%s",App::predefined_fps.c_str());
587 return synfigapp::Settings::get_value(key,value);
590 virtual bool set_value(const synfig::String& key,const synfig::String& value)
596 strscanf(value,"%f %f %f %f",
603 App::gamma.set_all(r,g,b,blk);
607 if(key=="time_format")
609 int i(atoi(value.c_str()));
610 App::set_time_format(static_cast<synfig::Time::Format>(i));
613 if(key=="auto_recover_backup_interval")
615 int i(atoi(value.c_str()));
616 App::auto_recover->set_timeout(i);
619 if(key=="file_history.size")
621 int i(atoi(value.c_str()));
622 App::set_max_recent_files(i);
625 if(key=="use_colorspace_gamma")
627 int i(atoi(value.c_str()));
628 App::use_colorspace_gamma=i;
631 if(key=="distance_system")
633 App::distance_system=Distance::ident_system(value);;
636 #ifdef SINGLE_THREADED
637 if(key=="single_threaded")
639 int i(atoi(value.c_str()));
640 App::single_threaded=i;
644 if(key=="restrict_radius_ducks")
646 int i(atoi(value.c_str()));
647 App::restrict_radius_ducks=i;
650 if(key=="resize_imported_images")
652 int i(atoi(value.c_str()));
653 App::resize_imported_images=i;
656 if(key=="browser_command")
658 App::browser_command=value;
661 if(key=="custom_filename_prefix")
663 App::custom_filename_prefix=value;
666 if(key=="preferred_x_size")
668 int i(atoi(value.c_str()));
669 App::preferred_x_size=i;
672 if(key=="preferred_y_size")
674 int i(atoi(value.c_str()));
675 App::preferred_y_size=i;
678 if(key=="predefined_size")
680 App::predefined_size=value;
683 if(key=="preferred_fps")
685 float i(atof(value.c_str()));
686 App::preferred_fps=i;
689 if(key=="predefined_fps")
691 App::predefined_fps=value;
695 return synfigapp::Settings::set_value(key,value);
698 virtual KeyList get_key_list()const
700 KeyList ret(synfigapp::Settings::get_key_list());
701 ret.push_back("gamma");
702 ret.push_back("time_format");
703 ret.push_back("distance_system");
704 ret.push_back("file_history.size");
705 ret.push_back("use_colorspace_gamma");
706 #ifdef SINGLE_THREADED
707 ret.push_back("single_threaded");
709 ret.push_back("auto_recover_backup_interval");
710 ret.push_back("restrict_radius_ducks");
711 ret.push_back("resize_imported_images");
712 ret.push_back("browser_command");
713 ret.push_back("custom_filename_prefix");
714 ret.push_back("preferred_x_size");
715 ret.push_back("preferred_y_size");
716 ret.push_back("predefined_size");
717 ret.push_back("preferred_fps");
718 ret.push_back("predefined_fps");
723 static ::Preferences _preferences;
728 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
730 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
732 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
734 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
735 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
736 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
737 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
738 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
739 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
740 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
741 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
742 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
743 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
744 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
745 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
746 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
748 // Add the synfigapp actions...
749 synfigapp::Action::Book::iterator iter;
750 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
752 actions_action_group->add(Gtk::Action::create(
753 "action-"+iter->second.name,
754 get_action_stock_id(iter->second),
755 iter->second.local_name,iter->second.local_name
759 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
760 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
761 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ group->add(action,sig); }
763 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
764 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
765 DEFINE_ACTION("new", Gtk::Stock::NEW);
766 DEFINE_ACTION("open", Gtk::Stock::OPEN);
767 DEFINE_ACTION("save", Gtk::Stock::SAVE);
768 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
769 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
770 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
771 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
772 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
773 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
774 DEFINE_ACTION("import", _("Import"));
775 DEFINE_ACTION("render", _("Render"));
776 DEFINE_ACTION("preview", _("Preview"));
777 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
778 DEFINE_ACTION("sound", _("Sound File"));
779 DEFINE_ACTION("options", _("Options"));
780 DEFINE_ACTION("close", _("Close View"));
781 DEFINE_ACTION("close-document", _("Close Document"));
782 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
785 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
786 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
787 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
788 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
789 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
790 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
791 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
792 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
793 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
794 DEFINE_ACTION("properties", _("Properties"));
796 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
797 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
798 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
799 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
800 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
801 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
802 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
803 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
804 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
805 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
806 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
807 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
808 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
809 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
810 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
811 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
812 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
813 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
814 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
815 DEFINE_ACTION("play", _("Play"));
816 // DEFINE_ACTION("pause", _("Pause"));
817 DEFINE_ACTION("stop", _("Stop"));
818 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
819 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
820 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
821 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
822 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
823 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
824 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
825 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
826 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
827 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
828 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
829 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
830 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
831 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
832 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
833 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
834 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
835 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
836 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
837 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
838 DEFINE_ACTION("seek-end", _("Seek to End"));
840 DEFINE_ACTION("action-group_add", _("Add group"));
842 DEFINE_ACTION("canvas-new", _("New Canvas"));
844 DEFINE_ACTION("amount-inc", _("Increase Amount"));
845 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
850 // Set up synfigapp actions
852 synfigapp::Action::Book::iterator iter;
854 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
856 Gtk::StockID stock_id;
858 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
860 //Gtk::Image* image(manage(new Gtk::Image()));
861 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
862 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
863 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
864 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
865 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
866 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
867 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
868 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
869 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
870 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
872 actions_action_group->add(Gtk::Action::create(
873 "action-"+iter->second.name,
875 iter->second.local_name,iter->second.local_name
883 Glib::ustring ui_info =
885 " <popup name='menu-toolbox' action='menu-toolbox'>"
886 " <menu action='menu-file'>"
889 " <popup name='menu-main' action='menu-main'>"
890 " <menu action='menu-file'>"
891 " <menuitem action='new' />"
892 " <menuitem action='open' />"
893 " <menuitem action='save' />"
894 " <menuitem action='save-as' />"
895 " <menuitem action='revert' />"
896 " <separator name='bleh01'/>"
897 " <menuitem action='cvs-add' />"
898 " <menuitem action='cvs-update' />"
899 " <menuitem action='cvs-commit' />"
900 " <menuitem action='cvs-revert' />"
901 " <separator name='bleh02'/>"
902 " <menuitem action='import' />"
903 " <separator name='bleh03'/>"
904 " <menuitem action='render' />"
905 " <menuitem action='preview' />"
906 " <menuitem action='sound' />"
907 " <separator name='bleh04'/>"
908 " <menuitem action='options' />"
909 " <menuitem action='close' />"
910 " <menuitem action='close-document' />"
911 " <menuitem action='quit' />"
913 " <menu action='menu-edit'>"
914 " <menuitem action='undo'/>"
915 " <menuitem action='redo'/>"
916 " <separator name='bleh05'/>"
917 " <menuitem action='cut'/>"
918 " <menuitem action='copy'/>"
919 " <menuitem action='paste'/>"
920 " <separator name='bleh06'/>"
921 " <menuitem action='select-all-layers'/>"
922 " <menuitem action='unselect-all-layers'/>"
923 " <menuitem action='select-all-ducks'/>"
924 " <menuitem action='unselect-all-ducks'/>"
925 " <separator name='bleh07'/>"
926 " <menuitem action='properties'/>"
928 " <menu action='menu-view'>"
929 " <menu action='menu-duck-mask'>"
930 " <menuitem action='mask-position-ducks' />"
931 " <menuitem action='mask-vertex-ducks' />"
932 " <menuitem action='mask-tangent-ducks' />"
933 " <menuitem action='mask-radius-ducks' />"
934 " <menuitem action='mask-width-ducks' />"
935 " <menuitem action='mask-angle-ducks' />"
937 " <menu action='menu-preview-quality'>"
938 " <menuitem action='quality-00' />"
939 " <menuitem action='quality-01' />"
940 " <menuitem action='quality-02' />"
941 " <menuitem action='quality-03' />"
942 " <menuitem action='quality-04' />"
943 " <menuitem action='quality-05' />"
944 " <menuitem action='quality-06' />"
945 " <menuitem action='quality-07' />"
946 " <menuitem action='quality-08' />"
947 " <menuitem action='quality-09' />"
948 " <menuitem action='quality-10' />"
950 " <menu action='menu-lowres-pixel'>"
951 " <menuitem action='decrease-low-res-pixel-size'/>"
952 " <menuitem action='increase-low-res-pixel-size'/>"
953 " <separator name='pixel-size-separator'/>"
956 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
957 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
961 " <separator name='bleh08'/>"
962 " <menuitem action='play'/>"
963 //" <menuitem action='pause'/>"
964 " <menuitem action='stop'/>"
965 " <menuitem action='dialog-flipbook'/>"
966 " <separator name='bleh09'/>"
967 " <menuitem action='toggle-grid-show'/>"
968 " <menuitem action='toggle-grid-snap'/>"
969 " <menuitem action='toggle-guide-show'/>"
970 " <menuitem action='toggle-low-res'/>"
971 " <menuitem action='toggle-onion-skin'/>"
972 " <separator name='bleh10'/>"
973 " <menuitem action='canvas-zoom-in'/>"
974 " <menuitem action='canvas-zoom-out'/>"
975 " <menuitem action='canvas-zoom-fit'/>"
976 " <menuitem action='canvas-zoom-100'/>"
977 " <separator name='bleh11'/>"
978 " <menuitem action='time-zoom-in'/>"
979 " <menuitem action='time-zoom-out'/>"
980 " <separator name='bleh12'/>"
981 " <menuitem action='jump-next-keyframe'/>"
982 " <menuitem action='jump-prev-keyframe'/>"
983 " <menuitem action='seek-next-frame'/>"
984 " <menuitem action='seek-prev-frame'/>"
985 " <menuitem action='seek-next-second'/>"
986 " <menuitem action='seek-prev-second'/>"
987 " <menuitem action='seek-begin'/>"
988 " <menuitem action='seek-end'/>"
990 " <menu action='menu-canvas'>"
991 " <menuitem action='canvas-new'/>"
993 " <menu name='menu-state' action='menu-state'>"
995 " <menu action='menu-group'>"
996 " <menuitem action='action-group_add'/>"
998 " <menu action='menu-layer'>"
999 //" <menuitem action='cut'/>"
1000 //" <menuitem action='copy'/>"
1001 //" <menuitem action='paste'/>"
1002 //" <separator name='bleh06'/>"
1003 " <menu action='menu-layer-new'></menu>"
1004 " <menuitem action='amount-inc'/>"
1005 " <menuitem action='amount-dec'/>"
1007 " <menu action='menu-keyframe'>"
1008 " <menuitem action='keyframe-properties'/>"
1015 " <menubar name='MenuBar'>"
1016 " <menu action='MenuFile'>"
1017 " <menuitem action='New'/>"
1018 " <menuitem action='Open'/>"
1020 " <menuitem action='Quit'/>"
1022 " <menu action='MenuEdit'>"
1023 " <menuitem action='Cut'/>"
1024 " <menuitem action='Copy'/>"
1025 " <menuitem action='Paste'/>"
1028 " <toolbar name='ToolBar'>"
1029 " <toolitem action='Open'/>"
1030 " <toolitem action='Quit'/>"
1036 actions_action_group->set_sensitive(false);
1037 App::ui_manager()->set_add_tearoffs(true);
1038 App::ui_manager()->insert_action_group(menus_action_group,1);
1039 App::ui_manager()->insert_action_group(actions_action_group,1);
1040 App::ui_manager()->add_ui_from_string(ui_info);
1042 //App::ui_manager()->get_accel_group()->unlock();
1044 catch(const Glib::Error& ex)
1046 synfig::error("building menus and toolbars failed: " + ex.what());
1049 // Add default keyboard accelerators
1050 #define ACCEL(accel,path) \
1052 Gtk::AccelKey accel_key(accel,path); \
1053 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1056 #define ACCEL2(accel) \
1058 Gtk::AccelKey accel_key(accel); \
1059 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1063 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1064 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1065 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1066 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1067 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1068 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1069 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1070 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1071 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1072 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1073 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1074 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1075 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1076 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1077 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1078 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1079 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1080 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1083 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1084 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1085 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1086 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1087 ACCEL("F9", "<Actions>/canvasview/render" );
1088 ACCEL("F11", "<Actions>/canvasview/preview" );
1089 ACCEL("F8", "<Actions>/canvasview/properties" );
1090 ACCEL("F12", "<Actions>/canvasview/options" );
1091 ACCEL("<control>i", "<Actions>/canvasview/import" );
1092 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1093 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1094 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1095 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1096 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1097 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1098 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1099 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1100 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1101 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1102 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1103 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1104 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1105 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1106 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1107 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1108 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1109 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1110 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1111 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1112 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1113 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1114 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1115 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1116 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1117 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1118 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1119 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1120 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1121 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1122 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1123 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1124 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1125 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1126 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1127 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1128 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1129 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1130 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1131 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1132 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1133 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1134 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1135 ACCEL("End", "<Actions>/canvasview/seek-end" );
1141 #define mkdir(x,y) mkdir(x)
1144 /* === M E T H O D S ======================================================= */
1146 App::App(int *argc, char ***argv):
1147 Gtk::Main(argc,argv),
1148 IconController(etl::dirname((*argv)[0]))
1150 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1153 ui_interface_=new GlobalUIInterface();
1157 // don't call thread_init() if threads are already initialized
1158 // on some machines bonobo_init() initialized threads before we get here
1159 if (!g_thread_supported())
1160 Glib::thread_init();
1162 distance_system=Distance::SYSTEM_UNITS;
1164 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1167 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1171 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1177 if(!SYNFIG_CHECK_VERSION())
1179 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1180 dialog_error_blocking("Synfig Studio",
1181 "This copy of Synfig Studio was compiled against a\n"
1182 "different version of libsynfig than what is currently\n"
1183 "installed. Synfig Studio will now abort. Try downloading\n"
1184 "the latest version from the Synfig website at\n"
1185 "http://synfig.org/en/current-release"
1189 Glib::set_application_name(_("Synfig Studio"));
1191 Splash splash_screen;
1192 splash_screen.show();
1194 shutdown_in_progress=false;
1195 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1196 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1198 // Initialize the Synfig library
1199 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1200 catch(std::runtime_error x)
1202 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1207 get_ui_interface()->error(_("Failed to initialize synfig!"));
1211 // add the preferences to the settings
1212 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1216 studio_init_cb.task(_("Init UI Manager..."));
1217 App::ui_manager_=studio::UIManager::create();
1220 studio_init_cb.task(_("Init Dock Manager..."));
1221 dock_manager=new studio::DockManager();
1223 studio_init_cb.task(_("Init State Manager..."));
1224 state_manager=new StateManager();
1226 studio_init_cb.task(_("Init Toolbox..."));
1227 toolbox=new studio::Toolbox();
1229 studio_init_cb.task(_("Init About Dialog..."));
1230 about=new studio::About();
1232 studio_init_cb.task(_("Init Tool Options..."));
1233 dialog_tool_options=new studio::Dialog_ToolOptions();
1234 dock_manager->register_dockable(*dialog_tool_options);
1236 studio_init_cb.task(_("Init History..."));
1237 dock_history=new studio::Dock_History();
1238 dock_manager->register_dockable(*dock_history);
1240 studio_init_cb.task(_("Init Canvases..."));
1241 dock_canvases=new studio::Dock_Canvases();
1242 dock_manager->register_dockable(*dock_canvases);
1244 studio_init_cb.task(_("Init Keyframes..."));
1245 dock_keyframes=new studio::Dock_Keyframes();
1246 dock_manager->register_dockable(*dock_keyframes);
1248 studio_init_cb.task(_("Init Layers..."));
1249 dock_layers=new studio::Dock_Layers();
1250 dock_manager->register_dockable(*dock_layers);
1252 studio_init_cb.task(_("Init Params..."));
1253 dock_params=new studio::Dock_Params();
1254 dock_manager->register_dockable(*dock_params);
1256 studio_init_cb.task(_("Init MetaData..."));
1257 dock_meta_data=new studio::Dock_MetaData();
1258 dock_manager->register_dockable(*dock_meta_data);
1260 studio_init_cb.task(_("Init Children..."));
1261 dock_children=new studio::Dock_Children();
1262 dock_manager->register_dockable(*dock_children);
1264 studio_init_cb.task(_("Init Info..."));
1265 dock_info = new studio::Dock_Info();
1266 dock_manager->register_dockable(*dock_info);
1268 studio_init_cb.task(_("Init Navigator..."));
1269 dock_navigator = new studio::Dock_Navigator();
1270 dock_manager->register_dockable(*dock_navigator);
1272 studio_init_cb.task(_("Init Timetrack..."));
1273 dock_timetrack = new studio::Dock_Timetrack();
1274 dock_manager->register_dockable(*dock_timetrack);
1276 studio_init_cb.task(_("Init Curve Editor..."));
1277 dock_curves = new studio::Dock_Curves();
1278 dock_manager->register_dockable(*dock_curves);
1280 studio_init_cb.task(_("Init Layer Groups..."));
1281 dock_layer_groups = new studio::Dock_LayerGroups();
1282 dock_manager->register_dockable(*dock_layer_groups);
1285 studio_init_cb.task(_("Init Color Dialog..."));
1286 dialog_color=new studio::Dialog_Color();
1288 studio_init_cb.task(_("Init Gradient Dialog..."));
1289 dialog_gradient=new studio::Dialog_Gradient();
1291 studio_init_cb.task(_("Init DeviceTracker..."));
1292 device_tracker=new studio::DeviceTracker();
1294 studio_init_cb.task(_("Init Tools..."));
1297 state_manager->add_state(&state_normal);
1298 state_manager->add_state(&state_smooth_move);
1299 state_manager->add_state(&state_scale);
1300 state_manager->add_state(&state_rotate);
1301 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1304 state_manager->add_state(&state_circle);
1305 state_manager->add_state(&state_rectangle);
1306 state_manager->add_state(&state_star);
1307 state_manager->add_state(&state_gradient);
1308 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1311 state_manager->add_state(&state_bline);
1312 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1313 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1314 state_manager->add_state(&state_fill);
1315 state_manager->add_state(&state_eyedrop);
1318 state_manager->add_state(&state_text);
1319 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1320 state_manager->add_state(&state_zoom);
1322 studio_init_cb.task(_("Init ModPalette..."));
1323 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1325 studio_init_cb.task(_("Init Setup Dialog..."));
1326 dialog_setup=new studio::Dialog_Setup();
1328 studio_init_cb.task(_("Init Input Dialog..."));
1329 dialog_input=new Gtk::InputDialog();
1330 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1331 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1333 studio_init_cb.task(_("Init auto recovery..."));
1334 auto_recover=new AutoRecover();
1336 studio_init_cb.amount_complete(9250,10000);
1337 studio_init_cb.task(_("Loading Settings..."));
1339 device_tracker->load_preferences();
1341 studio_init_cb.task(_("Checking auto-recover..."));
1343 studio_init_cb.amount_complete(9900,10000);
1345 bool opened_any = false;
1346 if(auto_recover->recovery_needed())
1348 splash_screen.hide();
1349 if (get_ui_interface()->confirmation("Crash Recovery",
1350 _("Auto recovery file found"),
1351 _("Synfig Studio seems to have crashed\n"
1352 "before you could save all your files.\n"
1353 "Recover unsaved changes?"),
1354 _("Recover"), _("Ignore"))
1355 == synfigapp::UIInterface::RESPONSE_OK)
1357 int number_recovered;
1358 if(!auto_recover->recover(number_recovered))
1359 if (number_recovered)
1360 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1362 get_ui_interface()->error(_("Unable to recover from previous crash"));
1364 get_ui_interface()->error(
1365 _("Synfig Studio has attempted to recover\n"
1366 "from a previous crash. The files that it has\n"
1367 "recovered are NOT YET SAVED. It would be a good\n"
1368 "idea to review them and save them now."));
1370 if (number_recovered)
1373 splash_screen.show();
1376 // Look for any files given on the command line,
1377 // and load them if found.
1378 for(;*argc>=1;(*argc)--)
1379 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1381 studio_init_cb.task(_("Loading files..."));
1382 splash_screen.hide();
1383 open((*argv)[*argc]);
1385 splash_screen.show();
1388 // if no file was specified to be opened, create a new document to help new users get started more easily
1389 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1392 studio_init_cb.task(_("Done."));
1393 studio_init_cb.amount_complete(10000,10000);
1395 // To avoid problems with some window managers and gtk >= 2.18
1396 // we should show dock dialogs after the settings load.
1397 // If dock dialogs are shown before the settings are loaded,
1398 // the windows manager can act over it.
1399 // See discussions here:
1400 // * http://synfig.org/forums/viewtopic.php?f=1&t=1131&st=0&sk=t&sd=a&start=30
1401 // * http://synfig.org/forums/viewtopic.php?f=15&t=1062
1402 dock_manager->show_all_dock_dialogs();
1408 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1412 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1416 StateManager* App::get_state_manager() { return state_manager; }
1420 shutdown_in_progress=true;
1424 synfigapp::Main::settings().remove_domain("pref");
1426 selected_instance=0;
1428 // Unload all of the modules
1429 for(;!module_list_.empty();module_list_.pop_back())
1432 delete state_manager;
1436 delete auto_recover;
1442 // studio::App::iteration(false);
1446 // studio::App::iteration(false);
1448 // studio::App::iteration(false);
1450 delete dialog_setup;
1452 delete dialog_gradient;
1454 delete dialog_color;
1456 delete dialog_input;
1458 delete dock_manager;
1460 instance_list.clear();
1462 // studio::App::iteration(false);
1466 App::get_user_app_directory()
1468 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1470 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1472 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1477 App::get_config_file(const synfig::String& file)
1479 return Glib::build_filename(get_user_app_directory(),file);
1482 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1484 App::set_recent_file_window_size(etl::handle<Instance> instance)
1487 const std::string &canvas_window_size = *recent_files_window_size.begin();
1489 if(canvas_window_size.empty())
1492 synfig::String::size_type current=0;
1493 bool seen_root(false), shown_non_root(false);
1495 while(current != synfig::String::npos)
1497 // find end of first field (canvas) or return
1498 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1499 if(separator == synfig::String::npos) break;
1502 synfig::Canvas::Handle canvas;
1505 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1507 catch(Exception::IDNotFound) {
1508 // can't find the canvas; skip to the next canvas or return
1509 separator = canvas_window_size.find_first_of('\t', current);
1510 if(separator == synfig::String::npos) return;
1511 current = separator+1;
1515 if (canvas->is_root())
1518 shown_non_root = true;
1520 // check that we have the tab character the ends this canvas' data or return
1521 current = separator+1;
1522 separator = canvas_window_size.find_first_of('\t', current);
1523 if(separator == synfig::String::npos) return;
1526 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1528 current = separator+1;
1531 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1532 canvasview->move(x,y);
1533 canvasview->resize(w,h);
1534 canvasview->present();
1536 current = separator+1;
1539 if (shown_non_root && !seen_root)
1540 instance->find_canvas_view(instance->get_canvas())->hide();
1544 App::add_recent_file(const etl::handle<Instance> instance)
1547 std::string canvas_window_size;
1549 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1550 Instance::CanvasViewList::const_iterator iter;
1552 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1554 if( !((*iter)->is_visible()) )
1557 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1558 int x_pos, y_pos, x_size, y_size;
1559 (*iter)->get_position(x_pos,y_pos);
1560 (*iter)->get_size(x_size,y_size);
1562 canvas_window_size += strprintf("%s %d %d %d %d\t",
1563 canvas->get_relative_id(canvas->get_root()).c_str(),
1568 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1572 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1574 std::string filename(file_name);
1576 assert(!filename.empty());
1578 if(filename.empty())
1581 // Toss out any "hidden" files
1582 if(basename(filename)[0]=='.')
1585 // If we aren't an absolute path, turn ourselves into one
1586 if(!is_absolute_path(filename))
1587 filename=absolute_path(filename);
1589 std::string old_window_size;
1591 list<string>::iterator iter;
1592 list<string>::iterator iter_wsize;
1593 // Check to see if the file is already on the list.
1594 // If it is, then remove it from the list
1595 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1598 recent_files.erase(iter);
1599 old_window_size = *iter_wsize;
1600 recent_files_window_size.erase(iter_wsize);
1605 // Push the filename to the front of the list
1606 recent_files.push_front(filename);
1607 if(window_size.empty())
1608 recent_files_window_size.push_front(old_window_size);
1610 recent_files_window_size.push_front(window_size);
1612 // Clean out the files at the end of the list.
1613 while(recent_files.size()>(unsigned)get_max_recent_files())
1615 recent_files.pop_back();
1616 recent_files_window_size.pop_back();
1619 signal_recent_files_changed_();
1624 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1627 App::get_time_format()
1629 return _App_time_format;
1633 App::set_time_format(synfig::Time::Format x)
1640 App::save_settings()
1645 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1646 setlocale(LC_NUMERIC, "C");
1648 std::string filename=get_config_file("accelrc");
1649 Gtk::AccelMap::save(filename);
1652 std::string filename=get_config_file("recentfiles");
1654 std::ofstream file(filename.c_str());
1658 synfig::warning("Unable to save %s",filename.c_str());
1662 list<string>::reverse_iterator iter;
1664 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1668 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1670 std::ofstream file(filename.c_str());
1674 synfig::warning("Unable to save %s",filename.c_str());
1678 list<string>::reverse_iterator iter;
1680 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1684 std::string filename=get_config_file("settings");
1685 synfigapp::Main::settings().save_to_file(filename);
1686 setlocale(LC_NUMERIC,old_locale);
1690 synfig::warning("Caught exception when attempting to save settings.");
1695 App::load_settings()
1700 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1701 setlocale(LC_NUMERIC, "C");
1703 std::string filename=get_config_file("accelrc");
1704 Gtk::AccelMap::load(filename);
1707 bool window_size_broken = false;
1709 std::string filename=get_config_file("recentfiles");
1710 std::string filename_window_size=filename+std::string("_window_size");
1712 std::ifstream file(filename.c_str());
1713 std::ifstream file_window_size(filename_window_size.c_str());
1715 if(!file_window_size)
1716 window_size_broken = true;
1720 std::string recent_file;
1721 std::string recent_file_window_size;
1722 getline(file,recent_file);
1723 if(!window_size_broken)
1724 getline(file_window_size,recent_file_window_size);
1725 if(!recent_file.empty())
1727 if(!window_size_broken && !file_window_size)
1728 window_size_broken = true;
1729 if (std::ifstream(recent_file.c_str()))
1731 if(!window_size_broken)
1732 add_recent_file(recent_file,recent_file_window_size);
1734 add_recent_file(recent_file);
1738 if(!window_size_broken && file_window_size)
1739 window_size_broken = true;
1741 if(window_size_broken)
1743 recent_files_window_size.clear();
1744 recent_files_window_size.resize(recent_files.size());
1747 std::string filename=get_config_file("settings");
1748 if(!synfigapp::Main::settings().load_from_file(filename))
1750 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1751 //if(!synfigapp::Main::settings().load_from_file(filename))
1753 gamma.set_gamma(1.0/2.2);
1754 reset_initial_window_configuration();
1757 setlocale(LC_NUMERIC,old_locale);
1761 synfig::warning("Caught exception when attempting to load settings.");
1766 App::reset_initial_window_configuration()
1768 Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
1769 Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
1770 Gdk::Rectangle rect;
1771 // A proper way to obtain the primary monitor is to use the
1772 // Gdk::Screen::get_primary_monitor () const member. But as it
1773 // was introduced in gtkmm 2.20 I assume that the monitor 0 is the
1775 screen->get_monitor_geometry(0,rect);
1776 #define hpanel_width 79.0f
1777 #define hpanel_height 25.0f
1778 #define vpanel_width 20.0f
1779 #define vpanel_height 100.0f
1783 /* percentages referred to width or height of the screen
1784 *---------------------------------------------------------------------*
1799 *-----hdock%----------------------------------------------|------------
1804 * --------------------------------------------------------------------*
1807 int v_xpos=rect.get_x() + rect.get_width()*(1.0-vpanel_width/100.0);
1808 int v_xsize=rect.get_width()*vpanel_width/100.0;
1809 int v_ypos=rect.get_y();
1810 int v_ysize=rect.get_height()*vpanel_height/100.0;
1811 std::string v_pos(strprintf("%d %d", v_xpos, v_ypos));
1812 std::string v_size(strprintf("%d %d", v_xsize, v_ysize));
1814 int h_xpos=rect.get_x();
1815 int h_xsize=rect.get_width()*hpanel_width/100.0;
1816 int h_ypos=rect.get_y()+ rect.get_height()*(1.0-hpanel_height/100.0);;
1817 int h_ysize=rect.get_height()*hpanel_height/100.0;
1818 std::string h_pos(strprintf("%d %d", h_xpos, h_ypos));
1819 std::string h_size(strprintf("%d %d", h_xsize, h_ysize));
1820 int v_dock1 = rect.get_height()*vdock*0.8/100.0;
1821 int v_dock2 = rect.get_height()*vdock*0.6/100.0;
1822 int v_dock3 = rect.get_height()*vdock*1.1/100.0;
1823 int h_dock = rect.get_width()*hdock/100.0;
1825 std::string v_contents(strprintf("%d %d %d", v_dock1, v_dock2, v_dock3));
1826 std::string h_contents(strprintf("%d", h_dock));
1827 // Tool Box position
1828 std::string tbox_pos(strprintf("%d %d", rect.get_x(), rect.get_y()));
1830 synfig::info("tool box pos: %s", tbox_pos.c_str());
1831 synfig::info("v_contents sizes: %s", v_contents.c_str());
1832 synfig::info("v_pos: %s", v_pos.c_str());
1833 synfig::info("v_sizes: %s", v_size.c_str());
1834 synfig::info("h_contents sizes: %s", h_contents.c_str());
1835 synfig::info("h_pos: %s", h_pos.c_str());
1836 synfig::info("h_sizes: %s", h_size.c_str());
1838 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1839 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1840 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size",v_contents);
1841 synfigapp::Main::settings().set_value("dock.dialog.1.size",v_size);
1842 synfigapp::Main::settings().set_value("dock.dialog.1.pos",v_pos);
1843 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1844 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1845 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size",h_contents);
1846 synfigapp::Main::settings().set_value("dock.dialog.2.size",h_size);
1847 synfigapp::Main::settings().set_value("dock.dialog.2.pos",h_pos);
1848 synfigapp::Main::settings().set_value("window.toolbox.pos",tbox_pos);
1850 dock_manager->show_all_dock_dialogs();
1854 App::reset_initial_preferences()
1856 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1857 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1858 #ifdef SINGLE_THREADED
1859 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1861 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1862 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1863 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1864 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1865 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1866 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1867 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1868 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1873 App::shutdown_request(GdkEventAny*)
1877 //return !shutdown_in_progress;
1883 if(shutdown_in_progress)return;
1886 get_ui_interface()->task(_("Quit Request"));
1889 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1893 std::list<etl::handle<Instance> >::iterator iter;
1894 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1896 if(!(*iter)->safe_close())
1900 if((*iter)->synfigapp::Instance::get_action_count())
1902 handle<synfigapp::UIInterface> uim;
1903 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1905 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1906 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1908 case synfigapp::UIInterface::RESPONSE_NO:
1910 case synfigapp::UIInterface::RESPONSE_YES:
1913 case synfigapp::UIInterface::RESPONSE_CANCEL:
1922 if((*iter)->synfigapp::Instance::is_modified())
1924 handle<synfigapp::UIInterface> uim;
1925 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1927 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() );
1928 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1930 case synfigapp::UIInterface::RESPONSE_NO:
1932 case synfigapp::UIInterface::RESPONSE_YES:
1933 (*iter)->dialog_cvs_commit();
1935 case synfigapp::UIInterface::RESPONSE_CANCEL:
1944 // This next line causes things to crash for some reason
1948 shutdown_in_progress=true;
1950 instance_list.clear();
1952 while(studio::App::events_pending())studio::App::iteration(false);
1955 auto_recover->normal_shutdown();
1957 get_ui_interface()->task(_("Quit Request sent"));
1963 dialog_setup->refresh();
1964 dialog_setup->show();
1967 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1968 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1971 //#define USE_WIN32_FILE_DIALOGS 1
1974 #ifdef USE_WIN32_FILE_DIALOGS
1975 static OPENFILENAME ofn={};
1979 #include <gdk/gdkwin32.h>
1983 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1985 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1987 #ifdef USE_WIN32_FILE_DIALOGS
1988 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1990 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1991 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1992 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1994 ofn.lStructSize=sizeof(OPENFILENAME);
1995 ofn.hwndOwner = hWnd;
1996 ofn.hInstance = hInstance;
1997 ofn.lpstrFilter = szFilter;
1998 // ofn.lpstrCustomFilter=NULL;
1999 // ofn.nMaxCustFilter=0;
2000 // ofn.nFilterIndex=0;
2001 // ofn.lpstrFile=NULL;
2002 ofn.nMaxFile=MAX_PATH;
2003 // ofn.lpstrFileTitle=NULL;
2004 // ofn.lpstrInitialDir=NULL;
2005 // ofn.lpstrTitle=NULL;
2006 ofn.Flags=OFN_HIDEREADONLY;
2007 // ofn.nFileOffset=0;
2008 // ofn.nFileExtension=0;
2009 ofn.lpstrDefExt=TEXT("sif");
2010 // ofn.lCustData = 0l;
2012 // ofn.lpTemplateName=NULL;
2014 CHAR szFilename[MAX_PATH];
2016 strcpy(szFilename,filename.c_str());
2017 strcpy(szTitle,title.c_str());
2019 ofn.lpstrFile=szFilename;
2020 ofn.lpstrFileTitle=szTitle;
2022 if(GetOpenFileName(&ofn))
2024 filename=szFilename;
2030 synfig::String prev_path;
2032 if(!_preferences.get_value(preference, prev_path))
2035 prev_path = absolute_path(prev_path);
2037 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2039 dialog->set_current_folder(prev_path);
2040 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2041 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
2043 if (filename.empty())
2044 dialog->set_filename(prev_path);
2045 else if (is_absolute_path(filename))
2046 dialog->set_filename(filename);
2048 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2050 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2051 filename = dialog->get_filename();
2052 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
2053 _preferences.set_value(preference, dirname(filename));
2067 GtkWidget *fileselection;
2068 fileselection = gtk_file_selection_new(title.c_str());
2071 if(basename(filename)==filename)
2073 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
2076 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
2078 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
2080 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
2081 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
2083 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
2084 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
2086 gtk_widget_show(fileselection);
2094 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
2095 _preferences.set_value(preference,dirname(filename));
2099 gtk_widget_destroy(fileselection);
2102 gtk_widget_destroy(fileselection);
2109 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2111 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2113 #if USE_WIN32_FILE_DIALOGS
2114 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2116 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2117 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2118 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2120 ofn.lStructSize=sizeof(OPENFILENAME);
2121 ofn.hwndOwner = hWnd;
2122 ofn.hInstance = hInstance;
2123 ofn.lpstrFilter = szFilter;
2124 // ofn.lpstrCustomFilter=NULL;
2125 // ofn.nMaxCustFilter=0;
2126 // ofn.nFilterIndex=0;
2127 // ofn.lpstrFile=NULL;
2128 ofn.nMaxFile=MAX_PATH;
2129 // ofn.lpstrFileTitle=NULL;
2130 // ofn.lpstrInitialDir=NULL;
2131 // ofn.lpstrTitle=NULL;
2132 ofn.Flags=OFN_OVERWRITEPROMPT;
2133 // ofn.nFileOffset=0;
2134 // ofn.nFileExtension=0;
2135 ofn.lpstrDefExt=TEXT("sif");
2136 // ofn.lCustData = 0l;
2138 // ofn.lpTemplateName=NULL;
2140 CHAR szFilename[MAX_PATH];
2142 strcpy(szFilename,filename.c_str());
2143 strcpy(szTitle,title.c_str());
2145 ofn.lpstrFile=szFilename;
2146 ofn.lpstrFileTitle=szTitle;
2148 if(GetSaveFileName(&ofn))
2150 filename=szFilename;
2151 _preferences.set_value(preference,dirname(filename));
2156 synfig::String prev_path;
2158 if(!_preferences.get_value(preference, prev_path))
2161 prev_path = absolute_path(prev_path);
2163 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2165 dialog->set_current_folder(prev_path);
2166 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2167 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2169 Widget_Enum *file_type_enum = 0;
2170 if (preference == ANIMATION_DIR_PREFERENCE)
2172 file_type_enum = manage(new Widget_Enum());
2173 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2174 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", strprintf("0.62.00 (%s)", _("current")))
2175 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2176 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2177 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2178 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2179 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2181 Gtk::HBox *hbox = manage(new Gtk::HBox);
2182 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2183 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2186 dialog->set_extra_widget(*hbox);
2189 if (filename.empty())
2190 dialog->set_filename(prev_path);
2193 std::string full_path;
2194 if (is_absolute_path(filename))
2195 full_path = filename;
2197 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2199 // select the file if it exists
2200 dialog->set_filename(full_path);
2202 // if the file doesn't exist, put its name into the filename box
2204 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2205 dialog->set_current_name(basename(filename));
2208 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2209 if (preference == ANIMATION_DIR_PREFERENCE)
2210 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2211 filename = dialog->get_filename();
2212 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2213 _preferences.set_value(preference, dirname(filename));
2224 App::dialog_error_blocking(const std::string &title, const std::string &message)
2226 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2227 dialog.set_title(title);
2233 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2235 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2236 dialog.set_title(title);
2242 App::dialog_yes_no(const std::string &title, const std::string &message)
2247 true // use_separator
2249 Gtk::Label label(message);
2252 dialog.get_vbox()->pack_start(label);
2253 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2254 dialog.add_button(Gtk::StockID("gtk-no"),0);
2256 return dialog.run();
2260 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2265 true // use_separator
2267 Gtk::Label label(message);
2270 dialog.get_vbox()->pack_start(label);
2271 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2272 dialog.add_button(Gtk::StockID("gtk-no"),0);
2273 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2275 return dialog.run();
2279 App::dialog_not_implemented()
2281 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2282 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2287 try_open_url(const std::string &url)
2290 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2292 std::vector<std::string> command_line;
2293 std::vector<std::string> browsers;
2294 browsers.reserve(23);
2296 // Browser wrapper scripts
2297 #ifdef USE_OPEN_FOR_URLS
2298 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2300 browsers.push_back("xdg-open"); // XDG wrapper
2301 browsers.push_back("sensible-browser"); // Debian wrapper
2302 browsers.push_back("gnome-open"); // GNOME wrapper
2303 browsers.push_back("kfmclient"); // KDE wrapper
2304 browsers.push_back("exo-open"); // XFCE wrapper
2306 // Alternatives system
2307 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2308 browsers.push_back("x-www-browser"); // Debian GUI alternative
2310 // Individual browsers
2311 browsers.push_back("firefox");
2312 browsers.push_back("epiphany-browser");
2313 browsers.push_back("epiphany");
2314 browsers.push_back("konqueror");
2315 browsers.push_back("iceweasel");
2316 browsers.push_back("mozilla");
2317 browsers.push_back("netscape");
2318 browsers.push_back("icecat");
2319 browsers.push_back("galeon");
2320 browsers.push_back("midori");
2321 browsers.push_back("safari");
2322 browsers.push_back("opera");
2323 browsers.push_back("amaya");
2324 browsers.push_back("netsurf");
2325 browsers.push_back("dillo");
2327 // Try the user-specified browser first
2328 command_line.push_back(App::browser_command);
2329 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2330 command_line.push_back(url);
2332 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2333 catch( Glib::SpawnError& exception ){
2335 while ( !browsers.empty() )
2337 // Skip the browser if we already tried it
2338 if( browsers[0] == App::browser_command )
2341 // Construct the command line
2342 command_line.clear();
2343 command_line.push_back(browsers[0]);
2344 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2345 command_line.push_back(url);
2347 // Remove the browser from the list
2348 browsers.erase(browsers.begin());
2350 // Try to spawn the browser
2351 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2352 // Failed, move on to the next one
2353 catch(Glib::SpawnError& exception){ continue; }
2354 return true; // No exception means we succeeded!
2365 if (!try_open_url("http://synfig.org/wiki/Category:Manual"))
2367 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2368 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://synfig.org/wiki/Category:Manual"));
2369 dialog.set_title(_("Help"));
2375 App::open_url(const std::string &url)
2377 if(!try_open_url(url))
2379 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2380 dialog.set_secondary_text(url);
2381 dialog.set_title(_("No browser found"));
2387 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2392 true); // use_separator
2394 Gtk::Label label(message);
2396 dialog.get_vbox()->pack_start(label);
2399 entry.set_text(text);
2401 entry.set_activates_default(true);
2403 dialog.get_vbox()->pack_start(entry);
2405 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2406 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2407 dialog.set_default_response(Gtk::RESPONSE_OK);
2409 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2412 if(dialog.run()!=Gtk::RESPONSE_OK)
2415 text=entry.get_text();
2421 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2426 true); // use_separator
2428 Gtk::Label label(message);
2430 dialog.get_vbox()->pack_start(label);
2432 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2433 text_buffer->set_text(text);
2434 Gtk::TextView text_view(text_buffer);
2437 dialog.get_vbox()->pack_start(text_view);
2439 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2440 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2441 dialog.set_default_response(Gtk::RESPONSE_OK);
2443 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2446 if(dialog.run()!=Gtk::RESPONSE_OK)
2449 text=text_buffer->get_text();
2455 App::open(std::string filename)
2457 return open_as(filename,filename);
2460 // this is called from autorecover.cpp:
2461 // App::open_as(get_shadow_file_name(filename),filename)
2462 // other than that, 'filename' and 'as' are the same
2464 App::open_as(std::string filename,std::string as)
2467 char long_name[1024];
2468 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2469 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2470 // don't use it if that's the case
2471 if (long_name[0] != '\0')
2477 OneMoment one_moment;
2478 String errors, warnings;
2480 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2481 if(canvas && get_instance(canvas))
2483 get_instance(canvas)->find_canvas_view(canvas)->present();
2484 info("%s is already open", filename.c_str());
2485 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2490 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2493 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2495 if (as.find(custom_filename_prefix.c_str()) != 0)
2496 add_recent_file(as);
2498 handle<Instance> instance(Instance::create(canvas));
2501 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2503 set_recent_file_window_size(instance);
2507 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)")))
2508 instance->dialog_cvs_update();
2513 dialog_error_blocking(_("Error"), x);
2516 catch(runtime_error x)
2518 dialog_error_blocking(_("Error"), x.what());
2523 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2534 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2536 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2537 canvas->set_name(file_name);
2538 file_name += ".sifz";
2540 canvas->rend_desc().set_frame_rate(preferred_fps);
2541 canvas->rend_desc().set_time_start(0.0);
2542 canvas->rend_desc().set_time_end(5.0);
2543 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2544 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2545 // The top left and botton right positions are expressed in units
2546 // Original convention is that 1 unit = 60 pixels
2547 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2548 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2549 canvas->rend_desc().set_w(preferred_x_size);
2550 canvas->rend_desc().set_h(preferred_y_size);
2551 canvas->rend_desc().set_antialias(1);
2552 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2553 canvas->set_file_name(file_name);
2555 handle<Instance> instance = Instance::create(canvas);
2557 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2558 instance->find_canvas_view(canvas)->canvas_properties.present();
2562 App::dialog_open(string filename)
2564 if (filename.empty())
2567 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2569 // If the filename still has wildcards, then we should
2570 // continue looking for the file we want
2571 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2577 get_ui_interface()->error(_("Unable to open file"));
2582 App::set_selected_instance(etl::loose_handle<Instance> instance)
2584 /* if(get_selected_instance()==instance)
2586 selected_instance=instance;
2587 signal_instance_selected()(instance);
2593 selected_instance=instance;
2594 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2598 instance->focus(instance->get_canvas());
2601 set_selected_canvas_view(0);
2603 signal_instance_selected()(instance);
2607 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2609 selected_canvas_view=canvas_view;
2610 signal_canvas_view_focus()(selected_canvas_view);
2613 selected_instance=canvas_view->get_instance();
2614 signal_instance_selected()(canvas_view->get_instance());
2617 if(get_selected_canvas_view()==canvas_view)
2619 signal_canvas_view_focus()(selected_canvas_view);
2620 signal_instance_selected()(canvas_view->get_instance());
2623 selected_canvas_view=canvas_view;
2624 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2625 set_selected_instance(canvas_view->get_instance());
2626 signal_canvas_view_focus()(selected_canvas_view);
2630 etl::loose_handle<Instance>
2631 App::get_instance(etl::handle<synfig::Canvas> canvas)
2633 if(!canvas) return 0;
2634 canvas=canvas->get_root();
2636 std::list<etl::handle<Instance> >::iterator iter;
2637 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2639 if((*iter)->get_canvas()==canvas)
2655 if(selected_instance)
2656 selected_instance->undo();
2662 if(selected_instance)
2663 selected_instance->redo();
2667 studio::App::get_base_path()
2669 return app_base_path_;