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 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
279 int studio::App::preferred_x_size=480;
280 int studio::App::preferred_y_size=270;
281 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
282 #ifdef USE_OPEN_FOR_URLS
283 String studio::App::browser_command("open"); // MacOS only
285 String studio::App::browser_command("xdg-open"); // Linux XDG standard
288 static int max_recent_files_=25;
289 int studio::App::get_max_recent_files() { return max_recent_files_; }
290 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
292 static synfig::String app_base_path_;
297 really_delete_widget(Gtk::Widget *widget)
299 // synfig::info("really delete %p", (void*)widget);
304 // nasty workaround - when we've finished with a popup menu, we want to delete it
305 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
306 // so schedule the real delete to happen in 50ms, giving the action a chance to run
308 delete_widget(Gtk::Widget *widget)
310 // synfig::info("delete %p", (void*)widget);
311 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
314 }; // END of namespace studio
315 studio::StateManager* state_manager;
320 class GlobalUIInterface : public synfigapp::UIInterface
324 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
329 true // use_separator
331 Gtk::Label label(message);
334 dialog.get_vbox()->pack_start(label);
335 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
336 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
338 dialog.set_default_response(dflt);
340 return (Response)dialog.run();
342 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
347 true // use_separator
349 Gtk::Label label(message);
352 dialog.get_vbox()->pack_start(label);
353 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
354 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
355 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
357 dialog.set_default_response(dflt);
359 return (Response)dialog.run();
361 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
366 true // use_separator
368 Gtk::Label label(message);
371 dialog.get_vbox()->pack_start(label);
372 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
373 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
375 dialog.set_default_response(dflt);
377 return (Response)dialog.run();
381 task(const std::string &task)
383 std::cerr<<task<<std::endl;
384 while(studio::App::events_pending())studio::App::iteration(false);
389 error(const std::string &err)
391 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
398 warning(const std::string &err)
400 std::cerr<<"warning: "<<err<<std::endl;
401 while(studio::App::events_pending())studio::App::iteration(false);
406 amount_complete(int /*current*/, int /*total*/)
408 while(studio::App::events_pending())studio::App::iteration(false);
413 /* === P R O C E D U R E S ================================================= */
417 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
419 action_group_list.push_back(action_group);
420 Gtk::UIManager::insert_action_group(action_group, pos);
424 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
426 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
427 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
428 if(*iter==action_group)
430 action_group_list.erase(iter);
431 Gtk::UIManager::remove_action_group(action_group);
434 synfig::error("Unable to find action group");
438 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
440 ui_manager->insert_action_group(group,0);
442 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
443 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
445 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
447 if(*iter && (*iter)->get_name()!="menus")
449 synfig::info("Removing action group "+(*iter)->get_name());
450 ui_manager->remove_action_group(*iter);
453 ui_manager->insert_action_group(group,0);
455 for(;!prev_groups.empty();prev_groups.pop_front())
457 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
458 ui_manager->insert_action_group(prev_groups.front(),1);
462 class Preferences : public synfigapp::Settings
465 virtual bool get_value(const synfig::String& key, synfig::String& value)const
469 value=strprintf("%f %f %f %f",
470 App::gamma.get_gamma_r(),
471 App::gamma.get_gamma_g(),
472 App::gamma.get_gamma_b(),
473 App::gamma.get_black_level()
477 if(key=="time_format")
479 value=strprintf("%i",App::get_time_format());
482 if(key=="file_history.size")
484 value=strprintf("%i",App::get_max_recent_files());
487 if(key=="use_colorspace_gamma")
489 value=strprintf("%i",(int)App::use_colorspace_gamma);
492 if(key=="distance_system")
494 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
497 #ifdef SINGLE_THREADED
498 if(key=="single_threaded")
500 value=strprintf("%i",(int)App::single_threaded);
504 if(key=="auto_recover_backup_interval")
506 value=strprintf("%i",App::auto_recover->get_timeout());
509 if(key=="restrict_radius_ducks")
511 value=strprintf("%i",(int)App::restrict_radius_ducks);
514 if(key=="browser_command")
516 value=App::browser_command;
519 if(key=="custom_filename_prefix")
521 value=App::custom_filename_prefix;
524 if(key=="preferred_x_size")
526 value=strprintf("%i",App::preferred_x_size);
529 if(key=="preferred_y_size")
531 value=strprintf("%i",App::preferred_y_size);
534 if(key=="predefined_size")
536 value=strprintf("%s",App::predefined_size.c_str());
540 return synfigapp::Settings::get_value(key,value);
543 virtual bool set_value(const synfig::String& key,const synfig::String& value)
549 strscanf(value,"%f %f %f %f",
556 App::gamma.set_all(r,g,b,blk);
560 if(key=="time_format")
562 int i(atoi(value.c_str()));
563 App::set_time_format(static_cast<synfig::Time::Format>(i));
566 if(key=="auto_recover_backup_interval")
568 int i(atoi(value.c_str()));
569 App::auto_recover->set_timeout(i);
572 if(key=="file_history.size")
574 int i(atoi(value.c_str()));
575 App::set_max_recent_files(i);
578 if(key=="use_colorspace_gamma")
580 int i(atoi(value.c_str()));
581 App::use_colorspace_gamma=i;
584 if(key=="distance_system")
586 App::distance_system=Distance::ident_system(value);;
589 #ifdef SINGLE_THREADED
590 if(key=="single_threaded")
592 int i(atoi(value.c_str()));
593 App::single_threaded=i;
597 if(key=="restrict_radius_ducks")
599 int i(atoi(value.c_str()));
600 App::restrict_radius_ducks=i;
603 if(key=="browser_command")
605 App::browser_command=value;
608 if(key=="custom_filename_prefix")
610 App::custom_filename_prefix=value;
613 if(key=="preferred_x_size")
615 int i(atoi(value.c_str()));
616 App::preferred_x_size=i;
619 if(key=="preferred_y_size")
621 int i(atoi(value.c_str()));
622 App::preferred_y_size=i;
625 if(key=="predefined_size")
627 App::predefined_size=value;
630 return synfigapp::Settings::set_value(key,value);
633 virtual KeyList get_key_list()const
635 KeyList ret(synfigapp::Settings::get_key_list());
636 ret.push_back("gamma");
637 ret.push_back("time_format");
638 ret.push_back("distance_system");
639 ret.push_back("file_history.size");
640 ret.push_back("use_colorspace_gamma");
641 #ifdef SINGLE_THREADED
642 ret.push_back("single_threaded");
644 ret.push_back("auto_recover_backup_interval");
645 ret.push_back("restrict_radius_ducks");
646 ret.push_back("browser_command");
647 ret.push_back("custom_filename_prefix");
648 ret.push_back("preferred_x_size");
649 ret.push_back("preferred_y_size");
650 ret.push_back("predefined_size");
655 static ::Preferences _preferences;
660 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
662 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
664 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
666 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
667 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
668 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
669 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
670 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
671 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
672 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
673 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
674 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
675 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
676 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
677 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
678 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
680 // Add the synfigapp actions...
681 synfigapp::Action::Book::iterator iter;
682 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
684 actions_action_group->add(Gtk::Action::create(
685 "action-"+iter->second.name,
686 get_action_stock_id(iter->second),
687 iter->second.local_name,iter->second.local_name
691 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
692 #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); }
693 #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); }
695 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
696 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
697 DEFINE_ACTION("new", Gtk::Stock::NEW);
698 DEFINE_ACTION("open", Gtk::Stock::OPEN);
699 DEFINE_ACTION("save", Gtk::Stock::SAVE);
700 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
701 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
702 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
703 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
704 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
705 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
706 DEFINE_ACTION("import", _("Import"));
707 DEFINE_ACTION("render", _("Render"));
708 DEFINE_ACTION("preview", _("Preview"));
709 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
710 DEFINE_ACTION("sound", _("Sound File"));
711 DEFINE_ACTION("options", _("Options"));
712 DEFINE_ACTION("close", _("Close View"));
713 DEFINE_ACTION("close-document", _("Close Document"));
714 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
717 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
718 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
719 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
720 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
721 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
722 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
723 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
724 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
725 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
726 DEFINE_ACTION("properties", _("Properties"));
728 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
729 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
730 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
731 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
732 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
733 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
734 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
735 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
736 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
737 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
738 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
739 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
740 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
741 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
742 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
743 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
744 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
745 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
746 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
747 DEFINE_ACTION("play", _("Play"));
748 // DEFINE_ACTION("pause", _("Pause"));
749 DEFINE_ACTION("stop", _("Stop"));
750 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
751 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
752 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
753 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
754 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
755 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
756 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
757 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
758 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
759 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
760 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
761 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
762 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
763 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
764 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
765 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
766 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
767 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
768 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
769 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
770 DEFINE_ACTION("seek-end", _("Seek to End"));
772 DEFINE_ACTION("action-group_add", _("Add group"));
774 DEFINE_ACTION("canvas-new", _("New Canvas"));
776 DEFINE_ACTION("amount-inc", _("Increase Amount"));
777 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
782 // Set up synfigapp actions
784 synfigapp::Action::Book::iterator iter;
786 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
788 Gtk::StockID stock_id;
790 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
792 //Gtk::Image* image(manage(new Gtk::Image()));
793 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
794 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
795 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
796 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
797 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
798 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
799 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
800 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
801 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
802 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
804 actions_action_group->add(Gtk::Action::create(
805 "action-"+iter->second.name,
807 iter->second.local_name,iter->second.local_name
815 Glib::ustring ui_info =
817 " <popup name='menu-toolbox' action='menu-toolbox'>"
818 " <menu action='menu-file'>"
821 " <popup name='menu-main' action='menu-main'>"
822 " <menu action='menu-file'>"
823 " <menuitem action='new' />"
824 " <menuitem action='open' />"
825 " <menuitem action='save' />"
826 " <menuitem action='save-as' />"
827 " <menuitem action='revert' />"
828 " <separator name='bleh01'/>"
829 " <menuitem action='cvs-add' />"
830 " <menuitem action='cvs-update' />"
831 " <menuitem action='cvs-commit' />"
832 " <menuitem action='cvs-revert' />"
833 " <separator name='bleh02'/>"
834 " <menuitem action='import' />"
835 " <separator name='bleh03'/>"
836 " <menuitem action='render' />"
837 " <menuitem action='preview' />"
838 " <menuitem action='sound' />"
839 " <separator name='bleh04'/>"
840 " <menuitem action='options' />"
841 " <menuitem action='close' />"
842 " <menuitem action='close-document' />"
843 " <menuitem action='quit' />"
845 " <menu action='menu-edit'>"
846 " <menuitem action='undo'/>"
847 " <menuitem action='redo'/>"
848 " <separator name='bleh05'/>"
849 " <menuitem action='cut'/>"
850 " <menuitem action='copy'/>"
851 " <menuitem action='paste'/>"
852 " <separator name='bleh06'/>"
853 " <menuitem action='select-all-layers'/>"
854 " <menuitem action='unselect-all-layers'/>"
855 " <menuitem action='select-all-ducks'/>"
856 " <menuitem action='unselect-all-ducks'/>"
857 " <separator name='bleh07'/>"
858 " <menuitem action='properties'/>"
860 " <menu action='menu-view'>"
861 " <menu action='menu-duck-mask'>"
862 " <menuitem action='mask-position-ducks' />"
863 " <menuitem action='mask-vertex-ducks' />"
864 " <menuitem action='mask-tangent-ducks' />"
865 " <menuitem action='mask-radius-ducks' />"
866 " <menuitem action='mask-width-ducks' />"
867 " <menuitem action='mask-angle-ducks' />"
869 " <menu action='menu-preview-quality'>"
870 " <menuitem action='quality-00' />"
871 " <menuitem action='quality-01' />"
872 " <menuitem action='quality-02' />"
873 " <menuitem action='quality-03' />"
874 " <menuitem action='quality-04' />"
875 " <menuitem action='quality-05' />"
876 " <menuitem action='quality-06' />"
877 " <menuitem action='quality-07' />"
878 " <menuitem action='quality-08' />"
879 " <menuitem action='quality-09' />"
880 " <menuitem action='quality-10' />"
882 " <menu action='menu-lowres-pixel'>"
883 " <menuitem action='decrease-low-res-pixel-size'/>"
884 " <menuitem action='increase-low-res-pixel-size'/>"
885 " <separator name='pixel-size-separator'/>"
888 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
889 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
893 " <separator name='bleh08'/>"
894 " <menuitem action='play'/>"
895 //" <menuitem action='pause'/>"
896 " <menuitem action='stop'/>"
897 " <menuitem action='dialog-flipbook'/>"
898 " <separator name='bleh09'/>"
899 " <menuitem action='toggle-grid-show'/>"
900 " <menuitem action='toggle-grid-snap'/>"
901 " <menuitem action='toggle-guide-show'/>"
902 " <menuitem action='toggle-low-res'/>"
903 " <menuitem action='toggle-onion-skin'/>"
904 " <separator name='bleh10'/>"
905 " <menuitem action='canvas-zoom-in'/>"
906 " <menuitem action='canvas-zoom-out'/>"
907 " <menuitem action='canvas-zoom-fit'/>"
908 " <menuitem action='canvas-zoom-100'/>"
909 " <separator name='bleh11'/>"
910 " <menuitem action='time-zoom-in'/>"
911 " <menuitem action='time-zoom-out'/>"
912 " <separator name='bleh12'/>"
913 " <menuitem action='jump-next-keyframe'/>"
914 " <menuitem action='jump-prev-keyframe'/>"
915 " <menuitem action='seek-next-frame'/>"
916 " <menuitem action='seek-prev-frame'/>"
917 " <menuitem action='seek-next-second'/>"
918 " <menuitem action='seek-prev-second'/>"
919 " <menuitem action='seek-begin'/>"
920 " <menuitem action='seek-end'/>"
922 " <menu action='menu-canvas'>"
923 " <menuitem action='canvas-new'/>"
925 " <menu name='menu-state' action='menu-state'>"
927 " <menu action='menu-group'>"
928 " <menuitem action='action-group_add'/>"
930 " <menu action='menu-layer'>"
931 //" <menuitem action='cut'/>"
932 //" <menuitem action='copy'/>"
933 //" <menuitem action='paste'/>"
934 //" <separator name='bleh06'/>"
935 " <menu action='menu-layer-new'></menu>"
936 " <menuitem action='amount-inc'/>"
937 " <menuitem action='amount-dec'/>"
939 " <menu action='menu-keyframe'>"
940 " <menuitem action='keyframe-properties'/>"
947 " <menubar name='MenuBar'>"
948 " <menu action='MenuFile'>"
949 " <menuitem action='New'/>"
950 " <menuitem action='Open'/>"
952 " <menuitem action='Quit'/>"
954 " <menu action='MenuEdit'>"
955 " <menuitem action='Cut'/>"
956 " <menuitem action='Copy'/>"
957 " <menuitem action='Paste'/>"
960 " <toolbar name='ToolBar'>"
961 " <toolitem action='Open'/>"
962 " <toolitem action='Quit'/>"
968 actions_action_group->set_sensitive(false);
969 App::ui_manager()->set_add_tearoffs(true);
970 App::ui_manager()->insert_action_group(menus_action_group,1);
971 App::ui_manager()->insert_action_group(actions_action_group,1);
972 App::ui_manager()->add_ui_from_string(ui_info);
974 //App::ui_manager()->get_accel_group()->unlock();
976 catch(const Glib::Error& ex)
978 synfig::error("building menus and toolbars failed: " + ex.what());
981 // Add default keyboard accelerators
982 #define ACCEL(path,accel) \
984 Gtk::AccelKey accel_key(accel,path); \
985 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
988 #define ACCEL2(accel) \
990 Gtk::AccelKey accel_key(accel); \
991 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
994 ACCEL("<Actions>//select-all-ducks","<Control>a");
995 ACCEL("<Actions>//unselect-all-ducks","<Control>d");
996 ACCEL("<Actions>//select-all-layers","<Control><Shift>a");
997 ACCEL("<Actions>//unselect-all-layers","<Control><Shift>d");
998 ACCEL("<Actions>//render","F9");
999 ACCEL("<Actions>//preview","F11");
1000 ACCEL("<Actions>//properties","F8");
1001 ACCEL("<Actions>//options","F12");
1002 ACCEL("<Actions>//import","<control>i");
1003 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
1004 ACCEL("<Actions>//toggle-grid-show","<Control>g");
1005 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
1006 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
1007 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
1008 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1009 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1010 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1011 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1012 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1014 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1015 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1017 ACCEL("<Actions>//quality-01","<Control>1");
1018 ACCEL("<Actions>//quality-02","<Control>2");
1019 ACCEL("<Actions>//quality-03","<Control>3");
1020 ACCEL("<Actions>//quality-04","<Control>4");
1021 ACCEL("<Actions>//quality-05","<Control>5");
1022 ACCEL("<Actions>//quality-06","<Control>6");
1023 ACCEL("<Actions>//quality-07","<Control>7");
1024 ACCEL("<Actions>//quality-08","<Control>8");
1025 ACCEL("<Actions>//quality-09","<Control>9");
1026 ACCEL("<Actions>//quality-10","<Control>0");
1027 ACCEL("<Actions>//undo","<Control>z");
1028 ACCEL("<Actions>//redo","<Control>r");
1029 ACCEL("<Actions>//action-layer_remove","Delete");
1031 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1032 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1033 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1034 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1035 ACCEL("<Actions>//time-zoom-in","+");
1036 ACCEL("<Actions>//time-zoom-out","_");
1038 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
1039 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
1041 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1042 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1044 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1045 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1046 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1047 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1048 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1049 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1050 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1051 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1052 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1053 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1054 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
1055 ACCEL("<Actions>//play", "<Control>p");
1056 ACCEL("<Actions>//seek-begin","Home");
1057 ACCEL("<Actions>//seek-end","End");
1059 ACCEL("<Actions>//state-normal", "<Mod1>a");
1060 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1061 ACCEL("<Actions>//state-scale", "<Mod1>s");
1062 ACCEL("<Actions>//state-rotate", "<Mod1>t");
1063 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1065 ACCEL("<Actions>//state-circle", "<Mod1>c");
1066 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1067 ACCEL("<Actions>//state-star", "<Mod1>q");
1068 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1069 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1071 ACCEL("<Actions>//state-bline", "<Mod1>b");
1072 ACCEL("<Actions>//state-text", "<Mod1>x");
1073 ACCEL("<Actions>//state-fill", "<Mod1>f");
1074 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1075 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1077 ACCEL("<Actions>//state-draw", "<Mod1>d");
1078 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1079 ACCEL("<Actions>//state-width", "<Mod1>w");
1081 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1087 #define mkdir(x,y) mkdir(x)
1090 /* === M E T H O D S ======================================================= */
1092 App::App(int *argc, char ***argv):
1093 Gtk::Main(argc,argv),
1094 IconController(etl::dirname((*argv)[0]))
1096 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1099 ui_interface_=new GlobalUIInterface();
1103 // don't call thread_init() if threads are already initialized
1104 // on some machines bonobo_init() initialized threads before we get here
1105 if (!g_thread_supported())
1106 Glib::thread_init();
1108 distance_system=Distance::SYSTEM_UNITS;
1110 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1113 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1117 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1123 if(!SYNFIG_CHECK_VERSION())
1125 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1126 dialog_error_blocking("Synfig Studio",
1127 "This copy of Synfig Studio was compiled against a\n"
1128 "different version of libsynfig than what is currently\n"
1129 "installed. Synfig Studio will now abort. Try downloading\n"
1130 "the latest version from the Synfig website at\n"
1131 "http://synfig.org/Download"
1135 Glib::set_application_name(_("Synfig Studio"));
1137 Splash splash_screen;
1138 splash_screen.show();
1140 shutdown_in_progress=false;
1141 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1142 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1144 // Initialize the Synfig library
1145 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1146 catch(std::runtime_error x)
1148 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1153 get_ui_interface()->error(_("Failed to initialize synfig!"));
1157 // add the preferences to the settings
1158 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1162 studio_init_cb.task(_("Init UI Manager..."));
1163 App::ui_manager_=studio::UIManager::create();
1166 studio_init_cb.task(_("Init Dock Manager..."));
1167 dock_manager=new studio::DockManager();
1169 studio_init_cb.task(_("Init State Manager..."));
1170 state_manager=new StateManager();
1172 studio_init_cb.task(_("Init Toolbox..."));
1173 toolbox=new studio::Toolbox();
1175 studio_init_cb.task(_("Init About Dialog..."));
1176 about=new studio::About();
1178 studio_init_cb.task(_("Init Tool Options..."));
1179 dialog_tool_options=new studio::Dialog_ToolOptions();
1180 dock_manager->register_dockable(*dialog_tool_options);
1182 studio_init_cb.task(_("Init History..."));
1183 dock_history=new studio::Dock_History();
1184 dock_manager->register_dockable(*dock_history);
1186 studio_init_cb.task(_("Init Canvases..."));
1187 dock_canvases=new studio::Dock_Canvases();
1188 dock_manager->register_dockable(*dock_canvases);
1190 studio_init_cb.task(_("Init Keyframes..."));
1191 dock_keyframes=new studio::Dock_Keyframes();
1192 dock_manager->register_dockable(*dock_keyframes);
1194 studio_init_cb.task(_("Init Layers..."));
1195 dock_layers=new studio::Dock_Layers();
1196 dock_manager->register_dockable(*dock_layers);
1198 studio_init_cb.task(_("Init Params..."));
1199 dock_params=new studio::Dock_Params();
1200 dock_manager->register_dockable(*dock_params);
1202 studio_init_cb.task(_("Init MetaData..."));
1203 dock_meta_data=new studio::Dock_MetaData();
1204 dock_manager->register_dockable(*dock_meta_data);
1206 studio_init_cb.task(_("Init Children..."));
1207 dock_children=new studio::Dock_Children();
1208 dock_manager->register_dockable(*dock_children);
1210 studio_init_cb.task(_("Init Info..."));
1211 dock_info = new studio::Dock_Info();
1212 dock_manager->register_dockable(*dock_info);
1214 studio_init_cb.task(_("Init Navigator..."));
1215 dock_navigator = new studio::Dock_Navigator();
1216 dock_manager->register_dockable(*dock_navigator);
1218 studio_init_cb.task(_("Init Timetrack..."));
1219 dock_timetrack = new studio::Dock_Timetrack();
1220 dock_manager->register_dockable(*dock_timetrack);
1222 studio_init_cb.task(_("Init Curve Editor..."));
1223 dock_curves = new studio::Dock_Curves();
1224 dock_manager->register_dockable(*dock_curves);
1226 studio_init_cb.task(_("Init Layer Groups..."));
1227 dock_layer_groups = new studio::Dock_LayerGroups();
1228 dock_manager->register_dockable(*dock_layer_groups);
1231 studio_init_cb.task(_("Init Color Dialog..."));
1232 dialog_color=new studio::Dialog_Color();
1234 studio_init_cb.task(_("Init Gradient Dialog..."));
1235 dialog_gradient=new studio::Dialog_Gradient();
1237 studio_init_cb.task(_("Init DeviceTracker..."));
1238 device_tracker=new studio::DeviceTracker();
1240 studio_init_cb.task(_("Init Tools..."));
1243 state_manager->add_state(&state_normal);
1244 state_manager->add_state(&state_smooth_move);
1245 state_manager->add_state(&state_scale);
1246 state_manager->add_state(&state_rotate);
1247 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1250 state_manager->add_state(&state_circle);
1251 state_manager->add_state(&state_rectangle);
1252 state_manager->add_state(&state_star);
1253 state_manager->add_state(&state_gradient);
1254 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1257 state_manager->add_state(&state_bline);
1258 state_manager->add_state(&state_text);
1259 state_manager->add_state(&state_fill);
1260 state_manager->add_state(&state_eyedrop);
1261 state_manager->add_state(&state_zoom);
1263 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1264 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1265 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1267 studio_init_cb.task(_("Init ModPalette..."));
1268 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1270 studio_init_cb.task(_("Init Setup Dialog..."));
1271 dialog_setup=new studio::Dialog_Setup();
1273 studio_init_cb.task(_("Init Input Dialog..."));
1274 dialog_input=new Gtk::InputDialog();
1275 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1276 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1278 studio_init_cb.task(_("Init auto recovery..."));
1279 auto_recover=new AutoRecover();
1281 studio_init_cb.amount_complete(9250,10000);
1282 studio_init_cb.task(_("Loading Settings..."));
1284 studio_init_cb.task(_("Checking auto-recover..."));
1286 studio_init_cb.amount_complete(9900,10000);
1288 bool opened_any = false;
1289 if(auto_recover->recovery_needed())
1291 splash_screen.hide();
1292 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1293 _("Synfig Studio seems to have crashed\n"
1294 "before you could save all your files.\n"
1295 "Would you like to re-open those files\n"
1296 "and recover your unsaved changes?")) ==
1297 synfigapp::UIInterface::RESPONSE_YES)
1299 int number_recovered;
1300 if(!auto_recover->recover(number_recovered))
1301 if (number_recovered)
1302 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1304 get_ui_interface()->error(_("Unable to recover from previous crash"));
1306 get_ui_interface()->error(
1307 _("Synfig Studio has attempted to recover\n"
1308 "from a previous crash. The files that it has\n"
1309 "recovered are NOT YET SAVED. It would be a good\n"
1310 "idea to review them and save them now."));
1312 if (number_recovered)
1315 splash_screen.show();
1318 // Look for any files given on the command line,
1319 // and load them if found.
1320 for(;*argc>=1;(*argc)--)
1321 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1323 studio_init_cb.task(_("Loading files..."));
1324 splash_screen.hide();
1325 open((*argv)[*argc]);
1327 splash_screen.show();
1330 // if no file was specified to be opened, create a new document to help new users get started more easily
1331 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1334 studio_init_cb.task(_("Done."));
1335 studio_init_cb.amount_complete(10000,10000);
1341 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1345 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1349 StateManager* App::get_state_manager() { return state_manager; }
1353 shutdown_in_progress=true;
1357 synfigapp::Main::settings().remove_domain("pref");
1359 selected_instance=0;
1361 // Unload all of the modules
1362 for(;!module_list_.empty();module_list_.pop_back())
1365 delete state_manager;
1369 delete auto_recover;
1375 // studio::App::iteration(false);
1379 // studio::App::iteration(false);
1381 // studio::App::iteration(false);
1383 delete dialog_setup;
1385 delete dialog_gradient;
1387 delete dialog_color;
1389 delete dialog_input;
1391 delete dock_manager;
1393 instance_list.clear();
1395 // studio::App::iteration(false);
1399 App::get_user_app_directory()
1401 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1403 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1405 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1410 App::get_config_file(const synfig::String& file)
1412 return Glib::build_filename(get_user_app_directory(),file);
1415 #define SCALE_FACTOR (1280)
1416 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1418 App::set_recent_file_window_size(etl::handle<Instance> instance)
1420 int screen_w(Gdk::screen_width());
1421 int screen_h(Gdk::screen_height());
1423 const std::string &canvas_window_size = *recent_files_window_size.begin();
1425 if(canvas_window_size.empty())
1428 synfig::String::size_type current=0;
1429 bool seen_root(false), shown_non_root(false);
1431 while(current != synfig::String::npos)
1433 // find end of first field (canvas) or return
1434 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1435 if(separator == synfig::String::npos) break;
1438 synfig::Canvas::Handle canvas;
1440 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1442 catch(Exception::IDNotFound) {
1443 // can't find the canvas; skip to the next canvas or return
1444 separator = canvas_window_size.find_first_of('\t', current);
1445 if(separator == synfig::String::npos) return;
1446 current = separator+1;
1450 if (canvas->is_root())
1453 shown_non_root = true;
1455 // check that we have the tab character the ends this canvas' data or return
1456 current = separator+1;
1457 separator = canvas_window_size.find_first_of('\t', current);
1458 if(separator == synfig::String::npos) return;
1461 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1463 current = separator+1;
1467 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1468 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1469 x=x*screen_w/SCALE_FACTOR;
1470 y=y*screen_h/SCALE_FACTOR;
1471 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1472 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1473 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1474 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1476 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1477 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1479 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1480 canvasview->move(x,y);
1481 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1482 canvasview->present();
1484 current = separator+1;
1487 if (shown_non_root && !seen_root)
1488 instance->find_canvas_view(instance->get_canvas())->hide();
1492 App::add_recent_file(const etl::handle<Instance> instance)
1494 int screen_w(Gdk::screen_width());
1495 int screen_h(Gdk::screen_height());
1497 std::string canvas_window_size;
1499 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1500 Instance::CanvasViewList::const_iterator iter;
1502 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1504 if( !((*iter)->is_visible()) )
1507 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1508 int x_pos, y_pos, x_size, y_size;
1509 (*iter)->get_position(x_pos,y_pos);
1510 (*iter)->get_size(x_size,y_size);
1512 canvas_window_size += strprintf("%s %d %d %d %d\t",
1513 canvas->get_relative_id(canvas->get_root()).c_str(),
1514 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1515 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1518 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1523 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1525 std::string filename(file_name);
1527 assert(!filename.empty());
1529 if(filename.empty())
1532 // Toss out any "hidden" files
1533 if(basename(filename)[0]=='.')
1536 // If we aren't an absolute path, turn ourselves into one
1537 if(!is_absolute_path(filename))
1538 filename=absolute_path(filename);
1540 std::string old_window_size;
1542 list<string>::iterator iter;
1543 list<string>::iterator iter_wsize;
1544 // Check to see if the file is already on the list.
1545 // If it is, then remove it from the list
1546 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1549 recent_files.erase(iter);
1550 old_window_size = *iter_wsize;
1551 recent_files_window_size.erase(iter_wsize);
1556 // Push the filename to the front of the list
1557 recent_files.push_front(filename);
1558 if(window_size.empty())
1559 recent_files_window_size.push_front(old_window_size);
1561 recent_files_window_size.push_front(window_size);
1563 // Clean out the files at the end of the list.
1564 while(recent_files.size()>(unsigned)get_max_recent_files())
1566 recent_files.pop_back();
1567 recent_files_window_size.pop_back();
1570 signal_recent_files_changed_();
1575 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1578 App::get_time_format()
1580 return _App_time_format;
1584 App::set_time_format(synfig::Time::Format x)
1591 App::save_settings()
1596 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1597 setlocale(LC_NUMERIC, "C");
1599 std::string filename=get_config_file("accelrc");
1600 Gtk::AccelMap::save(filename);
1603 std::string filename=get_config_file("recentfiles");
1605 std::ofstream file(filename.c_str());
1609 synfig::warning("Unable to save %s",filename.c_str());
1613 list<string>::reverse_iterator iter;
1615 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1619 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1621 std::ofstream file(filename.c_str());
1625 synfig::warning("Unable to save %s",filename.c_str());
1629 list<string>::reverse_iterator iter;
1631 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1635 std::string filename=get_config_file("settings");
1636 synfigapp::Main::settings().save_to_file(filename);
1637 setlocale(LC_NUMERIC,old_locale);
1641 synfig::warning("Caught exception when attempting to save settings.");
1646 App::load_settings()
1651 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1652 setlocale(LC_NUMERIC, "C");
1654 std::string filename=get_config_file("accelrc");
1655 Gtk::AccelMap::load(filename);
1658 bool window_size_broken = false;
1660 std::string filename=get_config_file("recentfiles");
1661 std::string filename_window_size=filename+std::string("_window_size");
1663 std::ifstream file(filename.c_str());
1664 std::ifstream file_window_size(filename_window_size.c_str());
1666 if(!file_window_size)
1667 window_size_broken = true;
1671 std::string recent_file;
1672 std::string recent_file_window_size;
1673 getline(file,recent_file);
1674 if(!window_size_broken)
1675 getline(file_window_size,recent_file_window_size);
1676 if(!recent_file.empty())
1678 if(!window_size_broken && !file_window_size)
1679 window_size_broken = true;
1680 if (std::ifstream(recent_file.c_str()))
1682 if(!window_size_broken)
1683 add_recent_file(recent_file,recent_file_window_size);
1685 add_recent_file(recent_file);
1689 if(!window_size_broken && file_window_size)
1690 window_size_broken = true;
1692 if(window_size_broken)
1694 recent_files_window_size.clear();
1695 recent_files_window_size.resize(recent_files.size());
1698 std::string filename=get_config_file("settings");
1699 if(!synfigapp::Main::settings().load_from_file(filename))
1701 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1702 //if(!synfigapp::Main::settings().load_from_file(filename))
1704 gamma.set_gamma(1.0/2.2);
1705 reset_initial_window_configuration();
1708 setlocale(LC_NUMERIC,old_locale);
1712 synfig::warning("Caught exception when attempting to load settings.");
1717 App::reset_initial_window_configuration()
1719 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1720 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1721 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1722 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1723 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1724 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1725 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1726 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1727 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1728 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1729 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1730 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1731 #ifdef SINGLE_THREADED
1732 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1734 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1735 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1736 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1737 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1738 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1739 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1743 App::shutdown_request(GdkEventAny*)
1747 //return !shutdown_in_progress;
1753 if(shutdown_in_progress)return;
1756 get_ui_interface()->task(_("Quit Request"));
1759 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1763 std::list<etl::handle<Instance> >::iterator iter;
1764 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1766 if(!(*iter)->safe_close())
1770 if((*iter)->synfigapp::Instance::get_action_count())
1772 handle<synfigapp::UIInterface> uim;
1773 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1775 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1776 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1778 case synfigapp::UIInterface::RESPONSE_NO:
1780 case synfigapp::UIInterface::RESPONSE_YES:
1783 case synfigapp::UIInterface::RESPONSE_CANCEL:
1792 if((*iter)->synfigapp::Instance::is_modified())
1794 handle<synfigapp::UIInterface> uim;
1795 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1797 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() );
1798 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1800 case synfigapp::UIInterface::RESPONSE_NO:
1802 case synfigapp::UIInterface::RESPONSE_YES:
1803 (*iter)->dialog_cvs_commit();
1805 case synfigapp::UIInterface::RESPONSE_CANCEL:
1814 // This next line causes things to crash for some reason
1818 shutdown_in_progress=true;
1820 instance_list.clear();
1822 while(studio::App::events_pending())studio::App::iteration(false);
1825 auto_recover->normal_shutdown();
1827 get_ui_interface()->task(_("Quit Request sent"));
1833 dialog_setup->refresh();
1834 dialog_setup->show();
1837 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1838 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1841 //#define USE_WIN32_FILE_DIALOGS 1
1844 #ifdef USE_WIN32_FILE_DIALOGS
1845 static OPENFILENAME ofn={};
1849 #include <gdk/gdkwin32.h>
1853 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1855 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1857 #ifdef USE_WIN32_FILE_DIALOGS
1858 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1860 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1861 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1862 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1864 ofn.lStructSize=sizeof(OPENFILENAME);
1865 ofn.hwndOwner = hWnd;
1866 ofn.hInstance = hInstance;
1867 ofn.lpstrFilter = szFilter;
1868 // ofn.lpstrCustomFilter=NULL;
1869 // ofn.nMaxCustFilter=0;
1870 // ofn.nFilterIndex=0;
1871 // ofn.lpstrFile=NULL;
1872 ofn.nMaxFile=MAX_PATH;
1873 // ofn.lpstrFileTitle=NULL;
1874 // ofn.lpstrInitialDir=NULL;
1875 // ofn.lpstrTitle=NULL;
1876 ofn.Flags=OFN_HIDEREADONLY;
1877 // ofn.nFileOffset=0;
1878 // ofn.nFileExtension=0;
1879 ofn.lpstrDefExt=TEXT("sif");
1880 // ofn.lCustData = 0l;
1882 // ofn.lpTemplateName=NULL;
1884 CHAR szFilename[MAX_PATH];
1886 strcpy(szFilename,filename.c_str());
1887 strcpy(szTitle,title.c_str());
1889 ofn.lpstrFile=szFilename;
1890 ofn.lpstrFileTitle=szTitle;
1892 if(GetOpenFileName(&ofn))
1894 filename=szFilename;
1900 synfig::String prev_path;
1902 if(!_preferences.get_value(preference, prev_path))
1905 prev_path = absolute_path(prev_path);
1907 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1909 dialog->set_current_folder(prev_path);
1910 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1911 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1913 if (filename.empty())
1914 dialog->set_filename(prev_path);
1915 else if (is_absolute_path(filename))
1916 dialog->set_filename(filename);
1918 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1920 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1921 filename = dialog->get_filename();
1922 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1923 _preferences.set_value(preference, dirname(filename));
1937 GtkWidget *fileselection;
1938 fileselection = gtk_file_selection_new(title.c_str());
1941 if(basename(filename)==filename)
1943 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1946 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1948 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1950 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1951 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1953 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1954 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1956 gtk_widget_show(fileselection);
1964 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1965 _preferences.set_value(preference,dirname(filename));
1969 gtk_widget_destroy(fileselection);
1972 gtk_widget_destroy(fileselection);
1979 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1981 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1983 #if USE_WIN32_FILE_DIALOGS
1984 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1986 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1987 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1988 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1990 ofn.lStructSize=sizeof(OPENFILENAME);
1991 ofn.hwndOwner = hWnd;
1992 ofn.hInstance = hInstance;
1993 ofn.lpstrFilter = szFilter;
1994 // ofn.lpstrCustomFilter=NULL;
1995 // ofn.nMaxCustFilter=0;
1996 // ofn.nFilterIndex=0;
1997 // ofn.lpstrFile=NULL;
1998 ofn.nMaxFile=MAX_PATH;
1999 // ofn.lpstrFileTitle=NULL;
2000 // ofn.lpstrInitialDir=NULL;
2001 // ofn.lpstrTitle=NULL;
2002 ofn.Flags=OFN_OVERWRITEPROMPT;
2003 // ofn.nFileOffset=0;
2004 // ofn.nFileExtension=0;
2005 ofn.lpstrDefExt=TEXT("sif");
2006 // ofn.lCustData = 0l;
2008 // ofn.lpTemplateName=NULL;
2010 CHAR szFilename[MAX_PATH];
2012 strcpy(szFilename,filename.c_str());
2013 strcpy(szTitle,title.c_str());
2015 ofn.lpstrFile=szFilename;
2016 ofn.lpstrFileTitle=szTitle;
2018 if(GetSaveFileName(&ofn))
2020 filename=szFilename;
2021 _preferences.set_value(preference,dirname(filename));
2026 synfig::String prev_path;
2028 if(!_preferences.get_value(preference, prev_path))
2031 prev_path = absolute_path(prev_path);
2033 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2035 dialog->set_current_folder(prev_path);
2036 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2037 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2039 Widget_Enum *file_type_enum = 0;
2040 if (preference == ANIMATION_DIR_PREFERENCE)
2042 file_type_enum = manage(new Widget_Enum());
2043 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2044 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2045 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2046 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2047 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2048 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2050 Gtk::HBox *hbox = manage(new Gtk::HBox);
2051 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2052 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2055 dialog->set_extra_widget(*hbox);
2058 if (filename.empty())
2059 dialog->set_filename(prev_path);
2062 std::string full_path;
2063 if (is_absolute_path(filename))
2064 full_path = filename;
2066 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2068 // select the file if it exists
2069 dialog->set_filename(full_path);
2071 // if the file doesn't exist, put its name into the filename box
2073 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2074 dialog->set_current_name(basename(filename));
2077 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2078 if (preference == ANIMATION_DIR_PREFERENCE)
2079 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2080 filename = dialog->get_filename();
2081 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2082 _preferences.set_value(preference, dirname(filename));
2093 App::dialog_error_blocking(const std::string &title, const std::string &message)
2095 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2096 dialog.set_title(title);
2102 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2104 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2105 dialog.set_title(title);
2111 App::dialog_yes_no(const std::string &title, const std::string &message)
2116 true // use_separator
2118 Gtk::Label label(message);
2121 dialog.get_vbox()->pack_start(label);
2122 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2123 dialog.add_button(Gtk::StockID("gtk-no"),0);
2125 return dialog.run();
2129 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2134 true // use_separator
2136 Gtk::Label label(message);
2139 dialog.get_vbox()->pack_start(label);
2140 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2141 dialog.add_button(Gtk::StockID("gtk-no"),0);
2142 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2144 return dialog.run();
2148 App::dialog_not_implemented()
2150 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2151 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2156 try_open_url(const std::string &url)
2159 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2161 std::vector<std::string> command_line;
2162 std::vector<std::string> browsers;
2163 browsers.reserve(23);
2165 // Browser wrapper scripts
2166 #ifdef USE_OPEN_FOR_URLS
2167 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2169 browsers.push_back("xdg-open"); // XDG wrapper
2170 browsers.push_back("sensible-browser"); // Debian wrapper
2171 browsers.push_back("gnome-open"); // GNOME wrapper
2172 browsers.push_back("kfmclient"); // KDE wrapper
2173 browsers.push_back("exo-open"); // XFCE wrapper
2175 // Alternatives system
2176 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2177 browsers.push_back("x-www-browser"); // Debian GUI alternative
2179 // Individual browsers
2180 browsers.push_back("firefox");
2181 browsers.push_back("epiphany-browser");
2182 browsers.push_back("epiphany");
2183 browsers.push_back("konqueror");
2184 browsers.push_back("iceweasel");
2185 browsers.push_back("mozilla");
2186 browsers.push_back("netscape");
2187 browsers.push_back("icecat");
2188 browsers.push_back("galeon");
2189 browsers.push_back("midori");
2190 browsers.push_back("safari");
2191 browsers.push_back("opera");
2192 browsers.push_back("amaya");
2193 browsers.push_back("netsurf");
2194 browsers.push_back("dillo");
2196 // Try the user-specified browser first
2197 command_line.push_back(App::browser_command);
2198 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2199 command_line.push_back(url);
2201 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2202 catch( Glib::SpawnError& exception ){
2204 while ( !browsers.empty() )
2206 // Skip the browser if we already tried it
2207 if( browsers[0] == App::browser_command )
2210 // Construct the command line
2211 command_line.clear();
2212 command_line.push_back(browsers[0]);
2213 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2214 command_line.push_back(url);
2216 // Remove the browser from the list
2217 browsers.erase(browsers.begin());
2219 // Try to spawn the browser
2220 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2221 // Failed, move on to the next one
2222 catch(Glib::SpawnError& exception){ continue; }
2223 return true; // No exception means we succeeded!
2234 if (!try_open_url("http://synfig.org/Documentation"))
2236 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2237 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2238 dialog.set_title(_("Help"));
2244 App::open_url(const std::string &url)
2246 if(!try_open_url(url))
2248 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2249 dialog.set_secondary_text(url);
2250 dialog.set_title(_("No browser found"));
2256 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2261 true); // use_separator
2263 Gtk::Label label(message);
2265 dialog.get_vbox()->pack_start(label);
2268 entry.set_text(text);
2270 entry.set_activates_default(true);
2272 dialog.get_vbox()->pack_start(entry);
2274 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2275 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2276 dialog.set_default_response(Gtk::RESPONSE_OK);
2278 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2281 if(dialog.run()!=Gtk::RESPONSE_OK)
2284 text=entry.get_text();
2290 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2295 true); // use_separator
2297 Gtk::Label label(message);
2299 dialog.get_vbox()->pack_start(label);
2301 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2302 text_buffer->set_text(text);
2303 Gtk::TextView text_view(text_buffer);
2306 dialog.get_vbox()->pack_start(text_view);
2308 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2309 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2310 dialog.set_default_response(Gtk::RESPONSE_OK);
2312 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2315 if(dialog.run()!=Gtk::RESPONSE_OK)
2318 text=text_buffer->get_text();
2324 App::open(std::string filename)
2326 return open_as(filename,filename);
2329 // this is called from autorecover.cpp:
2330 // App::open_as(get_shadow_file_name(filename),filename)
2331 // other than that, 'filename' and 'as' are the same
2333 App::open_as(std::string filename,std::string as)
2336 char long_name[1024];
2337 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2338 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2339 // don't use it if that's the case
2340 if (long_name[0] != '\0')
2346 OneMoment one_moment;
2349 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors));
2350 if(canvas && get_instance(canvas))
2352 get_instance(canvas)->find_canvas_view(canvas)->present();
2353 info("%s is already open", filename.c_str());
2354 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2359 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2361 if (as.find(custom_filename_prefix.c_str()) != 0)
2362 add_recent_file(as);
2364 handle<Instance> instance(Instance::create(canvas));
2367 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2369 set_recent_file_window_size(instance);
2373 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)")))
2374 instance->dialog_cvs_update();
2379 dialog_error_blocking(_("Error"), x);
2384 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2395 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2397 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2398 canvas->set_name(file_name);
2399 file_name += ".sifz";
2401 canvas->rend_desc().set_frame_rate(24.0);
2402 canvas->rend_desc().set_time_start(0.0);
2403 canvas->rend_desc().set_time_end(5.0);
2404 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2405 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2406 // The top left and botton right positions are expressed in units
2407 // Original convention is that 1 unit = 60 pixels
2408 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2409 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2410 canvas->rend_desc().set_w(preferred_x_size);
2411 canvas->rend_desc().set_h(preferred_y_size);
2412 canvas->rend_desc().set_antialias(1);
2413 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2414 canvas->set_file_name(file_name);
2416 handle<Instance> instance = Instance::create(canvas);
2418 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2419 instance->find_canvas_view(canvas)->canvas_properties.present();
2423 App::dialog_open(string filename)
2425 if (filename.empty())
2428 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2430 // If the filename still has wildcards, then we should
2431 // continue looking for the file we want
2432 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2438 get_ui_interface()->error(_("Unable to open file"));
2443 App::set_selected_instance(etl::loose_handle<Instance> instance)
2445 /* if(get_selected_instance()==instance)
2447 selected_instance=instance;
2448 signal_instance_selected()(instance);
2454 selected_instance=instance;
2455 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2459 instance->focus(instance->get_canvas());
2462 set_selected_canvas_view(0);
2464 signal_instance_selected()(instance);
2468 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2470 selected_canvas_view=canvas_view;
2471 signal_canvas_view_focus()(selected_canvas_view);
2474 selected_instance=canvas_view->get_instance();
2475 signal_instance_selected()(canvas_view->get_instance());
2478 if(get_selected_canvas_view()==canvas_view)
2480 signal_canvas_view_focus()(selected_canvas_view);
2481 signal_instance_selected()(canvas_view->get_instance());
2484 selected_canvas_view=canvas_view;
2485 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2486 set_selected_instance(canvas_view->get_instance());
2487 signal_canvas_view_focus()(selected_canvas_view);
2491 etl::loose_handle<Instance>
2492 App::get_instance(etl::handle<synfig::Canvas> canvas)
2494 if(!canvas) return 0;
2495 canvas=canvas->get_root();
2497 std::list<etl::handle<Instance> >::iterator iter;
2498 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2500 if((*iter)->get_canvas()==canvas)
2516 if(selected_instance)
2517 selected_instance->undo();
2523 if(selected_instance)
2524 selected_instance->redo();
2528 studio::App::get_base_path()
2530 return app_base_path_;