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
12 ** Copyright (c) 2009 Nikita Kitaev
14 ** This package is free software; you can redistribute it and/or
15 ** modify it under the terms of the GNU General Public License as
16 ** published by the Free Software Foundation; either version 2 of
17 ** the License, or (at your option) any later version.
19 ** This package is distributed in the hope that it will be useful,
20 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 ** General Public License for more details.
25 /* ========================================================================= */
27 /* === H E A D E R S ======================================================= */
46 #ifdef HAVE_SYS_ERRNO_H
47 #include <sys/errno.h>
49 #include <gtkmm/fileselection.h>
50 #include <gtkmm/dialog.h>
51 #include <gtkmm/messagedialog.h>
52 #include <gtkmm/label.h>
53 #include <gtkmm/stock.h>
54 #include <gtkmm/stockitem.h>
55 #include <gtkmm/iconsource.h>
56 #include <gtkmm/inputdialog.h>
57 #include <gtkmm/accelmap.h>
58 #include <gtkmm/uimanager.h>
59 #include <gtkmm/textview.h>
63 #include <gdkmm/general.h>
65 #include <synfig/loadcanvas.h>
66 #include <synfig/savecanvas.h>
72 #include "canvasview.h"
73 #include "dialog_setup.h"
74 #include "dialog_gradient.h"
75 #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 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
284 float studio::App::preferred_fps=24.0;
285 #ifdef USE_OPEN_FOR_URLS
286 String studio::App::browser_command("open"); // MacOS only
288 String studio::App::browser_command("xdg-open"); // Linux XDG standard
291 static int max_recent_files_=25;
292 int studio::App::get_max_recent_files() { return max_recent_files_; }
293 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
295 static synfig::String app_base_path_;
300 really_delete_widget(Gtk::Widget *widget)
302 // synfig::info("really delete %p", (void*)widget);
307 // nasty workaround - when we've finished with a popup menu, we want to delete it
308 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
309 // so schedule the real delete to happen in 50ms, giving the action a chance to run
311 delete_widget(Gtk::Widget *widget)
313 // synfig::info("delete %p", (void*)widget);
314 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
317 }; // END of namespace studio
318 studio::StateManager* state_manager;
323 class GlobalUIInterface : public synfigapp::UIInterface
327 virtual Response confirmation(const std::string &title,
328 const std::string &primaryText,
329 const std::string &secondaryText,
330 const std::string &confirmPhrase,
331 const std::string &cancelPhrase,
332 Response defaultResponse)
334 Gtk::MessageDialog dialog(
335 primaryText, // Message
337 Gtk::MESSAGE_WARNING, // Type
338 Gtk::BUTTONS_NONE, // Buttons
343 dialog.set_title(title);
344 if (! secondaryText.empty())
345 dialog.set_secondary_text(secondaryText);
347 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
348 dialog.add_button(confirmPhrase, RESPONSE_OK);
349 dialog.set_default_response(defaultResponse);
352 return (Response) dialog.run();
355 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
360 true // use_separator
362 Gtk::Label label(message);
365 dialog.get_vbox()->pack_start(label);
366 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
367 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
369 dialog.set_default_response(dflt);
371 return (Response)dialog.run();
373 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
378 true // use_separator
380 Gtk::Label label(message);
383 dialog.get_vbox()->pack_start(label);
384 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
385 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
386 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
388 dialog.set_default_response(dflt);
390 return (Response)dialog.run();
392 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
397 true // use_separator
399 Gtk::Label label(message);
402 dialog.get_vbox()->pack_start(label);
403 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
404 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
406 dialog.set_default_response(dflt);
408 return (Response)dialog.run();
412 task(const std::string &task)
414 std::cerr<<task<<std::endl;
415 while(studio::App::events_pending())studio::App::iteration(false);
420 error(const std::string &err)
422 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
429 warning(const std::string &err)
431 std::cerr<<"warning: "<<err<<std::endl;
432 while(studio::App::events_pending())studio::App::iteration(false);
437 amount_complete(int /*current*/, int /*total*/)
439 while(studio::App::events_pending())studio::App::iteration(false);
444 /* === P R O C E D U R E S ================================================= */
448 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
450 action_group_list.push_back(action_group);
451 Gtk::UIManager::insert_action_group(action_group, pos);
455 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
457 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
458 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
459 if(*iter==action_group)
461 action_group_list.erase(iter);
462 Gtk::UIManager::remove_action_group(action_group);
465 synfig::error("Unable to find action group");
469 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
471 ui_manager->insert_action_group(group,0);
473 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
474 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
476 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
478 if(*iter && (*iter)->get_name()!="menus")
480 synfig::info("Removing action group "+(*iter)->get_name());
481 ui_manager->remove_action_group(*iter);
484 ui_manager->insert_action_group(group,0);
486 for(;!prev_groups.empty();prev_groups.pop_front())
488 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
489 ui_manager->insert_action_group(prev_groups.front(),1);
493 class Preferences : public synfigapp::Settings
496 virtual bool get_value(const synfig::String& key, synfig::String& value)const
500 value=strprintf("%f %f %f %f",
501 App::gamma.get_gamma_r(),
502 App::gamma.get_gamma_g(),
503 App::gamma.get_gamma_b(),
504 App::gamma.get_black_level()
508 if(key=="time_format")
510 value=strprintf("%i",App::get_time_format());
513 if(key=="file_history.size")
515 value=strprintf("%i",App::get_max_recent_files());
518 if(key=="use_colorspace_gamma")
520 value=strprintf("%i",(int)App::use_colorspace_gamma);
523 if(key=="distance_system")
525 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
528 #ifdef SINGLE_THREADED
529 if(key=="single_threaded")
531 value=strprintf("%i",(int)App::single_threaded);
535 if(key=="auto_recover_backup_interval")
537 value=strprintf("%i",App::auto_recover->get_timeout());
540 if(key=="restrict_radius_ducks")
542 value=strprintf("%i",(int)App::restrict_radius_ducks);
545 if(key=="resize_imported_images")
547 value=strprintf("%i",(int)App::resize_imported_images);
550 if(key=="browser_command")
552 value=App::browser_command;
555 if(key=="custom_filename_prefix")
557 value=App::custom_filename_prefix;
560 if(key=="preferred_x_size")
562 value=strprintf("%i",App::preferred_x_size);
565 if(key=="preferred_y_size")
567 value=strprintf("%i",App::preferred_y_size);
570 if(key=="predefined_size")
572 value=strprintf("%s",App::predefined_size.c_str());
575 if(key=="preferred_fps")
577 value=strprintf("%f",App::preferred_fps);
580 if(key=="predefined_fps")
582 value=strprintf("%s",App::predefined_fps.c_str());
586 return synfigapp::Settings::get_value(key,value);
589 virtual bool set_value(const synfig::String& key,const synfig::String& value)
595 strscanf(value,"%f %f %f %f",
602 App::gamma.set_all(r,g,b,blk);
606 if(key=="time_format")
608 int i(atoi(value.c_str()));
609 App::set_time_format(static_cast<synfig::Time::Format>(i));
612 if(key=="auto_recover_backup_interval")
614 int i(atoi(value.c_str()));
615 App::auto_recover->set_timeout(i);
618 if(key=="file_history.size")
620 int i(atoi(value.c_str()));
621 App::set_max_recent_files(i);
624 if(key=="use_colorspace_gamma")
626 int i(atoi(value.c_str()));
627 App::use_colorspace_gamma=i;
630 if(key=="distance_system")
632 App::distance_system=Distance::ident_system(value);;
635 #ifdef SINGLE_THREADED
636 if(key=="single_threaded")
638 int i(atoi(value.c_str()));
639 App::single_threaded=i;
643 if(key=="restrict_radius_ducks")
645 int i(atoi(value.c_str()));
646 App::restrict_radius_ducks=i;
649 if(key=="resize_imported_images")
651 int i(atoi(value.c_str()));
652 App::resize_imported_images=i;
655 if(key=="browser_command")
657 App::browser_command=value;
660 if(key=="custom_filename_prefix")
662 App::custom_filename_prefix=value;
665 if(key=="preferred_x_size")
667 int i(atoi(value.c_str()));
668 App::preferred_x_size=i;
671 if(key=="preferred_y_size")
673 int i(atoi(value.c_str()));
674 App::preferred_y_size=i;
677 if(key=="predefined_size")
679 App::predefined_size=value;
682 if(key=="preferred_fps")
684 float i(atof(value.c_str()));
685 App::preferred_fps=i;
688 if(key=="predefined_fps")
690 App::predefined_fps=value;
694 return synfigapp::Settings::set_value(key,value);
697 virtual KeyList get_key_list()const
699 KeyList ret(synfigapp::Settings::get_key_list());
700 ret.push_back("gamma");
701 ret.push_back("time_format");
702 ret.push_back("distance_system");
703 ret.push_back("file_history.size");
704 ret.push_back("use_colorspace_gamma");
705 #ifdef SINGLE_THREADED
706 ret.push_back("single_threaded");
708 ret.push_back("auto_recover_backup_interval");
709 ret.push_back("restrict_radius_ducks");
710 ret.push_back("resize_imported_images");
711 ret.push_back("browser_command");
712 ret.push_back("custom_filename_prefix");
713 ret.push_back("preferred_x_size");
714 ret.push_back("preferred_y_size");
715 ret.push_back("predefined_size");
716 ret.push_back("preferred_fps");
717 ret.push_back("predefined_fps");
722 static ::Preferences _preferences;
727 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
729 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
731 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
733 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
734 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
735 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
736 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
737 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
738 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
739 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
740 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
741 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
742 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
743 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
744 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
745 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
747 // Add the synfigapp actions...
748 synfigapp::Action::Book::iterator iter;
749 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
751 actions_action_group->add(Gtk::Action::create(
752 "action-"+iter->second.name,
753 get_action_stock_id(iter->second),
754 iter->second.local_name,iter->second.local_name
758 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); actions_action_group->add(action); }
759 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); actions_action_group->add(action); }
760 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); group->add(action,sig); }
762 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
763 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
764 DEFINE_ACTION("new", Gtk::Stock::NEW);
765 DEFINE_ACTION("open", Gtk::Stock::OPEN);
766 DEFINE_ACTION("save", Gtk::Stock::SAVE);
767 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
768 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
769 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
770 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
771 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
772 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
773 DEFINE_ACTION("import", _("Import"));
774 DEFINE_ACTION("render", _("Render"));
775 DEFINE_ACTION("preview", _("Preview"));
776 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
777 DEFINE_ACTION("sound", _("Sound File"));
778 DEFINE_ACTION("options", _("Options"));
779 DEFINE_ACTION("close", _("Close View"));
780 DEFINE_ACTION("close-document", _("Close Document"));
781 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
784 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
785 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
786 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
787 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
788 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
789 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
790 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
791 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
792 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
793 DEFINE_ACTION("properties", _("Properties"));
795 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
796 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
797 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
798 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
799 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
800 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
801 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
802 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
803 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
804 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
805 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
806 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
807 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
808 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
809 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
810 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
811 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
812 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
813 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
814 DEFINE_ACTION("play", _("Play"));
815 // DEFINE_ACTION("pause", _("Pause"));
816 DEFINE_ACTION("stop", _("Stop"));
817 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
818 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
819 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
820 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
821 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
822 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
823 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
824 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
825 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
826 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
827 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
828 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
829 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
830 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
831 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
832 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
833 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
834 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
835 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
836 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
837 DEFINE_ACTION("seek-end", _("Seek to End"));
839 DEFINE_ACTION("action-group_add", _("Add group"));
841 DEFINE_ACTION("canvas-new", _("New Canvas"));
843 DEFINE_ACTION("amount-inc", _("Increase Amount"));
844 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
847 #undef DEFINE_ACTION_2
848 #undef DEFINE_ACTION_SIG
850 Glib::ustring ui_info =
852 " <popup name='menu-toolbox' action='menu-toolbox'>"
853 " <menu action='menu-file'>"
856 " <popup name='menu-main' action='menu-main'>"
857 " <menu action='menu-file'>"
858 " <menuitem action='new' />"
859 " <menuitem action='open' />"
860 " <menuitem action='save' />"
861 " <menuitem action='save-as' />"
862 " <menuitem action='revert' />"
863 " <separator name='bleh01'/>"
864 " <menuitem action='cvs-add' />"
865 " <menuitem action='cvs-update' />"
866 " <menuitem action='cvs-commit' />"
867 " <menuitem action='cvs-revert' />"
868 " <separator name='bleh02'/>"
869 " <menuitem action='import' />"
870 " <separator name='bleh03'/>"
871 " <menuitem action='render' />"
872 " <menuitem action='preview' />"
873 " <menuitem action='sound' />"
874 " <separator name='bleh04'/>"
875 " <menuitem action='options' />"
876 " <menuitem action='close' />"
877 " <menuitem action='close-document' />"
878 " <menuitem action='quit' />"
880 " <menu action='menu-edit'>"
881 " <menuitem action='undo'/>"
882 " <menuitem action='redo'/>"
883 " <separator name='bleh05'/>"
884 " <menuitem action='cut'/>"
885 " <menuitem action='copy'/>"
886 " <menuitem action='paste'/>"
887 " <separator name='bleh06'/>"
888 " <menuitem action='select-all-layers'/>"
889 " <menuitem action='unselect-all-layers'/>"
890 " <menuitem action='select-all-ducks'/>"
891 " <menuitem action='unselect-all-ducks'/>"
892 " <separator name='bleh07'/>"
893 " <menuitem action='properties'/>"
895 " <menu action='menu-view'>"
896 " <menu action='menu-duck-mask'>"
897 " <menuitem action='mask-position-ducks' />"
898 " <menuitem action='mask-vertex-ducks' />"
899 " <menuitem action='mask-tangent-ducks' />"
900 " <menuitem action='mask-radius-ducks' />"
901 " <menuitem action='mask-width-ducks' />"
902 " <menuitem action='mask-angle-ducks' />"
904 " <menu action='menu-preview-quality'>"
905 " <menuitem action='quality-00' />"
906 " <menuitem action='quality-01' />"
907 " <menuitem action='quality-02' />"
908 " <menuitem action='quality-03' />"
909 " <menuitem action='quality-04' />"
910 " <menuitem action='quality-05' />"
911 " <menuitem action='quality-06' />"
912 " <menuitem action='quality-07' />"
913 " <menuitem action='quality-08' />"
914 " <menuitem action='quality-09' />"
915 " <menuitem action='quality-10' />"
917 " <menu action='menu-lowres-pixel'>"
918 " <menuitem action='decrease-low-res-pixel-size'/>"
919 " <menuitem action='increase-low-res-pixel-size'/>"
920 " <separator name='pixel-size-separator'/>"
923 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
924 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
928 " <separator name='bleh08'/>"
929 " <menuitem action='play'/>"
930 //" <menuitem action='pause'/>"
931 " <menuitem action='stop'/>"
932 " <menuitem action='dialog-flipbook'/>"
933 " <separator name='bleh09'/>"
934 " <menuitem action='toggle-grid-show'/>"
935 " <menuitem action='toggle-grid-snap'/>"
936 " <menuitem action='toggle-guide-show'/>"
937 " <menuitem action='toggle-low-res'/>"
938 " <menuitem action='toggle-onion-skin'/>"
939 " <separator name='bleh10'/>"
940 " <menuitem action='canvas-zoom-in'/>"
941 " <menuitem action='canvas-zoom-out'/>"
942 " <menuitem action='canvas-zoom-fit'/>"
943 " <menuitem action='canvas-zoom-100'/>"
944 " <separator name='bleh11'/>"
945 " <menuitem action='time-zoom-in'/>"
946 " <menuitem action='time-zoom-out'/>"
947 " <separator name='bleh12'/>"
948 " <menuitem action='jump-next-keyframe'/>"
949 " <menuitem action='jump-prev-keyframe'/>"
950 " <menuitem action='seek-next-frame'/>"
951 " <menuitem action='seek-prev-frame'/>"
952 " <menuitem action='seek-next-second'/>"
953 " <menuitem action='seek-prev-second'/>"
954 " <menuitem action='seek-begin'/>"
955 " <menuitem action='seek-end'/>"
957 " <menu action='menu-canvas'>"
958 " <menuitem action='canvas-new'/>"
960 " <menu name='menu-state' action='menu-state'>"
962 " <menu action='menu-group'>"
963 " <menuitem action='action-group_add'/>"
965 " <menu action='menu-layer'>"
966 //" <menuitem action='cut'/>"
967 //" <menuitem action='copy'/>"
968 //" <menuitem action='paste'/>"
969 //" <separator name='bleh06'/>"
970 " <menu action='menu-layer-new'></menu>"
971 " <menuitem action='amount-inc'/>"
972 " <menuitem action='amount-dec'/>"
974 " <menu action='menu-keyframe'>"
975 " <menuitem action='keyframe-properties'/>"
982 " <menubar name='MenuBar'>"
983 " <menu action='MenuFile'>"
984 " <menuitem action='New'/>"
985 " <menuitem action='Open'/>"
987 " <menuitem action='Quit'/>"
989 " <menu action='MenuEdit'>"
990 " <menuitem action='Cut'/>"
991 " <menuitem action='Copy'/>"
992 " <menuitem action='Paste'/>"
995 " <toolbar name='ToolBar'>"
996 " <toolitem action='Open'/>"
997 " <toolitem action='Quit'/>"
1003 actions_action_group->set_sensitive(false);
1004 App::ui_manager()->set_add_tearoffs(true);
1005 App::ui_manager()->insert_action_group(menus_action_group,1);
1006 App::ui_manager()->insert_action_group(actions_action_group,1);
1007 App::ui_manager()->add_ui_from_string(ui_info);
1009 //App::ui_manager()->get_accel_group()->unlock();
1011 catch(const Glib::Error& ex)
1013 synfig::error("building menus and toolbars failed: " + ex.what());
1016 // Add default keyboard accelerators
1017 #define ACCEL(accel,path) \
1019 Gtk::AccelKey accel_key(accel,path); \
1020 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1023 #define ACCEL2(accel) \
1025 Gtk::AccelKey accel_key(accel); \
1026 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1030 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1031 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1032 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1033 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1034 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1035 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1036 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1037 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1038 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1039 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1040 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1041 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1042 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1043 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1044 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1045 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1046 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1047 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1050 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1051 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1052 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1053 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1054 ACCEL("F9", "<Actions>/canvasview/render" );
1055 ACCEL("F11", "<Actions>/canvasview/preview" );
1056 ACCEL("F8", "<Actions>/canvasview/properties" );
1057 ACCEL("F12", "<Actions>/canvasview/options" );
1058 ACCEL("<control>i", "<Actions>/canvasview/import" );
1059 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1060 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1061 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1062 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1063 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1064 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1065 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1066 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1067 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1068 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1069 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1070 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1071 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1072 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1073 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1074 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1075 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1076 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1077 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1078 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1079 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1080 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1081 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1082 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1083 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1084 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1085 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1086 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1087 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1088 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1089 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1090 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1091 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1092 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1093 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1094 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1095 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1096 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1097 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1098 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1099 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1100 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1101 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1102 ACCEL("End", "<Actions>/canvasview/seek-end" );
1109 #define mkdir(x,y) mkdir(x)
1112 /* === M E T H O D S ======================================================= */
1114 App::App(int *argc, char ***argv):
1115 Gtk::Main(argc,argv),
1116 IconController(etl::dirname((*argv)[0]))
1118 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1121 ui_interface_=new GlobalUIInterface();
1125 // don't call thread_init() if threads are already initialized
1126 // on some machines bonobo_init() initialized threads before we get here
1127 if (!g_thread_supported())
1128 Glib::thread_init();
1130 distance_system=Distance::SYSTEM_UNITS;
1132 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1135 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1139 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1145 if(!SYNFIG_CHECK_VERSION())
1147 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1148 dialog_error_blocking("Synfig Studio",
1149 "This copy of Synfig Studio was compiled against a\n"
1150 "different version of libsynfig than what is currently\n"
1151 "installed. Synfig Studio will now abort. Try downloading\n"
1152 "the latest version from the Synfig website at\n"
1153 "http://synfig.org/Download"
1157 Glib::set_application_name(_("Synfig Studio"));
1159 Splash splash_screen;
1160 splash_screen.show();
1162 shutdown_in_progress=false;
1163 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1164 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1166 // Initialize the Synfig library
1167 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1168 catch(std::runtime_error x)
1170 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1175 get_ui_interface()->error(_("Failed to initialize synfig!"));
1179 // add the preferences to the settings
1180 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1184 studio_init_cb.task(_("Init UI Manager..."));
1185 App::ui_manager_=studio::UIManager::create();
1188 studio_init_cb.task(_("Init Dock Manager..."));
1189 dock_manager=new studio::DockManager();
1191 studio_init_cb.task(_("Init State Manager..."));
1192 state_manager=new StateManager();
1194 studio_init_cb.task(_("Init Toolbox..."));
1195 toolbox=new studio::Toolbox();
1197 studio_init_cb.task(_("Init About Dialog..."));
1198 about=new studio::About();
1200 studio_init_cb.task(_("Init Tool Options..."));
1201 dialog_tool_options=new studio::Dialog_ToolOptions();
1202 dock_manager->register_dockable(*dialog_tool_options);
1204 studio_init_cb.task(_("Init History..."));
1205 dock_history=new studio::Dock_History();
1206 dock_manager->register_dockable(*dock_history);
1208 studio_init_cb.task(_("Init Canvases..."));
1209 dock_canvases=new studio::Dock_Canvases();
1210 dock_manager->register_dockable(*dock_canvases);
1212 studio_init_cb.task(_("Init Keyframes..."));
1213 dock_keyframes=new studio::Dock_Keyframes();
1214 dock_manager->register_dockable(*dock_keyframes);
1216 studio_init_cb.task(_("Init Layers..."));
1217 dock_layers=new studio::Dock_Layers();
1218 dock_manager->register_dockable(*dock_layers);
1220 studio_init_cb.task(_("Init Params..."));
1221 dock_params=new studio::Dock_Params();
1222 dock_manager->register_dockable(*dock_params);
1224 studio_init_cb.task(_("Init MetaData..."));
1225 dock_meta_data=new studio::Dock_MetaData();
1226 dock_manager->register_dockable(*dock_meta_data);
1228 studio_init_cb.task(_("Init Children..."));
1229 dock_children=new studio::Dock_Children();
1230 dock_manager->register_dockable(*dock_children);
1232 studio_init_cb.task(_("Init Info..."));
1233 dock_info = new studio::Dock_Info();
1234 dock_manager->register_dockable(*dock_info);
1236 studio_init_cb.task(_("Init Navigator..."));
1237 dock_navigator = new studio::Dock_Navigator();
1238 dock_manager->register_dockable(*dock_navigator);
1240 studio_init_cb.task(_("Init Timetrack..."));
1241 dock_timetrack = new studio::Dock_Timetrack();
1242 dock_manager->register_dockable(*dock_timetrack);
1244 studio_init_cb.task(_("Init Curve Editor..."));
1245 dock_curves = new studio::Dock_Curves();
1246 dock_manager->register_dockable(*dock_curves);
1248 studio_init_cb.task(_("Init Layer Groups..."));
1249 dock_layer_groups = new studio::Dock_LayerGroups();
1250 dock_manager->register_dockable(*dock_layer_groups);
1253 studio_init_cb.task(_("Init Color Dialog..."));
1254 dialog_color=new studio::Dialog_Color();
1256 studio_init_cb.task(_("Init Gradient Dialog..."));
1257 dialog_gradient=new studio::Dialog_Gradient();
1259 studio_init_cb.task(_("Init DeviceTracker..."));
1260 device_tracker=new studio::DeviceTracker();
1262 studio_init_cb.task(_("Init Tools..."));
1265 state_manager->add_state(&state_normal);
1266 state_manager->add_state(&state_smooth_move);
1267 state_manager->add_state(&state_scale);
1268 state_manager->add_state(&state_rotate);
1269 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1270 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1273 state_manager->add_state(&state_circle);
1274 state_manager->add_state(&state_rectangle);
1275 state_manager->add_state(&state_star);
1276 state_manager->add_state(&state_gradient);
1277 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1278 state_manager->add_state(&state_text);
1279 state_manager->add_state(&state_bline);
1280 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1283 state_manager->add_state(&state_fill);
1284 state_manager->add_state(&state_eyedrop);
1285 state_manager->add_state(&state_zoom);
1286 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1288 studio_init_cb.task(_("Init ModPalette..."));
1289 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1291 studio_init_cb.task(_("Init Setup Dialog..."));
1292 dialog_setup=new studio::Dialog_Setup();
1294 studio_init_cb.task(_("Init Input Dialog..."));
1295 dialog_input=new Gtk::InputDialog();
1296 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1297 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1299 studio_init_cb.task(_("Init auto recovery..."));
1300 auto_recover=new AutoRecover();
1302 studio_init_cb.amount_complete(9250,10000);
1303 studio_init_cb.task(_("Loading Settings..."));
1305 device_tracker->load_preferences();
1307 studio_init_cb.task(_("Checking auto-recover..."));
1309 studio_init_cb.amount_complete(9900,10000);
1311 bool opened_any = false;
1312 if(auto_recover->recovery_needed())
1314 splash_screen.hide();
1315 if (get_ui_interface()->confirmation("Crash Recovery",
1316 _("Auto recovery file found"),
1317 _("Synfig Studio seems to have crashed\n"
1318 "before you could save all your files.\n"
1319 "Recover unsaved changes?"),
1320 _("Recover"), _("Ignore"))
1321 == synfigapp::UIInterface::RESPONSE_OK)
1323 int number_recovered;
1324 if(!auto_recover->recover(number_recovered))
1325 if (number_recovered)
1326 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1328 get_ui_interface()->error(_("Unable to recover from previous crash"));
1330 get_ui_interface()->error(
1331 _("Synfig Studio has attempted to recover\n"
1332 "from a previous crash. The files that it has\n"
1333 "recovered are NOT YET SAVED. It would be a good\n"
1334 "idea to review them and save them now."));
1336 if (number_recovered)
1339 splash_screen.show();
1342 // Look for any files given on the command line,
1343 // and load them if found.
1344 for(;*argc>=1;(*argc)--)
1345 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1347 studio_init_cb.task(_("Loading files..."));
1348 splash_screen.hide();
1349 open((*argv)[*argc]);
1351 splash_screen.show();
1354 // if no file was specified to be opened, create a new document to help new users get started more easily
1355 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1358 studio_init_cb.task(_("Done."));
1359 studio_init_cb.amount_complete(10000,10000);
1365 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1369 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1373 StateManager* App::get_state_manager() { return state_manager; }
1377 shutdown_in_progress=true;
1381 synfigapp::Main::settings().remove_domain("pref");
1383 selected_instance=0;
1385 // Unload all of the modules
1386 for(;!module_list_.empty();module_list_.pop_back())
1389 delete state_manager;
1393 delete auto_recover;
1401 delete dialog_setup;
1403 delete dialog_gradient;
1405 delete dialog_color;
1407 delete dialog_input;
1409 delete dock_manager;
1411 instance_list.clear();
1415 App::get_user_app_directory()
1417 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1419 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1421 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1426 App::get_config_file(const synfig::String& file)
1428 return Glib::build_filename(get_user_app_directory(),file);
1431 #define SCALE_FACTOR (1280)
1432 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1434 App::set_recent_file_window_size(etl::handle<Instance> instance)
1436 int screen_w(Gdk::screen_width());
1437 int screen_h(Gdk::screen_height());
1439 const std::string &canvas_window_size = *recent_files_window_size.begin();
1441 if(canvas_window_size.empty())
1444 synfig::String::size_type current=0;
1445 bool seen_root(false), shown_non_root(false);
1447 while(current != synfig::String::npos)
1449 // find end of first field (canvas) or return
1450 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1451 if(separator == synfig::String::npos) break;
1454 synfig::Canvas::Handle canvas;
1457 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1459 catch(Exception::IDNotFound) {
1460 // can't find the canvas; skip to the next canvas or return
1461 separator = canvas_window_size.find_first_of('\t', current);
1462 if(separator == synfig::String::npos) return;
1463 current = separator+1;
1467 if (canvas->is_root())
1470 shown_non_root = true;
1472 // check that we have the tab character the ends this canvas' data or return
1473 current = separator+1;
1474 separator = canvas_window_size.find_first_of('\t', current);
1475 if(separator == synfig::String::npos) return;
1478 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1480 current = separator+1;
1484 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1485 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1486 x=x*screen_w/SCALE_FACTOR;
1487 y=y*screen_h/SCALE_FACTOR;
1488 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1489 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1490 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1491 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1493 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1494 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1496 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1497 canvasview->move(x,y);
1498 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1499 canvasview->present();
1501 current = separator+1;
1504 if (shown_non_root && !seen_root)
1505 instance->find_canvas_view(instance->get_canvas())->hide();
1509 App::add_recent_file(const etl::handle<Instance> instance)
1511 int screen_w(Gdk::screen_width());
1512 int screen_h(Gdk::screen_height());
1514 std::string canvas_window_size;
1516 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1517 Instance::CanvasViewList::const_iterator iter;
1519 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1521 if( !((*iter)->is_visible()) )
1524 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1525 int x_pos, y_pos, x_size, y_size;
1526 (*iter)->get_position(x_pos,y_pos);
1527 (*iter)->get_size(x_size,y_size);
1529 canvas_window_size += strprintf("%s %d %d %d %d\t",
1530 canvas->get_relative_id(canvas->get_root()).c_str(),
1531 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1532 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1535 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1540 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1542 std::string filename(file_name);
1544 assert(!filename.empty());
1546 if(filename.empty())
1549 // Toss out any "hidden" files
1550 if(basename(filename)[0]=='.')
1553 // If we aren't an absolute path, turn ourselves into one
1554 if(!is_absolute_path(filename))
1555 filename=absolute_path(filename);
1557 std::string old_window_size;
1559 list<string>::iterator iter;
1560 list<string>::iterator iter_wsize;
1561 // Check to see if the file is already on the list.
1562 // If it is, then remove it from the list
1563 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1566 recent_files.erase(iter);
1567 old_window_size = *iter_wsize;
1568 recent_files_window_size.erase(iter_wsize);
1573 // Push the filename to the front of the list
1574 recent_files.push_front(filename);
1575 if(window_size.empty())
1576 recent_files_window_size.push_front(old_window_size);
1578 recent_files_window_size.push_front(window_size);
1580 // Clean out the files at the end of the list.
1581 while(recent_files.size()>(unsigned)get_max_recent_files())
1583 recent_files.pop_back();
1584 recent_files_window_size.pop_back();
1587 signal_recent_files_changed_();
1592 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1595 App::get_time_format()
1597 return _App_time_format;
1601 App::set_time_format(synfig::Time::Format x)
1608 App::save_settings()
1613 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1614 setlocale(LC_NUMERIC, "C");
1616 std::string filename=get_config_file("accelrc");
1617 Gtk::AccelMap::save(filename);
1620 std::string filename=get_config_file("recentfiles");
1622 std::ofstream file(filename.c_str());
1626 synfig::warning("Unable to save %s",filename.c_str());
1630 list<string>::reverse_iterator iter;
1632 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1636 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1638 std::ofstream file(filename.c_str());
1642 synfig::warning("Unable to save %s",filename.c_str());
1646 list<string>::reverse_iterator iter;
1648 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1652 std::string filename=get_config_file("settings");
1653 synfigapp::Main::settings().save_to_file(filename);
1654 setlocale(LC_NUMERIC,old_locale);
1658 synfig::warning("Caught exception when attempting to save settings.");
1663 App::load_settings()
1668 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1669 setlocale(LC_NUMERIC, "C");
1671 std::string filename=get_config_file("accelrc");
1672 Gtk::AccelMap::load(filename);
1675 bool window_size_broken = false;
1677 std::string filename=get_config_file("recentfiles");
1678 std::string filename_window_size=filename+std::string("_window_size");
1680 std::ifstream file(filename.c_str());
1681 std::ifstream file_window_size(filename_window_size.c_str());
1683 if(!file_window_size)
1684 window_size_broken = true;
1688 std::string recent_file;
1689 std::string recent_file_window_size;
1690 getline(file,recent_file);
1691 if(!window_size_broken)
1692 getline(file_window_size,recent_file_window_size);
1693 if(!recent_file.empty())
1695 if(!window_size_broken && !file_window_size)
1696 window_size_broken = true;
1697 if (std::ifstream(recent_file.c_str()))
1699 if(!window_size_broken)
1700 add_recent_file(recent_file,recent_file_window_size);
1702 add_recent_file(recent_file);
1706 if(!window_size_broken && file_window_size)
1707 window_size_broken = true;
1709 if(window_size_broken)
1711 recent_files_window_size.clear();
1712 recent_files_window_size.resize(recent_files.size());
1715 std::string filename=get_config_file("settings");
1716 if(!synfigapp::Main::settings().load_from_file(filename))
1718 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1719 //if(!synfigapp::Main::settings().load_from_file(filename))
1721 gamma.set_gamma(1.0/2.2);
1722 reset_initial_window_configuration();
1725 setlocale(LC_NUMERIC,old_locale);
1729 synfig::warning("Caught exception when attempting to load settings.");
1734 App::reset_initial_window_configuration()
1736 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1737 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1738 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1739 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1740 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1741 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1742 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1743 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1744 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1745 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1746 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1747 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1748 #ifdef SINGLE_THREADED
1749 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1751 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1752 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1753 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1754 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1755 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1756 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1757 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1758 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1759 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1763 App::shutdown_request(GdkEventAny*)
1767 //return !shutdown_in_progress;
1773 if(shutdown_in_progress)return;
1776 get_ui_interface()->task(_("Quit Request"));
1779 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1783 std::list<etl::handle<Instance> >::iterator iter;
1784 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1786 if(!(*iter)->safe_close())
1790 if((*iter)->synfigapp::Instance::get_action_count())
1792 handle<synfigapp::UIInterface> uim;
1793 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1795 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1796 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1798 case synfigapp::UIInterface::RESPONSE_NO:
1800 case synfigapp::UIInterface::RESPONSE_YES:
1803 case synfigapp::UIInterface::RESPONSE_CANCEL:
1812 if((*iter)->synfigapp::Instance::is_modified())
1814 handle<synfigapp::UIInterface> uim;
1815 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1817 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() );
1818 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1820 case synfigapp::UIInterface::RESPONSE_NO:
1822 case synfigapp::UIInterface::RESPONSE_YES:
1823 (*iter)->dialog_cvs_commit();
1825 case synfigapp::UIInterface::RESPONSE_CANCEL:
1834 // This next line causes things to crash for some reason
1838 shutdown_in_progress=true;
1840 instance_list.clear();
1842 while(studio::App::events_pending())studio::App::iteration(false);
1845 auto_recover->normal_shutdown();
1847 get_ui_interface()->task(_("Quit Request sent"));
1853 dialog_setup->refresh();
1854 dialog_setup->show();
1857 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1858 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1861 //#define USE_WIN32_FILE_DIALOGS 1
1864 #ifdef USE_WIN32_FILE_DIALOGS
1865 static OPENFILENAME ofn={};
1869 #include <gdk/gdkwin32.h>
1873 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1875 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1877 #ifdef USE_WIN32_FILE_DIALOGS
1878 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1880 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1881 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1882 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1884 ofn.lStructSize=sizeof(OPENFILENAME);
1885 ofn.hwndOwner = hWnd;
1886 ofn.hInstance = hInstance;
1887 ofn.lpstrFilter = szFilter;
1888 // ofn.lpstrCustomFilter=NULL;
1889 // ofn.nMaxCustFilter=0;
1890 // ofn.nFilterIndex=0;
1891 // ofn.lpstrFile=NULL;
1892 ofn.nMaxFile=MAX_PATH;
1893 // ofn.lpstrFileTitle=NULL;
1894 // ofn.lpstrInitialDir=NULL;
1895 // ofn.lpstrTitle=NULL;
1896 ofn.Flags=OFN_HIDEREADONLY;
1897 // ofn.nFileOffset=0;
1898 // ofn.nFileExtension=0;
1899 ofn.lpstrDefExt=TEXT("sif");
1900 // ofn.lCustData = 0l;
1902 // ofn.lpTemplateName=NULL;
1904 CHAR szFilename[MAX_PATH];
1906 strcpy(szFilename,filename.c_str());
1907 strcpy(szTitle,title.c_str());
1909 ofn.lpstrFile=szFilename;
1910 ofn.lpstrFileTitle=szTitle;
1912 if(GetOpenFileName(&ofn))
1914 filename=szFilename;
1919 #else // not USE_WIN32_FILE_DIALOGS
1920 synfig::String prev_path;
1922 if(!_preferences.get_value(preference, prev_path))
1925 prev_path = absolute_path(prev_path);
1927 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1929 dialog->set_current_folder(prev_path);
1930 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1931 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1933 if (filename.empty())
1934 dialog->set_filename(prev_path);
1935 else if (is_absolute_path(filename))
1936 dialog->set_filename(filename);
1938 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1940 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1941 filename = dialog->get_filename();
1942 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1943 _preferences.set_value(preference, dirname(filename));
1950 #endif // not USE_WIN32_FILE_DIALOGS
1954 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1956 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1958 #if USE_WIN32_FILE_DIALOGS
1959 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1961 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1962 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1963 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1965 ofn.lStructSize=sizeof(OPENFILENAME);
1966 ofn.hwndOwner = hWnd;
1967 ofn.hInstance = hInstance;
1968 ofn.lpstrFilter = szFilter;
1969 // ofn.lpstrCustomFilter=NULL;
1970 // ofn.nMaxCustFilter=0;
1971 // ofn.nFilterIndex=0;
1972 // ofn.lpstrFile=NULL;
1973 ofn.nMaxFile=MAX_PATH;
1974 // ofn.lpstrFileTitle=NULL;
1975 // ofn.lpstrInitialDir=NULL;
1976 // ofn.lpstrTitle=NULL;
1977 ofn.Flags=OFN_OVERWRITEPROMPT;
1978 // ofn.nFileOffset=0;
1979 // ofn.nFileExtension=0;
1980 ofn.lpstrDefExt=TEXT("sif");
1981 // ofn.lCustData = 0l;
1983 // ofn.lpTemplateName=NULL;
1985 CHAR szFilename[MAX_PATH];
1987 strcpy(szFilename,filename.c_str());
1988 strcpy(szTitle,title.c_str());
1990 ofn.lpstrFile=szFilename;
1991 ofn.lpstrFileTitle=szTitle;
1993 if(GetSaveFileName(&ofn))
1995 filename=szFilename;
1996 _preferences.set_value(preference,dirname(filename));
2001 synfig::String prev_path;
2003 if(!_preferences.get_value(preference, prev_path))
2006 prev_path = absolute_path(prev_path);
2008 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2010 dialog->set_current_folder(prev_path);
2011 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2012 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2014 Widget_Enum *file_type_enum = 0;
2015 if (preference == ANIMATION_DIR_PREFERENCE)
2017 file_type_enum = manage(new Widget_Enum());
2018 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2019 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", strprintf("0.62.00 (%s)", _("current")))
2020 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2021 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2022 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2023 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2024 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2026 Gtk::HBox *hbox = manage(new Gtk::HBox);
2027 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2028 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2031 dialog->set_extra_widget(*hbox);
2034 if (filename.empty())
2035 dialog->set_filename(prev_path);
2038 std::string full_path;
2039 if (is_absolute_path(filename))
2040 full_path = filename;
2042 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2044 // select the file if it exists
2045 dialog->set_filename(full_path);
2047 // if the file doesn't exist, put its name into the filename box
2049 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2050 dialog->set_current_name(basename(filename));
2053 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2054 if (preference == ANIMATION_DIR_PREFERENCE)
2055 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2056 filename = dialog->get_filename();
2057 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2058 _preferences.set_value(preference, dirname(filename));
2069 App::dialog_error_blocking(const std::string &title, const std::string &message)
2071 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2072 dialog.set_title(title);
2078 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2080 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2081 dialog.set_title(title);
2087 App::dialog_yes_no(const std::string &title, const std::string &message)
2092 true // use_separator
2094 Gtk::Label label(message);
2097 dialog.get_vbox()->pack_start(label);
2098 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2099 dialog.add_button(Gtk::StockID("gtk-no"),0);
2101 return dialog.run();
2105 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2110 true // use_separator
2112 Gtk::Label label(message);
2115 dialog.get_vbox()->pack_start(label);
2116 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2117 dialog.add_button(Gtk::StockID("gtk-no"),0);
2118 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2120 return dialog.run();
2124 App::dialog_not_implemented()
2126 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2127 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2132 try_open_url(const std::string &url)
2135 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2137 std::vector<std::string> command_line;
2138 std::vector<std::string> browsers;
2139 browsers.reserve(23);
2141 // Browser wrapper scripts
2142 #ifdef USE_OPEN_FOR_URLS
2143 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2145 browsers.push_back("xdg-open"); // XDG wrapper
2146 browsers.push_back("sensible-browser"); // Debian wrapper
2147 browsers.push_back("gnome-open"); // GNOME wrapper
2148 browsers.push_back("kfmclient"); // KDE wrapper
2149 browsers.push_back("exo-open"); // XFCE wrapper
2151 // Alternatives system
2152 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2153 browsers.push_back("x-www-browser"); // Debian GUI alternative
2155 // Individual browsers
2156 browsers.push_back("firefox");
2157 browsers.push_back("epiphany-browser");
2158 browsers.push_back("epiphany");
2159 browsers.push_back("konqueror");
2160 browsers.push_back("iceweasel");
2161 browsers.push_back("mozilla");
2162 browsers.push_back("netscape");
2163 browsers.push_back("icecat");
2164 browsers.push_back("galeon");
2165 browsers.push_back("midori");
2166 browsers.push_back("safari");
2167 browsers.push_back("opera");
2168 browsers.push_back("amaya");
2169 browsers.push_back("netsurf");
2170 browsers.push_back("dillo");
2172 // Try the user-specified browser first
2173 command_line.push_back(App::browser_command);
2174 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2175 command_line.push_back(url);
2177 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2178 catch( Glib::SpawnError& exception ){
2180 while ( !browsers.empty() )
2182 // Skip the browser if we already tried it
2183 if( browsers[0] == App::browser_command )
2186 // Construct the command line
2187 command_line.clear();
2188 command_line.push_back(browsers[0]);
2189 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2190 command_line.push_back(url);
2192 // Remove the browser from the list
2193 browsers.erase(browsers.begin());
2195 // Try to spawn the browser
2196 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2197 // Failed, move on to the next one
2198 catch(Glib::SpawnError& exception){ continue; }
2199 return true; // No exception means we succeeded!
2210 if (!try_open_url("http://synfig.org/Documentation"))
2212 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2213 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2214 dialog.set_title(_("Help"));
2220 App::open_url(const std::string &url)
2222 if(!try_open_url(url))
2224 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2225 dialog.set_secondary_text(url);
2226 dialog.set_title(_("No browser found"));
2232 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2237 true); // use_separator
2239 Gtk::Label label(message);
2241 dialog.get_vbox()->pack_start(label);
2244 entry.set_text(text);
2246 entry.set_activates_default(true);
2248 dialog.get_vbox()->pack_start(entry);
2250 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2251 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2252 dialog.set_default_response(Gtk::RESPONSE_OK);
2254 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2257 if(dialog.run()!=Gtk::RESPONSE_OK)
2260 text=entry.get_text();
2266 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2271 true); // use_separator
2273 Gtk::Label label(message);
2275 dialog.get_vbox()->pack_start(label);
2277 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2278 text_buffer->set_text(text);
2279 Gtk::TextView text_view(text_buffer);
2282 dialog.get_vbox()->pack_start(text_view);
2284 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2285 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2286 dialog.set_default_response(Gtk::RESPONSE_OK);
2288 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2291 if(dialog.run()!=Gtk::RESPONSE_OK)
2294 text=text_buffer->get_text();
2300 App::open(std::string filename)
2302 return open_as(filename,filename);
2305 // this is called from autorecover.cpp:
2306 // App::open_as(get_shadow_file_name(filename),filename)
2307 // other than that, 'filename' and 'as' are the same
2309 App::open_as(std::string filename,std::string as)
2312 char long_name[1024];
2313 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2314 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2315 // don't use it if that's the case
2316 if (long_name[0] != '\0')
2322 OneMoment one_moment;
2323 String errors, warnings;
2325 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2326 if(canvas && get_instance(canvas))
2328 get_instance(canvas)->find_canvas_view(canvas)->present();
2329 info("%s is already open", filename.c_str());
2330 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2335 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2338 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2340 if (as.find(custom_filename_prefix.c_str()) != 0)
2341 add_recent_file(as);
2343 handle<Instance> instance(Instance::create(canvas));
2346 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2348 set_recent_file_window_size(instance);
2352 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)")))
2353 instance->dialog_cvs_update();
2358 dialog_error_blocking(_("Error"), x);
2361 catch(runtime_error x)
2363 dialog_error_blocking(_("Error"), x.what());
2368 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2379 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2381 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2382 canvas->set_name(file_name);
2383 file_name += ".sifz";
2385 canvas->rend_desc().set_frame_rate(preferred_fps);
2386 canvas->rend_desc().set_time_start(0.0);
2387 canvas->rend_desc().set_time_end(5.0);
2388 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2389 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2390 // The top left and botton right positions are expressed in units
2391 // Original convention is that 1 unit = 60 pixels
2392 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2393 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2394 canvas->rend_desc().set_w(preferred_x_size);
2395 canvas->rend_desc().set_h(preferred_y_size);
2396 canvas->rend_desc().set_antialias(1);
2397 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2398 canvas->set_file_name(file_name);
2400 handle<Instance> instance = Instance::create(canvas);
2402 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2403 instance->find_canvas_view(canvas)->canvas_properties.present();
2407 App::dialog_open(string filename)
2409 if (filename.empty())
2412 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2414 // If the filename still has wildcards, then we should
2415 // continue looking for the file we want
2416 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2422 get_ui_interface()->error(_("Unable to open file"));
2427 App::set_selected_instance(etl::loose_handle<Instance> instance)
2429 /* if(get_selected_instance()==instance)
2431 selected_instance=instance;
2432 signal_instance_selected()(instance);
2438 selected_instance=instance;
2439 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2443 instance->focus(instance->get_canvas());
2446 set_selected_canvas_view(0);
2448 signal_instance_selected()(instance);
2452 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2454 selected_canvas_view=canvas_view;
2455 signal_canvas_view_focus()(selected_canvas_view);
2458 selected_instance=canvas_view->get_instance();
2459 signal_instance_selected()(canvas_view->get_instance());
2462 if(get_selected_canvas_view()==canvas_view)
2464 signal_canvas_view_focus()(selected_canvas_view);
2465 signal_instance_selected()(canvas_view->get_instance());
2468 selected_canvas_view=canvas_view;
2469 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2470 set_selected_instance(canvas_view->get_instance());
2471 signal_canvas_view_focus()(selected_canvas_view);
2475 etl::loose_handle<Instance>
2476 App::get_instance(etl::handle<synfig::Canvas> canvas)
2478 if(!canvas) return 0;
2479 canvas=canvas->get_root();
2481 std::list<etl::handle<Instance> >::iterator iter;
2482 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2484 if((*iter)->get_canvas()==canvas)
2500 if(selected_instance)
2501 selected_instance->undo();
2507 if(selected_instance)
2508 selected_instance->redo();
2512 studio::App::get_base_path()
2514 return app_base_path_;