1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2008 Gerald Young
11 ** Copyright (c) 2008 Carlos López
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
24 /* ========================================================================= */
26 /* === H E A D E R S ======================================================= */
45 #ifdef HAVE_SYS_ERRNO_H
46 #include <sys/errno.h>
48 #include <gtkmm/fileselection.h>
49 #include <gtkmm/dialog.h>
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/label.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/stockitem.h>
54 #include <gtkmm/iconsource.h>
55 #include <gtkmm/inputdialog.h>
56 #include <gtkmm/accelmap.h>
57 #include <gtkmm/uimanager.h>
58 #include <gtkmm/textview.h>
62 #include <gdkmm/general.h>
64 #include <synfig/loadcanvas.h>
65 #include <synfig/savecanvas.h>
71 #include "canvasview.h"
72 #include "dialog_setup.h"
73 #include "dialog_gradient.h"
74 #include "dialog_color.h"
77 #include "onemoment.h"
79 #include "dockmanager.h"
81 #include "state_eyedrop.h"
82 #include "state_normal.h"
83 #include "state_draw.h"
84 #include "state_fill.h"
85 #include "state_bline.h"
86 #include "state_polygon.h"
87 #include "state_sketch.h"
88 #include "state_gradient.h"
89 #include "state_circle.h"
90 #include "state_rectangle.h"
91 #include "state_smoothmove.h"
92 #include "state_scale.h"
93 #include "state_star.h"
94 #include "state_text.h"
95 #include "state_width.h"
96 #include "state_rotate.h"
97 #include "state_zoom.h"
99 #include "devicetracker.h"
100 #include "dialog_tooloptions.h"
101 #include "widget_enum.h"
103 #include "autorecover.h"
105 #include <synfigapp/settings.h>
106 #include "dock_history.h"
107 #include "dock_canvases.h"
108 #include "dock_keyframes.h"
109 #include "dock_layers.h"
110 #include "dock_params.h"
111 #include "dock_metadata.h"
112 #include "dock_children.h"
113 #include "dock_info.h"
114 #include "dock_navigator.h"
115 #include "dock_layergroups.h"
116 #include "dock_timetrack.h"
117 #include "dock_curves.h"
119 #include "mod_palette/mod_palette.h"
120 #include "mod_mirror/mod_mirror.h"
122 #include <sys/stat.h>
128 #include "statemanager.h"
134 #include <gtkmm/accelmap.h>
135 #include <gtkmm/filechooser.h>
136 #include <gtkmm/filechooserdialog.h>
142 /* === U S I N G =========================================================== */
146 using namespace synfig;
147 using namespace studio;
149 /* === M A C R O S ========================================================= */
151 #ifndef SYNFIG_USER_APP_DIR
153 #define SYNFIG_USER_APP_DIR "Library/Synfig"
154 #elif defined(_WIN32)
155 #define SYNFIG_USER_APP_DIR "Synfig"
157 #define SYNFIG_USER_APP_DIR ".synfig"
162 #define DPM2DPI(x) (float(x)/39.3700787402f)
163 #define DPI2DPM(x) (float(x)*39.3700787402f)
169 # define IMAGE_DIR "share\\pixmaps"
174 # define IMAGE_DIR "/usr/local/share/pixmaps"
178 # define IMAGE_EXT "tif"
181 #include <synfigapp/main.h>
183 /* === S I G N A L S ======================================================= */
185 static sigc::signal<void> signal_present_all_;
187 App::signal_present_all() { return signal_present_all_; }
189 static sigc::signal<void> signal_recent_files_changed_;
191 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
193 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
194 sigc::signal<void,etl::loose_handle<CanvasView> >&
195 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_selected() { return signal_instance_selected_; }
201 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
202 sigc::signal<void,etl::handle<Instance> >&
203 App::signal_instance_created() { return signal_instance_created_; }
205 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
206 sigc::signal<void,etl::handle<Instance> >&
207 App::signal_instance_deleted() { return signal_instance_deleted_; }
209 /* === G L O B A L S ======================================================= */
211 static std::list<std::string> recent_files;
212 const std::list<std::string>& App::get_recent_files() { return recent_files; }
214 static std::list<std::string> recent_files_window_size;
216 int App::Busy::count;
217 bool App::shutdown_in_progress;
219 synfig::Gamma App::gamma;
221 Glib::RefPtr<studio::UIManager> App::ui_manager_;
223 synfig::Distance::System App::distance_system;
225 studio::Dialog_Setup* App::dialog_setup;
227 etl::handle< studio::ModPalette > mod_palette_;
228 //studio::Dialog_Palette* App::dialog_palette;
230 std::list<etl::handle<Instance> > App::instance_list;
232 static etl::handle<synfigapp::UIInterface> ui_interface_;
233 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
235 etl::handle<Instance> App::selected_instance;
236 etl::handle<CanvasView> App::selected_canvas_view;
238 studio::About *studio::App::about=NULL;
240 studio::Toolbox *studio::App::toolbox=NULL;
242 studio::AutoRecover *studio::App::auto_recover=NULL;
244 studio::IPC *ipc=NULL;
246 studio::DockManager* studio::App::dock_manager=0;
248 studio::DeviceTracker* studio::App::device_tracker=0;
250 studio::Dialog_Gradient* studio::App::dialog_gradient;
252 studio::Dialog_Color* studio::App::dialog_color;
254 Gtk::InputDialog* studio::App::dialog_input;
256 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
258 studio::Dock_History* dock_history;
259 studio::Dock_Canvases* dock_canvases;
260 studio::Dock_Keyframes* dock_keyframes;
261 studio::Dock_Layers* dock_layers;
262 studio::Dock_Params* dock_params;
263 studio::Dock_MetaData* dock_meta_data;
264 studio::Dock_Children* dock_children;
265 studio::Dock_Info* dock_info;
266 studio::Dock_LayerGroups* dock_layer_groups;
267 studio::Dock_Navigator* dock_navigator;
268 studio::Dock_Timetrack* dock_timetrack;
269 studio::Dock_Curves* dock_curves;
271 std::list< etl::handle< studio::Module > > module_list_;
273 bool studio::App::use_colorspace_gamma=true;
274 #ifdef SINGLE_THREADED
275 bool studio::App::single_threaded=false;
277 bool studio::App::restrict_radius_ducks=false;
278 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
279 int studio::App::preferred_x_size=480;
280 int studio::App::preferred_y_size=270;
281 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
282 #ifdef USE_OPEN_FOR_URLS
283 String studio::App::browser_command("open"); // MacOS only
285 String studio::App::browser_command("xdg-open"); // Linux XDG standard
288 static int max_recent_files_=25;
289 int studio::App::get_max_recent_files() { return max_recent_files_; }
290 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
292 static synfig::String app_base_path_;
297 really_delete_widget(Gtk::Widget *widget)
299 // synfig::info("really delete %p", (void*)widget);
304 // nasty workaround - when we've finished with a popup menu, we want to delete it
305 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
306 // so schedule the real delete to happen in 50ms, giving the action a chance to run
308 delete_widget(Gtk::Widget *widget)
310 // synfig::info("delete %p", (void*)widget);
311 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
314 }; // END of namespace studio
315 studio::StateManager* state_manager;
320 class GlobalUIInterface : public synfigapp::UIInterface
324 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
329 true // use_separator
331 Gtk::Label label(message);
334 dialog.get_vbox()->pack_start(label);
335 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
336 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
338 dialog.set_default_response(dflt);
340 return (Response)dialog.run();
342 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
347 true // use_separator
349 Gtk::Label label(message);
352 dialog.get_vbox()->pack_start(label);
353 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
354 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
355 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
357 dialog.set_default_response(dflt);
359 return (Response)dialog.run();
361 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
366 true // use_separator
368 Gtk::Label label(message);
371 dialog.get_vbox()->pack_start(label);
372 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
373 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
375 dialog.set_default_response(dflt);
377 return (Response)dialog.run();
381 task(const std::string &task)
383 std::cerr<<task<<std::endl;
384 while(studio::App::events_pending())studio::App::iteration(false);
389 error(const std::string &err)
391 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
398 warning(const std::string &err)
400 std::cerr<<"warning: "<<err<<std::endl;
401 while(studio::App::events_pending())studio::App::iteration(false);
406 amount_complete(int /*current*/, int /*total*/)
408 while(studio::App::events_pending())studio::App::iteration(false);
413 /* === P R O C E D U R E S ================================================= */
417 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
419 action_group_list.push_back(action_group);
420 Gtk::UIManager::insert_action_group(action_group, pos);
424 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
426 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
427 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
428 if(*iter==action_group)
430 action_group_list.erase(iter);
431 Gtk::UIManager::remove_action_group(action_group);
434 synfig::error("Unable to find action group");
438 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
440 ui_manager->insert_action_group(group,0);
442 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
443 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
445 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
447 if(*iter && (*iter)->get_name()!="menus")
449 synfig::info("Removing action group "+(*iter)->get_name());
450 ui_manager->remove_action_group(*iter);
453 ui_manager->insert_action_group(group,0);
455 for(;!prev_groups.empty();prev_groups.pop_front())
457 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
458 ui_manager->insert_action_group(prev_groups.front(),1);
462 class Preferences : public synfigapp::Settings
465 virtual bool get_value(const synfig::String& key, synfig::String& value)const
469 value=strprintf("%f %f %f %f",
470 App::gamma.get_gamma_r(),
471 App::gamma.get_gamma_g(),
472 App::gamma.get_gamma_b(),
473 App::gamma.get_black_level()
477 if(key=="time_format")
479 value=strprintf("%i",App::get_time_format());
482 if(key=="file_history.size")
484 value=strprintf("%i",App::get_max_recent_files());
487 if(key=="use_colorspace_gamma")
489 value=strprintf("%i",(int)App::use_colorspace_gamma);
492 if(key=="distance_system")
494 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
497 #ifdef SINGLE_THREADED
498 if(key=="single_threaded")
500 value=strprintf("%i",(int)App::single_threaded);
504 if(key=="auto_recover_backup_interval")
506 value=strprintf("%i",App::auto_recover->get_timeout());
509 if(key=="restrict_radius_ducks")
511 value=strprintf("%i",(int)App::restrict_radius_ducks);
514 if(key=="browser_command")
516 value=App::browser_command;
519 if(key=="custom_filename_prefix")
521 value=App::custom_filename_prefix;
524 if(key=="preferred_x_size")
526 value=strprintf("%i",App::preferred_x_size);
529 if(key=="preferred_y_size")
531 value=strprintf("%i",App::preferred_y_size);
534 if(key=="predefined_size")
536 value=strprintf("%s",App::predefined_size.c_str());
540 return synfigapp::Settings::get_value(key,value);
543 virtual bool set_value(const synfig::String& key,const synfig::String& value)
549 strscanf(value,"%f %f %f %f",
556 App::gamma.set_all(r,g,b,blk);
560 if(key=="time_format")
562 int i(atoi(value.c_str()));
563 App::set_time_format(static_cast<synfig::Time::Format>(i));
566 if(key=="auto_recover_backup_interval")
568 int i(atoi(value.c_str()));
569 App::auto_recover->set_timeout(i);
572 if(key=="file_history.size")
574 int i(atoi(value.c_str()));
575 App::set_max_recent_files(i);
578 if(key=="use_colorspace_gamma")
580 int i(atoi(value.c_str()));
581 App::use_colorspace_gamma=i;
584 if(key=="distance_system")
586 App::distance_system=Distance::ident_system(value);;
589 #ifdef SINGLE_THREADED
590 if(key=="single_threaded")
592 int i(atoi(value.c_str()));
593 App::single_threaded=i;
597 if(key=="restrict_radius_ducks")
599 int i(atoi(value.c_str()));
600 App::restrict_radius_ducks=i;
603 if(key=="browser_command")
605 App::browser_command=value;
608 if(key=="custom_filename_prefix")
610 App::custom_filename_prefix=value;
613 if(key=="preferred_x_size")
615 int i(atoi(value.c_str()));
616 App::preferred_x_size=i;
619 if(key=="preferred_y_size")
621 int i(atoi(value.c_str()));
622 App::preferred_y_size=i;
625 if(key=="predefined_size")
627 App::predefined_size=value;
630 return synfigapp::Settings::set_value(key,value);
633 virtual KeyList get_key_list()const
635 KeyList ret(synfigapp::Settings::get_key_list());
636 ret.push_back("gamma");
637 ret.push_back("time_format");
638 ret.push_back("distance_system");
639 ret.push_back("file_history.size");
640 ret.push_back("use_colorspace_gamma");
641 #ifdef SINGLE_THREADED
642 ret.push_back("single_threaded");
644 ret.push_back("auto_recover_backup_interval");
645 ret.push_back("restrict_radius_ducks");
646 ret.push_back("browser_command");
647 ret.push_back("custom_filename_prefix");
648 ret.push_back("preferred_x_size");
649 ret.push_back("preferred_y_size");
650 ret.push_back("predefined_size");
655 static ::Preferences _preferences;
660 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
662 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
664 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
666 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
667 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
668 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
669 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
670 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
671 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
672 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
673 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
674 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
675 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
676 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
677 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
678 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
680 // Add the synfigapp actions...
681 synfigapp::Action::Book::iterator iter;
682 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
684 actions_action_group->add(Gtk::Action::create(
685 "action-"+iter->second.name,
686 get_action_stock_id(iter->second),
687 iter->second.local_name,iter->second.local_name
691 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
692 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
693 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ group->add(action,sig); }
695 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
696 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
697 DEFINE_ACTION("new", Gtk::Stock::NEW);
698 DEFINE_ACTION("open", Gtk::Stock::OPEN);
699 DEFINE_ACTION("save", Gtk::Stock::SAVE);
700 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
701 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
702 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
703 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
704 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
705 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
706 DEFINE_ACTION("import", _("Import"));
707 DEFINE_ACTION("render", _("Render"));
708 DEFINE_ACTION("preview", _("Preview"));
709 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
710 DEFINE_ACTION("sound", _("Sound File"));
711 DEFINE_ACTION("options", _("Options"));
712 DEFINE_ACTION("close", _("Close View"));
713 DEFINE_ACTION("close-document", _("Close Document"));
714 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
717 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
718 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
719 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
720 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
721 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
722 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
723 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
724 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
725 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
726 DEFINE_ACTION("properties", _("Properties"));
728 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
729 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
730 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
731 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
732 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
733 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
734 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
735 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
736 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
737 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
738 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
739 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
740 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
741 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
742 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
743 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
744 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
745 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
746 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
747 DEFINE_ACTION("play", _("Play"));
748 // DEFINE_ACTION("pause", _("Pause"));
749 DEFINE_ACTION("stop", _("Stop"));
750 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
751 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
752 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
753 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
754 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
755 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
756 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
757 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
758 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
759 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
760 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
761 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
762 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
763 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
764 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
765 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
766 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
767 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
768 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
769 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
770 DEFINE_ACTION("seek-end", _("Seek to End"));
772 DEFINE_ACTION("action-group_add", _("Add group"));
774 DEFINE_ACTION("canvas-new", _("New Canvas"));
776 DEFINE_ACTION("amount-inc", _("Increase Amount"));
777 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
782 // Set up synfigapp actions
784 synfigapp::Action::Book::iterator iter;
786 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
788 Gtk::StockID stock_id;
790 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
792 //Gtk::Image* image(manage(new Gtk::Image()));
793 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
794 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
795 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
796 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
797 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
798 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
799 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
800 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
801 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
802 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
804 actions_action_group->add(Gtk::Action::create(
805 "action-"+iter->second.name,
807 iter->second.local_name,iter->second.local_name
815 Glib::ustring ui_info =
817 " <popup name='menu-toolbox' action='menu-toolbox'>"
818 " <menu action='menu-file'>"
821 " <popup name='menu-main' action='menu-main'>"
822 " <menu action='menu-file'>"
823 " <menuitem action='new' />"
824 " <menuitem action='open' />"
825 " <menuitem action='save' />"
826 " <menuitem action='save-as' />"
827 " <menuitem action='revert' />"
828 " <separator name='bleh01'/>"
829 " <menuitem action='cvs-add' />"
830 " <menuitem action='cvs-update' />"
831 " <menuitem action='cvs-commit' />"
832 " <menuitem action='cvs-revert' />"
833 " <separator name='bleh02'/>"
834 " <menuitem action='import' />"
835 " <separator name='bleh03'/>"
836 " <menuitem action='render' />"
837 " <menuitem action='preview' />"
838 " <menuitem action='sound' />"
839 " <separator name='bleh04'/>"
840 " <menuitem action='options' />"
841 " <menuitem action='close' />"
842 " <menuitem action='close-document' />"
843 " <menuitem action='quit' />"
845 " <menu action='menu-edit'>"
846 " <menuitem action='undo'/>"
847 " <menuitem action='redo'/>"
848 " <separator name='bleh05'/>"
849 " <menuitem action='cut'/>"
850 " <menuitem action='copy'/>"
851 " <menuitem action='paste'/>"
852 " <separator name='bleh06'/>"
853 " <menuitem action='select-all-layers'/>"
854 " <menuitem action='unselect-all-layers'/>"
855 " <menuitem action='select-all-ducks'/>"
856 " <menuitem action='unselect-all-ducks'/>"
857 " <separator name='bleh07'/>"
858 " <menuitem action='properties'/>"
860 " <menu action='menu-view'>"
861 " <menu action='menu-duck-mask'>"
862 " <menuitem action='mask-position-ducks' />"
863 " <menuitem action='mask-vertex-ducks' />"
864 " <menuitem action='mask-tangent-ducks' />"
865 " <menuitem action='mask-radius-ducks' />"
866 " <menuitem action='mask-width-ducks' />"
867 " <menuitem action='mask-angle-ducks' />"
869 " <menu action='menu-preview-quality'>"
870 " <menuitem action='quality-00' />"
871 " <menuitem action='quality-01' />"
872 " <menuitem action='quality-02' />"
873 " <menuitem action='quality-03' />"
874 " <menuitem action='quality-04' />"
875 " <menuitem action='quality-05' />"
876 " <menuitem action='quality-06' />"
877 " <menuitem action='quality-07' />"
878 " <menuitem action='quality-08' />"
879 " <menuitem action='quality-09' />"
880 " <menuitem action='quality-10' />"
882 " <menu action='menu-lowres-pixel'>"
883 " <menuitem action='decrease-low-res-pixel-size'/>"
884 " <menuitem action='increase-low-res-pixel-size'/>"
885 " <separator name='pixel-size-separator'/>"
888 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
889 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
893 " <separator name='bleh08'/>"
894 " <menuitem action='play'/>"
895 //" <menuitem action='pause'/>"
896 " <menuitem action='stop'/>"
897 " <menuitem action='dialog-flipbook'/>"
898 " <separator name='bleh09'/>"
899 " <menuitem action='toggle-grid-show'/>"
900 " <menuitem action='toggle-grid-snap'/>"
901 " <menuitem action='toggle-guide-show'/>"
902 " <menuitem action='toggle-low-res'/>"
903 " <menuitem action='toggle-onion-skin'/>"
904 " <separator name='bleh10'/>"
905 " <menuitem action='canvas-zoom-in'/>"
906 " <menuitem action='canvas-zoom-out'/>"
907 " <menuitem action='canvas-zoom-fit'/>"
908 " <menuitem action='canvas-zoom-100'/>"
909 " <separator name='bleh11'/>"
910 " <menuitem action='time-zoom-in'/>"
911 " <menuitem action='time-zoom-out'/>"
912 " <separator name='bleh12'/>"
913 " <menuitem action='jump-next-keyframe'/>"
914 " <menuitem action='jump-prev-keyframe'/>"
915 " <menuitem action='seek-next-frame'/>"
916 " <menuitem action='seek-prev-frame'/>"
917 " <menuitem action='seek-next-second'/>"
918 " <menuitem action='seek-prev-second'/>"
919 " <menuitem action='seek-begin'/>"
920 " <menuitem action='seek-end'/>"
922 " <menu action='menu-canvas'>"
923 " <menuitem action='canvas-new'/>"
925 " <menu name='menu-state' action='menu-state'>"
927 " <menu action='menu-group'>"
928 " <menuitem action='action-group_add'/>"
930 " <menu action='menu-layer'>"
931 //" <menuitem action='cut'/>"
932 //" <menuitem action='copy'/>"
933 //" <menuitem action='paste'/>"
934 //" <separator name='bleh06'/>"
935 " <menu action='menu-layer-new'></menu>"
936 " <menuitem action='amount-inc'/>"
937 " <menuitem action='amount-dec'/>"
939 " <menu action='menu-keyframe'>"
940 " <menuitem action='keyframe-properties'/>"
947 " <menubar name='MenuBar'>"
948 " <menu action='MenuFile'>"
949 " <menuitem action='New'/>"
950 " <menuitem action='Open'/>"
952 " <menuitem action='Quit'/>"
954 " <menu action='MenuEdit'>"
955 " <menuitem action='Cut'/>"
956 " <menuitem action='Copy'/>"
957 " <menuitem action='Paste'/>"
960 " <toolbar name='ToolBar'>"
961 " <toolitem action='Open'/>"
962 " <toolitem action='Quit'/>"
968 actions_action_group->set_sensitive(false);
969 App::ui_manager()->set_add_tearoffs(true);
970 App::ui_manager()->insert_action_group(menus_action_group,1);
971 App::ui_manager()->insert_action_group(actions_action_group,1);
972 App::ui_manager()->add_ui_from_string(ui_info);
974 //App::ui_manager()->get_accel_group()->unlock();
976 catch(const Glib::Error& ex)
978 synfig::error("building menus and toolbars failed: " + ex.what());
981 // Add default keyboard accelerators
982 #define ACCEL(path,accel) \
984 Gtk::AccelKey accel_key(accel,path); \
985 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
988 #define ACCEL2(accel) \
990 Gtk::AccelKey accel_key(accel); \
991 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
994 ACCEL("<Actions>//select-all-ducks","<Control>a");
995 ACCEL("<Actions>//unselect-all-ducks","<Control>d");
996 ACCEL("<Actions>//select-all-layers","<Control><Shift>a");
997 ACCEL("<Actions>//unselect-all-layers","<Control><Shift>d");
998 ACCEL("<Actions>//render","F9");
999 ACCEL("<Actions>//preview","F11");
1000 ACCEL("<Actions>//properties","F8");
1001 ACCEL("<Actions>//options","F12");
1002 ACCEL("<Actions>//import","<control>i");
1003 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
1004 ACCEL("<Actions>//toggle-grid-show","<Control>g");
1005 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
1006 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
1007 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
1008 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1009 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1010 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1011 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1012 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1014 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1015 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1017 ACCEL("<Actions>//quality-01","<Control>1");
1018 ACCEL("<Actions>//quality-02","<Control>2");
1019 ACCEL("<Actions>//quality-03","<Control>3");
1020 ACCEL("<Actions>//quality-04","<Control>4");
1021 ACCEL("<Actions>//quality-05","<Control>5");
1022 ACCEL("<Actions>//quality-06","<Control>6");
1023 ACCEL("<Actions>//quality-07","<Control>7");
1024 ACCEL("<Actions>//quality-08","<Control>8");
1025 ACCEL("<Actions>//quality-09","<Control>9");
1026 ACCEL("<Actions>//quality-10","<Control>0");
1027 ACCEL("<Actions>//undo","<Control>z");
1028 ACCEL("<Actions>//redo","<Control>r");
1029 ACCEL("<Actions>//action-layer_remove","Delete");
1031 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1032 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1033 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1034 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1035 ACCEL("<Actions>//time-zoom-in","+");
1036 ACCEL("<Actions>//time-zoom-out","_");
1038 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
1039 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
1041 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1042 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1044 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1045 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1046 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1047 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1048 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1049 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1050 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1051 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1052 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1053 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1054 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
1055 ACCEL("<Actions>//play", "<Control>p");
1056 ACCEL("<Actions>//seek-begin","Home");
1057 ACCEL("<Actions>//seek-end","End");
1059 ACCEL("<Actions>//state-normal", "<Mod1>a");
1060 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1061 ACCEL("<Actions>//state-scale", "<Mod1>s");
1062 ACCEL("<Actions>//state-rotate", "<Mod1>t");
1063 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1065 ACCEL("<Actions>//state-circle", "<Mod1>c");
1066 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1067 ACCEL("<Actions>//state-star", "<Mod1>q");
1068 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1069 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1071 ACCEL("<Actions>//state-bline", "<Mod1>b");
1072 ACCEL("<Actions>//state-text", "<Mod1>x");
1073 ACCEL("<Actions>//state-fill", "<Mod1>f");
1074 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1075 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1077 ACCEL("<Actions>//state-draw", "<Mod1>d");
1078 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1079 ACCEL("<Actions>//state-width", "<Mod1>w");
1081 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1087 #define mkdir(x,y) mkdir(x)
1090 /* === M E T H O D S ======================================================= */
1092 App::App(int *argc, char ***argv):
1093 Gtk::Main(argc,argv),
1094 IconController(etl::dirname((*argv)[0]))
1096 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1099 ui_interface_=new GlobalUIInterface();
1103 // don't call thread_init() if threads are already initialized
1104 // on some machines bonobo_init() initialized threads before we get here
1105 if (!g_thread_supported())
1106 Glib::thread_init();
1108 distance_system=Distance::SYSTEM_UNITS;
1110 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1113 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1117 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1123 if(!SYNFIG_CHECK_VERSION())
1125 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1126 dialog_error_blocking("Synfig Studio",
1127 "This copy of Synfig Studio was compiled against a\n"
1128 "different version of libsynfig than what is currently\n"
1129 "installed. Synfig Studio will now abort. Try downloading\n"
1130 "the latest version from the Synfig website at\n"
1131 "http://synfig.org/Download"
1135 Glib::set_application_name(_("Synfig Studio"));
1137 Splash splash_screen;
1138 splash_screen.show();
1140 shutdown_in_progress=false;
1141 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1142 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1144 // Initialize the Synfig library
1145 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1148 get_ui_interface()->error(_("Failed to initialize synfig!"));
1152 // add the preferences to the settings
1153 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1157 studio_init_cb.task(_("Init UI Manager..."));
1158 App::ui_manager_=studio::UIManager::create();
1161 studio_init_cb.task(_("Init Dock Manager..."));
1162 dock_manager=new studio::DockManager();
1164 studio_init_cb.task(_("Init State Manager..."));
1165 state_manager=new StateManager();
1167 studio_init_cb.task(_("Init Toolbox..."));
1168 toolbox=new studio::Toolbox();
1170 studio_init_cb.task(_("Init About Dialog..."));
1171 about=new studio::About();
1173 studio_init_cb.task(_("Init Tool Options..."));
1174 dialog_tool_options=new studio::Dialog_ToolOptions();
1175 dock_manager->register_dockable(*dialog_tool_options);
1177 studio_init_cb.task(_("Init History..."));
1178 dock_history=new studio::Dock_History();
1179 dock_manager->register_dockable(*dock_history);
1181 studio_init_cb.task(_("Init Canvases..."));
1182 dock_canvases=new studio::Dock_Canvases();
1183 dock_manager->register_dockable(*dock_canvases);
1185 studio_init_cb.task(_("Init Keyframes..."));
1186 dock_keyframes=new studio::Dock_Keyframes();
1187 dock_manager->register_dockable(*dock_keyframes);
1189 studio_init_cb.task(_("Init Layers..."));
1190 dock_layers=new studio::Dock_Layers();
1191 dock_manager->register_dockable(*dock_layers);
1193 studio_init_cb.task(_("Init Params..."));
1194 dock_params=new studio::Dock_Params();
1195 dock_manager->register_dockable(*dock_params);
1197 studio_init_cb.task(_("Init MetaData..."));
1198 dock_meta_data=new studio::Dock_MetaData();
1199 dock_manager->register_dockable(*dock_meta_data);
1201 studio_init_cb.task(_("Init Children..."));
1202 dock_children=new studio::Dock_Children();
1203 dock_manager->register_dockable(*dock_children);
1205 studio_init_cb.task(_("Init Info..."));
1206 dock_info = new studio::Dock_Info();
1207 dock_manager->register_dockable(*dock_info);
1209 studio_init_cb.task(_("Init Navigator..."));
1210 dock_navigator = new studio::Dock_Navigator();
1211 dock_manager->register_dockable(*dock_navigator);
1213 studio_init_cb.task(_("Init Timetrack..."));
1214 dock_timetrack = new studio::Dock_Timetrack();
1215 dock_manager->register_dockable(*dock_timetrack);
1217 studio_init_cb.task(_("Init Curve Editor..."));
1218 dock_curves = new studio::Dock_Curves();
1219 dock_manager->register_dockable(*dock_curves);
1221 studio_init_cb.task(_("Init Layer Groups..."));
1222 dock_layer_groups = new studio::Dock_LayerGroups();
1223 dock_manager->register_dockable(*dock_layer_groups);
1226 studio_init_cb.task(_("Init Color Dialog..."));
1227 dialog_color=new studio::Dialog_Color();
1229 studio_init_cb.task(_("Init Gradient Dialog..."));
1230 dialog_gradient=new studio::Dialog_Gradient();
1232 studio_init_cb.task(_("Init DeviceTracker..."));
1233 device_tracker=new studio::DeviceTracker();
1235 studio_init_cb.task(_("Init Tools..."));
1238 state_manager->add_state(&state_normal);
1239 state_manager->add_state(&state_smooth_move);
1240 state_manager->add_state(&state_scale);
1241 state_manager->add_state(&state_rotate);
1242 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1245 state_manager->add_state(&state_circle);
1246 state_manager->add_state(&state_rectangle);
1247 state_manager->add_state(&state_star);
1248 state_manager->add_state(&state_gradient);
1249 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1252 state_manager->add_state(&state_bline);
1253 state_manager->add_state(&state_text);
1254 state_manager->add_state(&state_fill);
1255 state_manager->add_state(&state_eyedrop);
1256 state_manager->add_state(&state_zoom);
1258 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1259 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1260 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1262 studio_init_cb.task(_("Init ModPalette..."));
1263 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1265 studio_init_cb.task(_("Init Setup Dialog..."));
1266 dialog_setup=new studio::Dialog_Setup();
1268 studio_init_cb.task(_("Init Input Dialog..."));
1269 dialog_input=new Gtk::InputDialog();
1270 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1271 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1273 studio_init_cb.task(_("Init auto recovery..."));
1274 auto_recover=new AutoRecover();
1276 studio_init_cb.amount_complete(9250,10000);
1277 studio_init_cb.task(_("Loading Settings..."));
1279 studio_init_cb.task(_("Checking auto-recover..."));
1281 studio_init_cb.amount_complete(9900,10000);
1283 bool opened_any = false;
1284 if(auto_recover->recovery_needed())
1286 splash_screen.hide();
1287 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1288 _("Synfig Studio seems to have crashed\n"
1289 "before you could save all your files.\n"
1290 "Would you like to re-open those files\n"
1291 "and recover your unsaved changes?")) ==
1292 synfigapp::UIInterface::RESPONSE_YES)
1294 int number_recovered;
1295 if(!auto_recover->recover(number_recovered))
1296 if (number_recovered)
1297 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1299 get_ui_interface()->error(_("Unable to recover from previous crash"));
1301 get_ui_interface()->error(
1302 _("Synfig Studio has attempted to recover\n"
1303 "from a previous crash. The files that it has\n"
1304 "recovered are NOT YET SAVED. It would be a good\n"
1305 "idea to review them and save them now."));
1307 if (number_recovered)
1310 splash_screen.show();
1313 // Look for any files given on the command line,
1314 // and load them if found.
1315 for(;*argc>=1;(*argc)--)
1316 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1318 studio_init_cb.task(_("Loading files..."));
1319 splash_screen.hide();
1320 open((*argv)[*argc]);
1322 splash_screen.show();
1325 // if no file was specified to be opened, create a new document to help new users get started more easily
1326 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1329 studio_init_cb.task(_("Done."));
1330 studio_init_cb.amount_complete(10000,10000);
1336 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1340 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1344 StateManager* App::get_state_manager() { return state_manager; }
1348 shutdown_in_progress=true;
1352 synfigapp::Main::settings().remove_domain("pref");
1354 selected_instance=0;
1356 // Unload all of the modules
1357 for(;!module_list_.empty();module_list_.pop_back())
1360 delete state_manager;
1364 delete auto_recover;
1370 // studio::App::iteration(false);
1374 // studio::App::iteration(false);
1376 // studio::App::iteration(false);
1378 delete dialog_setup;
1380 delete dialog_gradient;
1382 delete dialog_color;
1384 delete dialog_input;
1386 delete dock_manager;
1388 instance_list.clear();
1390 // studio::App::iteration(false);
1394 App::get_user_app_directory()
1396 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1398 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1400 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1405 App::get_config_file(const synfig::String& file)
1407 return Glib::build_filename(get_user_app_directory(),file);
1410 #define SCALE_FACTOR (1280)
1411 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1413 App::set_recent_file_window_size(etl::handle<Instance> instance)
1415 int screen_w(Gdk::screen_width());
1416 int screen_h(Gdk::screen_height());
1418 const std::string &canvas_window_size = *recent_files_window_size.begin();
1420 if(canvas_window_size.empty())
1423 synfig::String::size_type current=0;
1424 bool seen_root(false), shown_non_root(false);
1426 while(current != synfig::String::npos)
1428 // find end of first field (canvas) or return
1429 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1430 if(separator == synfig::String::npos) break;
1433 synfig::Canvas::Handle canvas;
1435 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1437 catch(Exception::IDNotFound) {
1438 // can't find the canvas; skip to the next canvas or return
1439 separator = canvas_window_size.find_first_of('\t', current);
1440 if(separator == synfig::String::npos) return;
1441 current = separator+1;
1445 if (canvas->is_root())
1448 shown_non_root = true;
1450 // check that we have the tab character the ends this canvas' data or return
1451 current = separator+1;
1452 separator = canvas_window_size.find_first_of('\t', current);
1453 if(separator == synfig::String::npos) return;
1456 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1458 current = separator+1;
1462 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1463 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1464 x=x*screen_w/SCALE_FACTOR;
1465 y=y*screen_h/SCALE_FACTOR;
1466 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1467 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1468 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1469 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1471 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1472 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1474 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1475 canvasview->move(x,y);
1476 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1477 canvasview->present();
1479 current = separator+1;
1482 if (shown_non_root && !seen_root)
1483 instance->find_canvas_view(instance->get_canvas())->hide();
1487 App::add_recent_file(const etl::handle<Instance> instance)
1489 int screen_w(Gdk::screen_width());
1490 int screen_h(Gdk::screen_height());
1492 std::string canvas_window_size;
1494 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1495 Instance::CanvasViewList::const_iterator iter;
1497 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1499 if( !((*iter)->is_visible()) )
1502 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1503 int x_pos, y_pos, x_size, y_size;
1504 (*iter)->get_position(x_pos,y_pos);
1505 (*iter)->get_size(x_size,y_size);
1507 canvas_window_size += strprintf("%s %d %d %d %d\t",
1508 canvas->get_relative_id(canvas->get_root()).c_str(),
1509 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1510 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1513 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1518 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1520 std::string filename(file_name);
1522 assert(!filename.empty());
1524 if(filename.empty())
1527 // Toss out any "hidden" files
1528 if(basename(filename)[0]=='.')
1531 // If we aren't an absolute path, turn ourselves into one
1532 if(!is_absolute_path(filename))
1533 filename=absolute_path(filename);
1535 std::string old_window_size;
1537 list<string>::iterator iter;
1538 list<string>::iterator iter_wsize;
1539 // Check to see if the file is already on the list.
1540 // If it is, then remove it from the list
1541 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1544 recent_files.erase(iter);
1545 old_window_size = *iter_wsize;
1546 recent_files_window_size.erase(iter_wsize);
1551 // Push the filename to the front of the list
1552 recent_files.push_front(filename);
1553 if(window_size.empty())
1554 recent_files_window_size.push_front(old_window_size);
1556 recent_files_window_size.push_front(window_size);
1558 // Clean out the files at the end of the list.
1559 while(recent_files.size()>(unsigned)get_max_recent_files())
1561 recent_files.pop_back();
1562 recent_files_window_size.pop_back();
1565 signal_recent_files_changed_();
1570 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1573 App::get_time_format()
1575 return _App_time_format;
1579 App::set_time_format(synfig::Time::Format x)
1586 App::save_settings()
1591 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1592 setlocale(LC_NUMERIC, "C");
1594 std::string filename=get_config_file("accelrc");
1595 Gtk::AccelMap::save(filename);
1598 std::string filename=get_config_file("recentfiles");
1600 std::ofstream file(filename.c_str());
1604 synfig::warning("Unable to save %s",filename.c_str());
1608 list<string>::reverse_iterator iter;
1610 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1614 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1616 std::ofstream file(filename.c_str());
1620 synfig::warning("Unable to save %s",filename.c_str());
1624 list<string>::reverse_iterator iter;
1626 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1630 std::string filename=get_config_file("settings");
1631 synfigapp::Main::settings().save_to_file(filename);
1632 setlocale(LC_NUMERIC,old_locale);
1636 synfig::warning("Caught exception when attempting to save settings.");
1641 App::load_settings()
1646 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1647 setlocale(LC_NUMERIC, "C");
1649 std::string filename=get_config_file("accelrc");
1650 Gtk::AccelMap::load(filename);
1653 bool window_size_broken = false;
1655 std::string filename=get_config_file("recentfiles");
1656 std::string filename_window_size=filename+std::string("_window_size");
1658 std::ifstream file(filename.c_str());
1659 std::ifstream file_window_size(filename_window_size.c_str());
1661 if(!file_window_size)
1662 window_size_broken = true;
1666 std::string recent_file;
1667 std::string recent_file_window_size;
1668 getline(file,recent_file);
1669 if(!window_size_broken)
1670 getline(file_window_size,recent_file_window_size);
1671 if(!recent_file.empty())
1673 if(!window_size_broken && !file_window_size)
1674 window_size_broken = true;
1675 if (std::ifstream(recent_file.c_str()))
1677 if(!window_size_broken)
1678 add_recent_file(recent_file,recent_file_window_size);
1680 add_recent_file(recent_file);
1684 if(!window_size_broken && file_window_size)
1685 window_size_broken = true;
1687 if(window_size_broken)
1689 recent_files_window_size.clear();
1690 recent_files_window_size.resize(recent_files.size());
1693 std::string filename=get_config_file("settings");
1694 if(!synfigapp::Main::settings().load_from_file(filename))
1696 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1697 //if(!synfigapp::Main::settings().load_from_file(filename))
1699 gamma.set_gamma(1.0/2.2);
1700 reset_initial_window_configuration();
1703 setlocale(LC_NUMERIC,old_locale);
1707 synfig::warning("Caught exception when attempting to load settings.");
1712 App::reset_initial_window_configuration()
1714 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1715 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1716 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1717 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1718 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1719 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1720 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1721 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1722 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1723 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1724 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1725 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1726 #ifdef SINGLE_THREADED
1727 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1729 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1730 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1731 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1732 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1733 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1734 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1738 App::shutdown_request(GdkEventAny*)
1742 //return !shutdown_in_progress;
1748 if(shutdown_in_progress)return;
1751 get_ui_interface()->task(_("Quit Request"));
1754 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1758 std::list<etl::handle<Instance> >::iterator iter;
1759 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1761 if(!(*iter)->safe_close())
1765 if((*iter)->synfigapp::Instance::get_action_count())
1767 handle<synfigapp::UIInterface> uim;
1768 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1770 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1771 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1773 case synfigapp::UIInterface::RESPONSE_NO:
1775 case synfigapp::UIInterface::RESPONSE_YES:
1778 case synfigapp::UIInterface::RESPONSE_CANCEL:
1787 if((*iter)->synfigapp::Instance::is_modified())
1789 handle<synfigapp::UIInterface> uim;
1790 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1792 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() );
1793 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1795 case synfigapp::UIInterface::RESPONSE_NO:
1797 case synfigapp::UIInterface::RESPONSE_YES:
1798 (*iter)->dialog_cvs_commit();
1800 case synfigapp::UIInterface::RESPONSE_CANCEL:
1809 // This next line causes things to crash for some reason
1813 shutdown_in_progress=true;
1815 instance_list.clear();
1817 while(studio::App::events_pending())studio::App::iteration(false);
1820 auto_recover->normal_shutdown();
1822 get_ui_interface()->task(_("Quit Request sent"));
1828 dialog_setup->refresh();
1829 dialog_setup->show();
1832 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1833 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1836 //#define USE_WIN32_FILE_DIALOGS 1
1839 #ifdef USE_WIN32_FILE_DIALOGS
1840 static OPENFILENAME ofn={};
1844 #include <gdk/gdkwin32.h>
1848 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1850 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1852 #ifdef USE_WIN32_FILE_DIALOGS
1853 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1855 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1856 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1857 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1859 ofn.lStructSize=sizeof(OPENFILENAME);
1860 ofn.hwndOwner = hWnd;
1861 ofn.hInstance = hInstance;
1862 ofn.lpstrFilter = szFilter;
1863 // ofn.lpstrCustomFilter=NULL;
1864 // ofn.nMaxCustFilter=0;
1865 // ofn.nFilterIndex=0;
1866 // ofn.lpstrFile=NULL;
1867 ofn.nMaxFile=MAX_PATH;
1868 // ofn.lpstrFileTitle=NULL;
1869 // ofn.lpstrInitialDir=NULL;
1870 // ofn.lpstrTitle=NULL;
1871 ofn.Flags=OFN_HIDEREADONLY;
1872 // ofn.nFileOffset=0;
1873 // ofn.nFileExtension=0;
1874 ofn.lpstrDefExt=TEXT("sif");
1875 // ofn.lCustData = 0l;
1877 // ofn.lpTemplateName=NULL;
1879 CHAR szFilename[MAX_PATH];
1881 strcpy(szFilename,filename.c_str());
1882 strcpy(szTitle,title.c_str());
1884 ofn.lpstrFile=szFilename;
1885 ofn.lpstrFileTitle=szTitle;
1887 if(GetOpenFileName(&ofn))
1889 filename=szFilename;
1895 synfig::String prev_path;
1897 if(!_preferences.get_value(preference, prev_path))
1900 prev_path = absolute_path(prev_path);
1902 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1904 dialog->set_current_folder(prev_path);
1905 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1906 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1908 if (filename.empty())
1909 dialog->set_filename(prev_path);
1910 else if (is_absolute_path(filename))
1911 dialog->set_filename(filename);
1913 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1915 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1916 filename = dialog->get_filename();
1917 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1918 _preferences.set_value(preference, dirname(filename));
1932 GtkWidget *fileselection;
1933 fileselection = gtk_file_selection_new(title.c_str());
1936 if(basename(filename)==filename)
1938 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1941 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1943 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1945 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1946 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1948 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1949 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1951 gtk_widget_show(fileselection);
1959 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1960 _preferences.set_value(preference,dirname(filename));
1964 gtk_widget_destroy(fileselection);
1967 gtk_widget_destroy(fileselection);
1974 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1976 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1978 #if USE_WIN32_FILE_DIALOGS
1979 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1981 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1982 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1983 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1985 ofn.lStructSize=sizeof(OPENFILENAME);
1986 ofn.hwndOwner = hWnd;
1987 ofn.hInstance = hInstance;
1988 ofn.lpstrFilter = szFilter;
1989 // ofn.lpstrCustomFilter=NULL;
1990 // ofn.nMaxCustFilter=0;
1991 // ofn.nFilterIndex=0;
1992 // ofn.lpstrFile=NULL;
1993 ofn.nMaxFile=MAX_PATH;
1994 // ofn.lpstrFileTitle=NULL;
1995 // ofn.lpstrInitialDir=NULL;
1996 // ofn.lpstrTitle=NULL;
1997 ofn.Flags=OFN_OVERWRITEPROMPT;
1998 // ofn.nFileOffset=0;
1999 // ofn.nFileExtension=0;
2000 ofn.lpstrDefExt=TEXT("sif");
2001 // ofn.lCustData = 0l;
2003 // ofn.lpTemplateName=NULL;
2005 CHAR szFilename[MAX_PATH];
2007 strcpy(szFilename,filename.c_str());
2008 strcpy(szTitle,title.c_str());
2010 ofn.lpstrFile=szFilename;
2011 ofn.lpstrFileTitle=szTitle;
2013 if(GetSaveFileName(&ofn))
2015 filename=szFilename;
2016 _preferences.set_value(preference,dirname(filename));
2021 synfig::String prev_path;
2023 if(!_preferences.get_value(preference, prev_path))
2026 prev_path = absolute_path(prev_path);
2028 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2030 dialog->set_current_folder(prev_path);
2031 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2032 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2034 Widget_Enum *file_type_enum = 0;
2035 if (preference == ANIMATION_DIR_PREFERENCE)
2037 file_type_enum = manage(new Widget_Enum());
2038 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2039 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2040 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2041 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2042 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2043 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2045 Gtk::HBox *hbox = manage(new Gtk::HBox);
2046 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2047 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2050 dialog->set_extra_widget(*hbox);
2053 if (filename.empty())
2054 dialog->set_filename(prev_path);
2057 std::string full_path;
2058 if (is_absolute_path(filename))
2059 full_path = filename;
2061 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2063 // select the file if it exists
2064 dialog->set_filename(full_path);
2066 // if the file doesn't exist, put its name into the filename box
2068 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2069 dialog->set_current_name(basename(filename));
2072 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2073 if (preference == ANIMATION_DIR_PREFERENCE)
2074 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2075 filename = dialog->get_filename();
2076 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2077 _preferences.set_value(preference, dirname(filename));
2088 App::dialog_error_blocking(const std::string &title, const std::string &message)
2090 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2091 dialog.set_title(title);
2097 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2099 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2100 dialog.set_title(title);
2106 App::dialog_yes_no(const std::string &title, const std::string &message)
2111 true // use_separator
2113 Gtk::Label label(message);
2116 dialog.get_vbox()->pack_start(label);
2117 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2118 dialog.add_button(Gtk::StockID("gtk-no"),0);
2120 return dialog.run();
2124 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2129 true // use_separator
2131 Gtk::Label label(message);
2134 dialog.get_vbox()->pack_start(label);
2135 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2136 dialog.add_button(Gtk::StockID("gtk-no"),0);
2137 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2139 return dialog.run();
2143 App::dialog_not_implemented()
2145 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2146 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2151 try_open_url(const std::string &url)
2154 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2156 std::vector<std::string> command_line;
2157 std::vector<std::string> browsers;
2158 browsers.reserve(23);
2160 // Browser wrapper scripts
2161 #ifdef USE_OPEN_FOR_URLS
2162 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2164 browsers.push_back("xdg-open"); // XDG wrapper
2165 browsers.push_back("sensible-browser"); // Debian wrapper
2166 browsers.push_back("gnome-open"); // GNOME wrapper
2167 browsers.push_back("kfmclient"); // KDE wrapper
2168 browsers.push_back("exo-open"); // XFCE wrapper
2170 // Alternatives system
2171 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2172 browsers.push_back("x-www-browser"); // Debian GUI alternative
2174 // Individual browsers
2175 browsers.push_back("firefox");
2176 browsers.push_back("epiphany-browser");
2177 browsers.push_back("epiphany");
2178 browsers.push_back("konqueror");
2179 browsers.push_back("iceweasel");
2180 browsers.push_back("mozilla");
2181 browsers.push_back("netscape");
2182 browsers.push_back("icecat");
2183 browsers.push_back("galeon");
2184 browsers.push_back("midori");
2185 browsers.push_back("safari");
2186 browsers.push_back("opera");
2187 browsers.push_back("amaya");
2188 browsers.push_back("netsurf");
2189 browsers.push_back("dillo");
2191 // Try the user-specified browser first
2192 command_line.push_back(App::browser_command);
2193 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2194 command_line.push_back(url);
2196 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2197 catch( Glib::SpawnError& exception ){
2199 while ( !browsers.empty() )
2201 // Skip the browser if we already tried it
2202 if( browsers[0] == App::browser_command )
2205 // Construct the command line
2206 command_line.clear();
2207 command_line.push_back(browsers[0]);
2208 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2209 command_line.push_back(url);
2211 // Remove the browser from the list
2212 browsers.erase(browsers.begin());
2214 // Try to spawn the browser
2215 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2216 // Failed, move on to the next one
2217 catch(Glib::SpawnError& exception){ continue; }
2218 return true; // No exception means we succeeded!
2229 if (!try_open_url("http://synfig.org/Documentation"))
2231 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2232 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2233 dialog.set_title(_("Help"));
2239 App::open_url(const std::string &url)
2241 if(!try_open_url(url))
2243 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2244 dialog.set_secondary_text(url);
2245 dialog.set_title(_("No browser found"));
2251 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2256 true); // use_separator
2258 Gtk::Label label(message);
2260 dialog.get_vbox()->pack_start(label);
2263 entry.set_text(text);
2265 entry.set_activates_default(true);
2267 dialog.get_vbox()->pack_start(entry);
2269 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2270 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2271 dialog.set_default_response(Gtk::RESPONSE_OK);
2273 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2276 if(dialog.run()!=Gtk::RESPONSE_OK)
2279 text=entry.get_text();
2285 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2290 true); // use_separator
2292 Gtk::Label label(message);
2294 dialog.get_vbox()->pack_start(label);
2296 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2297 text_buffer->set_text(text);
2298 Gtk::TextView text_view(text_buffer);
2301 dialog.get_vbox()->pack_start(text_view);
2303 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2304 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2305 dialog.set_default_response(Gtk::RESPONSE_OK);
2307 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2310 if(dialog.run()!=Gtk::RESPONSE_OK)
2313 text=text_buffer->get_text();
2319 App::open(std::string filename)
2321 return open_as(filename,filename);
2324 // this is called from autorecover.cpp:
2325 // App::open_as(get_shadow_file_name(filename),filename)
2326 // other than that, 'filename' and 'as' are the same
2328 App::open_as(std::string filename,std::string as)
2331 char long_name[1024];
2332 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2333 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2334 // don't use it if that's the case
2335 if (long_name[0] != '\0')
2341 OneMoment one_moment;
2344 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors));
2345 if(canvas && get_instance(canvas))
2347 get_instance(canvas)->find_canvas_view(canvas)->present();
2348 info("%s is already open", filename.c_str());
2349 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2354 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2356 if (as.find(custom_filename_prefix.c_str()) != 0)
2357 add_recent_file(as);
2359 handle<Instance> instance(Instance::create(canvas));
2362 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2364 set_recent_file_window_size(instance);
2368 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)")))
2369 instance->dialog_cvs_update();
2374 dialog_error_blocking(_("Error"), x);
2379 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2390 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2392 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2393 canvas->set_name(file_name);
2394 file_name += ".sifz";
2396 canvas->rend_desc().set_frame_rate(24.0);
2397 canvas->rend_desc().set_time_start(0.0);
2398 canvas->rend_desc().set_time_end(5.0);
2399 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2400 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2401 // The top left and botton right positions are expressed in units
2402 // Original convention is that 1 unit = 60 pixels
2403 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2404 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2405 canvas->rend_desc().set_w(preferred_x_size);
2406 canvas->rend_desc().set_h(preferred_y_size);
2407 canvas->rend_desc().set_antialias(1);
2408 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2409 canvas->set_file_name(file_name);
2411 handle<Instance> instance = Instance::create(canvas);
2413 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2414 instance->find_canvas_view(canvas)->canvas_properties.present();
2418 App::dialog_open(string filename)
2420 if (filename.empty())
2423 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2425 // If the filename still has wildcards, then we should
2426 // continue looking for the file we want
2427 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2433 get_ui_interface()->error(_("Unable to open file"));
2438 App::set_selected_instance(etl::loose_handle<Instance> instance)
2440 /* if(get_selected_instance()==instance)
2442 selected_instance=instance;
2443 signal_instance_selected()(instance);
2449 selected_instance=instance;
2450 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2454 instance->focus(instance->get_canvas());
2457 set_selected_canvas_view(0);
2459 signal_instance_selected()(instance);
2463 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2465 selected_canvas_view=canvas_view;
2466 signal_canvas_view_focus()(selected_canvas_view);
2469 selected_instance=canvas_view->get_instance();
2470 signal_instance_selected()(canvas_view->get_instance());
2473 if(get_selected_canvas_view()==canvas_view)
2475 signal_canvas_view_focus()(selected_canvas_view);
2476 signal_instance_selected()(canvas_view->get_instance());
2479 selected_canvas_view=canvas_view;
2480 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2481 set_selected_instance(canvas_view->get_instance());
2482 signal_canvas_view_focus()(selected_canvas_view);
2486 etl::loose_handle<Instance>
2487 App::get_instance(etl::handle<synfig::Canvas> canvas)
2489 if(!canvas) return 0;
2490 canvas=canvas->get_root();
2492 std::list<etl::handle<Instance> >::iterator iter;
2493 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2495 if((*iter)->get_canvas()==canvas)
2511 if(selected_instance)
2512 selected_instance->undo();
2518 if(selected_instance)
2519 selected_instance->redo();
2523 studio::App::get_base_path()
2525 return app_base_path_;