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::ptr_fun(studio::App::dialog_not_implemented) );
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 studio_init_cb.task(_("Checking auto-recover..."));
1285 studio_init_cb.amount_complete(9900,10000);
1287 bool opened_any = false;
1288 if(auto_recover->recovery_needed())
1290 splash_screen.hide();
1291 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1292 _("Synfig Studio seems to have crashed\n"
1293 "before you could save all your files.\n"
1294 "Would you like to re-open those files\n"
1295 "and recover your unsaved changes?")) ==
1296 synfigapp::UIInterface::RESPONSE_YES)
1298 int number_recovered;
1299 if(!auto_recover->recover(number_recovered))
1300 if (number_recovered)
1301 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1303 get_ui_interface()->error(_("Unable to recover from previous crash"));
1305 get_ui_interface()->error(
1306 _("Synfig Studio has attempted to recover\n"
1307 "from a previous crash. The files that it has\n"
1308 "recovered are NOT YET SAVED. It would be a good\n"
1309 "idea to review them and save them now."));
1311 if (number_recovered)
1314 splash_screen.show();
1317 // Look for any files given on the command line,
1318 // and load them if found.
1319 for(;*argc>=1;(*argc)--)
1320 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1322 studio_init_cb.task(_("Loading files..."));
1323 splash_screen.hide();
1324 open((*argv)[*argc]);
1326 splash_screen.show();
1329 // if no file was specified to be opened, create a new document to help new users get started more easily
1330 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1333 studio_init_cb.task(_("Done."));
1334 studio_init_cb.amount_complete(10000,10000);
1340 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1344 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1348 StateManager* App::get_state_manager() { return state_manager; }
1352 shutdown_in_progress=true;
1356 synfigapp::Main::settings().remove_domain("pref");
1358 selected_instance=0;
1360 // Unload all of the modules
1361 for(;!module_list_.empty();module_list_.pop_back())
1364 delete state_manager;
1368 delete auto_recover;
1374 // studio::App::iteration(false);
1378 // studio::App::iteration(false);
1380 // studio::App::iteration(false);
1382 delete dialog_setup;
1384 delete dialog_gradient;
1386 delete dialog_color;
1388 delete dialog_input;
1390 delete dock_manager;
1392 instance_list.clear();
1394 // studio::App::iteration(false);
1398 App::get_user_app_directory()
1400 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1402 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1404 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1409 App::get_config_file(const synfig::String& file)
1411 return Glib::build_filename(get_user_app_directory(),file);
1414 #define SCALE_FACTOR (1280)
1415 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1417 App::set_recent_file_window_size(etl::handle<Instance> instance)
1419 int screen_w(Gdk::screen_width());
1420 int screen_h(Gdk::screen_height());
1422 const std::string &canvas_window_size = *recent_files_window_size.begin();
1424 if(canvas_window_size.empty())
1427 synfig::String::size_type current=0;
1428 bool seen_root(false), shown_non_root(false);
1430 while(current != synfig::String::npos)
1432 // find end of first field (canvas) or return
1433 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1434 if(separator == synfig::String::npos) break;
1437 synfig::Canvas::Handle canvas;
1440 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
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.resize_imported_images","0");
1736 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1737 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1738 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1739 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1740 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1744 App::shutdown_request(GdkEventAny*)
1748 //return !shutdown_in_progress;
1754 if(shutdown_in_progress)return;
1757 get_ui_interface()->task(_("Quit Request"));
1760 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1764 std::list<etl::handle<Instance> >::iterator iter;
1765 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1767 if(!(*iter)->safe_close())
1771 if((*iter)->synfigapp::Instance::get_action_count())
1773 handle<synfigapp::UIInterface> uim;
1774 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1776 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1777 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1779 case synfigapp::UIInterface::RESPONSE_NO:
1781 case synfigapp::UIInterface::RESPONSE_YES:
1784 case synfigapp::UIInterface::RESPONSE_CANCEL:
1793 if((*iter)->synfigapp::Instance::is_modified())
1795 handle<synfigapp::UIInterface> uim;
1796 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1798 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() );
1799 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1801 case synfigapp::UIInterface::RESPONSE_NO:
1803 case synfigapp::UIInterface::RESPONSE_YES:
1804 (*iter)->dialog_cvs_commit();
1806 case synfigapp::UIInterface::RESPONSE_CANCEL:
1815 // This next line causes things to crash for some reason
1819 shutdown_in_progress=true;
1821 instance_list.clear();
1823 while(studio::App::events_pending())studio::App::iteration(false);
1826 auto_recover->normal_shutdown();
1828 get_ui_interface()->task(_("Quit Request sent"));
1834 dialog_setup->refresh();
1835 dialog_setup->show();
1838 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1839 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1842 //#define USE_WIN32_FILE_DIALOGS 1
1845 #ifdef USE_WIN32_FILE_DIALOGS
1846 static OPENFILENAME ofn={};
1850 #include <gdk/gdkwin32.h>
1854 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1856 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1858 #ifdef USE_WIN32_FILE_DIALOGS
1859 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1861 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1862 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1863 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1865 ofn.lStructSize=sizeof(OPENFILENAME);
1866 ofn.hwndOwner = hWnd;
1867 ofn.hInstance = hInstance;
1868 ofn.lpstrFilter = szFilter;
1869 // ofn.lpstrCustomFilter=NULL;
1870 // ofn.nMaxCustFilter=0;
1871 // ofn.nFilterIndex=0;
1872 // ofn.lpstrFile=NULL;
1873 ofn.nMaxFile=MAX_PATH;
1874 // ofn.lpstrFileTitle=NULL;
1875 // ofn.lpstrInitialDir=NULL;
1876 // ofn.lpstrTitle=NULL;
1877 ofn.Flags=OFN_HIDEREADONLY;
1878 // ofn.nFileOffset=0;
1879 // ofn.nFileExtension=0;
1880 ofn.lpstrDefExt=TEXT("sif");
1881 // ofn.lCustData = 0l;
1883 // ofn.lpTemplateName=NULL;
1885 CHAR szFilename[MAX_PATH];
1887 strcpy(szFilename,filename.c_str());
1888 strcpy(szTitle,title.c_str());
1890 ofn.lpstrFile=szFilename;
1891 ofn.lpstrFileTitle=szTitle;
1893 if(GetOpenFileName(&ofn))
1895 filename=szFilename;
1901 synfig::String prev_path;
1903 if(!_preferences.get_value(preference, prev_path))
1906 prev_path = absolute_path(prev_path);
1908 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1910 dialog->set_current_folder(prev_path);
1911 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1912 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1914 if (filename.empty())
1915 dialog->set_filename(prev_path);
1916 else if (is_absolute_path(filename))
1917 dialog->set_filename(filename);
1919 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1921 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1922 filename = dialog->get_filename();
1923 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1924 _preferences.set_value(preference, dirname(filename));
1938 GtkWidget *fileselection;
1939 fileselection = gtk_file_selection_new(title.c_str());
1942 if(basename(filename)==filename)
1944 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1947 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1949 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1951 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1952 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1954 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1955 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1957 gtk_widget_show(fileselection);
1965 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1966 _preferences.set_value(preference,dirname(filename));
1970 gtk_widget_destroy(fileselection);
1973 gtk_widget_destroy(fileselection);
1980 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1982 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1984 #if USE_WIN32_FILE_DIALOGS
1985 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1987 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1988 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1989 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1991 ofn.lStructSize=sizeof(OPENFILENAME);
1992 ofn.hwndOwner = hWnd;
1993 ofn.hInstance = hInstance;
1994 ofn.lpstrFilter = szFilter;
1995 // ofn.lpstrCustomFilter=NULL;
1996 // ofn.nMaxCustFilter=0;
1997 // ofn.nFilterIndex=0;
1998 // ofn.lpstrFile=NULL;
1999 ofn.nMaxFile=MAX_PATH;
2000 // ofn.lpstrFileTitle=NULL;
2001 // ofn.lpstrInitialDir=NULL;
2002 // ofn.lpstrTitle=NULL;
2003 ofn.Flags=OFN_OVERWRITEPROMPT;
2004 // ofn.nFileOffset=0;
2005 // ofn.nFileExtension=0;
2006 ofn.lpstrDefExt=TEXT("sif");
2007 // ofn.lCustData = 0l;
2009 // ofn.lpTemplateName=NULL;
2011 CHAR szFilename[MAX_PATH];
2013 strcpy(szFilename,filename.c_str());
2014 strcpy(szTitle,title.c_str());
2016 ofn.lpstrFile=szFilename;
2017 ofn.lpstrFileTitle=szTitle;
2019 if(GetSaveFileName(&ofn))
2021 filename=szFilename;
2022 _preferences.set_value(preference,dirname(filename));
2027 synfig::String prev_path;
2029 if(!_preferences.get_value(preference, prev_path))
2032 prev_path = absolute_path(prev_path);
2034 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2036 dialog->set_current_folder(prev_path);
2037 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2038 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2040 Widget_Enum *file_type_enum = 0;
2041 if (preference == ANIMATION_DIR_PREFERENCE)
2043 file_type_enum = manage(new Widget_Enum());
2044 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2045 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2046 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2047 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2048 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2049 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2051 Gtk::HBox *hbox = manage(new Gtk::HBox);
2052 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2053 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2056 dialog->set_extra_widget(*hbox);
2059 if (filename.empty())
2060 dialog->set_filename(prev_path);
2063 std::string full_path;
2064 if (is_absolute_path(filename))
2065 full_path = filename;
2067 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2069 // select the file if it exists
2070 dialog->set_filename(full_path);
2072 // if the file doesn't exist, put its name into the filename box
2074 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2075 dialog->set_current_name(basename(filename));
2078 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2079 if (preference == ANIMATION_DIR_PREFERENCE)
2080 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2081 filename = dialog->get_filename();
2082 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2083 _preferences.set_value(preference, dirname(filename));
2094 App::dialog_error_blocking(const std::string &title, const std::string &message)
2096 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2097 dialog.set_title(title);
2103 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2105 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2106 dialog.set_title(title);
2112 App::dialog_yes_no(const std::string &title, const std::string &message)
2117 true // use_separator
2119 Gtk::Label label(message);
2122 dialog.get_vbox()->pack_start(label);
2123 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2124 dialog.add_button(Gtk::StockID("gtk-no"),0);
2126 return dialog.run();
2130 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2135 true // use_separator
2137 Gtk::Label label(message);
2140 dialog.get_vbox()->pack_start(label);
2141 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2142 dialog.add_button(Gtk::StockID("gtk-no"),0);
2143 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2145 return dialog.run();
2149 App::dialog_not_implemented()
2151 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2152 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2157 try_open_url(const std::string &url)
2160 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2162 std::vector<std::string> command_line;
2163 std::vector<std::string> browsers;
2164 browsers.reserve(23);
2166 // Browser wrapper scripts
2167 #ifdef USE_OPEN_FOR_URLS
2168 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2170 browsers.push_back("xdg-open"); // XDG wrapper
2171 browsers.push_back("sensible-browser"); // Debian wrapper
2172 browsers.push_back("gnome-open"); // GNOME wrapper
2173 browsers.push_back("kfmclient"); // KDE wrapper
2174 browsers.push_back("exo-open"); // XFCE wrapper
2176 // Alternatives system
2177 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2178 browsers.push_back("x-www-browser"); // Debian GUI alternative
2180 // Individual browsers
2181 browsers.push_back("firefox");
2182 browsers.push_back("epiphany-browser");
2183 browsers.push_back("epiphany");
2184 browsers.push_back("konqueror");
2185 browsers.push_back("iceweasel");
2186 browsers.push_back("mozilla");
2187 browsers.push_back("netscape");
2188 browsers.push_back("icecat");
2189 browsers.push_back("galeon");
2190 browsers.push_back("midori");
2191 browsers.push_back("safari");
2192 browsers.push_back("opera");
2193 browsers.push_back("amaya");
2194 browsers.push_back("netsurf");
2195 browsers.push_back("dillo");
2197 // Try the user-specified browser first
2198 command_line.push_back(App::browser_command);
2199 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2200 command_line.push_back(url);
2202 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2203 catch( Glib::SpawnError& exception ){
2205 while ( !browsers.empty() )
2207 // Skip the browser if we already tried it
2208 if( browsers[0] == App::browser_command )
2211 // Construct the command line
2212 command_line.clear();
2213 command_line.push_back(browsers[0]);
2214 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2215 command_line.push_back(url);
2217 // Remove the browser from the list
2218 browsers.erase(browsers.begin());
2220 // Try to spawn the browser
2221 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2222 // Failed, move on to the next one
2223 catch(Glib::SpawnError& exception){ continue; }
2224 return true; // No exception means we succeeded!
2235 if (!try_open_url("http://synfig.org/Documentation"))
2237 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2238 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2239 dialog.set_title(_("Help"));
2245 App::open_url(const std::string &url)
2247 if(!try_open_url(url))
2249 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2250 dialog.set_secondary_text(url);
2251 dialog.set_title(_("No browser found"));
2257 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2262 true); // use_separator
2264 Gtk::Label label(message);
2266 dialog.get_vbox()->pack_start(label);
2269 entry.set_text(text);
2271 entry.set_activates_default(true);
2273 dialog.get_vbox()->pack_start(entry);
2275 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2276 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2277 dialog.set_default_response(Gtk::RESPONSE_OK);
2279 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2282 if(dialog.run()!=Gtk::RESPONSE_OK)
2285 text=entry.get_text();
2291 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2296 true); // use_separator
2298 Gtk::Label label(message);
2300 dialog.get_vbox()->pack_start(label);
2302 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2303 text_buffer->set_text(text);
2304 Gtk::TextView text_view(text_buffer);
2307 dialog.get_vbox()->pack_start(text_view);
2309 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2310 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2311 dialog.set_default_response(Gtk::RESPONSE_OK);
2313 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2316 if(dialog.run()!=Gtk::RESPONSE_OK)
2319 text=text_buffer->get_text();
2325 App::open(std::string filename)
2327 return open_as(filename,filename);
2330 // this is called from autorecover.cpp:
2331 // App::open_as(get_shadow_file_name(filename),filename)
2332 // other than that, 'filename' and 'as' are the same
2334 App::open_as(std::string filename,std::string as)
2337 char long_name[1024];
2338 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2339 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2340 // don't use it if that's the case
2341 if (long_name[0] != '\0')
2347 OneMoment one_moment;
2348 String errors, warnings;
2350 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2351 if(canvas && get_instance(canvas))
2353 get_instance(canvas)->find_canvas_view(canvas)->present();
2354 info("%s is already open", filename.c_str());
2355 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2360 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2363 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2365 if (as.find(custom_filename_prefix.c_str()) != 0)
2366 add_recent_file(as);
2368 handle<Instance> instance(Instance::create(canvas));
2371 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2373 set_recent_file_window_size(instance);
2377 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)")))
2378 instance->dialog_cvs_update();
2383 dialog_error_blocking(_("Error"), x);
2386 catch(runtime_error x)
2388 dialog_error_blocking(_("Error"), x.what());
2393 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2404 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2406 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2407 canvas->set_name(file_name);
2408 file_name += ".sifz";
2410 canvas->rend_desc().set_frame_rate(24.0);
2411 canvas->rend_desc().set_time_start(0.0);
2412 canvas->rend_desc().set_time_end(5.0);
2413 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2414 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2415 // The top left and botton right positions are expressed in units
2416 // Original convention is that 1 unit = 60 pixels
2417 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2418 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2419 canvas->rend_desc().set_w(preferred_x_size);
2420 canvas->rend_desc().set_h(preferred_y_size);
2421 canvas->rend_desc().set_antialias(1);
2422 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2423 canvas->set_file_name(file_name);
2425 handle<Instance> instance = Instance::create(canvas);
2427 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2428 instance->find_canvas_view(canvas)->canvas_properties.present();
2432 App::dialog_open(string filename)
2434 if (filename.empty())
2437 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2439 // If the filename still has wildcards, then we should
2440 // continue looking for the file we want
2441 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2447 get_ui_interface()->error(_("Unable to open file"));
2452 App::set_selected_instance(etl::loose_handle<Instance> instance)
2454 /* if(get_selected_instance()==instance)
2456 selected_instance=instance;
2457 signal_instance_selected()(instance);
2463 selected_instance=instance;
2464 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2468 instance->focus(instance->get_canvas());
2471 set_selected_canvas_view(0);
2473 signal_instance_selected()(instance);
2477 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2479 selected_canvas_view=canvas_view;
2480 signal_canvas_view_focus()(selected_canvas_view);
2483 selected_instance=canvas_view->get_instance();
2484 signal_instance_selected()(canvas_view->get_instance());
2487 if(get_selected_canvas_view()==canvas_view)
2489 signal_canvas_view_focus()(selected_canvas_view);
2490 signal_instance_selected()(canvas_view->get_instance());
2493 selected_canvas_view=canvas_view;
2494 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2495 set_selected_instance(canvas_view->get_instance());
2496 signal_canvas_view_focus()(selected_canvas_view);
2500 etl::loose_handle<Instance>
2501 App::get_instance(etl::handle<synfig::Canvas> canvas)
2503 if(!canvas) return 0;
2504 canvas=canvas->get_root();
2506 std::list<etl::handle<Instance> >::iterator iter;
2507 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2509 if((*iter)->get_canvas()==canvas)
2525 if(selected_instance)
2526 selected_instance->undo();
2532 if(selected_instance)
2533 selected_instance->redo();
2537 studio::App::get_base_path()
2539 return app_base_path_;