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(accel,path) \
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()); \
1008 ACCEL("<Mod1>a", "<Actions>//state-normal" );
1009 ACCEL("<Mod1>v", "<Actions>//state-smooth_move" );
1010 ACCEL("<Mod1>s", "<Actions>//state-scale" );
1011 ACCEL("<Mod1>t", "<Actions>//state-rotate" );
1012 ACCEL("<Mod1>m", "<Actions>//state-mirror" );
1013 ACCEL("<Mod1>c", "<Actions>//state-circle" );
1014 ACCEL("<Mod1>r", "<Actions>//state-rectangle" );
1015 ACCEL("<Mod1>q", "<Actions>//state-star" );
1016 ACCEL("<Mod1>g", "<Actions>//state-gradient" );
1017 ACCEL("<Mod1>p", "<Actions>//state-polygon" );
1018 ACCEL("<Mod1>b", "<Actions>//state-bline" );
1019 ACCEL("<Mod1>x", "<Actions>//state-text" );
1020 ACCEL("<Mod1>f", "<Actions>//state-fill" );
1021 ACCEL("<Mod1>e", "<Actions>//state-eyedrop" );
1022 ACCEL("<Mod1>z", "<Actions>//state-zoom" );
1023 ACCEL("<Mod1>d", "<Actions>//state-draw" );
1024 ACCEL("<Mod1>k", "<Actions>//state-sketch" );
1025 ACCEL("<Mod1>w", "<Actions>//state-width" );
1028 ACCEL("<Control>a", "<Actions>//select-all-ducks" );
1029 ACCEL("<Control>d", "<Actions>//unselect-all-ducks" );
1030 ACCEL("<Control><Shift>a", "<Actions>//select-all-layers" );
1031 ACCEL("<Control><Shift>d", "<Actions>//unselect-all-layers" );
1032 ACCEL("F9", "<Actions>//render" );
1033 ACCEL("F11", "<Actions>//preview" );
1034 ACCEL("F8", "<Actions>//properties" );
1035 ACCEL("F12", "<Actions>//options" );
1036 ACCEL("<control>i", "<Actions>//import" );
1037 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>//stop" ));
1038 ACCEL("<Control>g", "<Actions>//toggle-grid-show" );
1039 ACCEL("<Control>l", "<Actions>//toggle-grid-snap" );
1040 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>//toggle-low-res" ));
1041 ACCEL("<Mod1>1", "<Actions>//mask-position-ducks" );
1042 ACCEL("<Mod1>2", "<Actions>//mask-vertex-ducks" );
1043 ACCEL("<Mod1>3", "<Actions>//mask-tangent-ducks" );
1044 ACCEL("<Mod1>4", "<Actions>//mask-radius-ducks" );
1045 ACCEL("<Mod1>5", "<Actions>//mask-width-ducks" );
1046 ACCEL("<Mod1>6", "<Actions>//mask-angle-ducks" );
1047 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>//action-LayerRaise" ));
1048 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>//action-LayerLower" ));
1049 ACCEL("<Control>1", "<Actions>//quality-01" );
1050 ACCEL("<Control>2", "<Actions>//quality-02" );
1051 ACCEL("<Control>3", "<Actions>//quality-03" );
1052 ACCEL("<Control>4", "<Actions>//quality-04" );
1053 ACCEL("<Control>5", "<Actions>//quality-05" );
1054 ACCEL("<Control>6", "<Actions>//quality-06" );
1055 ACCEL("<Control>7", "<Actions>//quality-07" );
1056 ACCEL("<Control>8", "<Actions>//quality-08" );
1057 ACCEL("<Control>9", "<Actions>//quality-09" );
1058 ACCEL("<Control>0", "<Actions>//quality-10" );
1059 ACCEL("<Control>z", "<Actions>//undo" );
1060 ACCEL("<Control>r", "<Actions>//redo" );
1061 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>//action-LayerRemove" ));
1062 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>//decrease-low-res-pixel-size" ));
1063 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>//increase-low-res-pixel-size" ));
1064 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>//amount-dec" ));
1065 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>//amount-inc" ));
1066 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>//jump-next-keyframe" ));
1067 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>//jump-prev-keyframe" ));
1068 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>//canvas-zoom-in" ));
1069 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>//canvas-zoom-out" ));
1070 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>//time-zoom-in" ));
1071 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>//time-zoom-out" ));
1072 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>//seek-next-frame" ));
1073 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>//seek-prev-frame" ));
1074 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>//seek-next-second" ));
1075 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>//seek-prev-second" ));
1076 ACCEL("<Mod1>o", "<Actions>//toggle-onion-skin" );
1077 ACCEL("<Control><Shift>z", "<Actions>//canvas-zoom-fit" );
1078 ACCEL("<Control>p", "<Actions>//play" );
1079 ACCEL("Home", "<Actions>//seek-begin" );
1080 ACCEL("End", "<Actions>//seek-end" );
1086 #define mkdir(x,y) mkdir(x)
1089 /* === M E T H O D S ======================================================= */
1091 App::App(int *argc, char ***argv):
1092 Gtk::Main(argc,argv),
1093 IconController(etl::dirname((*argv)[0]))
1095 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1098 ui_interface_=new GlobalUIInterface();
1102 // don't call thread_init() if threads are already initialized
1103 // on some machines bonobo_init() initialized threads before we get here
1104 if (!g_thread_supported())
1105 Glib::thread_init();
1107 distance_system=Distance::SYSTEM_UNITS;
1109 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1112 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1116 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1122 if(!SYNFIG_CHECK_VERSION())
1124 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1125 dialog_error_blocking("Synfig Studio",
1126 "This copy of Synfig Studio was compiled against a\n"
1127 "different version of libsynfig than what is currently\n"
1128 "installed. Synfig Studio will now abort. Try downloading\n"
1129 "the latest version from the Synfig website at\n"
1130 "http://synfig.org/Download"
1134 Glib::set_application_name(_("Synfig Studio"));
1136 Splash splash_screen;
1137 splash_screen.show();
1139 shutdown_in_progress=false;
1140 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1141 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1143 // Initialize the Synfig library
1144 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1145 catch(std::runtime_error x)
1147 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1152 get_ui_interface()->error(_("Failed to initialize synfig!"));
1156 // add the preferences to the settings
1157 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1161 studio_init_cb.task(_("Init UI Manager..."));
1162 App::ui_manager_=studio::UIManager::create();
1165 studio_init_cb.task(_("Init Dock Manager..."));
1166 dock_manager=new studio::DockManager();
1168 studio_init_cb.task(_("Init State Manager..."));
1169 state_manager=new StateManager();
1171 studio_init_cb.task(_("Init Toolbox..."));
1172 toolbox=new studio::Toolbox();
1174 studio_init_cb.task(_("Init About Dialog..."));
1175 about=new studio::About();
1177 studio_init_cb.task(_("Init Tool Options..."));
1178 dialog_tool_options=new studio::Dialog_ToolOptions();
1179 dock_manager->register_dockable(*dialog_tool_options);
1181 studio_init_cb.task(_("Init History..."));
1182 dock_history=new studio::Dock_History();
1183 dock_manager->register_dockable(*dock_history);
1185 studio_init_cb.task(_("Init Canvases..."));
1186 dock_canvases=new studio::Dock_Canvases();
1187 dock_manager->register_dockable(*dock_canvases);
1189 studio_init_cb.task(_("Init Keyframes..."));
1190 dock_keyframes=new studio::Dock_Keyframes();
1191 dock_manager->register_dockable(*dock_keyframes);
1193 studio_init_cb.task(_("Init Layers..."));
1194 dock_layers=new studio::Dock_Layers();
1195 dock_manager->register_dockable(*dock_layers);
1197 studio_init_cb.task(_("Init Params..."));
1198 dock_params=new studio::Dock_Params();
1199 dock_manager->register_dockable(*dock_params);
1201 studio_init_cb.task(_("Init MetaData..."));
1202 dock_meta_data=new studio::Dock_MetaData();
1203 dock_manager->register_dockable(*dock_meta_data);
1205 studio_init_cb.task(_("Init Children..."));
1206 dock_children=new studio::Dock_Children();
1207 dock_manager->register_dockable(*dock_children);
1209 studio_init_cb.task(_("Init Info..."));
1210 dock_info = new studio::Dock_Info();
1211 dock_manager->register_dockable(*dock_info);
1213 studio_init_cb.task(_("Init Navigator..."));
1214 dock_navigator = new studio::Dock_Navigator();
1215 dock_manager->register_dockable(*dock_navigator);
1217 studio_init_cb.task(_("Init Timetrack..."));
1218 dock_timetrack = new studio::Dock_Timetrack();
1219 dock_manager->register_dockable(*dock_timetrack);
1221 studio_init_cb.task(_("Init Curve Editor..."));
1222 dock_curves = new studio::Dock_Curves();
1223 dock_manager->register_dockable(*dock_curves);
1225 studio_init_cb.task(_("Init Layer Groups..."));
1226 dock_layer_groups = new studio::Dock_LayerGroups();
1227 dock_manager->register_dockable(*dock_layer_groups);
1230 studio_init_cb.task(_("Init Color Dialog..."));
1231 dialog_color=new studio::Dialog_Color();
1233 studio_init_cb.task(_("Init Gradient Dialog..."));
1234 dialog_gradient=new studio::Dialog_Gradient();
1236 studio_init_cb.task(_("Init DeviceTracker..."));
1237 device_tracker=new studio::DeviceTracker();
1239 studio_init_cb.task(_("Init Tools..."));
1242 state_manager->add_state(&state_normal);
1243 state_manager->add_state(&state_smooth_move);
1244 state_manager->add_state(&state_scale);
1245 state_manager->add_state(&state_rotate);
1246 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1249 state_manager->add_state(&state_circle);
1250 state_manager->add_state(&state_rectangle);
1251 state_manager->add_state(&state_star);
1252 state_manager->add_state(&state_gradient);
1253 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1256 state_manager->add_state(&state_bline);
1257 state_manager->add_state(&state_text);
1258 state_manager->add_state(&state_fill);
1259 state_manager->add_state(&state_eyedrop);
1260 state_manager->add_state(&state_zoom);
1262 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1263 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1264 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1266 studio_init_cb.task(_("Init ModPalette..."));
1267 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1269 studio_init_cb.task(_("Init Setup Dialog..."));
1270 dialog_setup=new studio::Dialog_Setup();
1272 studio_init_cb.task(_("Init Input Dialog..."));
1273 dialog_input=new Gtk::InputDialog();
1274 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1275 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1277 studio_init_cb.task(_("Init auto recovery..."));
1278 auto_recover=new AutoRecover();
1280 studio_init_cb.amount_complete(9250,10000);
1281 studio_init_cb.task(_("Loading Settings..."));
1283 device_tracker->load_preferences();
1285 studio_init_cb.task(_("Checking auto-recover..."));
1287 studio_init_cb.amount_complete(9900,10000);
1289 bool opened_any = false;
1290 if(auto_recover->recovery_needed())
1292 splash_screen.hide();
1293 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1294 _("Synfig Studio seems to have crashed\n"
1295 "before you could save all your files.\n"
1296 "Would you like to re-open those files\n"
1297 "and recover your unsaved changes?")) ==
1298 synfigapp::UIInterface::RESPONSE_YES)
1300 int number_recovered;
1301 if(!auto_recover->recover(number_recovered))
1302 if (number_recovered)
1303 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1305 get_ui_interface()->error(_("Unable to recover from previous crash"));
1307 get_ui_interface()->error(
1308 _("Synfig Studio has attempted to recover\n"
1309 "from a previous crash. The files that it has\n"
1310 "recovered are NOT YET SAVED. It would be a good\n"
1311 "idea to review them and save them now."));
1313 if (number_recovered)
1316 splash_screen.show();
1319 // Look for any files given on the command line,
1320 // and load them if found.
1321 for(;*argc>=1;(*argc)--)
1322 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1324 studio_init_cb.task(_("Loading files..."));
1325 splash_screen.hide();
1326 open((*argv)[*argc]);
1328 splash_screen.show();
1331 // if no file was specified to be opened, create a new document to help new users get started more easily
1332 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1335 studio_init_cb.task(_("Done."));
1336 studio_init_cb.amount_complete(10000,10000);
1342 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1346 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1350 StateManager* App::get_state_manager() { return state_manager; }
1354 shutdown_in_progress=true;
1358 synfigapp::Main::settings().remove_domain("pref");
1360 selected_instance=0;
1362 // Unload all of the modules
1363 for(;!module_list_.empty();module_list_.pop_back())
1366 delete state_manager;
1370 delete auto_recover;
1376 // studio::App::iteration(false);
1380 // studio::App::iteration(false);
1382 // studio::App::iteration(false);
1384 delete dialog_setup;
1386 delete dialog_gradient;
1388 delete dialog_color;
1390 delete dialog_input;
1392 delete dock_manager;
1394 instance_list.clear();
1396 // studio::App::iteration(false);
1400 App::get_user_app_directory()
1402 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1404 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1406 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1411 App::get_config_file(const synfig::String& file)
1413 return Glib::build_filename(get_user_app_directory(),file);
1416 #define SCALE_FACTOR (1280)
1417 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1419 App::set_recent_file_window_size(etl::handle<Instance> instance)
1421 int screen_w(Gdk::screen_width());
1422 int screen_h(Gdk::screen_height());
1424 const std::string &canvas_window_size = *recent_files_window_size.begin();
1426 if(canvas_window_size.empty())
1429 synfig::String::size_type current=0;
1430 bool seen_root(false), shown_non_root(false);
1432 while(current != synfig::String::npos)
1434 // find end of first field (canvas) or return
1435 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1436 if(separator == synfig::String::npos) break;
1439 synfig::Canvas::Handle canvas;
1442 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1444 catch(Exception::IDNotFound) {
1445 // can't find the canvas; skip to the next canvas or return
1446 separator = canvas_window_size.find_first_of('\t', current);
1447 if(separator == synfig::String::npos) return;
1448 current = separator+1;
1452 if (canvas->is_root())
1455 shown_non_root = true;
1457 // check that we have the tab character the ends this canvas' data or return
1458 current = separator+1;
1459 separator = canvas_window_size.find_first_of('\t', current);
1460 if(separator == synfig::String::npos) return;
1463 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1465 current = separator+1;
1469 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1470 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1471 x=x*screen_w/SCALE_FACTOR;
1472 y=y*screen_h/SCALE_FACTOR;
1473 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1474 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1475 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1476 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1478 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1479 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1481 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1482 canvasview->move(x,y);
1483 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1484 canvasview->present();
1486 current = separator+1;
1489 if (shown_non_root && !seen_root)
1490 instance->find_canvas_view(instance->get_canvas())->hide();
1494 App::add_recent_file(const etl::handle<Instance> instance)
1496 int screen_w(Gdk::screen_width());
1497 int screen_h(Gdk::screen_height());
1499 std::string canvas_window_size;
1501 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1502 Instance::CanvasViewList::const_iterator iter;
1504 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1506 if( !((*iter)->is_visible()) )
1509 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1510 int x_pos, y_pos, x_size, y_size;
1511 (*iter)->get_position(x_pos,y_pos);
1512 (*iter)->get_size(x_size,y_size);
1514 canvas_window_size += strprintf("%s %d %d %d %d\t",
1515 canvas->get_relative_id(canvas->get_root()).c_str(),
1516 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1517 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1520 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1525 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1527 std::string filename(file_name);
1529 assert(!filename.empty());
1531 if(filename.empty())
1534 // Toss out any "hidden" files
1535 if(basename(filename)[0]=='.')
1538 // If we aren't an absolute path, turn ourselves into one
1539 if(!is_absolute_path(filename))
1540 filename=absolute_path(filename);
1542 std::string old_window_size;
1544 list<string>::iterator iter;
1545 list<string>::iterator iter_wsize;
1546 // Check to see if the file is already on the list.
1547 // If it is, then remove it from the list
1548 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1551 recent_files.erase(iter);
1552 old_window_size = *iter_wsize;
1553 recent_files_window_size.erase(iter_wsize);
1558 // Push the filename to the front of the list
1559 recent_files.push_front(filename);
1560 if(window_size.empty())
1561 recent_files_window_size.push_front(old_window_size);
1563 recent_files_window_size.push_front(window_size);
1565 // Clean out the files at the end of the list.
1566 while(recent_files.size()>(unsigned)get_max_recent_files())
1568 recent_files.pop_back();
1569 recent_files_window_size.pop_back();
1572 signal_recent_files_changed_();
1577 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1580 App::get_time_format()
1582 return _App_time_format;
1586 App::set_time_format(synfig::Time::Format x)
1593 App::save_settings()
1598 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1599 setlocale(LC_NUMERIC, "C");
1601 std::string filename=get_config_file("accelrc");
1602 Gtk::AccelMap::save(filename);
1605 std::string filename=get_config_file("recentfiles");
1607 std::ofstream file(filename.c_str());
1611 synfig::warning("Unable to save %s",filename.c_str());
1615 list<string>::reverse_iterator iter;
1617 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1621 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1623 std::ofstream file(filename.c_str());
1627 synfig::warning("Unable to save %s",filename.c_str());
1631 list<string>::reverse_iterator iter;
1633 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1637 std::string filename=get_config_file("settings");
1638 synfigapp::Main::settings().save_to_file(filename);
1639 setlocale(LC_NUMERIC,old_locale);
1643 synfig::warning("Caught exception when attempting to save settings.");
1648 App::load_settings()
1653 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1654 setlocale(LC_NUMERIC, "C");
1656 std::string filename=get_config_file("accelrc");
1657 Gtk::AccelMap::load(filename);
1660 bool window_size_broken = false;
1662 std::string filename=get_config_file("recentfiles");
1663 std::string filename_window_size=filename+std::string("_window_size");
1665 std::ifstream file(filename.c_str());
1666 std::ifstream file_window_size(filename_window_size.c_str());
1668 if(!file_window_size)
1669 window_size_broken = true;
1673 std::string recent_file;
1674 std::string recent_file_window_size;
1675 getline(file,recent_file);
1676 if(!window_size_broken)
1677 getline(file_window_size,recent_file_window_size);
1678 if(!recent_file.empty())
1680 if(!window_size_broken && !file_window_size)
1681 window_size_broken = true;
1682 if (std::ifstream(recent_file.c_str()))
1684 if(!window_size_broken)
1685 add_recent_file(recent_file,recent_file_window_size);
1687 add_recent_file(recent_file);
1691 if(!window_size_broken && file_window_size)
1692 window_size_broken = true;
1694 if(window_size_broken)
1696 recent_files_window_size.clear();
1697 recent_files_window_size.resize(recent_files.size());
1700 std::string filename=get_config_file("settings");
1701 if(!synfigapp::Main::settings().load_from_file(filename))
1703 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1704 //if(!synfigapp::Main::settings().load_from_file(filename))
1706 gamma.set_gamma(1.0/2.2);
1707 reset_initial_window_configuration();
1710 setlocale(LC_NUMERIC,old_locale);
1714 synfig::warning("Caught exception when attempting to load settings.");
1719 App::reset_initial_window_configuration()
1721 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1722 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1723 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1724 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1725 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1726 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1727 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1728 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1729 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1730 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1731 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1732 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1733 #ifdef SINGLE_THREADED
1734 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1736 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1737 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1738 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1739 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1740 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1741 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1742 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1746 App::shutdown_request(GdkEventAny*)
1750 //return !shutdown_in_progress;
1756 if(shutdown_in_progress)return;
1759 get_ui_interface()->task(_("Quit Request"));
1762 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1766 std::list<etl::handle<Instance> >::iterator iter;
1767 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1769 if(!(*iter)->safe_close())
1773 if((*iter)->synfigapp::Instance::get_action_count())
1775 handle<synfigapp::UIInterface> uim;
1776 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1778 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1779 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1781 case synfigapp::UIInterface::RESPONSE_NO:
1783 case synfigapp::UIInterface::RESPONSE_YES:
1786 case synfigapp::UIInterface::RESPONSE_CANCEL:
1795 if((*iter)->synfigapp::Instance::is_modified())
1797 handle<synfigapp::UIInterface> uim;
1798 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1800 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() );
1801 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1803 case synfigapp::UIInterface::RESPONSE_NO:
1805 case synfigapp::UIInterface::RESPONSE_YES:
1806 (*iter)->dialog_cvs_commit();
1808 case synfigapp::UIInterface::RESPONSE_CANCEL:
1817 // This next line causes things to crash for some reason
1821 shutdown_in_progress=true;
1823 instance_list.clear();
1825 while(studio::App::events_pending())studio::App::iteration(false);
1828 auto_recover->normal_shutdown();
1830 get_ui_interface()->task(_("Quit Request sent"));
1836 dialog_setup->refresh();
1837 dialog_setup->show();
1840 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1841 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1844 //#define USE_WIN32_FILE_DIALOGS 1
1847 #ifdef USE_WIN32_FILE_DIALOGS
1848 static OPENFILENAME ofn={};
1852 #include <gdk/gdkwin32.h>
1856 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1858 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1860 #ifdef USE_WIN32_FILE_DIALOGS
1861 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1863 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1864 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1865 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1867 ofn.lStructSize=sizeof(OPENFILENAME);
1868 ofn.hwndOwner = hWnd;
1869 ofn.hInstance = hInstance;
1870 ofn.lpstrFilter = szFilter;
1871 // ofn.lpstrCustomFilter=NULL;
1872 // ofn.nMaxCustFilter=0;
1873 // ofn.nFilterIndex=0;
1874 // ofn.lpstrFile=NULL;
1875 ofn.nMaxFile=MAX_PATH;
1876 // ofn.lpstrFileTitle=NULL;
1877 // ofn.lpstrInitialDir=NULL;
1878 // ofn.lpstrTitle=NULL;
1879 ofn.Flags=OFN_HIDEREADONLY;
1880 // ofn.nFileOffset=0;
1881 // ofn.nFileExtension=0;
1882 ofn.lpstrDefExt=TEXT("sif");
1883 // ofn.lCustData = 0l;
1885 // ofn.lpTemplateName=NULL;
1887 CHAR szFilename[MAX_PATH];
1889 strcpy(szFilename,filename.c_str());
1890 strcpy(szTitle,title.c_str());
1892 ofn.lpstrFile=szFilename;
1893 ofn.lpstrFileTitle=szTitle;
1895 if(GetOpenFileName(&ofn))
1897 filename=szFilename;
1903 synfig::String prev_path;
1905 if(!_preferences.get_value(preference, prev_path))
1908 prev_path = absolute_path(prev_path);
1910 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1912 dialog->set_current_folder(prev_path);
1913 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1914 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1916 if (filename.empty())
1917 dialog->set_filename(prev_path);
1918 else if (is_absolute_path(filename))
1919 dialog->set_filename(filename);
1921 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1923 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1924 filename = dialog->get_filename();
1925 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1926 _preferences.set_value(preference, dirname(filename));
1940 GtkWidget *fileselection;
1941 fileselection = gtk_file_selection_new(title.c_str());
1944 if(basename(filename)==filename)
1946 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1949 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1951 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1953 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1954 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1956 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1957 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1959 gtk_widget_show(fileselection);
1967 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1968 _preferences.set_value(preference,dirname(filename));
1972 gtk_widget_destroy(fileselection);
1975 gtk_widget_destroy(fileselection);
1982 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1984 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1986 #if USE_WIN32_FILE_DIALOGS
1987 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1989 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1990 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1991 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1993 ofn.lStructSize=sizeof(OPENFILENAME);
1994 ofn.hwndOwner = hWnd;
1995 ofn.hInstance = hInstance;
1996 ofn.lpstrFilter = szFilter;
1997 // ofn.lpstrCustomFilter=NULL;
1998 // ofn.nMaxCustFilter=0;
1999 // ofn.nFilterIndex=0;
2000 // ofn.lpstrFile=NULL;
2001 ofn.nMaxFile=MAX_PATH;
2002 // ofn.lpstrFileTitle=NULL;
2003 // ofn.lpstrInitialDir=NULL;
2004 // ofn.lpstrTitle=NULL;
2005 ofn.Flags=OFN_OVERWRITEPROMPT;
2006 // ofn.nFileOffset=0;
2007 // ofn.nFileExtension=0;
2008 ofn.lpstrDefExt=TEXT("sif");
2009 // ofn.lCustData = 0l;
2011 // ofn.lpTemplateName=NULL;
2013 CHAR szFilename[MAX_PATH];
2015 strcpy(szFilename,filename.c_str());
2016 strcpy(szTitle,title.c_str());
2018 ofn.lpstrFile=szFilename;
2019 ofn.lpstrFileTitle=szTitle;
2021 if(GetSaveFileName(&ofn))
2023 filename=szFilename;
2024 _preferences.set_value(preference,dirname(filename));
2029 synfig::String prev_path;
2031 if(!_preferences.get_value(preference, prev_path))
2034 prev_path = absolute_path(prev_path);
2036 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2038 dialog->set_current_folder(prev_path);
2039 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2040 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2042 Widget_Enum *file_type_enum = 0;
2043 if (preference == ANIMATION_DIR_PREFERENCE)
2045 file_type_enum = manage(new Widget_Enum());
2046 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2047 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2048 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2049 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2050 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2051 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2053 Gtk::HBox *hbox = manage(new Gtk::HBox);
2054 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2055 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2058 dialog->set_extra_widget(*hbox);
2061 if (filename.empty())
2062 dialog->set_filename(prev_path);
2065 std::string full_path;
2066 if (is_absolute_path(filename))
2067 full_path = filename;
2069 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2071 // select the file if it exists
2072 dialog->set_filename(full_path);
2074 // if the file doesn't exist, put its name into the filename box
2076 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2077 dialog->set_current_name(basename(filename));
2080 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2081 if (preference == ANIMATION_DIR_PREFERENCE)
2082 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2083 filename = dialog->get_filename();
2084 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2085 _preferences.set_value(preference, dirname(filename));
2096 App::dialog_error_blocking(const std::string &title, const std::string &message)
2098 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2099 dialog.set_title(title);
2105 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2107 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2108 dialog.set_title(title);
2114 App::dialog_yes_no(const std::string &title, const std::string &message)
2119 true // use_separator
2121 Gtk::Label label(message);
2124 dialog.get_vbox()->pack_start(label);
2125 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2126 dialog.add_button(Gtk::StockID("gtk-no"),0);
2128 return dialog.run();
2132 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2137 true // use_separator
2139 Gtk::Label label(message);
2142 dialog.get_vbox()->pack_start(label);
2143 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2144 dialog.add_button(Gtk::StockID("gtk-no"),0);
2145 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2147 return dialog.run();
2151 App::dialog_not_implemented()
2153 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2154 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2159 try_open_url(const std::string &url)
2162 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2164 std::vector<std::string> command_line;
2165 std::vector<std::string> browsers;
2166 browsers.reserve(23);
2168 // Browser wrapper scripts
2169 #ifdef USE_OPEN_FOR_URLS
2170 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2172 browsers.push_back("xdg-open"); // XDG wrapper
2173 browsers.push_back("sensible-browser"); // Debian wrapper
2174 browsers.push_back("gnome-open"); // GNOME wrapper
2175 browsers.push_back("kfmclient"); // KDE wrapper
2176 browsers.push_back("exo-open"); // XFCE wrapper
2178 // Alternatives system
2179 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2180 browsers.push_back("x-www-browser"); // Debian GUI alternative
2182 // Individual browsers
2183 browsers.push_back("firefox");
2184 browsers.push_back("epiphany-browser");
2185 browsers.push_back("epiphany");
2186 browsers.push_back("konqueror");
2187 browsers.push_back("iceweasel");
2188 browsers.push_back("mozilla");
2189 browsers.push_back("netscape");
2190 browsers.push_back("icecat");
2191 browsers.push_back("galeon");
2192 browsers.push_back("midori");
2193 browsers.push_back("safari");
2194 browsers.push_back("opera");
2195 browsers.push_back("amaya");
2196 browsers.push_back("netsurf");
2197 browsers.push_back("dillo");
2199 // Try the user-specified browser first
2200 command_line.push_back(App::browser_command);
2201 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2202 command_line.push_back(url);
2204 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2205 catch( Glib::SpawnError& exception ){
2207 while ( !browsers.empty() )
2209 // Skip the browser if we already tried it
2210 if( browsers[0] == App::browser_command )
2213 // Construct the command line
2214 command_line.clear();
2215 command_line.push_back(browsers[0]);
2216 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2217 command_line.push_back(url);
2219 // Remove the browser from the list
2220 browsers.erase(browsers.begin());
2222 // Try to spawn the browser
2223 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2224 // Failed, move on to the next one
2225 catch(Glib::SpawnError& exception){ continue; }
2226 return true; // No exception means we succeeded!
2237 if (!try_open_url("http://synfig.org/Documentation"))
2239 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2240 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2241 dialog.set_title(_("Help"));
2247 App::open_url(const std::string &url)
2249 if(!try_open_url(url))
2251 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2252 dialog.set_secondary_text(url);
2253 dialog.set_title(_("No browser found"));
2259 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2264 true); // use_separator
2266 Gtk::Label label(message);
2268 dialog.get_vbox()->pack_start(label);
2271 entry.set_text(text);
2273 entry.set_activates_default(true);
2275 dialog.get_vbox()->pack_start(entry);
2277 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2278 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2279 dialog.set_default_response(Gtk::RESPONSE_OK);
2281 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2284 if(dialog.run()!=Gtk::RESPONSE_OK)
2287 text=entry.get_text();
2293 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2298 true); // use_separator
2300 Gtk::Label label(message);
2302 dialog.get_vbox()->pack_start(label);
2304 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2305 text_buffer->set_text(text);
2306 Gtk::TextView text_view(text_buffer);
2309 dialog.get_vbox()->pack_start(text_view);
2311 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2312 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2313 dialog.set_default_response(Gtk::RESPONSE_OK);
2315 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2318 if(dialog.run()!=Gtk::RESPONSE_OK)
2321 text=text_buffer->get_text();
2327 App::open(std::string filename)
2329 return open_as(filename,filename);
2332 // this is called from autorecover.cpp:
2333 // App::open_as(get_shadow_file_name(filename),filename)
2334 // other than that, 'filename' and 'as' are the same
2336 App::open_as(std::string filename,std::string as)
2339 char long_name[1024];
2340 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2341 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2342 // don't use it if that's the case
2343 if (long_name[0] != '\0')
2349 OneMoment one_moment;
2350 String errors, warnings;
2352 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2353 if(canvas && get_instance(canvas))
2355 get_instance(canvas)->find_canvas_view(canvas)->present();
2356 info("%s is already open", filename.c_str());
2357 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2362 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2365 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2367 if (as.find(custom_filename_prefix.c_str()) != 0)
2368 add_recent_file(as);
2370 handle<Instance> instance(Instance::create(canvas));
2373 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2375 set_recent_file_window_size(instance);
2379 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)")))
2380 instance->dialog_cvs_update();
2385 dialog_error_blocking(_("Error"), x);
2388 catch(runtime_error x)
2390 dialog_error_blocking(_("Error"), x.what());
2395 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2406 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2408 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2409 canvas->set_name(file_name);
2410 file_name += ".sifz";
2412 canvas->rend_desc().set_frame_rate(24.0);
2413 canvas->rend_desc().set_time_start(0.0);
2414 canvas->rend_desc().set_time_end(5.0);
2415 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2416 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2417 // The top left and botton right positions are expressed in units
2418 // Original convention is that 1 unit = 60 pixels
2419 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2420 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2421 canvas->rend_desc().set_w(preferred_x_size);
2422 canvas->rend_desc().set_h(preferred_y_size);
2423 canvas->rend_desc().set_antialias(1);
2424 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2425 canvas->set_file_name(file_name);
2427 handle<Instance> instance = Instance::create(canvas);
2429 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2430 instance->find_canvas_view(canvas)->canvas_properties.present();
2434 App::dialog_open(string filename)
2436 if (filename.empty())
2439 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2441 // If the filename still has wildcards, then we should
2442 // continue looking for the file we want
2443 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2449 get_ui_interface()->error(_("Unable to open file"));
2454 App::set_selected_instance(etl::loose_handle<Instance> instance)
2456 /* if(get_selected_instance()==instance)
2458 selected_instance=instance;
2459 signal_instance_selected()(instance);
2465 selected_instance=instance;
2466 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2470 instance->focus(instance->get_canvas());
2473 set_selected_canvas_view(0);
2475 signal_instance_selected()(instance);
2479 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2481 selected_canvas_view=canvas_view;
2482 signal_canvas_view_focus()(selected_canvas_view);
2485 selected_instance=canvas_view->get_instance();
2486 signal_instance_selected()(canvas_view->get_instance());
2489 if(get_selected_canvas_view()==canvas_view)
2491 signal_canvas_view_focus()(selected_canvas_view);
2492 signal_instance_selected()(canvas_view->get_instance());
2495 selected_canvas_view=canvas_view;
2496 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2497 set_selected_instance(canvas_view->get_instance());
2498 signal_canvas_view_focus()(selected_canvas_view);
2502 etl::loose_handle<Instance>
2503 App::get_instance(etl::handle<synfig::Canvas> canvas)
2505 if(!canvas) return 0;
2506 canvas=canvas->get_root();
2508 std::list<etl::handle<Instance> >::iterator iter;
2509 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2511 if((*iter)->get_canvas()==canvas)
2527 if(selected_instance)
2528 selected_instance->undo();
2534 if(selected_instance)
2535 selected_instance->redo();
2539 studio::App::get_base_path()
2541 return app_base_path_;