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
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
24 /* ========================================================================= */
26 /* === H E A D E R S ======================================================= */
45 #ifdef HAVE_SYS_ERRNO_H
46 #include <sys/errno.h>
48 #include <gtkmm/fileselection.h>
49 #include <gtkmm/dialog.h>
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/label.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/stockitem.h>
54 #include <gtkmm/iconsource.h>
55 #include <gtkmm/inputdialog.h>
56 #include <gtkmm/accelmap.h>
57 #include <gtkmm/uimanager.h>
58 #include <gtkmm/textview.h>
62 #include <gdkmm/general.h>
64 #include <synfig/loadcanvas.h>
65 #include <synfig/savecanvas.h>
71 #include "canvasview.h"
72 #include "dialog_setup.h"
73 #include "dialog_gradient.h"
74 #include "dialog_color.h"
77 #include "onemoment.h"
79 #include "dockmanager.h"
81 #include "state_eyedrop.h"
82 #include "state_normal.h"
83 #include "state_draw.h"
84 #include "state_fill.h"
85 #include "state_bline.h"
86 #include "state_polygon.h"
87 #include "state_sketch.h"
88 #include "state_gradient.h"
89 #include "state_circle.h"
90 #include "state_rectangle.h"
91 #include "state_smoothmove.h"
92 #include "state_scale.h"
93 #include "state_star.h"
94 #include "state_text.h"
95 #include "state_width.h"
96 #include "state_rotate.h"
97 #include "state_zoom.h"
99 #include "devicetracker.h"
100 #include "dialog_tooloptions.h"
101 #include "widget_enum.h"
103 #include "autorecover.h"
105 #include <synfigapp/settings.h>
106 #include "dock_history.h"
107 #include "dock_canvases.h"
108 #include "dock_keyframes.h"
109 #include "dock_layers.h"
110 #include "dock_params.h"
111 #include "dock_metadata.h"
112 #include "dock_children.h"
113 #include "dock_info.h"
114 #include "dock_navigator.h"
115 #include "dock_layergroups.h"
116 #include "dock_timetrack.h"
117 #include "dock_curves.h"
119 #include "mod_palette/mod_palette.h"
120 #include "mod_mirror/mod_mirror.h"
122 #include <sys/stat.h>
128 #include "statemanager.h"
134 #include <gtkmm/accelmap.h>
135 #include <gtkmm/filechooser.h>
136 #include <gtkmm/filechooserdialog.h>
142 /* === U S I N G =========================================================== */
146 using namespace synfig;
147 using namespace studio;
149 /* === M A C R O S ========================================================= */
151 #ifndef SYNFIG_USER_APP_DIR
153 #define SYNFIG_USER_APP_DIR "Library/Synfig"
154 #elif defined(_WIN32)
155 #define SYNFIG_USER_APP_DIR "Synfig"
157 #define SYNFIG_USER_APP_DIR ".synfig"
162 #define DPM2DPI(x) (float(x)/39.3700787402f)
163 #define DPI2DPM(x) (float(x)*39.3700787402f)
169 # define IMAGE_DIR "share\\pixmaps"
174 # define IMAGE_DIR "/usr/local/share/pixmaps"
178 # define IMAGE_EXT "tif"
181 #include <synfigapp/main.h>
183 /* === S I G N A L S ======================================================= */
185 static sigc::signal<void> signal_present_all_;
187 App::signal_present_all() { return signal_present_all_; }
189 static sigc::signal<void> signal_recent_files_changed_;
191 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
193 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
194 sigc::signal<void,etl::loose_handle<CanvasView> >&
195 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_selected() { return signal_instance_selected_; }
201 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
202 sigc::signal<void,etl::handle<Instance> >&
203 App::signal_instance_created() { return signal_instance_created_; }
205 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
206 sigc::signal<void,etl::handle<Instance> >&
207 App::signal_instance_deleted() { return signal_instance_deleted_; }
209 /* === G L O B A L S ======================================================= */
211 static std::list<std::string> recent_files;
212 const std::list<std::string>& App::get_recent_files() { return recent_files; }
214 static std::list<std::string> recent_files_window_size;
216 int App::Busy::count;
217 bool App::shutdown_in_progress;
219 synfig::Gamma App::gamma;
221 Glib::RefPtr<studio::UIManager> App::ui_manager_;
223 synfig::Distance::System App::distance_system;
225 studio::Dialog_Setup* App::dialog_setup;
227 etl::handle< studio::ModPalette > mod_palette_;
228 //studio::Dialog_Palette* App::dialog_palette;
230 std::list<etl::handle<Instance> > App::instance_list;
232 static etl::handle<synfigapp::UIInterface> ui_interface_;
233 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
235 etl::handle<Instance> App::selected_instance;
236 etl::handle<CanvasView> App::selected_canvas_view;
238 studio::About *studio::App::about=NULL;
240 studio::Toolbox *studio::App::toolbox=NULL;
242 studio::AutoRecover *studio::App::auto_recover=NULL;
244 studio::IPC *ipc=NULL;
246 studio::DockManager* studio::App::dock_manager=0;
248 studio::DeviceTracker* studio::App::device_tracker=0;
250 studio::Dialog_Gradient* studio::App::dialog_gradient;
252 studio::Dialog_Color* studio::App::dialog_color;
254 Gtk::InputDialog* studio::App::dialog_input;
256 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
258 studio::Dock_History* dock_history;
259 studio::Dock_Canvases* dock_canvases;
260 studio::Dock_Keyframes* dock_keyframes;
261 studio::Dock_Layers* dock_layers;
262 studio::Dock_Params* dock_params;
263 studio::Dock_MetaData* dock_meta_data;
264 studio::Dock_Children* dock_children;
265 studio::Dock_Info* dock_info;
266 studio::Dock_LayerGroups* dock_layer_groups;
267 studio::Dock_Navigator* dock_navigator;
268 studio::Dock_Timetrack* dock_timetrack;
269 studio::Dock_Curves* dock_curves;
271 std::list< etl::handle< studio::Module > > module_list_;
273 bool studio::App::use_colorspace_gamma=true;
274 #ifdef SINGLE_THREADED
275 bool studio::App::single_threaded=false;
277 bool studio::App::restrict_radius_ducks=false;
278 bool studio::App::resize_imported_images=false;
279 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
280 int studio::App::preferred_x_size=480;
281 int studio::App::preferred_y_size=270;
282 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
283 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
284 float studio::App::preferred_fps=24.0;
285 #ifdef USE_OPEN_FOR_URLS
286 String studio::App::browser_command("open"); // MacOS only
288 String studio::App::browser_command("xdg-open"); // Linux XDG standard
291 static int max_recent_files_=25;
292 int studio::App::get_max_recent_files() { return max_recent_files_; }
293 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
295 static synfig::String app_base_path_;
300 really_delete_widget(Gtk::Widget *widget)
302 // synfig::info("really delete %p", (void*)widget);
307 // nasty workaround - when we've finished with a popup menu, we want to delete it
308 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
309 // so schedule the real delete to happen in 50ms, giving the action a chance to run
311 delete_widget(Gtk::Widget *widget)
313 // synfig::info("delete %p", (void*)widget);
314 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
317 }; // END of namespace studio
318 studio::StateManager* state_manager;
323 class GlobalUIInterface : public synfigapp::UIInterface
327 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
332 true // use_separator
334 Gtk::Label label(message);
337 dialog.get_vbox()->pack_start(label);
338 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
339 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
341 dialog.set_default_response(dflt);
343 return (Response)dialog.run();
345 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
350 true // use_separator
352 Gtk::Label label(message);
355 dialog.get_vbox()->pack_start(label);
356 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
357 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
358 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
360 dialog.set_default_response(dflt);
362 return (Response)dialog.run();
364 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
369 true // use_separator
371 Gtk::Label label(message);
374 dialog.get_vbox()->pack_start(label);
375 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
376 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
378 dialog.set_default_response(dflt);
380 return (Response)dialog.run();
384 task(const std::string &task)
386 std::cerr<<task<<std::endl;
387 while(studio::App::events_pending())studio::App::iteration(false);
392 error(const std::string &err)
394 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
401 warning(const std::string &err)
403 std::cerr<<"warning: "<<err<<std::endl;
404 while(studio::App::events_pending())studio::App::iteration(false);
409 amount_complete(int /*current*/, int /*total*/)
411 while(studio::App::events_pending())studio::App::iteration(false);
416 /* === P R O C E D U R E S ================================================= */
420 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
422 action_group_list.push_back(action_group);
423 Gtk::UIManager::insert_action_group(action_group, pos);
427 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
429 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
430 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
431 if(*iter==action_group)
433 action_group_list.erase(iter);
434 Gtk::UIManager::remove_action_group(action_group);
437 synfig::error("Unable to find action group");
441 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
443 ui_manager->insert_action_group(group,0);
445 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
446 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
448 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
450 if(*iter && (*iter)->get_name()!="menus")
452 synfig::info("Removing action group "+(*iter)->get_name());
453 ui_manager->remove_action_group(*iter);
456 ui_manager->insert_action_group(group,0);
458 for(;!prev_groups.empty();prev_groups.pop_front())
460 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
461 ui_manager->insert_action_group(prev_groups.front(),1);
465 class Preferences : public synfigapp::Settings
468 virtual bool get_value(const synfig::String& key, synfig::String& value)const
472 value=strprintf("%f %f %f %f",
473 App::gamma.get_gamma_r(),
474 App::gamma.get_gamma_g(),
475 App::gamma.get_gamma_b(),
476 App::gamma.get_black_level()
480 if(key=="time_format")
482 value=strprintf("%i",App::get_time_format());
485 if(key=="file_history.size")
487 value=strprintf("%i",App::get_max_recent_files());
490 if(key=="use_colorspace_gamma")
492 value=strprintf("%i",(int)App::use_colorspace_gamma);
495 if(key=="distance_system")
497 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
500 #ifdef SINGLE_THREADED
501 if(key=="single_threaded")
503 value=strprintf("%i",(int)App::single_threaded);
507 if(key=="auto_recover_backup_interval")
509 value=strprintf("%i",App::auto_recover->get_timeout());
512 if(key=="restrict_radius_ducks")
514 value=strprintf("%i",(int)App::restrict_radius_ducks);
517 if(key=="resize_imported_images")
519 value=strprintf("%i",(int)App::resize_imported_images);
522 if(key=="browser_command")
524 value=App::browser_command;
527 if(key=="custom_filename_prefix")
529 value=App::custom_filename_prefix;
532 if(key=="preferred_x_size")
534 value=strprintf("%i",App::preferred_x_size);
537 if(key=="preferred_y_size")
539 value=strprintf("%i",App::preferred_y_size);
542 if(key=="predefined_size")
544 value=strprintf("%s",App::predefined_size.c_str());
547 if(key=="preferred_fps")
549 value=strprintf("%f",App::preferred_fps);
552 if(key=="predefined_fps")
554 value=strprintf("%s",App::predefined_fps.c_str());
558 return synfigapp::Settings::get_value(key,value);
561 virtual bool set_value(const synfig::String& key,const synfig::String& value)
567 strscanf(value,"%f %f %f %f",
574 App::gamma.set_all(r,g,b,blk);
578 if(key=="time_format")
580 int i(atoi(value.c_str()));
581 App::set_time_format(static_cast<synfig::Time::Format>(i));
584 if(key=="auto_recover_backup_interval")
586 int i(atoi(value.c_str()));
587 App::auto_recover->set_timeout(i);
590 if(key=="file_history.size")
592 int i(atoi(value.c_str()));
593 App::set_max_recent_files(i);
596 if(key=="use_colorspace_gamma")
598 int i(atoi(value.c_str()));
599 App::use_colorspace_gamma=i;
602 if(key=="distance_system")
604 App::distance_system=Distance::ident_system(value);;
607 #ifdef SINGLE_THREADED
608 if(key=="single_threaded")
610 int i(atoi(value.c_str()));
611 App::single_threaded=i;
615 if(key=="restrict_radius_ducks")
617 int i(atoi(value.c_str()));
618 App::restrict_radius_ducks=i;
621 if(key=="resize_imported_images")
623 int i(atoi(value.c_str()));
624 App::resize_imported_images=i;
627 if(key=="browser_command")
629 App::browser_command=value;
632 if(key=="custom_filename_prefix")
634 App::custom_filename_prefix=value;
637 if(key=="preferred_x_size")
639 int i(atoi(value.c_str()));
640 App::preferred_x_size=i;
643 if(key=="preferred_y_size")
645 int i(atoi(value.c_str()));
646 App::preferred_y_size=i;
649 if(key=="predefined_size")
651 App::predefined_size=value;
654 if(key=="preferred_fps")
656 float i(atof(value.c_str()));
657 App::preferred_fps=i;
660 if(key=="predefined_fps")
662 App::predefined_fps=value;
666 return synfigapp::Settings::set_value(key,value);
669 virtual KeyList get_key_list()const
671 KeyList ret(synfigapp::Settings::get_key_list());
672 ret.push_back("gamma");
673 ret.push_back("time_format");
674 ret.push_back("distance_system");
675 ret.push_back("file_history.size");
676 ret.push_back("use_colorspace_gamma");
677 #ifdef SINGLE_THREADED
678 ret.push_back("single_threaded");
680 ret.push_back("auto_recover_backup_interval");
681 ret.push_back("restrict_radius_ducks");
682 ret.push_back("resize_imported_images");
683 ret.push_back("browser_command");
684 ret.push_back("custom_filename_prefix");
685 ret.push_back("preferred_x_size");
686 ret.push_back("preferred_y_size");
687 ret.push_back("predefined_size");
688 ret.push_back("preferred_fps");
689 ret.push_back("predefined_fps");
694 static ::Preferences _preferences;
699 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
701 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
703 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
705 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
706 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
707 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
708 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
709 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
710 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
711 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
712 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
713 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
714 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
715 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
716 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
717 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
719 // Add the synfigapp actions...
720 synfigapp::Action::Book::iterator iter;
721 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
723 actions_action_group->add(Gtk::Action::create(
724 "action-"+iter->second.name,
725 get_action_stock_id(iter->second),
726 iter->second.local_name,iter->second.local_name
730 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
731 #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); }
732 #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); }
734 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
735 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
736 DEFINE_ACTION("new", Gtk::Stock::NEW);
737 DEFINE_ACTION("open", Gtk::Stock::OPEN);
738 DEFINE_ACTION("save", Gtk::Stock::SAVE);
739 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
740 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
741 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
742 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
743 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
744 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
745 DEFINE_ACTION("import", _("Import"));
746 DEFINE_ACTION("render", _("Render"));
747 DEFINE_ACTION("preview", _("Preview"));
748 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
749 DEFINE_ACTION("sound", _("Sound File"));
750 DEFINE_ACTION("options", _("Options"));
751 DEFINE_ACTION("close", _("Close View"));
752 DEFINE_ACTION("close-document", _("Close Document"));
753 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
756 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
757 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
758 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
759 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
760 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
761 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
762 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
763 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
764 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
765 DEFINE_ACTION("properties", _("Properties"));
767 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
768 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
769 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
770 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
771 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
772 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
773 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
774 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
775 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
776 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
777 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
778 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
779 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
780 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
781 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
782 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
783 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
784 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
785 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
786 DEFINE_ACTION("play", _("Play"));
787 // DEFINE_ACTION("pause", _("Pause"));
788 DEFINE_ACTION("stop", _("Stop"));
789 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
790 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
791 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
792 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
793 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
794 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
795 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
796 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
797 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
798 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
799 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
800 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
801 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
802 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
803 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
804 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
805 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
806 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
807 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
808 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
809 DEFINE_ACTION("seek-end", _("Seek to End"));
811 DEFINE_ACTION("action-group_add", _("Add group"));
813 DEFINE_ACTION("canvas-new", _("New Canvas"));
815 DEFINE_ACTION("amount-inc", _("Increase Amount"));
816 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
821 // Set up synfigapp actions
823 synfigapp::Action::Book::iterator iter;
825 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
827 Gtk::StockID stock_id;
829 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
831 //Gtk::Image* image(manage(new Gtk::Image()));
832 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
833 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
834 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
835 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
836 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
837 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
838 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
839 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
840 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
841 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
843 actions_action_group->add(Gtk::Action::create(
844 "action-"+iter->second.name,
846 iter->second.local_name,iter->second.local_name
854 Glib::ustring ui_info =
856 " <popup name='menu-toolbox' action='menu-toolbox'>"
857 " <menu action='menu-file'>"
860 " <popup name='menu-main' action='menu-main'>"
861 " <menu action='menu-file'>"
862 " <menuitem action='new' />"
863 " <menuitem action='open' />"
864 " <menuitem action='save' />"
865 " <menuitem action='save-as' />"
866 " <menuitem action='revert' />"
867 " <separator name='bleh01'/>"
868 " <menuitem action='cvs-add' />"
869 " <menuitem action='cvs-update' />"
870 " <menuitem action='cvs-commit' />"
871 " <menuitem action='cvs-revert' />"
872 " <separator name='bleh02'/>"
873 " <menuitem action='import' />"
874 " <separator name='bleh03'/>"
875 " <menuitem action='render' />"
876 " <menuitem action='preview' />"
877 " <menuitem action='sound' />"
878 " <separator name='bleh04'/>"
879 " <menuitem action='options' />"
880 " <menuitem action='close' />"
881 " <menuitem action='close-document' />"
882 " <menuitem action='quit' />"
884 " <menu action='menu-edit'>"
885 " <menuitem action='undo'/>"
886 " <menuitem action='redo'/>"
887 " <separator name='bleh05'/>"
888 " <menuitem action='cut'/>"
889 " <menuitem action='copy'/>"
890 " <menuitem action='paste'/>"
891 " <separator name='bleh06'/>"
892 " <menuitem action='select-all-layers'/>"
893 " <menuitem action='unselect-all-layers'/>"
894 " <menuitem action='select-all-ducks'/>"
895 " <menuitem action='unselect-all-ducks'/>"
896 " <separator name='bleh07'/>"
897 " <menuitem action='properties'/>"
899 " <menu action='menu-view'>"
900 " <menu action='menu-duck-mask'>"
901 " <menuitem action='mask-position-ducks' />"
902 " <menuitem action='mask-vertex-ducks' />"
903 " <menuitem action='mask-tangent-ducks' />"
904 " <menuitem action='mask-radius-ducks' />"
905 " <menuitem action='mask-width-ducks' />"
906 " <menuitem action='mask-angle-ducks' />"
908 " <menu action='menu-preview-quality'>"
909 " <menuitem action='quality-00' />"
910 " <menuitem action='quality-01' />"
911 " <menuitem action='quality-02' />"
912 " <menuitem action='quality-03' />"
913 " <menuitem action='quality-04' />"
914 " <menuitem action='quality-05' />"
915 " <menuitem action='quality-06' />"
916 " <menuitem action='quality-07' />"
917 " <menuitem action='quality-08' />"
918 " <menuitem action='quality-09' />"
919 " <menuitem action='quality-10' />"
921 " <menu action='menu-lowres-pixel'>"
922 " <menuitem action='decrease-low-res-pixel-size'/>"
923 " <menuitem action='increase-low-res-pixel-size'/>"
924 " <separator name='pixel-size-separator'/>"
927 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
928 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
932 " <separator name='bleh08'/>"
933 " <menuitem action='play'/>"
934 //" <menuitem action='pause'/>"
935 " <menuitem action='stop'/>"
936 " <menuitem action='dialog-flipbook'/>"
937 " <separator name='bleh09'/>"
938 " <menuitem action='toggle-grid-show'/>"
939 " <menuitem action='toggle-grid-snap'/>"
940 " <menuitem action='toggle-guide-show'/>"
941 " <menuitem action='toggle-low-res'/>"
942 " <menuitem action='toggle-onion-skin'/>"
943 " <separator name='bleh10'/>"
944 " <menuitem action='canvas-zoom-in'/>"
945 " <menuitem action='canvas-zoom-out'/>"
946 " <menuitem action='canvas-zoom-fit'/>"
947 " <menuitem action='canvas-zoom-100'/>"
948 " <separator name='bleh11'/>"
949 " <menuitem action='time-zoom-in'/>"
950 " <menuitem action='time-zoom-out'/>"
951 " <separator name='bleh12'/>"
952 " <menuitem action='jump-next-keyframe'/>"
953 " <menuitem action='jump-prev-keyframe'/>"
954 " <menuitem action='seek-next-frame'/>"
955 " <menuitem action='seek-prev-frame'/>"
956 " <menuitem action='seek-next-second'/>"
957 " <menuitem action='seek-prev-second'/>"
958 " <menuitem action='seek-begin'/>"
959 " <menuitem action='seek-end'/>"
961 " <menu action='menu-canvas'>"
962 " <menuitem action='canvas-new'/>"
964 " <menu name='menu-state' action='menu-state'>"
966 " <menu action='menu-group'>"
967 " <menuitem action='action-group_add'/>"
969 " <menu action='menu-layer'>"
970 //" <menuitem action='cut'/>"
971 //" <menuitem action='copy'/>"
972 //" <menuitem action='paste'/>"
973 //" <separator name='bleh06'/>"
974 " <menu action='menu-layer-new'></menu>"
975 " <menuitem action='amount-inc'/>"
976 " <menuitem action='amount-dec'/>"
978 " <menu action='menu-keyframe'>"
979 " <menuitem action='keyframe-properties'/>"
986 " <menubar name='MenuBar'>"
987 " <menu action='MenuFile'>"
988 " <menuitem action='New'/>"
989 " <menuitem action='Open'/>"
991 " <menuitem action='Quit'/>"
993 " <menu action='MenuEdit'>"
994 " <menuitem action='Cut'/>"
995 " <menuitem action='Copy'/>"
996 " <menuitem action='Paste'/>"
999 " <toolbar name='ToolBar'>"
1000 " <toolitem action='Open'/>"
1001 " <toolitem action='Quit'/>"
1007 actions_action_group->set_sensitive(false);
1008 App::ui_manager()->set_add_tearoffs(true);
1009 App::ui_manager()->insert_action_group(menus_action_group,1);
1010 App::ui_manager()->insert_action_group(actions_action_group,1);
1011 App::ui_manager()->add_ui_from_string(ui_info);
1013 //App::ui_manager()->get_accel_group()->unlock();
1015 catch(const Glib::Error& ex)
1017 synfig::error("building menus and toolbars failed: " + ex.what());
1020 // Add default keyboard accelerators
1021 #define ACCEL(accel,path) \
1023 Gtk::AccelKey accel_key(accel,path); \
1024 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1027 #define ACCEL2(accel) \
1029 Gtk::AccelKey accel_key(accel); \
1030 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1034 ACCEL("<Mod1>a", "<Actions>//state-normal" );
1035 ACCEL("<Mod1>v", "<Actions>//state-smooth_move" );
1036 ACCEL("<Mod1>s", "<Actions>//state-scale" );
1037 ACCEL("<Mod1>t", "<Actions>//state-rotate" );
1038 ACCEL("<Mod1>m", "<Actions>//state-mirror" );
1039 ACCEL("<Mod1>c", "<Actions>//state-circle" );
1040 ACCEL("<Mod1>r", "<Actions>//state-rectangle" );
1041 ACCEL("<Mod1>q", "<Actions>//state-star" );
1042 ACCEL("<Mod1>g", "<Actions>//state-gradient" );
1043 ACCEL("<Mod1>p", "<Actions>//state-polygon" );
1044 ACCEL("<Mod1>b", "<Actions>//state-bline" );
1045 ACCEL("<Mod1>x", "<Actions>//state-text" );
1046 ACCEL("<Mod1>f", "<Actions>//state-fill" );
1047 ACCEL("<Mod1>e", "<Actions>//state-eyedrop" );
1048 ACCEL("<Mod1>z", "<Actions>//state-zoom" );
1049 ACCEL("<Mod1>d", "<Actions>//state-draw" );
1050 ACCEL("<Mod1>k", "<Actions>//state-sketch" );
1051 ACCEL("<Mod1>w", "<Actions>//state-width" );
1054 ACCEL("<Control>a", "<Actions>//select-all-ducks" );
1055 ACCEL("<Control>d", "<Actions>//unselect-all-ducks" );
1056 ACCEL("<Control><Shift>a", "<Actions>//select-all-layers" );
1057 ACCEL("<Control><Shift>d", "<Actions>//unselect-all-layers" );
1058 ACCEL("F9", "<Actions>//render" );
1059 ACCEL("F11", "<Actions>//preview" );
1060 ACCEL("F8", "<Actions>//properties" );
1061 ACCEL("F12", "<Actions>//options" );
1062 ACCEL("<control>i", "<Actions>//import" );
1063 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>//stop" ));
1064 ACCEL("<Control>g", "<Actions>//toggle-grid-show" );
1065 ACCEL("<Control>l", "<Actions>//toggle-grid-snap" );
1066 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>//toggle-low-res" ));
1067 ACCEL("<Mod1>1", "<Actions>//mask-position-ducks" );
1068 ACCEL("<Mod1>2", "<Actions>//mask-vertex-ducks" );
1069 ACCEL("<Mod1>3", "<Actions>//mask-tangent-ducks" );
1070 ACCEL("<Mod1>4", "<Actions>//mask-radius-ducks" );
1071 ACCEL("<Mod1>5", "<Actions>//mask-width-ducks" );
1072 ACCEL("<Mod1>6", "<Actions>//mask-angle-ducks" );
1073 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>//action-LayerRaise" ));
1074 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>//action-LayerLower" ));
1075 ACCEL("<Control>1", "<Actions>//quality-01" );
1076 ACCEL("<Control>2", "<Actions>//quality-02" );
1077 ACCEL("<Control>3", "<Actions>//quality-03" );
1078 ACCEL("<Control>4", "<Actions>//quality-04" );
1079 ACCEL("<Control>5", "<Actions>//quality-05" );
1080 ACCEL("<Control>6", "<Actions>//quality-06" );
1081 ACCEL("<Control>7", "<Actions>//quality-07" );
1082 ACCEL("<Control>8", "<Actions>//quality-08" );
1083 ACCEL("<Control>9", "<Actions>//quality-09" );
1084 ACCEL("<Control>0", "<Actions>//quality-10" );
1085 ACCEL("<Control>z", "<Actions>//undo" );
1086 ACCEL("<Control>r", "<Actions>//redo" );
1087 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>//action-LayerRemove" ));
1088 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>//decrease-low-res-pixel-size" ));
1089 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>//increase-low-res-pixel-size" ));
1090 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>//amount-dec" ));
1091 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>//amount-inc" ));
1092 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>//jump-next-keyframe" ));
1093 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>//jump-prev-keyframe" ));
1094 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>//canvas-zoom-in" ));
1095 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>//canvas-zoom-out" ));
1096 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>//time-zoom-in" ));
1097 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>//time-zoom-out" ));
1098 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>//seek-next-frame" ));
1099 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>//seek-prev-frame" ));
1100 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>//seek-next-second" ));
1101 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>//seek-prev-second" ));
1102 ACCEL("<Mod1>o", "<Actions>//toggle-onion-skin" );
1103 ACCEL("<Control><Shift>z", "<Actions>//canvas-zoom-fit" );
1104 ACCEL("<Control>p", "<Actions>//play" );
1105 ACCEL("Home", "<Actions>//seek-begin" );
1106 ACCEL("End", "<Actions>//seek-end" );
1112 #define mkdir(x,y) mkdir(x)
1115 /* === M E T H O D S ======================================================= */
1117 App::App(int *argc, char ***argv):
1118 Gtk::Main(argc,argv),
1119 IconController(etl::dirname((*argv)[0]))
1121 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1124 ui_interface_=new GlobalUIInterface();
1128 // don't call thread_init() if threads are already initialized
1129 // on some machines bonobo_init() initialized threads before we get here
1130 if (!g_thread_supported())
1131 Glib::thread_init();
1133 distance_system=Distance::SYSTEM_UNITS;
1135 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1138 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1142 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1148 if(!SYNFIG_CHECK_VERSION())
1150 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1151 dialog_error_blocking("Synfig Studio",
1152 "This copy of Synfig Studio was compiled against a\n"
1153 "different version of libsynfig than what is currently\n"
1154 "installed. Synfig Studio will now abort. Try downloading\n"
1155 "the latest version from the Synfig website at\n"
1156 "http://synfig.org/Download"
1160 Glib::set_application_name(_("Synfig Studio"));
1162 Splash splash_screen;
1163 splash_screen.show();
1165 shutdown_in_progress=false;
1166 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1167 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1169 // Initialize the Synfig library
1170 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1171 catch(std::runtime_error x)
1173 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1178 get_ui_interface()->error(_("Failed to initialize synfig!"));
1182 // add the preferences to the settings
1183 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1187 studio_init_cb.task(_("Init UI Manager..."));
1188 App::ui_manager_=studio::UIManager::create();
1191 studio_init_cb.task(_("Init Dock Manager..."));
1192 dock_manager=new studio::DockManager();
1194 studio_init_cb.task(_("Init State Manager..."));
1195 state_manager=new StateManager();
1197 studio_init_cb.task(_("Init Toolbox..."));
1198 toolbox=new studio::Toolbox();
1200 studio_init_cb.task(_("Init About Dialog..."));
1201 about=new studio::About();
1203 studio_init_cb.task(_("Init Tool Options..."));
1204 dialog_tool_options=new studio::Dialog_ToolOptions();
1205 dock_manager->register_dockable(*dialog_tool_options);
1207 studio_init_cb.task(_("Init History..."));
1208 dock_history=new studio::Dock_History();
1209 dock_manager->register_dockable(*dock_history);
1211 studio_init_cb.task(_("Init Canvases..."));
1212 dock_canvases=new studio::Dock_Canvases();
1213 dock_manager->register_dockable(*dock_canvases);
1215 studio_init_cb.task(_("Init Keyframes..."));
1216 dock_keyframes=new studio::Dock_Keyframes();
1217 dock_manager->register_dockable(*dock_keyframes);
1219 studio_init_cb.task(_("Init Layers..."));
1220 dock_layers=new studio::Dock_Layers();
1221 dock_manager->register_dockable(*dock_layers);
1223 studio_init_cb.task(_("Init Params..."));
1224 dock_params=new studio::Dock_Params();
1225 dock_manager->register_dockable(*dock_params);
1227 studio_init_cb.task(_("Init MetaData..."));
1228 dock_meta_data=new studio::Dock_MetaData();
1229 dock_manager->register_dockable(*dock_meta_data);
1231 studio_init_cb.task(_("Init Children..."));
1232 dock_children=new studio::Dock_Children();
1233 dock_manager->register_dockable(*dock_children);
1235 studio_init_cb.task(_("Init Info..."));
1236 dock_info = new studio::Dock_Info();
1237 dock_manager->register_dockable(*dock_info);
1239 studio_init_cb.task(_("Init Navigator..."));
1240 dock_navigator = new studio::Dock_Navigator();
1241 dock_manager->register_dockable(*dock_navigator);
1243 studio_init_cb.task(_("Init Timetrack..."));
1244 dock_timetrack = new studio::Dock_Timetrack();
1245 dock_manager->register_dockable(*dock_timetrack);
1247 studio_init_cb.task(_("Init Curve Editor..."));
1248 dock_curves = new studio::Dock_Curves();
1249 dock_manager->register_dockable(*dock_curves);
1251 studio_init_cb.task(_("Init Layer Groups..."));
1252 dock_layer_groups = new studio::Dock_LayerGroups();
1253 dock_manager->register_dockable(*dock_layer_groups);
1256 studio_init_cb.task(_("Init Color Dialog..."));
1257 dialog_color=new studio::Dialog_Color();
1259 studio_init_cb.task(_("Init Gradient Dialog..."));
1260 dialog_gradient=new studio::Dialog_Gradient();
1262 studio_init_cb.task(_("Init DeviceTracker..."));
1263 device_tracker=new studio::DeviceTracker();
1265 studio_init_cb.task(_("Init Tools..."));
1268 state_manager->add_state(&state_normal);
1269 state_manager->add_state(&state_smooth_move);
1270 state_manager->add_state(&state_scale);
1271 state_manager->add_state(&state_rotate);
1272 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1275 state_manager->add_state(&state_circle);
1276 state_manager->add_state(&state_rectangle);
1277 state_manager->add_state(&state_star);
1278 state_manager->add_state(&state_gradient);
1279 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1282 state_manager->add_state(&state_bline);
1283 state_manager->add_state(&state_text);
1284 state_manager->add_state(&state_fill);
1285 state_manager->add_state(&state_eyedrop);
1286 state_manager->add_state(&state_zoom);
1288 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1289 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1290 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1292 studio_init_cb.task(_("Init ModPalette..."));
1293 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1295 studio_init_cb.task(_("Init Setup Dialog..."));
1296 dialog_setup=new studio::Dialog_Setup();
1298 studio_init_cb.task(_("Init Input Dialog..."));
1299 dialog_input=new Gtk::InputDialog();
1300 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1301 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1303 studio_init_cb.task(_("Init auto recovery..."));
1304 auto_recover=new AutoRecover();
1306 studio_init_cb.amount_complete(9250,10000);
1307 studio_init_cb.task(_("Loading Settings..."));
1309 device_tracker->load_preferences();
1311 studio_init_cb.task(_("Checking auto-recover..."));
1313 studio_init_cb.amount_complete(9900,10000);
1315 bool opened_any = false;
1316 if(auto_recover->recovery_needed())
1318 splash_screen.hide();
1319 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1320 _("Synfig Studio seems to have crashed\n"
1321 "before you could save all your files.\n"
1322 "Would you like to re-open those files\n"
1323 "and recover your unsaved changes?")) ==
1324 synfigapp::UIInterface::RESPONSE_YES)
1326 int number_recovered;
1327 if(!auto_recover->recover(number_recovered))
1328 if (number_recovered)
1329 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1331 get_ui_interface()->error(_("Unable to recover from previous crash"));
1333 get_ui_interface()->error(
1334 _("Synfig Studio has attempted to recover\n"
1335 "from a previous crash. The files that it has\n"
1336 "recovered are NOT YET SAVED. It would be a good\n"
1337 "idea to review them and save them now."));
1339 if (number_recovered)
1342 splash_screen.show();
1345 // Look for any files given on the command line,
1346 // and load them if found.
1347 for(;*argc>=1;(*argc)--)
1348 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1350 studio_init_cb.task(_("Loading files..."));
1351 splash_screen.hide();
1352 open((*argv)[*argc]);
1354 splash_screen.show();
1357 // if no file was specified to be opened, create a new document to help new users get started more easily
1358 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1361 studio_init_cb.task(_("Done."));
1362 studio_init_cb.amount_complete(10000,10000);
1368 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1372 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1376 StateManager* App::get_state_manager() { return state_manager; }
1380 shutdown_in_progress=true;
1384 synfigapp::Main::settings().remove_domain("pref");
1386 selected_instance=0;
1388 // Unload all of the modules
1389 for(;!module_list_.empty();module_list_.pop_back())
1392 delete state_manager;
1396 delete auto_recover;
1402 // studio::App::iteration(false);
1406 // studio::App::iteration(false);
1408 // studio::App::iteration(false);
1410 delete dialog_setup;
1412 delete dialog_gradient;
1414 delete dialog_color;
1416 delete dialog_input;
1418 delete dock_manager;
1420 instance_list.clear();
1422 // studio::App::iteration(false);
1426 App::get_user_app_directory()
1428 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1430 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1432 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1437 App::get_config_file(const synfig::String& file)
1439 return Glib::build_filename(get_user_app_directory(),file);
1442 #define SCALE_FACTOR (1280)
1443 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1445 App::set_recent_file_window_size(etl::handle<Instance> instance)
1447 int screen_w(Gdk::screen_width());
1448 int screen_h(Gdk::screen_height());
1450 const std::string &canvas_window_size = *recent_files_window_size.begin();
1452 if(canvas_window_size.empty())
1455 synfig::String::size_type current=0;
1456 bool seen_root(false), shown_non_root(false);
1458 while(current != synfig::String::npos)
1460 // find end of first field (canvas) or return
1461 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1462 if(separator == synfig::String::npos) break;
1465 synfig::Canvas::Handle canvas;
1468 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1470 catch(Exception::IDNotFound) {
1471 // can't find the canvas; skip to the next canvas or return
1472 separator = canvas_window_size.find_first_of('\t', current);
1473 if(separator == synfig::String::npos) return;
1474 current = separator+1;
1478 if (canvas->is_root())
1481 shown_non_root = true;
1483 // check that we have the tab character the ends this canvas' data or return
1484 current = separator+1;
1485 separator = canvas_window_size.find_first_of('\t', current);
1486 if(separator == synfig::String::npos) return;
1489 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1491 current = separator+1;
1495 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1496 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1497 x=x*screen_w/SCALE_FACTOR;
1498 y=y*screen_h/SCALE_FACTOR;
1499 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1500 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1501 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1502 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1504 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1505 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1507 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1508 canvasview->move(x,y);
1509 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1510 canvasview->present();
1512 current = separator+1;
1515 if (shown_non_root && !seen_root)
1516 instance->find_canvas_view(instance->get_canvas())->hide();
1520 App::add_recent_file(const etl::handle<Instance> instance)
1522 int screen_w(Gdk::screen_width());
1523 int screen_h(Gdk::screen_height());
1525 std::string canvas_window_size;
1527 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1528 Instance::CanvasViewList::const_iterator iter;
1530 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1532 if( !((*iter)->is_visible()) )
1535 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1536 int x_pos, y_pos, x_size, y_size;
1537 (*iter)->get_position(x_pos,y_pos);
1538 (*iter)->get_size(x_size,y_size);
1540 canvas_window_size += strprintf("%s %d %d %d %d\t",
1541 canvas->get_relative_id(canvas->get_root()).c_str(),
1542 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1543 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1546 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1551 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1553 std::string filename(file_name);
1555 assert(!filename.empty());
1557 if(filename.empty())
1560 // Toss out any "hidden" files
1561 if(basename(filename)[0]=='.')
1564 // If we aren't an absolute path, turn ourselves into one
1565 if(!is_absolute_path(filename))
1566 filename=absolute_path(filename);
1568 std::string old_window_size;
1570 list<string>::iterator iter;
1571 list<string>::iterator iter_wsize;
1572 // Check to see if the file is already on the list.
1573 // If it is, then remove it from the list
1574 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1577 recent_files.erase(iter);
1578 old_window_size = *iter_wsize;
1579 recent_files_window_size.erase(iter_wsize);
1584 // Push the filename to the front of the list
1585 recent_files.push_front(filename);
1586 if(window_size.empty())
1587 recent_files_window_size.push_front(old_window_size);
1589 recent_files_window_size.push_front(window_size);
1591 // Clean out the files at the end of the list.
1592 while(recent_files.size()>(unsigned)get_max_recent_files())
1594 recent_files.pop_back();
1595 recent_files_window_size.pop_back();
1598 signal_recent_files_changed_();
1603 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1606 App::get_time_format()
1608 return _App_time_format;
1612 App::set_time_format(synfig::Time::Format x)
1619 App::save_settings()
1624 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1625 setlocale(LC_NUMERIC, "C");
1627 std::string filename=get_config_file("accelrc");
1628 Gtk::AccelMap::save(filename);
1631 std::string filename=get_config_file("recentfiles");
1633 std::ofstream file(filename.c_str());
1637 synfig::warning("Unable to save %s",filename.c_str());
1641 list<string>::reverse_iterator iter;
1643 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1647 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1649 std::ofstream file(filename.c_str());
1653 synfig::warning("Unable to save %s",filename.c_str());
1657 list<string>::reverse_iterator iter;
1659 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1663 std::string filename=get_config_file("settings");
1664 synfigapp::Main::settings().save_to_file(filename);
1665 setlocale(LC_NUMERIC,old_locale);
1669 synfig::warning("Caught exception when attempting to save settings.");
1674 App::load_settings()
1679 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1680 setlocale(LC_NUMERIC, "C");
1682 std::string filename=get_config_file("accelrc");
1683 Gtk::AccelMap::load(filename);
1686 bool window_size_broken = false;
1688 std::string filename=get_config_file("recentfiles");
1689 std::string filename_window_size=filename+std::string("_window_size");
1691 std::ifstream file(filename.c_str());
1692 std::ifstream file_window_size(filename_window_size.c_str());
1694 if(!file_window_size)
1695 window_size_broken = true;
1699 std::string recent_file;
1700 std::string recent_file_window_size;
1701 getline(file,recent_file);
1702 if(!window_size_broken)
1703 getline(file_window_size,recent_file_window_size);
1704 if(!recent_file.empty())
1706 if(!window_size_broken && !file_window_size)
1707 window_size_broken = true;
1708 if (std::ifstream(recent_file.c_str()))
1710 if(!window_size_broken)
1711 add_recent_file(recent_file,recent_file_window_size);
1713 add_recent_file(recent_file);
1717 if(!window_size_broken && file_window_size)
1718 window_size_broken = true;
1720 if(window_size_broken)
1722 recent_files_window_size.clear();
1723 recent_files_window_size.resize(recent_files.size());
1726 std::string filename=get_config_file("settings");
1727 if(!synfigapp::Main::settings().load_from_file(filename))
1729 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1730 //if(!synfigapp::Main::settings().load_from_file(filename))
1732 gamma.set_gamma(1.0/2.2);
1733 reset_initial_window_configuration();
1736 setlocale(LC_NUMERIC,old_locale);
1740 synfig::warning("Caught exception when attempting to load settings.");
1745 App::reset_initial_window_configuration()
1747 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1748 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1749 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1750 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1751 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1752 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1753 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1754 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1755 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1756 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1757 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1758 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1759 #ifdef SINGLE_THREADED
1760 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1762 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1763 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1764 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1765 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1766 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1767 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1768 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1769 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1770 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1774 App::shutdown_request(GdkEventAny*)
1778 //return !shutdown_in_progress;
1784 if(shutdown_in_progress)return;
1787 get_ui_interface()->task(_("Quit Request"));
1790 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1794 std::list<etl::handle<Instance> >::iterator iter;
1795 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1797 if(!(*iter)->safe_close())
1801 if((*iter)->synfigapp::Instance::get_action_count())
1803 handle<synfigapp::UIInterface> uim;
1804 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1806 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1807 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1809 case synfigapp::UIInterface::RESPONSE_NO:
1811 case synfigapp::UIInterface::RESPONSE_YES:
1814 case synfigapp::UIInterface::RESPONSE_CANCEL:
1823 if((*iter)->synfigapp::Instance::is_modified())
1825 handle<synfigapp::UIInterface> uim;
1826 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1828 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() );
1829 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1831 case synfigapp::UIInterface::RESPONSE_NO:
1833 case synfigapp::UIInterface::RESPONSE_YES:
1834 (*iter)->dialog_cvs_commit();
1836 case synfigapp::UIInterface::RESPONSE_CANCEL:
1845 // This next line causes things to crash for some reason
1849 shutdown_in_progress=true;
1851 instance_list.clear();
1853 while(studio::App::events_pending())studio::App::iteration(false);
1856 auto_recover->normal_shutdown();
1858 get_ui_interface()->task(_("Quit Request sent"));
1864 dialog_setup->refresh();
1865 dialog_setup->show();
1868 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1869 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1872 //#define USE_WIN32_FILE_DIALOGS 1
1875 #ifdef USE_WIN32_FILE_DIALOGS
1876 static OPENFILENAME ofn={};
1880 #include <gdk/gdkwin32.h>
1884 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1886 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1888 #ifdef USE_WIN32_FILE_DIALOGS
1889 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1891 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1892 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1893 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1895 ofn.lStructSize=sizeof(OPENFILENAME);
1896 ofn.hwndOwner = hWnd;
1897 ofn.hInstance = hInstance;
1898 ofn.lpstrFilter = szFilter;
1899 // ofn.lpstrCustomFilter=NULL;
1900 // ofn.nMaxCustFilter=0;
1901 // ofn.nFilterIndex=0;
1902 // ofn.lpstrFile=NULL;
1903 ofn.nMaxFile=MAX_PATH;
1904 // ofn.lpstrFileTitle=NULL;
1905 // ofn.lpstrInitialDir=NULL;
1906 // ofn.lpstrTitle=NULL;
1907 ofn.Flags=OFN_HIDEREADONLY;
1908 // ofn.nFileOffset=0;
1909 // ofn.nFileExtension=0;
1910 ofn.lpstrDefExt=TEXT("sif");
1911 // ofn.lCustData = 0l;
1913 // ofn.lpTemplateName=NULL;
1915 CHAR szFilename[MAX_PATH];
1917 strcpy(szFilename,filename.c_str());
1918 strcpy(szTitle,title.c_str());
1920 ofn.lpstrFile=szFilename;
1921 ofn.lpstrFileTitle=szTitle;
1923 if(GetOpenFileName(&ofn))
1925 filename=szFilename;
1931 synfig::String prev_path;
1933 if(!_preferences.get_value(preference, prev_path))
1936 prev_path = absolute_path(prev_path);
1938 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1940 dialog->set_current_folder(prev_path);
1941 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1942 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1944 if (filename.empty())
1945 dialog->set_filename(prev_path);
1946 else if (is_absolute_path(filename))
1947 dialog->set_filename(filename);
1949 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1951 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1952 filename = dialog->get_filename();
1953 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1954 _preferences.set_value(preference, dirname(filename));
1968 GtkWidget *fileselection;
1969 fileselection = gtk_file_selection_new(title.c_str());
1972 if(basename(filename)==filename)
1974 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1977 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1979 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1981 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1982 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1984 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1985 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1987 gtk_widget_show(fileselection);
1995 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1996 _preferences.set_value(preference,dirname(filename));
2000 gtk_widget_destroy(fileselection);
2003 gtk_widget_destroy(fileselection);
2010 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2012 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2014 #if USE_WIN32_FILE_DIALOGS
2015 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2017 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2018 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2019 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2021 ofn.lStructSize=sizeof(OPENFILENAME);
2022 ofn.hwndOwner = hWnd;
2023 ofn.hInstance = hInstance;
2024 ofn.lpstrFilter = szFilter;
2025 // ofn.lpstrCustomFilter=NULL;
2026 // ofn.nMaxCustFilter=0;
2027 // ofn.nFilterIndex=0;
2028 // ofn.lpstrFile=NULL;
2029 ofn.nMaxFile=MAX_PATH;
2030 // ofn.lpstrFileTitle=NULL;
2031 // ofn.lpstrInitialDir=NULL;
2032 // ofn.lpstrTitle=NULL;
2033 ofn.Flags=OFN_OVERWRITEPROMPT;
2034 // ofn.nFileOffset=0;
2035 // ofn.nFileExtension=0;
2036 ofn.lpstrDefExt=TEXT("sif");
2037 // ofn.lCustData = 0l;
2039 // ofn.lpTemplateName=NULL;
2041 CHAR szFilename[MAX_PATH];
2043 strcpy(szFilename,filename.c_str());
2044 strcpy(szTitle,title.c_str());
2046 ofn.lpstrFile=szFilename;
2047 ofn.lpstrFileTitle=szTitle;
2049 if(GetSaveFileName(&ofn))
2051 filename=szFilename;
2052 _preferences.set_value(preference,dirname(filename));
2057 synfig::String prev_path;
2059 if(!_preferences.get_value(preference, prev_path))
2062 prev_path = absolute_path(prev_path);
2064 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2066 dialog->set_current_folder(prev_path);
2067 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2068 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2070 Widget_Enum *file_type_enum = 0;
2071 if (preference == ANIMATION_DIR_PREFERENCE)
2073 file_type_enum = manage(new Widget_Enum());
2074 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2075 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2076 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2077 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2078 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2079 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2081 Gtk::HBox *hbox = manage(new Gtk::HBox);
2082 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2083 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2086 dialog->set_extra_widget(*hbox);
2089 if (filename.empty())
2090 dialog->set_filename(prev_path);
2093 std::string full_path;
2094 if (is_absolute_path(filename))
2095 full_path = filename;
2097 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2099 // select the file if it exists
2100 dialog->set_filename(full_path);
2102 // if the file doesn't exist, put its name into the filename box
2104 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2105 dialog->set_current_name(basename(filename));
2108 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2109 if (preference == ANIMATION_DIR_PREFERENCE)
2110 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2111 filename = dialog->get_filename();
2112 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2113 _preferences.set_value(preference, dirname(filename));
2124 App::dialog_error_blocking(const std::string &title, const std::string &message)
2126 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2127 dialog.set_title(title);
2133 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2135 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2136 dialog.set_title(title);
2142 App::dialog_yes_no(const std::string &title, const std::string &message)
2147 true // use_separator
2149 Gtk::Label label(message);
2152 dialog.get_vbox()->pack_start(label);
2153 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2154 dialog.add_button(Gtk::StockID("gtk-no"),0);
2156 return dialog.run();
2160 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2165 true // use_separator
2167 Gtk::Label label(message);
2170 dialog.get_vbox()->pack_start(label);
2171 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2172 dialog.add_button(Gtk::StockID("gtk-no"),0);
2173 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2175 return dialog.run();
2179 App::dialog_not_implemented()
2181 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2182 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2187 try_open_url(const std::string &url)
2190 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2192 std::vector<std::string> command_line;
2193 std::vector<std::string> browsers;
2194 browsers.reserve(23);
2196 // Browser wrapper scripts
2197 #ifdef USE_OPEN_FOR_URLS
2198 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2200 browsers.push_back("xdg-open"); // XDG wrapper
2201 browsers.push_back("sensible-browser"); // Debian wrapper
2202 browsers.push_back("gnome-open"); // GNOME wrapper
2203 browsers.push_back("kfmclient"); // KDE wrapper
2204 browsers.push_back("exo-open"); // XFCE wrapper
2206 // Alternatives system
2207 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2208 browsers.push_back("x-www-browser"); // Debian GUI alternative
2210 // Individual browsers
2211 browsers.push_back("firefox");
2212 browsers.push_back("epiphany-browser");
2213 browsers.push_back("epiphany");
2214 browsers.push_back("konqueror");
2215 browsers.push_back("iceweasel");
2216 browsers.push_back("mozilla");
2217 browsers.push_back("netscape");
2218 browsers.push_back("icecat");
2219 browsers.push_back("galeon");
2220 browsers.push_back("midori");
2221 browsers.push_back("safari");
2222 browsers.push_back("opera");
2223 browsers.push_back("amaya");
2224 browsers.push_back("netsurf");
2225 browsers.push_back("dillo");
2227 // Try the user-specified browser first
2228 command_line.push_back(App::browser_command);
2229 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2230 command_line.push_back(url);
2232 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2233 catch( Glib::SpawnError& exception ){
2235 while ( !browsers.empty() )
2237 // Skip the browser if we already tried it
2238 if( browsers[0] == App::browser_command )
2241 // Construct the command line
2242 command_line.clear();
2243 command_line.push_back(browsers[0]);
2244 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2245 command_line.push_back(url);
2247 // Remove the browser from the list
2248 browsers.erase(browsers.begin());
2250 // Try to spawn the browser
2251 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2252 // Failed, move on to the next one
2253 catch(Glib::SpawnError& exception){ continue; }
2254 return true; // No exception means we succeeded!
2265 if (!try_open_url("http://synfig.org/Documentation"))
2267 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2268 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2269 dialog.set_title(_("Help"));
2275 App::open_url(const std::string &url)
2277 if(!try_open_url(url))
2279 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2280 dialog.set_secondary_text(url);
2281 dialog.set_title(_("No browser found"));
2287 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2292 true); // use_separator
2294 Gtk::Label label(message);
2296 dialog.get_vbox()->pack_start(label);
2299 entry.set_text(text);
2301 entry.set_activates_default(true);
2303 dialog.get_vbox()->pack_start(entry);
2305 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2306 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2307 dialog.set_default_response(Gtk::RESPONSE_OK);
2309 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2312 if(dialog.run()!=Gtk::RESPONSE_OK)
2315 text=entry.get_text();
2321 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2326 true); // use_separator
2328 Gtk::Label label(message);
2330 dialog.get_vbox()->pack_start(label);
2332 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2333 text_buffer->set_text(text);
2334 Gtk::TextView text_view(text_buffer);
2337 dialog.get_vbox()->pack_start(text_view);
2339 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2340 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2341 dialog.set_default_response(Gtk::RESPONSE_OK);
2343 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2346 if(dialog.run()!=Gtk::RESPONSE_OK)
2349 text=text_buffer->get_text();
2355 App::open(std::string filename)
2357 return open_as(filename,filename);
2360 // this is called from autorecover.cpp:
2361 // App::open_as(get_shadow_file_name(filename),filename)
2362 // other than that, 'filename' and 'as' are the same
2364 App::open_as(std::string filename,std::string as)
2367 char long_name[1024];
2368 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2369 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2370 // don't use it if that's the case
2371 if (long_name[0] != '\0')
2377 OneMoment one_moment;
2378 String errors, warnings;
2380 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2381 if(canvas && get_instance(canvas))
2383 get_instance(canvas)->find_canvas_view(canvas)->present();
2384 info("%s is already open", filename.c_str());
2385 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2390 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2393 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2395 if (as.find(custom_filename_prefix.c_str()) != 0)
2396 add_recent_file(as);
2398 handle<Instance> instance(Instance::create(canvas));
2401 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2403 set_recent_file_window_size(instance);
2407 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)")))
2408 instance->dialog_cvs_update();
2413 dialog_error_blocking(_("Error"), x);
2416 catch(runtime_error x)
2418 dialog_error_blocking(_("Error"), x.what());
2423 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2434 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2436 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2437 canvas->set_name(file_name);
2438 file_name += ".sifz";
2440 canvas->rend_desc().set_frame_rate(preferred_fps);
2441 canvas->rend_desc().set_time_start(0.0);
2442 canvas->rend_desc().set_time_end(5.0);
2443 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2444 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2445 // The top left and botton right positions are expressed in units
2446 // Original convention is that 1 unit = 60 pixels
2447 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2448 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2449 canvas->rend_desc().set_w(preferred_x_size);
2450 canvas->rend_desc().set_h(preferred_y_size);
2451 canvas->rend_desc().set_antialias(1);
2452 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2453 canvas->set_file_name(file_name);
2455 handle<Instance> instance = Instance::create(canvas);
2457 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2458 instance->find_canvas_view(canvas)->canvas_properties.present();
2462 App::dialog_open(string filename)
2464 if (filename.empty())
2467 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2469 // If the filename still has wildcards, then we should
2470 // continue looking for the file we want
2471 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2477 get_ui_interface()->error(_("Unable to open file"));
2482 App::set_selected_instance(etl::loose_handle<Instance> instance)
2484 /* if(get_selected_instance()==instance)
2486 selected_instance=instance;
2487 signal_instance_selected()(instance);
2493 selected_instance=instance;
2494 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2498 instance->focus(instance->get_canvas());
2501 set_selected_canvas_view(0);
2503 signal_instance_selected()(instance);
2507 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2509 selected_canvas_view=canvas_view;
2510 signal_canvas_view_focus()(selected_canvas_view);
2513 selected_instance=canvas_view->get_instance();
2514 signal_instance_selected()(canvas_view->get_instance());
2517 if(get_selected_canvas_view()==canvas_view)
2519 signal_canvas_view_focus()(selected_canvas_view);
2520 signal_instance_selected()(canvas_view->get_instance());
2523 selected_canvas_view=canvas_view;
2524 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2525 set_selected_instance(canvas_view->get_instance());
2526 signal_canvas_view_focus()(selected_canvas_view);
2530 etl::loose_handle<Instance>
2531 App::get_instance(etl::handle<synfig::Canvas> canvas)
2533 if(!canvas) return 0;
2534 canvas=canvas->get_root();
2536 std::list<etl::handle<Instance> >::iterator iter;
2537 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2539 if((*iter)->get_canvas()==canvas)
2555 if(selected_instance)
2556 selected_instance->undo();
2562 if(selected_instance)
2563 selected_instance->redo();
2567 studio::App::get_base_path()
2569 return app_base_path_;