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;
1453 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1455 catch(Exception::IDNotFound) {
1456 // can't find the canvas; skip to the next canvas or return
1457 separator = canvas_window_size.find_first_of('\t', current);
1458 if(separator == synfig::String::npos) return;
1459 current = separator+1;
1463 if (canvas->is_root())
1466 shown_non_root = true;
1468 // check that we have the tab character the ends this canvas' data or return
1469 current = separator+1;
1470 separator = canvas_window_size.find_first_of('\t', current);
1471 if(separator == synfig::String::npos) return;
1474 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1476 current = separator+1;
1480 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1481 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1482 x=x*screen_w/SCALE_FACTOR;
1483 y=y*screen_h/SCALE_FACTOR;
1484 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1485 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1486 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1487 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1489 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1490 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1492 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1493 canvasview->move(x,y);
1494 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1495 canvasview->present();
1497 current = separator+1;
1500 if (shown_non_root && !seen_root)
1501 instance->find_canvas_view(instance->get_canvas())->hide();
1505 App::add_recent_file(const etl::handle<Instance> instance)
1507 int screen_w(Gdk::screen_width());
1508 int screen_h(Gdk::screen_height());
1510 std::string canvas_window_size;
1512 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1513 Instance::CanvasViewList::const_iterator iter;
1515 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1517 if( !((*iter)->is_visible()) )
1520 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1521 int x_pos, y_pos, x_size, y_size;
1522 (*iter)->get_position(x_pos,y_pos);
1523 (*iter)->get_size(x_size,y_size);
1525 canvas_window_size += strprintf("%s %d %d %d %d\t",
1526 canvas->get_relative_id(canvas->get_root()).c_str(),
1527 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1528 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1531 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1536 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1538 std::string filename(file_name);
1540 assert(!filename.empty());
1542 if(filename.empty())
1545 // Toss out any "hidden" files
1546 if(basename(filename)[0]=='.')
1549 // If we aren't an absolute path, turn ourselves into one
1550 if(!is_absolute_path(filename))
1551 filename=absolute_path(filename);
1553 std::string old_window_size;
1555 list<string>::iterator iter;
1556 list<string>::iterator iter_wsize;
1557 // Check to see if the file is already on the list.
1558 // If it is, then remove it from the list
1559 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1562 recent_files.erase(iter);
1563 old_window_size = *iter_wsize;
1564 recent_files_window_size.erase(iter_wsize);
1569 // Push the filename to the front of the list
1570 recent_files.push_front(filename);
1571 if(window_size.empty())
1572 recent_files_window_size.push_front(old_window_size);
1574 recent_files_window_size.push_front(window_size);
1576 // Clean out the files at the end of the list.
1577 while(recent_files.size()>(unsigned)get_max_recent_files())
1579 recent_files.pop_back();
1580 recent_files_window_size.pop_back();
1583 signal_recent_files_changed_();
1588 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1591 App::get_time_format()
1593 return _App_time_format;
1597 App::set_time_format(synfig::Time::Format x)
1604 App::save_settings()
1609 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1610 setlocale(LC_NUMERIC, "C");
1612 std::string filename=get_config_file("accelrc");
1613 Gtk::AccelMap::save(filename);
1616 std::string filename=get_config_file("recentfiles");
1618 std::ofstream file(filename.c_str());
1622 synfig::warning("Unable to save %s",filename.c_str());
1626 list<string>::reverse_iterator iter;
1628 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1632 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1634 std::ofstream file(filename.c_str());
1638 synfig::warning("Unable to save %s",filename.c_str());
1642 list<string>::reverse_iterator iter;
1644 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1648 std::string filename=get_config_file("settings");
1649 synfigapp::Main::settings().save_to_file(filename);
1650 setlocale(LC_NUMERIC,old_locale);
1654 synfig::warning("Caught exception when attempting to save settings.");
1659 App::load_settings()
1664 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1665 setlocale(LC_NUMERIC, "C");
1667 std::string filename=get_config_file("accelrc");
1668 Gtk::AccelMap::load(filename);
1671 bool window_size_broken = false;
1673 std::string filename=get_config_file("recentfiles");
1674 std::string filename_window_size=filename+std::string("_window_size");
1676 std::ifstream file(filename.c_str());
1677 std::ifstream file_window_size(filename_window_size.c_str());
1679 if(!file_window_size)
1680 window_size_broken = true;
1684 std::string recent_file;
1685 std::string recent_file_window_size;
1686 getline(file,recent_file);
1687 if(!window_size_broken)
1688 getline(file_window_size,recent_file_window_size);
1689 if(!recent_file.empty())
1691 if(!window_size_broken && !file_window_size)
1692 window_size_broken = true;
1693 if (std::ifstream(recent_file.c_str()))
1695 if(!window_size_broken)
1696 add_recent_file(recent_file,recent_file_window_size);
1698 add_recent_file(recent_file);
1702 if(!window_size_broken && file_window_size)
1703 window_size_broken = true;
1705 if(window_size_broken)
1707 recent_files_window_size.clear();
1708 recent_files_window_size.resize(recent_files.size());
1711 std::string filename=get_config_file("settings");
1712 if(!synfigapp::Main::settings().load_from_file(filename))
1714 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1715 //if(!synfigapp::Main::settings().load_from_file(filename))
1717 gamma.set_gamma(1.0/2.2);
1718 reset_initial_window_configuration();
1721 setlocale(LC_NUMERIC,old_locale);
1725 synfig::warning("Caught exception when attempting to load settings.");
1730 App::reset_initial_window_configuration()
1732 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1733 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1734 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1735 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1736 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1737 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1738 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1739 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1740 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1741 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1742 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1743 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1744 #ifdef SINGLE_THREADED
1745 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1747 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1748 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1749 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1750 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1751 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1752 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1753 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1757 App::shutdown_request(GdkEventAny*)
1761 //return !shutdown_in_progress;
1767 if(shutdown_in_progress)return;
1770 get_ui_interface()->task(_("Quit Request"));
1773 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1777 std::list<etl::handle<Instance> >::iterator iter;
1778 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1780 if(!(*iter)->safe_close())
1784 if((*iter)->synfigapp::Instance::get_action_count())
1786 handle<synfigapp::UIInterface> uim;
1787 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1789 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1790 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1792 case synfigapp::UIInterface::RESPONSE_NO:
1794 case synfigapp::UIInterface::RESPONSE_YES:
1797 case synfigapp::UIInterface::RESPONSE_CANCEL:
1806 if((*iter)->synfigapp::Instance::is_modified())
1808 handle<synfigapp::UIInterface> uim;
1809 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1811 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() );
1812 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1814 case synfigapp::UIInterface::RESPONSE_NO:
1816 case synfigapp::UIInterface::RESPONSE_YES:
1817 (*iter)->dialog_cvs_commit();
1819 case synfigapp::UIInterface::RESPONSE_CANCEL:
1828 // This next line causes things to crash for some reason
1832 shutdown_in_progress=true;
1834 instance_list.clear();
1836 while(studio::App::events_pending())studio::App::iteration(false);
1839 auto_recover->normal_shutdown();
1841 get_ui_interface()->task(_("Quit Request sent"));
1847 dialog_setup->refresh();
1848 dialog_setup->show();
1851 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1852 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1855 //#define USE_WIN32_FILE_DIALOGS 1
1858 #ifdef USE_WIN32_FILE_DIALOGS
1859 static OPENFILENAME ofn={};
1863 #include <gdk/gdkwin32.h>
1867 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1869 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1871 #ifdef USE_WIN32_FILE_DIALOGS
1872 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1874 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1875 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1876 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1878 ofn.lStructSize=sizeof(OPENFILENAME);
1879 ofn.hwndOwner = hWnd;
1880 ofn.hInstance = hInstance;
1881 ofn.lpstrFilter = szFilter;
1882 // ofn.lpstrCustomFilter=NULL;
1883 // ofn.nMaxCustFilter=0;
1884 // ofn.nFilterIndex=0;
1885 // ofn.lpstrFile=NULL;
1886 ofn.nMaxFile=MAX_PATH;
1887 // ofn.lpstrFileTitle=NULL;
1888 // ofn.lpstrInitialDir=NULL;
1889 // ofn.lpstrTitle=NULL;
1890 ofn.Flags=OFN_HIDEREADONLY;
1891 // ofn.nFileOffset=0;
1892 // ofn.nFileExtension=0;
1893 ofn.lpstrDefExt=TEXT("sif");
1894 // ofn.lCustData = 0l;
1896 // ofn.lpTemplateName=NULL;
1898 CHAR szFilename[MAX_PATH];
1900 strcpy(szFilename,filename.c_str());
1901 strcpy(szTitle,title.c_str());
1903 ofn.lpstrFile=szFilename;
1904 ofn.lpstrFileTitle=szTitle;
1906 if(GetOpenFileName(&ofn))
1908 filename=szFilename;
1914 synfig::String prev_path;
1916 if(!_preferences.get_value(preference, prev_path))
1919 prev_path = absolute_path(prev_path);
1921 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1923 dialog->set_current_folder(prev_path);
1924 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1925 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1927 if (filename.empty())
1928 dialog->set_filename(prev_path);
1929 else if (is_absolute_path(filename))
1930 dialog->set_filename(filename);
1932 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1934 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1935 filename = dialog->get_filename();
1936 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1937 _preferences.set_value(preference, dirname(filename));
1951 GtkWidget *fileselection;
1952 fileselection = gtk_file_selection_new(title.c_str());
1955 if(basename(filename)==filename)
1957 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1960 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1962 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1964 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1965 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1967 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1968 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1970 gtk_widget_show(fileselection);
1978 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1979 _preferences.set_value(preference,dirname(filename));
1983 gtk_widget_destroy(fileselection);
1986 gtk_widget_destroy(fileselection);
1993 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1995 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1997 #if USE_WIN32_FILE_DIALOGS
1998 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2000 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2001 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2002 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2004 ofn.lStructSize=sizeof(OPENFILENAME);
2005 ofn.hwndOwner = hWnd;
2006 ofn.hInstance = hInstance;
2007 ofn.lpstrFilter = szFilter;
2008 // ofn.lpstrCustomFilter=NULL;
2009 // ofn.nMaxCustFilter=0;
2010 // ofn.nFilterIndex=0;
2011 // ofn.lpstrFile=NULL;
2012 ofn.nMaxFile=MAX_PATH;
2013 // ofn.lpstrFileTitle=NULL;
2014 // ofn.lpstrInitialDir=NULL;
2015 // ofn.lpstrTitle=NULL;
2016 ofn.Flags=OFN_OVERWRITEPROMPT;
2017 // ofn.nFileOffset=0;
2018 // ofn.nFileExtension=0;
2019 ofn.lpstrDefExt=TEXT("sif");
2020 // ofn.lCustData = 0l;
2022 // ofn.lpTemplateName=NULL;
2024 CHAR szFilename[MAX_PATH];
2026 strcpy(szFilename,filename.c_str());
2027 strcpy(szTitle,title.c_str());
2029 ofn.lpstrFile=szFilename;
2030 ofn.lpstrFileTitle=szTitle;
2032 if(GetSaveFileName(&ofn))
2034 filename=szFilename;
2035 _preferences.set_value(preference,dirname(filename));
2040 synfig::String prev_path;
2042 if(!_preferences.get_value(preference, prev_path))
2045 prev_path = absolute_path(prev_path);
2047 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2049 dialog->set_current_folder(prev_path);
2050 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2051 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2053 Widget_Enum *file_type_enum = 0;
2054 if (preference == ANIMATION_DIR_PREFERENCE)
2056 file_type_enum = manage(new Widget_Enum());
2057 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2058 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2059 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2060 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2061 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2062 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2064 Gtk::HBox *hbox = manage(new Gtk::HBox);
2065 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2066 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2069 dialog->set_extra_widget(*hbox);
2072 if (filename.empty())
2073 dialog->set_filename(prev_path);
2076 std::string full_path;
2077 if (is_absolute_path(filename))
2078 full_path = filename;
2080 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2082 // select the file if it exists
2083 dialog->set_filename(full_path);
2085 // if the file doesn't exist, put its name into the filename box
2087 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2088 dialog->set_current_name(basename(filename));
2091 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2092 if (preference == ANIMATION_DIR_PREFERENCE)
2093 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2094 filename = dialog->get_filename();
2095 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2096 _preferences.set_value(preference, dirname(filename));
2107 App::dialog_error_blocking(const std::string &title, const std::string &message)
2109 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2110 dialog.set_title(title);
2116 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2118 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2119 dialog.set_title(title);
2125 App::dialog_yes_no(const std::string &title, const std::string &message)
2130 true // use_separator
2132 Gtk::Label label(message);
2135 dialog.get_vbox()->pack_start(label);
2136 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2137 dialog.add_button(Gtk::StockID("gtk-no"),0);
2139 return dialog.run();
2143 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2148 true // use_separator
2150 Gtk::Label label(message);
2153 dialog.get_vbox()->pack_start(label);
2154 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2155 dialog.add_button(Gtk::StockID("gtk-no"),0);
2156 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2158 return dialog.run();
2162 App::dialog_not_implemented()
2164 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2165 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2170 try_open_url(const std::string &url)
2173 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2175 std::vector<std::string> command_line;
2176 std::vector<std::string> browsers;
2177 browsers.reserve(23);
2179 // Browser wrapper scripts
2180 #ifdef USE_OPEN_FOR_URLS
2181 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2183 browsers.push_back("xdg-open"); // XDG wrapper
2184 browsers.push_back("sensible-browser"); // Debian wrapper
2185 browsers.push_back("gnome-open"); // GNOME wrapper
2186 browsers.push_back("kfmclient"); // KDE wrapper
2187 browsers.push_back("exo-open"); // XFCE wrapper
2189 // Alternatives system
2190 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2191 browsers.push_back("x-www-browser"); // Debian GUI alternative
2193 // Individual browsers
2194 browsers.push_back("firefox");
2195 browsers.push_back("epiphany-browser");
2196 browsers.push_back("epiphany");
2197 browsers.push_back("konqueror");
2198 browsers.push_back("iceweasel");
2199 browsers.push_back("mozilla");
2200 browsers.push_back("netscape");
2201 browsers.push_back("icecat");
2202 browsers.push_back("galeon");
2203 browsers.push_back("midori");
2204 browsers.push_back("safari");
2205 browsers.push_back("opera");
2206 browsers.push_back("amaya");
2207 browsers.push_back("netsurf");
2208 browsers.push_back("dillo");
2210 // Try the user-specified browser first
2211 command_line.push_back(App::browser_command);
2212 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2213 command_line.push_back(url);
2215 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2216 catch( Glib::SpawnError& exception ){
2218 while ( !browsers.empty() )
2220 // Skip the browser if we already tried it
2221 if( browsers[0] == App::browser_command )
2224 // Construct the command line
2225 command_line.clear();
2226 command_line.push_back(browsers[0]);
2227 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2228 command_line.push_back(url);
2230 // Remove the browser from the list
2231 browsers.erase(browsers.begin());
2233 // Try to spawn the browser
2234 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2235 // Failed, move on to the next one
2236 catch(Glib::SpawnError& exception){ continue; }
2237 return true; // No exception means we succeeded!
2248 if (!try_open_url("http://synfig.org/Documentation"))
2250 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2251 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2252 dialog.set_title(_("Help"));
2258 App::open_url(const std::string &url)
2260 if(!try_open_url(url))
2262 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2263 dialog.set_secondary_text(url);
2264 dialog.set_title(_("No browser found"));
2270 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2275 true); // use_separator
2277 Gtk::Label label(message);
2279 dialog.get_vbox()->pack_start(label);
2282 entry.set_text(text);
2284 entry.set_activates_default(true);
2286 dialog.get_vbox()->pack_start(entry);
2288 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2289 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2290 dialog.set_default_response(Gtk::RESPONSE_OK);
2292 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2295 if(dialog.run()!=Gtk::RESPONSE_OK)
2298 text=entry.get_text();
2304 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2309 true); // use_separator
2311 Gtk::Label label(message);
2313 dialog.get_vbox()->pack_start(label);
2315 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2316 text_buffer->set_text(text);
2317 Gtk::TextView text_view(text_buffer);
2320 dialog.get_vbox()->pack_start(text_view);
2322 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2323 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2324 dialog.set_default_response(Gtk::RESPONSE_OK);
2326 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2329 if(dialog.run()!=Gtk::RESPONSE_OK)
2332 text=text_buffer->get_text();
2338 App::open(std::string filename)
2340 return open_as(filename,filename);
2343 // this is called from autorecover.cpp:
2344 // App::open_as(get_shadow_file_name(filename),filename)
2345 // other than that, 'filename' and 'as' are the same
2347 App::open_as(std::string filename,std::string as)
2350 char long_name[1024];
2351 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2352 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2353 // don't use it if that's the case
2354 if (long_name[0] != '\0')
2360 OneMoment one_moment;
2363 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors));
2364 if(canvas && get_instance(canvas))
2366 get_instance(canvas)->find_canvas_view(canvas)->present();
2367 info("%s is already open", filename.c_str());
2368 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2373 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2375 if (as.find(custom_filename_prefix.c_str()) != 0)
2376 add_recent_file(as);
2378 handle<Instance> instance(Instance::create(canvas));
2381 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2383 set_recent_file_window_size(instance);
2387 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)")))
2388 instance->dialog_cvs_update();
2393 dialog_error_blocking(_("Error"), x);
2398 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2409 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2411 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2412 canvas->set_name(file_name);
2413 file_name += ".sifz";
2415 canvas->rend_desc().set_frame_rate(24.0);
2416 canvas->rend_desc().set_time_start(0.0);
2417 canvas->rend_desc().set_time_end(5.0);
2418 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2419 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2420 // The top left and botton right positions are expressed in units
2421 // Original convention is that 1 unit = 60 pixels
2422 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2423 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2424 canvas->rend_desc().set_w(preferred_x_size);
2425 canvas->rend_desc().set_h(preferred_y_size);
2426 canvas->rend_desc().set_antialias(1);
2427 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2428 canvas->set_file_name(file_name);
2430 handle<Instance> instance = Instance::create(canvas);
2432 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2433 instance->find_canvas_view(canvas)->canvas_properties.present();
2437 App::dialog_open(string filename)
2439 if (filename.empty())
2442 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2444 // If the filename still has wildcards, then we should
2445 // continue looking for the file we want
2446 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2452 get_ui_interface()->error(_("Unable to open file"));
2457 App::set_selected_instance(etl::loose_handle<Instance> instance)
2459 /* if(get_selected_instance()==instance)
2461 selected_instance=instance;
2462 signal_instance_selected()(instance);
2468 selected_instance=instance;
2469 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2473 instance->focus(instance->get_canvas());
2476 set_selected_canvas_view(0);
2478 signal_instance_selected()(instance);
2482 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2484 selected_canvas_view=canvas_view;
2485 signal_canvas_view_focus()(selected_canvas_view);
2488 selected_instance=canvas_view->get_instance();
2489 signal_instance_selected()(canvas_view->get_instance());
2492 if(get_selected_canvas_view()==canvas_view)
2494 signal_canvas_view_focus()(selected_canvas_view);
2495 signal_instance_selected()(canvas_view->get_instance());
2498 selected_canvas_view=canvas_view;
2499 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2500 set_selected_instance(canvas_view->get_instance());
2501 signal_canvas_view_focus()(selected_canvas_view);
2505 etl::loose_handle<Instance>
2506 App::get_instance(etl::handle<synfig::Canvas> canvas)
2508 if(!canvas) return 0;
2509 canvas=canvas->get_root();
2511 std::list<etl::handle<Instance> >::iterator iter;
2512 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2514 if((*iter)->get_canvas()==canvas)
2530 if(selected_instance)
2531 selected_instance->undo();
2537 if(selected_instance)
2538 selected_instance->redo();
2542 studio::App::get_base_path()
2544 return app_base_path_;