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 #ifdef USE_OPEN_FOR_URLS
284 String studio::App::browser_command("open"); // MacOS only
286 String studio::App::browser_command("xdg-open"); // Linux XDG standard
289 static int max_recent_files_=25;
290 int studio::App::get_max_recent_files() { return max_recent_files_; }
291 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
293 static synfig::String app_base_path_;
298 really_delete_widget(Gtk::Widget *widget)
300 // synfig::info("really delete %p", (void*)widget);
305 // nasty workaround - when we've finished with a popup menu, we want to delete it
306 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
307 // so schedule the real delete to happen in 50ms, giving the action a chance to run
309 delete_widget(Gtk::Widget *widget)
311 // synfig::info("delete %p", (void*)widget);
312 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
315 }; // END of namespace studio
316 studio::StateManager* state_manager;
321 class GlobalUIInterface : public synfigapp::UIInterface
325 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
330 true // use_separator
332 Gtk::Label label(message);
335 dialog.get_vbox()->pack_start(label);
336 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
337 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
339 dialog.set_default_response(dflt);
341 return (Response)dialog.run();
343 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
348 true // use_separator
350 Gtk::Label label(message);
353 dialog.get_vbox()->pack_start(label);
354 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
355 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
356 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
358 dialog.set_default_response(dflt);
360 return (Response)dialog.run();
362 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
367 true // use_separator
369 Gtk::Label label(message);
372 dialog.get_vbox()->pack_start(label);
373 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
374 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
376 dialog.set_default_response(dflt);
378 return (Response)dialog.run();
382 task(const std::string &task)
384 std::cerr<<task<<std::endl;
385 while(studio::App::events_pending())studio::App::iteration(false);
390 error(const std::string &err)
392 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
399 warning(const std::string &err)
401 std::cerr<<"warning: "<<err<<std::endl;
402 while(studio::App::events_pending())studio::App::iteration(false);
407 amount_complete(int /*current*/, int /*total*/)
409 while(studio::App::events_pending())studio::App::iteration(false);
414 /* === P R O C E D U R E S ================================================= */
418 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
420 action_group_list.push_back(action_group);
421 Gtk::UIManager::insert_action_group(action_group, pos);
425 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
427 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
428 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
429 if(*iter==action_group)
431 action_group_list.erase(iter);
432 Gtk::UIManager::remove_action_group(action_group);
435 synfig::error("Unable to find action group");
439 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
441 ui_manager->insert_action_group(group,0);
443 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
444 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
446 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
448 if(*iter && (*iter)->get_name()!="menus")
450 synfig::info("Removing action group "+(*iter)->get_name());
451 ui_manager->remove_action_group(*iter);
454 ui_manager->insert_action_group(group,0);
456 for(;!prev_groups.empty();prev_groups.pop_front())
458 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
459 ui_manager->insert_action_group(prev_groups.front(),1);
463 class Preferences : public synfigapp::Settings
466 virtual bool get_value(const synfig::String& key, synfig::String& value)const
470 value=strprintf("%f %f %f %f",
471 App::gamma.get_gamma_r(),
472 App::gamma.get_gamma_g(),
473 App::gamma.get_gamma_b(),
474 App::gamma.get_black_level()
478 if(key=="time_format")
480 value=strprintf("%i",App::get_time_format());
483 if(key=="file_history.size")
485 value=strprintf("%i",App::get_max_recent_files());
488 if(key=="use_colorspace_gamma")
490 value=strprintf("%i",(int)App::use_colorspace_gamma);
493 if(key=="distance_system")
495 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
498 #ifdef SINGLE_THREADED
499 if(key=="single_threaded")
501 value=strprintf("%i",(int)App::single_threaded);
505 if(key=="auto_recover_backup_interval")
507 value=strprintf("%i",App::auto_recover->get_timeout());
510 if(key=="restrict_radius_ducks")
512 value=strprintf("%i",(int)App::restrict_radius_ducks);
515 if(key=="resize_imported_images")
517 value=strprintf("%i",(int)App::resize_imported_images);
520 if(key=="browser_command")
522 value=App::browser_command;
525 if(key=="custom_filename_prefix")
527 value=App::custom_filename_prefix;
530 if(key=="preferred_x_size")
532 value=strprintf("%i",App::preferred_x_size);
535 if(key=="preferred_y_size")
537 value=strprintf("%i",App::preferred_y_size);
540 if(key=="predefined_size")
542 value=strprintf("%s",App::predefined_size.c_str());
546 return synfigapp::Settings::get_value(key,value);
549 virtual bool set_value(const synfig::String& key,const synfig::String& value)
555 strscanf(value,"%f %f %f %f",
562 App::gamma.set_all(r,g,b,blk);
566 if(key=="time_format")
568 int i(atoi(value.c_str()));
569 App::set_time_format(static_cast<synfig::Time::Format>(i));
572 if(key=="auto_recover_backup_interval")
574 int i(atoi(value.c_str()));
575 App::auto_recover->set_timeout(i);
578 if(key=="file_history.size")
580 int i(atoi(value.c_str()));
581 App::set_max_recent_files(i);
584 if(key=="use_colorspace_gamma")
586 int i(atoi(value.c_str()));
587 App::use_colorspace_gamma=i;
590 if(key=="distance_system")
592 App::distance_system=Distance::ident_system(value);;
595 #ifdef SINGLE_THREADED
596 if(key=="single_threaded")
598 int i(atoi(value.c_str()));
599 App::single_threaded=i;
603 if(key=="restrict_radius_ducks")
605 int i(atoi(value.c_str()));
606 App::restrict_radius_ducks=i;
609 if(key=="resize_imported_images")
611 int i(atoi(value.c_str()));
612 App::resize_imported_images=i;
615 if(key=="browser_command")
617 App::browser_command=value;
620 if(key=="custom_filename_prefix")
622 App::custom_filename_prefix=value;
625 if(key=="preferred_x_size")
627 int i(atoi(value.c_str()));
628 App::preferred_x_size=i;
631 if(key=="preferred_y_size")
633 int i(atoi(value.c_str()));
634 App::preferred_y_size=i;
637 if(key=="predefined_size")
639 App::predefined_size=value;
642 return synfigapp::Settings::set_value(key,value);
645 virtual KeyList get_key_list()const
647 KeyList ret(synfigapp::Settings::get_key_list());
648 ret.push_back("gamma");
649 ret.push_back("time_format");
650 ret.push_back("distance_system");
651 ret.push_back("file_history.size");
652 ret.push_back("use_colorspace_gamma");
653 #ifdef SINGLE_THREADED
654 ret.push_back("single_threaded");
656 ret.push_back("auto_recover_backup_interval");
657 ret.push_back("restrict_radius_ducks");
658 ret.push_back("resize_imported_images");
659 ret.push_back("browser_command");
660 ret.push_back("custom_filename_prefix");
661 ret.push_back("preferred_x_size");
662 ret.push_back("preferred_y_size");
663 ret.push_back("predefined_size");
668 static ::Preferences _preferences;
673 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
675 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
677 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
679 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
680 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
681 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
682 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
683 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
684 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
685 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
686 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
687 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
688 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
689 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
690 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
691 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
693 // Add the synfigapp actions...
694 synfigapp::Action::Book::iterator iter;
695 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
697 actions_action_group->add(Gtk::Action::create(
698 "action-"+iter->second.name,
699 get_action_stock_id(iter->second),
700 iter->second.local_name,iter->second.local_name
704 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
705 #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); }
706 #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); }
708 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
709 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
710 DEFINE_ACTION("new", Gtk::Stock::NEW);
711 DEFINE_ACTION("open", Gtk::Stock::OPEN);
712 DEFINE_ACTION("save", Gtk::Stock::SAVE);
713 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
714 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
715 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
716 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
717 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
718 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
719 DEFINE_ACTION("import", _("Import"));
720 DEFINE_ACTION("render", _("Render"));
721 DEFINE_ACTION("preview", _("Preview"));
722 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
723 DEFINE_ACTION("sound", _("Sound File"));
724 DEFINE_ACTION("options", _("Options"));
725 DEFINE_ACTION("close", _("Close View"));
726 DEFINE_ACTION("close-document", _("Close Document"));
727 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
730 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
731 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
732 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
733 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
734 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
735 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
736 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
737 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
738 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
739 DEFINE_ACTION("properties", _("Properties"));
741 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
742 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
743 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
744 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
745 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
746 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
747 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
748 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
749 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
750 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
751 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
752 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
753 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
754 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
755 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
756 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
757 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
758 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
759 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
760 DEFINE_ACTION("play", _("Play"));
761 // DEFINE_ACTION("pause", _("Pause"));
762 DEFINE_ACTION("stop", _("Stop"));
763 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
764 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
765 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
766 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
767 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
768 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
769 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
770 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
771 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
772 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
773 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
774 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
775 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
776 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
777 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
778 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
779 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
780 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
781 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
782 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
783 DEFINE_ACTION("seek-end", _("Seek to End"));
785 DEFINE_ACTION("action-group_add", _("Add group"));
787 DEFINE_ACTION("canvas-new", _("New Canvas"));
789 DEFINE_ACTION("amount-inc", _("Increase Amount"));
790 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
795 // Set up synfigapp actions
797 synfigapp::Action::Book::iterator iter;
799 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
801 Gtk::StockID stock_id;
803 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
805 //Gtk::Image* image(manage(new Gtk::Image()));
806 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
807 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
808 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
809 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
810 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
811 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
812 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
813 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
814 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
815 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
817 actions_action_group->add(Gtk::Action::create(
818 "action-"+iter->second.name,
820 iter->second.local_name,iter->second.local_name
828 Glib::ustring ui_info =
830 " <popup name='menu-toolbox' action='menu-toolbox'>"
831 " <menu action='menu-file'>"
834 " <popup name='menu-main' action='menu-main'>"
835 " <menu action='menu-file'>"
836 " <menuitem action='new' />"
837 " <menuitem action='open' />"
838 " <menuitem action='save' />"
839 " <menuitem action='save-as' />"
840 " <menuitem action='revert' />"
841 " <separator name='bleh01'/>"
842 " <menuitem action='cvs-add' />"
843 " <menuitem action='cvs-update' />"
844 " <menuitem action='cvs-commit' />"
845 " <menuitem action='cvs-revert' />"
846 " <separator name='bleh02'/>"
847 " <menuitem action='import' />"
848 " <separator name='bleh03'/>"
849 " <menuitem action='render' />"
850 " <menuitem action='preview' />"
851 " <menuitem action='sound' />"
852 " <separator name='bleh04'/>"
853 " <menuitem action='options' />"
854 " <menuitem action='close' />"
855 " <menuitem action='close-document' />"
856 " <menuitem action='quit' />"
858 " <menu action='menu-edit'>"
859 " <menuitem action='undo'/>"
860 " <menuitem action='redo'/>"
861 " <separator name='bleh05'/>"
862 " <menuitem action='cut'/>"
863 " <menuitem action='copy'/>"
864 " <menuitem action='paste'/>"
865 " <separator name='bleh06'/>"
866 " <menuitem action='select-all-layers'/>"
867 " <menuitem action='unselect-all-layers'/>"
868 " <menuitem action='select-all-ducks'/>"
869 " <menuitem action='unselect-all-ducks'/>"
870 " <separator name='bleh07'/>"
871 " <menuitem action='properties'/>"
873 " <menu action='menu-view'>"
874 " <menu action='menu-duck-mask'>"
875 " <menuitem action='mask-position-ducks' />"
876 " <menuitem action='mask-vertex-ducks' />"
877 " <menuitem action='mask-tangent-ducks' />"
878 " <menuitem action='mask-radius-ducks' />"
879 " <menuitem action='mask-width-ducks' />"
880 " <menuitem action='mask-angle-ducks' />"
882 " <menu action='menu-preview-quality'>"
883 " <menuitem action='quality-00' />"
884 " <menuitem action='quality-01' />"
885 " <menuitem action='quality-02' />"
886 " <menuitem action='quality-03' />"
887 " <menuitem action='quality-04' />"
888 " <menuitem action='quality-05' />"
889 " <menuitem action='quality-06' />"
890 " <menuitem action='quality-07' />"
891 " <menuitem action='quality-08' />"
892 " <menuitem action='quality-09' />"
893 " <menuitem action='quality-10' />"
895 " <menu action='menu-lowres-pixel'>"
896 " <menuitem action='decrease-low-res-pixel-size'/>"
897 " <menuitem action='increase-low-res-pixel-size'/>"
898 " <separator name='pixel-size-separator'/>"
901 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
902 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
906 " <separator name='bleh08'/>"
907 " <menuitem action='play'/>"
908 //" <menuitem action='pause'/>"
909 " <menuitem action='stop'/>"
910 " <menuitem action='dialog-flipbook'/>"
911 " <separator name='bleh09'/>"
912 " <menuitem action='toggle-grid-show'/>"
913 " <menuitem action='toggle-grid-snap'/>"
914 " <menuitem action='toggle-guide-show'/>"
915 " <menuitem action='toggle-low-res'/>"
916 " <menuitem action='toggle-onion-skin'/>"
917 " <separator name='bleh10'/>"
918 " <menuitem action='canvas-zoom-in'/>"
919 " <menuitem action='canvas-zoom-out'/>"
920 " <menuitem action='canvas-zoom-fit'/>"
921 " <menuitem action='canvas-zoom-100'/>"
922 " <separator name='bleh11'/>"
923 " <menuitem action='time-zoom-in'/>"
924 " <menuitem action='time-zoom-out'/>"
925 " <separator name='bleh12'/>"
926 " <menuitem action='jump-next-keyframe'/>"
927 " <menuitem action='jump-prev-keyframe'/>"
928 " <menuitem action='seek-next-frame'/>"
929 " <menuitem action='seek-prev-frame'/>"
930 " <menuitem action='seek-next-second'/>"
931 " <menuitem action='seek-prev-second'/>"
932 " <menuitem action='seek-begin'/>"
933 " <menuitem action='seek-end'/>"
935 " <menu action='menu-canvas'>"
936 " <menuitem action='canvas-new'/>"
938 " <menu name='menu-state' action='menu-state'>"
940 " <menu action='menu-group'>"
941 " <menuitem action='action-group_add'/>"
943 " <menu action='menu-layer'>"
944 //" <menuitem action='cut'/>"
945 //" <menuitem action='copy'/>"
946 //" <menuitem action='paste'/>"
947 //" <separator name='bleh06'/>"
948 " <menu action='menu-layer-new'></menu>"
949 " <menuitem action='amount-inc'/>"
950 " <menuitem action='amount-dec'/>"
952 " <menu action='menu-keyframe'>"
953 " <menuitem action='keyframe-properties'/>"
960 " <menubar name='MenuBar'>"
961 " <menu action='MenuFile'>"
962 " <menuitem action='New'/>"
963 " <menuitem action='Open'/>"
965 " <menuitem action='Quit'/>"
967 " <menu action='MenuEdit'>"
968 " <menuitem action='Cut'/>"
969 " <menuitem action='Copy'/>"
970 " <menuitem action='Paste'/>"
973 " <toolbar name='ToolBar'>"
974 " <toolitem action='Open'/>"
975 " <toolitem action='Quit'/>"
981 actions_action_group->set_sensitive(false);
982 App::ui_manager()->set_add_tearoffs(true);
983 App::ui_manager()->insert_action_group(menus_action_group,1);
984 App::ui_manager()->insert_action_group(actions_action_group,1);
985 App::ui_manager()->add_ui_from_string(ui_info);
987 //App::ui_manager()->get_accel_group()->unlock();
989 catch(const Glib::Error& ex)
991 synfig::error("building menus and toolbars failed: " + ex.what());
994 // Add default keyboard accelerators
995 #define ACCEL(path,accel) \
997 Gtk::AccelKey accel_key(accel,path); \
998 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1001 #define ACCEL2(accel) \
1003 Gtk::AccelKey accel_key(accel); \
1004 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1007 ACCEL("<Actions>//select-all-ducks","<Control>a");
1008 ACCEL("<Actions>//unselect-all-ducks","<Control>d");
1009 ACCEL("<Actions>//select-all-layers","<Control><Shift>a");
1010 ACCEL("<Actions>//unselect-all-layers","<Control><Shift>d");
1011 ACCEL("<Actions>//render","F9");
1012 ACCEL("<Actions>//preview","F11");
1013 ACCEL("<Actions>//properties","F8");
1014 ACCEL("<Actions>//options","F12");
1015 ACCEL("<Actions>//import","<control>i");
1016 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
1017 ACCEL("<Actions>//toggle-grid-show","<Control>g");
1018 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
1019 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
1020 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
1021 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1022 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1023 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1024 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1025 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1027 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1028 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1030 ACCEL("<Actions>//quality-01","<Control>1");
1031 ACCEL("<Actions>//quality-02","<Control>2");
1032 ACCEL("<Actions>//quality-03","<Control>3");
1033 ACCEL("<Actions>//quality-04","<Control>4");
1034 ACCEL("<Actions>//quality-05","<Control>5");
1035 ACCEL("<Actions>//quality-06","<Control>6");
1036 ACCEL("<Actions>//quality-07","<Control>7");
1037 ACCEL("<Actions>//quality-08","<Control>8");
1038 ACCEL("<Actions>//quality-09","<Control>9");
1039 ACCEL("<Actions>//quality-10","<Control>0");
1040 ACCEL("<Actions>//undo","<Control>z");
1041 ACCEL("<Actions>//redo","<Control>r");
1042 ACCEL("<Actions>//action-layer_remove","Delete");
1044 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1045 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1046 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1047 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1048 ACCEL("<Actions>//time-zoom-in","+");
1049 ACCEL("<Actions>//time-zoom-out","_");
1051 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
1052 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
1054 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1055 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1057 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1058 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1059 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1060 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1061 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1062 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1063 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1064 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1065 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1066 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1067 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
1068 ACCEL("<Actions>//play", "<Control>p");
1069 ACCEL("<Actions>//seek-begin","Home");
1070 ACCEL("<Actions>//seek-end","End");
1072 ACCEL("<Actions>//state-normal", "<Mod1>a");
1073 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1074 ACCEL("<Actions>//state-scale", "<Mod1>s");
1075 ACCEL("<Actions>//state-rotate", "<Mod1>t");
1076 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1078 ACCEL("<Actions>//state-circle", "<Mod1>c");
1079 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1080 ACCEL("<Actions>//state-star", "<Mod1>q");
1081 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1082 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1084 ACCEL("<Actions>//state-bline", "<Mod1>b");
1085 ACCEL("<Actions>//state-text", "<Mod1>x");
1086 ACCEL("<Actions>//state-fill", "<Mod1>f");
1087 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1088 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1090 ACCEL("<Actions>//state-draw", "<Mod1>d");
1091 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1092 ACCEL("<Actions>//state-width", "<Mod1>w");
1094 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1100 #define mkdir(x,y) mkdir(x)
1103 /* === M E T H O D S ======================================================= */
1105 App::App(int *argc, char ***argv):
1106 Gtk::Main(argc,argv),
1107 IconController(etl::dirname((*argv)[0]))
1109 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1112 ui_interface_=new GlobalUIInterface();
1116 // don't call thread_init() if threads are already initialized
1117 // on some machines bonobo_init() initialized threads before we get here
1118 if (!g_thread_supported())
1119 Glib::thread_init();
1121 distance_system=Distance::SYSTEM_UNITS;
1123 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1126 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1130 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1136 if(!SYNFIG_CHECK_VERSION())
1138 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1139 dialog_error_blocking("Synfig Studio",
1140 "This copy of Synfig Studio was compiled against a\n"
1141 "different version of libsynfig than what is currently\n"
1142 "installed. Synfig Studio will now abort. Try downloading\n"
1143 "the latest version from the Synfig website at\n"
1144 "http://synfig.org/Download"
1148 Glib::set_application_name(_("Synfig Studio"));
1150 Splash splash_screen;
1151 splash_screen.show();
1153 shutdown_in_progress=false;
1154 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1155 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1157 // Initialize the Synfig library
1158 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1159 catch(std::runtime_error x)
1161 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1166 get_ui_interface()->error(_("Failed to initialize synfig!"));
1170 // add the preferences to the settings
1171 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1175 studio_init_cb.task(_("Init UI Manager..."));
1176 App::ui_manager_=studio::UIManager::create();
1179 studio_init_cb.task(_("Init Dock Manager..."));
1180 dock_manager=new studio::DockManager();
1182 studio_init_cb.task(_("Init State Manager..."));
1183 state_manager=new StateManager();
1185 studio_init_cb.task(_("Init Toolbox..."));
1186 toolbox=new studio::Toolbox();
1188 studio_init_cb.task(_("Init About Dialog..."));
1189 about=new studio::About();
1191 studio_init_cb.task(_("Init Tool Options..."));
1192 dialog_tool_options=new studio::Dialog_ToolOptions();
1193 dock_manager->register_dockable(*dialog_tool_options);
1195 studio_init_cb.task(_("Init History..."));
1196 dock_history=new studio::Dock_History();
1197 dock_manager->register_dockable(*dock_history);
1199 studio_init_cb.task(_("Init Canvases..."));
1200 dock_canvases=new studio::Dock_Canvases();
1201 dock_manager->register_dockable(*dock_canvases);
1203 studio_init_cb.task(_("Init Keyframes..."));
1204 dock_keyframes=new studio::Dock_Keyframes();
1205 dock_manager->register_dockable(*dock_keyframes);
1207 studio_init_cb.task(_("Init Layers..."));
1208 dock_layers=new studio::Dock_Layers();
1209 dock_manager->register_dockable(*dock_layers);
1211 studio_init_cb.task(_("Init Params..."));
1212 dock_params=new studio::Dock_Params();
1213 dock_manager->register_dockable(*dock_params);
1215 studio_init_cb.task(_("Init MetaData..."));
1216 dock_meta_data=new studio::Dock_MetaData();
1217 dock_manager->register_dockable(*dock_meta_data);
1219 studio_init_cb.task(_("Init Children..."));
1220 dock_children=new studio::Dock_Children();
1221 dock_manager->register_dockable(*dock_children);
1223 studio_init_cb.task(_("Init Info..."));
1224 dock_info = new studio::Dock_Info();
1225 dock_manager->register_dockable(*dock_info);
1227 studio_init_cb.task(_("Init Navigator..."));
1228 dock_navigator = new studio::Dock_Navigator();
1229 dock_manager->register_dockable(*dock_navigator);
1231 studio_init_cb.task(_("Init Timetrack..."));
1232 dock_timetrack = new studio::Dock_Timetrack();
1233 dock_manager->register_dockable(*dock_timetrack);
1235 studio_init_cb.task(_("Init Curve Editor..."));
1236 dock_curves = new studio::Dock_Curves();
1237 dock_manager->register_dockable(*dock_curves);
1239 studio_init_cb.task(_("Init Layer Groups..."));
1240 dock_layer_groups = new studio::Dock_LayerGroups();
1241 dock_manager->register_dockable(*dock_layer_groups);
1244 studio_init_cb.task(_("Init Color Dialog..."));
1245 dialog_color=new studio::Dialog_Color();
1247 studio_init_cb.task(_("Init Gradient Dialog..."));
1248 dialog_gradient=new studio::Dialog_Gradient();
1250 studio_init_cb.task(_("Init DeviceTracker..."));
1251 device_tracker=new studio::DeviceTracker();
1253 studio_init_cb.task(_("Init Tools..."));
1256 state_manager->add_state(&state_normal);
1257 state_manager->add_state(&state_smooth_move);
1258 state_manager->add_state(&state_scale);
1259 state_manager->add_state(&state_rotate);
1260 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1263 state_manager->add_state(&state_circle);
1264 state_manager->add_state(&state_rectangle);
1265 state_manager->add_state(&state_star);
1266 state_manager->add_state(&state_gradient);
1267 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1270 state_manager->add_state(&state_bline);
1271 state_manager->add_state(&state_text);
1272 state_manager->add_state(&state_fill);
1273 state_manager->add_state(&state_eyedrop);
1274 state_manager->add_state(&state_zoom);
1276 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1277 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1278 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1280 studio_init_cb.task(_("Init ModPalette..."));
1281 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1283 studio_init_cb.task(_("Init Setup Dialog..."));
1284 dialog_setup=new studio::Dialog_Setup();
1286 studio_init_cb.task(_("Init Input Dialog..."));
1287 dialog_input=new Gtk::InputDialog();
1288 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1289 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1291 studio_init_cb.task(_("Init auto recovery..."));
1292 auto_recover=new AutoRecover();
1294 studio_init_cb.amount_complete(9250,10000);
1295 studio_init_cb.task(_("Loading Settings..."));
1297 studio_init_cb.task(_("Checking auto-recover..."));
1299 studio_init_cb.amount_complete(9900,10000);
1301 bool opened_any = false;
1302 if(auto_recover->recovery_needed())
1304 splash_screen.hide();
1305 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1306 _("Synfig Studio seems to have crashed\n"
1307 "before you could save all your files.\n"
1308 "Would you like to re-open those files\n"
1309 "and recover your unsaved changes?")) ==
1310 synfigapp::UIInterface::RESPONSE_YES)
1312 int number_recovered;
1313 if(!auto_recover->recover(number_recovered))
1314 if (number_recovered)
1315 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1317 get_ui_interface()->error(_("Unable to recover from previous crash"));
1319 get_ui_interface()->error(
1320 _("Synfig Studio has attempted to recover\n"
1321 "from a previous crash. The files that it has\n"
1322 "recovered are NOT YET SAVED. It would be a good\n"
1323 "idea to review them and save them now."));
1325 if (number_recovered)
1328 splash_screen.show();
1331 // Look for any files given on the command line,
1332 // and load them if found.
1333 for(;*argc>=1;(*argc)--)
1334 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1336 studio_init_cb.task(_("Loading files..."));
1337 splash_screen.hide();
1338 open((*argv)[*argc]);
1340 splash_screen.show();
1343 // if no file was specified to be opened, create a new document to help new users get started more easily
1344 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1347 studio_init_cb.task(_("Done."));
1348 studio_init_cb.amount_complete(10000,10000);
1354 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1358 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1362 StateManager* App::get_state_manager() { return state_manager; }
1366 shutdown_in_progress=true;
1370 synfigapp::Main::settings().remove_domain("pref");
1372 selected_instance=0;
1374 // Unload all of the modules
1375 for(;!module_list_.empty();module_list_.pop_back())
1378 delete state_manager;
1382 delete auto_recover;
1388 // studio::App::iteration(false);
1392 // studio::App::iteration(false);
1394 // studio::App::iteration(false);
1396 delete dialog_setup;
1398 delete dialog_gradient;
1400 delete dialog_color;
1402 delete dialog_input;
1404 delete dock_manager;
1406 instance_list.clear();
1408 // studio::App::iteration(false);
1412 App::get_user_app_directory()
1414 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1416 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1418 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1423 App::get_config_file(const synfig::String& file)
1425 return Glib::build_filename(get_user_app_directory(),file);
1428 #define SCALE_FACTOR (1280)
1429 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1431 App::set_recent_file_window_size(etl::handle<Instance> instance)
1433 int screen_w(Gdk::screen_width());
1434 int screen_h(Gdk::screen_height());
1436 const std::string &canvas_window_size = *recent_files_window_size.begin();
1438 if(canvas_window_size.empty())
1441 synfig::String::size_type current=0;
1442 bool seen_root(false), shown_non_root(false);
1444 while(current != synfig::String::npos)
1446 // find end of first field (canvas) or return
1447 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1448 if(separator == synfig::String::npos) break;
1451 synfig::Canvas::Handle canvas;
1454 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1456 catch(Exception::IDNotFound) {
1457 // can't find the canvas; skip to the next canvas or return
1458 separator = canvas_window_size.find_first_of('\t', current);
1459 if(separator == synfig::String::npos) return;
1460 current = separator+1;
1464 if (canvas->is_root())
1467 shown_non_root = true;
1469 // check that we have the tab character the ends this canvas' data or return
1470 current = separator+1;
1471 separator = canvas_window_size.find_first_of('\t', current);
1472 if(separator == synfig::String::npos) return;
1475 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1477 current = separator+1;
1481 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1482 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1483 x=x*screen_w/SCALE_FACTOR;
1484 y=y*screen_h/SCALE_FACTOR;
1485 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1486 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1487 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1488 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1490 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1491 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1493 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1494 canvasview->move(x,y);
1495 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1496 canvasview->present();
1498 current = separator+1;
1501 if (shown_non_root && !seen_root)
1502 instance->find_canvas_view(instance->get_canvas())->hide();
1506 App::add_recent_file(const etl::handle<Instance> instance)
1508 int screen_w(Gdk::screen_width());
1509 int screen_h(Gdk::screen_height());
1511 std::string canvas_window_size;
1513 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1514 Instance::CanvasViewList::const_iterator iter;
1516 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1518 if( !((*iter)->is_visible()) )
1521 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1522 int x_pos, y_pos, x_size, y_size;
1523 (*iter)->get_position(x_pos,y_pos);
1524 (*iter)->get_size(x_size,y_size);
1526 canvas_window_size += strprintf("%s %d %d %d %d\t",
1527 canvas->get_relative_id(canvas->get_root()).c_str(),
1528 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1529 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1532 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1537 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1539 std::string filename(file_name);
1541 assert(!filename.empty());
1543 if(filename.empty())
1546 // Toss out any "hidden" files
1547 if(basename(filename)[0]=='.')
1550 // If we aren't an absolute path, turn ourselves into one
1551 if(!is_absolute_path(filename))
1552 filename=absolute_path(filename);
1554 std::string old_window_size;
1556 list<string>::iterator iter;
1557 list<string>::iterator iter_wsize;
1558 // Check to see if the file is already on the list.
1559 // If it is, then remove it from the list
1560 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1563 recent_files.erase(iter);
1564 old_window_size = *iter_wsize;
1565 recent_files_window_size.erase(iter_wsize);
1570 // Push the filename to the front of the list
1571 recent_files.push_front(filename);
1572 if(window_size.empty())
1573 recent_files_window_size.push_front(old_window_size);
1575 recent_files_window_size.push_front(window_size);
1577 // Clean out the files at the end of the list.
1578 while(recent_files.size()>(unsigned)get_max_recent_files())
1580 recent_files.pop_back();
1581 recent_files_window_size.pop_back();
1584 signal_recent_files_changed_();
1589 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1592 App::get_time_format()
1594 return _App_time_format;
1598 App::set_time_format(synfig::Time::Format x)
1605 App::save_settings()
1610 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1611 setlocale(LC_NUMERIC, "C");
1613 std::string filename=get_config_file("accelrc");
1614 Gtk::AccelMap::save(filename);
1617 std::string filename=get_config_file("recentfiles");
1619 std::ofstream file(filename.c_str());
1623 synfig::warning("Unable to save %s",filename.c_str());
1627 list<string>::reverse_iterator iter;
1629 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1633 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1635 std::ofstream file(filename.c_str());
1639 synfig::warning("Unable to save %s",filename.c_str());
1643 list<string>::reverse_iterator iter;
1645 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1649 std::string filename=get_config_file("settings");
1650 synfigapp::Main::settings().save_to_file(filename);
1651 setlocale(LC_NUMERIC,old_locale);
1655 synfig::warning("Caught exception when attempting to save settings.");
1660 App::load_settings()
1665 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1666 setlocale(LC_NUMERIC, "C");
1668 std::string filename=get_config_file("accelrc");
1669 Gtk::AccelMap::load(filename);
1672 bool window_size_broken = false;
1674 std::string filename=get_config_file("recentfiles");
1675 std::string filename_window_size=filename+std::string("_window_size");
1677 std::ifstream file(filename.c_str());
1678 std::ifstream file_window_size(filename_window_size.c_str());
1680 if(!file_window_size)
1681 window_size_broken = true;
1685 std::string recent_file;
1686 std::string recent_file_window_size;
1687 getline(file,recent_file);
1688 if(!window_size_broken)
1689 getline(file_window_size,recent_file_window_size);
1690 if(!recent_file.empty())
1692 if(!window_size_broken && !file_window_size)
1693 window_size_broken = true;
1694 if (std::ifstream(recent_file.c_str()))
1696 if(!window_size_broken)
1697 add_recent_file(recent_file,recent_file_window_size);
1699 add_recent_file(recent_file);
1703 if(!window_size_broken && file_window_size)
1704 window_size_broken = true;
1706 if(window_size_broken)
1708 recent_files_window_size.clear();
1709 recent_files_window_size.resize(recent_files.size());
1712 std::string filename=get_config_file("settings");
1713 if(!synfigapp::Main::settings().load_from_file(filename))
1715 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1716 //if(!synfigapp::Main::settings().load_from_file(filename))
1718 gamma.set_gamma(1.0/2.2);
1719 reset_initial_window_configuration();
1722 setlocale(LC_NUMERIC,old_locale);
1726 synfig::warning("Caught exception when attempting to load settings.");
1731 App::reset_initial_window_configuration()
1733 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1734 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1735 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1736 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1737 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1738 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1739 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1740 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1741 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1742 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1743 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1744 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1745 #ifdef SINGLE_THREADED
1746 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1748 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1749 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1750 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1751 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1752 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1753 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1754 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1758 App::shutdown_request(GdkEventAny*)
1762 //return !shutdown_in_progress;
1768 if(shutdown_in_progress)return;
1771 get_ui_interface()->task(_("Quit Request"));
1774 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1778 std::list<etl::handle<Instance> >::iterator iter;
1779 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1781 if(!(*iter)->safe_close())
1785 if((*iter)->synfigapp::Instance::get_action_count())
1787 handle<synfigapp::UIInterface> uim;
1788 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1790 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1791 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1793 case synfigapp::UIInterface::RESPONSE_NO:
1795 case synfigapp::UIInterface::RESPONSE_YES:
1798 case synfigapp::UIInterface::RESPONSE_CANCEL:
1807 if((*iter)->synfigapp::Instance::is_modified())
1809 handle<synfigapp::UIInterface> uim;
1810 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1812 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() );
1813 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1815 case synfigapp::UIInterface::RESPONSE_NO:
1817 case synfigapp::UIInterface::RESPONSE_YES:
1818 (*iter)->dialog_cvs_commit();
1820 case synfigapp::UIInterface::RESPONSE_CANCEL:
1829 // This next line causes things to crash for some reason
1833 shutdown_in_progress=true;
1835 instance_list.clear();
1837 while(studio::App::events_pending())studio::App::iteration(false);
1840 auto_recover->normal_shutdown();
1842 get_ui_interface()->task(_("Quit Request sent"));
1848 dialog_setup->refresh();
1849 dialog_setup->show();
1852 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1853 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1856 //#define USE_WIN32_FILE_DIALOGS 1
1859 #ifdef USE_WIN32_FILE_DIALOGS
1860 static OPENFILENAME ofn={};
1864 #include <gdk/gdkwin32.h>
1868 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1870 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1872 #ifdef USE_WIN32_FILE_DIALOGS
1873 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1875 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1876 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1877 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1879 ofn.lStructSize=sizeof(OPENFILENAME);
1880 ofn.hwndOwner = hWnd;
1881 ofn.hInstance = hInstance;
1882 ofn.lpstrFilter = szFilter;
1883 // ofn.lpstrCustomFilter=NULL;
1884 // ofn.nMaxCustFilter=0;
1885 // ofn.nFilterIndex=0;
1886 // ofn.lpstrFile=NULL;
1887 ofn.nMaxFile=MAX_PATH;
1888 // ofn.lpstrFileTitle=NULL;
1889 // ofn.lpstrInitialDir=NULL;
1890 // ofn.lpstrTitle=NULL;
1891 ofn.Flags=OFN_HIDEREADONLY;
1892 // ofn.nFileOffset=0;
1893 // ofn.nFileExtension=0;
1894 ofn.lpstrDefExt=TEXT("sif");
1895 // ofn.lCustData = 0l;
1897 // ofn.lpTemplateName=NULL;
1899 CHAR szFilename[MAX_PATH];
1901 strcpy(szFilename,filename.c_str());
1902 strcpy(szTitle,title.c_str());
1904 ofn.lpstrFile=szFilename;
1905 ofn.lpstrFileTitle=szTitle;
1907 if(GetOpenFileName(&ofn))
1909 filename=szFilename;
1915 synfig::String prev_path;
1917 if(!_preferences.get_value(preference, prev_path))
1920 prev_path = absolute_path(prev_path);
1922 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1924 dialog->set_current_folder(prev_path);
1925 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1926 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1928 if (filename.empty())
1929 dialog->set_filename(prev_path);
1930 else if (is_absolute_path(filename))
1931 dialog->set_filename(filename);
1933 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1935 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1936 filename = dialog->get_filename();
1937 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1938 _preferences.set_value(preference, dirname(filename));
1952 GtkWidget *fileselection;
1953 fileselection = gtk_file_selection_new(title.c_str());
1956 if(basename(filename)==filename)
1958 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1961 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1963 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1965 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1966 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1968 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1969 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1971 gtk_widget_show(fileselection);
1979 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1980 _preferences.set_value(preference,dirname(filename));
1984 gtk_widget_destroy(fileselection);
1987 gtk_widget_destroy(fileselection);
1994 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1996 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1998 #if USE_WIN32_FILE_DIALOGS
1999 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2001 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2002 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2003 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2005 ofn.lStructSize=sizeof(OPENFILENAME);
2006 ofn.hwndOwner = hWnd;
2007 ofn.hInstance = hInstance;
2008 ofn.lpstrFilter = szFilter;
2009 // ofn.lpstrCustomFilter=NULL;
2010 // ofn.nMaxCustFilter=0;
2011 // ofn.nFilterIndex=0;
2012 // ofn.lpstrFile=NULL;
2013 ofn.nMaxFile=MAX_PATH;
2014 // ofn.lpstrFileTitle=NULL;
2015 // ofn.lpstrInitialDir=NULL;
2016 // ofn.lpstrTitle=NULL;
2017 ofn.Flags=OFN_OVERWRITEPROMPT;
2018 // ofn.nFileOffset=0;
2019 // ofn.nFileExtension=0;
2020 ofn.lpstrDefExt=TEXT("sif");
2021 // ofn.lCustData = 0l;
2023 // ofn.lpTemplateName=NULL;
2025 CHAR szFilename[MAX_PATH];
2027 strcpy(szFilename,filename.c_str());
2028 strcpy(szTitle,title.c_str());
2030 ofn.lpstrFile=szFilename;
2031 ofn.lpstrFileTitle=szTitle;
2033 if(GetSaveFileName(&ofn))
2035 filename=szFilename;
2036 _preferences.set_value(preference,dirname(filename));
2041 synfig::String prev_path;
2043 if(!_preferences.get_value(preference, prev_path))
2046 prev_path = absolute_path(prev_path);
2048 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2050 dialog->set_current_folder(prev_path);
2051 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2052 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2054 Widget_Enum *file_type_enum = 0;
2055 if (preference == ANIMATION_DIR_PREFERENCE)
2057 file_type_enum = manage(new Widget_Enum());
2058 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2059 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2060 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2061 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2062 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2063 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2065 Gtk::HBox *hbox = manage(new Gtk::HBox);
2066 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2067 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2070 dialog->set_extra_widget(*hbox);
2073 if (filename.empty())
2074 dialog->set_filename(prev_path);
2077 std::string full_path;
2078 if (is_absolute_path(filename))
2079 full_path = filename;
2081 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2083 // select the file if it exists
2084 dialog->set_filename(full_path);
2086 // if the file doesn't exist, put its name into the filename box
2088 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2089 dialog->set_current_name(basename(filename));
2092 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2093 if (preference == ANIMATION_DIR_PREFERENCE)
2094 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2095 filename = dialog->get_filename();
2096 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2097 _preferences.set_value(preference, dirname(filename));
2108 App::dialog_error_blocking(const std::string &title, const std::string &message)
2110 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2111 dialog.set_title(title);
2117 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2119 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2120 dialog.set_title(title);
2126 App::dialog_yes_no(const std::string &title, const std::string &message)
2131 true // use_separator
2133 Gtk::Label label(message);
2136 dialog.get_vbox()->pack_start(label);
2137 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2138 dialog.add_button(Gtk::StockID("gtk-no"),0);
2140 return dialog.run();
2144 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2149 true // use_separator
2151 Gtk::Label label(message);
2154 dialog.get_vbox()->pack_start(label);
2155 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2156 dialog.add_button(Gtk::StockID("gtk-no"),0);
2157 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2159 return dialog.run();
2163 App::dialog_not_implemented()
2165 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2166 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2171 try_open_url(const std::string &url)
2174 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2176 std::vector<std::string> command_line;
2177 std::vector<std::string> browsers;
2178 browsers.reserve(23);
2180 // Browser wrapper scripts
2181 #ifdef USE_OPEN_FOR_URLS
2182 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2184 browsers.push_back("xdg-open"); // XDG wrapper
2185 browsers.push_back("sensible-browser"); // Debian wrapper
2186 browsers.push_back("gnome-open"); // GNOME wrapper
2187 browsers.push_back("kfmclient"); // KDE wrapper
2188 browsers.push_back("exo-open"); // XFCE wrapper
2190 // Alternatives system
2191 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2192 browsers.push_back("x-www-browser"); // Debian GUI alternative
2194 // Individual browsers
2195 browsers.push_back("firefox");
2196 browsers.push_back("epiphany-browser");
2197 browsers.push_back("epiphany");
2198 browsers.push_back("konqueror");
2199 browsers.push_back("iceweasel");
2200 browsers.push_back("mozilla");
2201 browsers.push_back("netscape");
2202 browsers.push_back("icecat");
2203 browsers.push_back("galeon");
2204 browsers.push_back("midori");
2205 browsers.push_back("safari");
2206 browsers.push_back("opera");
2207 browsers.push_back("amaya");
2208 browsers.push_back("netsurf");
2209 browsers.push_back("dillo");
2211 // Try the user-specified browser first
2212 command_line.push_back(App::browser_command);
2213 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2214 command_line.push_back(url);
2216 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2217 catch( Glib::SpawnError& exception ){
2219 while ( !browsers.empty() )
2221 // Skip the browser if we already tried it
2222 if( browsers[0] == App::browser_command )
2225 // Construct the command line
2226 command_line.clear();
2227 command_line.push_back(browsers[0]);
2228 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2229 command_line.push_back(url);
2231 // Remove the browser from the list
2232 browsers.erase(browsers.begin());
2234 // Try to spawn the browser
2235 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2236 // Failed, move on to the next one
2237 catch(Glib::SpawnError& exception){ continue; }
2238 return true; // No exception means we succeeded!
2249 if (!try_open_url("http://synfig.org/Documentation"))
2251 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2252 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2253 dialog.set_title(_("Help"));
2259 App::open_url(const std::string &url)
2261 if(!try_open_url(url))
2263 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2264 dialog.set_secondary_text(url);
2265 dialog.set_title(_("No browser found"));
2271 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2276 true); // use_separator
2278 Gtk::Label label(message);
2280 dialog.get_vbox()->pack_start(label);
2283 entry.set_text(text);
2285 entry.set_activates_default(true);
2287 dialog.get_vbox()->pack_start(entry);
2289 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2290 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2291 dialog.set_default_response(Gtk::RESPONSE_OK);
2293 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2296 if(dialog.run()!=Gtk::RESPONSE_OK)
2299 text=entry.get_text();
2305 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2310 true); // use_separator
2312 Gtk::Label label(message);
2314 dialog.get_vbox()->pack_start(label);
2316 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2317 text_buffer->set_text(text);
2318 Gtk::TextView text_view(text_buffer);
2321 dialog.get_vbox()->pack_start(text_view);
2323 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2324 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2325 dialog.set_default_response(Gtk::RESPONSE_OK);
2327 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2330 if(dialog.run()!=Gtk::RESPONSE_OK)
2333 text=text_buffer->get_text();
2339 App::open(std::string filename)
2341 return open_as(filename,filename);
2344 // this is called from autorecover.cpp:
2345 // App::open_as(get_shadow_file_name(filename),filename)
2346 // other than that, 'filename' and 'as' are the same
2348 App::open_as(std::string filename,std::string as)
2351 char long_name[1024];
2352 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2353 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2354 // don't use it if that's the case
2355 if (long_name[0] != '\0')
2361 OneMoment one_moment;
2362 String errors, warnings;
2364 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2365 if(canvas && get_instance(canvas))
2367 get_instance(canvas)->find_canvas_view(canvas)->present();
2368 info("%s is already open", filename.c_str());
2369 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2374 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2377 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2379 if (as.find(custom_filename_prefix.c_str()) != 0)
2380 add_recent_file(as);
2382 handle<Instance> instance(Instance::create(canvas));
2385 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2387 set_recent_file_window_size(instance);
2391 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)")))
2392 instance->dialog_cvs_update();
2397 dialog_error_blocking(_("Error"), x);
2400 catch(runtime_error x)
2402 dialog_error_blocking(_("Error"), x.what());
2407 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2418 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2420 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2421 canvas->set_name(file_name);
2422 file_name += ".sifz";
2424 canvas->rend_desc().set_frame_rate(24.0);
2425 canvas->rend_desc().set_time_start(0.0);
2426 canvas->rend_desc().set_time_end(5.0);
2427 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2428 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2429 // The top left and botton right positions are expressed in units
2430 // Original convention is that 1 unit = 60 pixels
2431 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2432 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2433 canvas->rend_desc().set_w(preferred_x_size);
2434 canvas->rend_desc().set_h(preferred_y_size);
2435 canvas->rend_desc().set_antialias(1);
2436 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2437 canvas->set_file_name(file_name);
2439 handle<Instance> instance = Instance::create(canvas);
2441 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2442 instance->find_canvas_view(canvas)->canvas_properties.present();
2446 App::dialog_open(string filename)
2448 if (filename.empty())
2451 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2453 // If the filename still has wildcards, then we should
2454 // continue looking for the file we want
2455 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2461 get_ui_interface()->error(_("Unable to open file"));
2466 App::set_selected_instance(etl::loose_handle<Instance> instance)
2468 /* if(get_selected_instance()==instance)
2470 selected_instance=instance;
2471 signal_instance_selected()(instance);
2477 selected_instance=instance;
2478 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2482 instance->focus(instance->get_canvas());
2485 set_selected_canvas_view(0);
2487 signal_instance_selected()(instance);
2491 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2493 selected_canvas_view=canvas_view;
2494 signal_canvas_view_focus()(selected_canvas_view);
2497 selected_instance=canvas_view->get_instance();
2498 signal_instance_selected()(canvas_view->get_instance());
2501 if(get_selected_canvas_view()==canvas_view)
2503 signal_canvas_view_focus()(selected_canvas_view);
2504 signal_instance_selected()(canvas_view->get_instance());
2507 selected_canvas_view=canvas_view;
2508 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2509 set_selected_instance(canvas_view->get_instance());
2510 signal_canvas_view_focus()(selected_canvas_view);
2514 etl::loose_handle<Instance>
2515 App::get_instance(etl::handle<synfig::Canvas> canvas)
2517 if(!canvas) return 0;
2518 canvas=canvas->get_root();
2520 std::list<etl::handle<Instance> >::iterator iter;
2521 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2523 if((*iter)->get_canvas()==canvas)
2539 if(selected_instance)
2540 selected_instance->undo();
2546 if(selected_instance)
2547 selected_instance->redo();
2551 studio::App::get_base_path()
2553 return app_base_path_;