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"
78 #include "onemoment.h"
80 #include "dockmanager.h"
82 #include "state_eyedrop.h"
83 #include "state_normal.h"
84 #include "state_draw.h"
85 #include "state_fill.h"
86 #include "state_bline.h"
87 #include "state_polygon.h"
88 #include "state_sketch.h"
89 #include "state_gradient.h"
90 #include "state_circle.h"
91 #include "state_rectangle.h"
92 #include "state_smoothmove.h"
93 #include "state_star.h"
94 #include "state_text.h"
95 #include "state_width.h"
96 #include "state_zoom.h"
98 #include "devicetracker.h"
99 #include "dialog_tooloptions.h"
100 #include "widget_enum.h"
102 #include "autorecover.h"
104 #include <synfigapp/settings.h>
105 #include "dock_history.h"
106 #include "dock_canvases.h"
107 #include "dock_keyframes.h"
108 #include "dock_layers.h"
109 #include "dock_params.h"
110 #include "dock_metadata.h"
111 #include "dock_children.h"
112 #include "dock_info.h"
113 #include "dock_navigator.h"
114 #include "dock_layergroups.h"
115 #include "dock_timetrack.h"
116 #include "dock_curves.h"
118 #include "mod_palette/mod_palette.h"
119 #include "mod_mirror/mod_mirror.h"
121 #include <sys/stat.h>
127 #include "statemanager.h"
133 #include <gtkmm/accelmap.h>
134 #include <gtkmm/filechooser.h>
135 #include <gtkmm/filechooserdialog.h>
141 /* === U S I N G =========================================================== */
145 using namespace synfig;
146 using namespace studio;
148 /* === M A C R O S ========================================================= */
150 #ifndef SYNFIG_USER_APP_DIR
152 #define SYNFIG_USER_APP_DIR "Library/Synfig"
153 #elif defined(_WIN32)
154 #define SYNFIG_USER_APP_DIR "Synfig"
156 #define SYNFIG_USER_APP_DIR ".synfig"
161 #define DPM2DPI(x) (float(x)/39.3700787402f)
162 #define DPI2DPM(x) (float(x)*39.3700787402f)
168 # define IMAGE_DIR "share\\pixmaps"
173 # define IMAGE_DIR "/usr/local/share/pixmaps"
177 # define IMAGE_EXT "tif"
180 #include <synfigapp/main.h>
182 /* === S I G N A L S ======================================================= */
184 static sigc::signal<void> signal_present_all_;
186 App::signal_present_all() { return signal_present_all_; }
188 static sigc::signal<void> signal_recent_files_changed_;
190 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
192 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
193 sigc::signal<void,etl::loose_handle<CanvasView> >&
194 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
196 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
197 sigc::signal<void,etl::handle<Instance> >&
198 App::signal_instance_selected() { return signal_instance_selected_; }
200 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
201 sigc::signal<void,etl::handle<Instance> >&
202 App::signal_instance_created() { return signal_instance_created_; }
204 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
205 sigc::signal<void,etl::handle<Instance> >&
206 App::signal_instance_deleted() { return signal_instance_deleted_; }
208 /* === G L O B A L S ======================================================= */
210 static std::list<std::string> recent_files;
211 const std::list<std::string>& App::get_recent_files() { return recent_files; }
213 static std::list<std::string> recent_files_window_size;
215 int App::Busy::count;
216 bool App::shutdown_in_progress;
218 synfig::Gamma App::gamma;
220 Glib::RefPtr<studio::UIManager> App::ui_manager_;
222 synfig::Distance::System App::distance_system;
224 studio::Dialog_Setup* App::dialog_setup;
226 etl::handle< studio::ModPalette > mod_palette_;
227 //studio::Dialog_Palette* App::dialog_palette;
229 std::list<etl::handle<Instance> > App::instance_list;
231 static etl::handle<synfigapp::UIInterface> ui_interface_;
232 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
234 etl::handle<Instance> App::selected_instance;
235 etl::handle<CanvasView> App::selected_canvas_view;
237 studio::About *studio::App::about=NULL;
239 studio::Toolbox *studio::App::toolbox=NULL;
241 studio::AutoRecover *studio::App::auto_recover=NULL;
243 studio::IPC *ipc=NULL;
245 studio::DockManager* studio::App::dock_manager=0;
247 studio::DeviceTracker* studio::App::device_tracker=0;
249 studio::Dialog_Gradient* studio::App::dialog_gradient;
251 studio::Dialog_Color* studio::App::dialog_color;
253 Gtk::InputDialog* studio::App::dialog_input;
255 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
257 studio::Dock_History* dock_history;
258 studio::Dock_Canvases* dock_canvases;
259 studio::Dock_Keyframes* dock_keyframes;
260 studio::Dock_Layers* dock_layers;
261 studio::Dock_Params* dock_params;
262 studio::Dock_MetaData* dock_meta_data;
263 studio::Dock_Children* dock_children;
264 studio::Dock_Info* dock_info;
265 studio::Dock_LayerGroups* dock_layer_groups;
266 studio::Dock_Navigator* dock_navigator;
267 studio::Dock_Timetrack* dock_timetrack;
268 studio::Dock_Curves* dock_curves;
270 std::list< etl::handle< studio::Module > > module_list_;
272 bool studio::App::use_colorspace_gamma=true;
273 #ifdef SINGLE_THREADED
274 bool studio::App::single_threaded=false;
276 bool studio::App::restrict_radius_ducks=false;
277 bool studio::App::resize_imported_images=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 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
283 float studio::App::preferred_fps=24.0;
284 #ifdef USE_OPEN_FOR_URLS
285 String studio::App::browser_command("open"); // MacOS only
287 String studio::App::browser_command("xdg-open"); // Linux XDG standard
290 static int max_recent_files_=25;
291 int studio::App::get_max_recent_files() { return max_recent_files_; }
292 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
294 static synfig::String app_base_path_;
299 really_delete_widget(Gtk::Widget *widget)
301 // synfig::info("really delete %p", (void*)widget);
306 // nasty workaround - when we've finished with a popup menu, we want to delete it
307 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
308 // so schedule the real delete to happen in 50ms, giving the action a chance to run
310 delete_widget(Gtk::Widget *widget)
312 // synfig::info("delete %p", (void*)widget);
313 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
316 }; // END of namespace studio
317 studio::StateManager* state_manager;
322 class GlobalUIInterface : public synfigapp::UIInterface
326 virtual Response confirmation(const std::string &title,
327 const std::string &primaryText,
328 const std::string &secondaryText,
329 const std::string &confirmPhrase,
330 const std::string &cancelPhrase,
331 Response defaultResponse)
333 Gtk::MessageDialog dialog(
334 primaryText, // Message
336 Gtk::MESSAGE_WARNING, // Type
337 Gtk::BUTTONS_NONE, // Buttons
342 dialog.set_title(title);
343 if (! secondaryText.empty())
344 dialog.set_secondary_text(secondaryText);
346 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
347 dialog.add_button(confirmPhrase, RESPONSE_OK);
348 dialog.set_default_response(defaultResponse);
351 return (Response) dialog.run();
354 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
359 true // use_separator
361 Gtk::Label label(message);
364 dialog.get_vbox()->pack_start(label);
365 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
366 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
368 dialog.set_default_response(dflt);
370 return (Response)dialog.run();
372 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
377 true // use_separator
379 Gtk::Label label(message);
382 dialog.get_vbox()->pack_start(label);
383 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
384 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
385 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
387 dialog.set_default_response(dflt);
389 return (Response)dialog.run();
391 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
396 true // use_separator
398 Gtk::Label label(message);
401 dialog.get_vbox()->pack_start(label);
402 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
403 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
405 dialog.set_default_response(dflt);
407 return (Response)dialog.run();
411 task(const std::string &task)
413 std::cerr<<task<<std::endl;
414 while(studio::App::events_pending())studio::App::iteration(false);
419 error(const std::string &err)
421 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
428 warning(const std::string &err)
430 std::cerr<<"warning: "<<err<<std::endl;
431 while(studio::App::events_pending())studio::App::iteration(false);
436 amount_complete(int /*current*/, int /*total*/)
438 while(studio::App::events_pending())studio::App::iteration(false);
443 /* === P R O C E D U R E S ================================================= */
447 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
449 action_group_list.push_back(action_group);
450 Gtk::UIManager::insert_action_group(action_group, pos);
454 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
456 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
457 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
458 if(*iter==action_group)
460 action_group_list.erase(iter);
461 Gtk::UIManager::remove_action_group(action_group);
464 synfig::error("Unable to find action group");
468 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
470 ui_manager->insert_action_group(group,0);
472 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
473 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
475 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
477 if(*iter && (*iter)->get_name()!="menus")
479 synfig::info("Removing action group "+(*iter)->get_name());
480 ui_manager->remove_action_group(*iter);
483 ui_manager->insert_action_group(group,0);
485 for(;!prev_groups.empty();prev_groups.pop_front())
487 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
488 ui_manager->insert_action_group(prev_groups.front(),1);
492 class Preferences : public synfigapp::Settings
495 virtual bool get_value(const synfig::String& key, synfig::String& value)const
499 value=strprintf("%f %f %f %f",
500 App::gamma.get_gamma_r(),
501 App::gamma.get_gamma_g(),
502 App::gamma.get_gamma_b(),
503 App::gamma.get_black_level()
507 if(key=="time_format")
509 value=strprintf("%i",App::get_time_format());
512 if(key=="file_history.size")
514 value=strprintf("%i",App::get_max_recent_files());
517 if(key=="use_colorspace_gamma")
519 value=strprintf("%i",(int)App::use_colorspace_gamma);
522 if(key=="distance_system")
524 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
527 #ifdef SINGLE_THREADED
528 if(key=="single_threaded")
530 value=strprintf("%i",(int)App::single_threaded);
534 if(key=="auto_recover_backup_interval")
536 value=strprintf("%i",App::auto_recover->get_timeout());
539 if(key=="restrict_radius_ducks")
541 value=strprintf("%i",(int)App::restrict_radius_ducks);
544 if(key=="resize_imported_images")
546 value=strprintf("%i",(int)App::resize_imported_images);
549 if(key=="browser_command")
551 value=App::browser_command;
554 if(key=="custom_filename_prefix")
556 value=App::custom_filename_prefix;
559 if(key=="preferred_x_size")
561 value=strprintf("%i",App::preferred_x_size);
564 if(key=="preferred_y_size")
566 value=strprintf("%i",App::preferred_y_size);
569 if(key=="predefined_size")
571 value=strprintf("%s",App::predefined_size.c_str());
574 if(key=="preferred_fps")
576 value=strprintf("%f",App::preferred_fps);
579 if(key=="predefined_fps")
581 value=strprintf("%s",App::predefined_fps.c_str());
585 return synfigapp::Settings::get_value(key,value);
588 virtual bool set_value(const synfig::String& key,const synfig::String& value)
594 strscanf(value,"%f %f %f %f",
601 App::gamma.set_all(r,g,b,blk);
605 if(key=="time_format")
607 int i(atoi(value.c_str()));
608 App::set_time_format(static_cast<synfig::Time::Format>(i));
611 if(key=="auto_recover_backup_interval")
613 int i(atoi(value.c_str()));
614 App::auto_recover->set_timeout(i);
617 if(key=="file_history.size")
619 int i(atoi(value.c_str()));
620 App::set_max_recent_files(i);
623 if(key=="use_colorspace_gamma")
625 int i(atoi(value.c_str()));
626 App::use_colorspace_gamma=i;
629 if(key=="distance_system")
631 App::distance_system=Distance::ident_system(value);;
634 #ifdef SINGLE_THREADED
635 if(key=="single_threaded")
637 int i(atoi(value.c_str()));
638 App::single_threaded=i;
642 if(key=="restrict_radius_ducks")
644 int i(atoi(value.c_str()));
645 App::restrict_radius_ducks=i;
648 if(key=="resize_imported_images")
650 int i(atoi(value.c_str()));
651 App::resize_imported_images=i;
654 if(key=="browser_command")
656 App::browser_command=value;
659 if(key=="custom_filename_prefix")
661 App::custom_filename_prefix=value;
664 if(key=="preferred_x_size")
666 int i(atoi(value.c_str()));
667 App::preferred_x_size=i;
670 if(key=="preferred_y_size")
672 int i(atoi(value.c_str()));
673 App::preferred_y_size=i;
676 if(key=="predefined_size")
678 App::predefined_size=value;
681 if(key=="preferred_fps")
683 float i(atof(value.c_str()));
684 App::preferred_fps=i;
687 if(key=="predefined_fps")
689 App::predefined_fps=value;
693 return synfigapp::Settings::set_value(key,value);
696 virtual KeyList get_key_list()const
698 KeyList ret(synfigapp::Settings::get_key_list());
699 ret.push_back("gamma");
700 ret.push_back("time_format");
701 ret.push_back("distance_system");
702 ret.push_back("file_history.size");
703 ret.push_back("use_colorspace_gamma");
704 #ifdef SINGLE_THREADED
705 ret.push_back("single_threaded");
707 ret.push_back("auto_recover_backup_interval");
708 ret.push_back("restrict_radius_ducks");
709 ret.push_back("resize_imported_images");
710 ret.push_back("browser_command");
711 ret.push_back("custom_filename_prefix");
712 ret.push_back("preferred_x_size");
713 ret.push_back("preferred_y_size");
714 ret.push_back("predefined_size");
715 ret.push_back("preferred_fps");
716 ret.push_back("predefined_fps");
721 static ::Preferences _preferences;
726 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
728 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
730 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
732 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
733 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
734 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
735 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
736 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
737 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
738 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
739 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
740 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
741 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
742 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
743 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
744 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
746 // Add the synfigapp actions...
747 synfigapp::Action::Book::iterator iter;
748 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
750 actions_action_group->add(Gtk::Action::create(
751 "action-"+iter->second.name,
752 get_action_stock_id(iter->second),
753 iter->second.local_name,iter->second.local_name
757 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
758 #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); }
759 #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); }
761 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
762 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
763 DEFINE_ACTION("new", Gtk::Stock::NEW);
764 DEFINE_ACTION("open", Gtk::Stock::OPEN);
765 DEFINE_ACTION("save", Gtk::Stock::SAVE);
766 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
767 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
768 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
769 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
770 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
771 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
772 DEFINE_ACTION("import", _("Import"));
773 DEFINE_ACTION("render", _("Render"));
774 DEFINE_ACTION("preview", _("Preview"));
775 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
776 DEFINE_ACTION("sound", _("Sound File"));
777 DEFINE_ACTION("options", _("Options"));
778 DEFINE_ACTION("close", _("Close View"));
779 DEFINE_ACTION("close-document", _("Close Document"));
780 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
783 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
784 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
785 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
786 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
787 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
788 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
789 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
790 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
791 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
792 DEFINE_ACTION("properties", _("Properties"));
794 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
795 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
796 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
797 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
798 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
799 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
800 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
801 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
802 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
803 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
804 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
805 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
806 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
807 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
808 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
809 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
810 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
811 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
812 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
813 DEFINE_ACTION("play", _("Play"));
814 // DEFINE_ACTION("pause", _("Pause"));
815 DEFINE_ACTION("stop", _("Stop"));
816 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
817 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
818 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
819 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
820 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
821 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
822 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
823 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
824 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
825 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
826 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
827 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
828 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
829 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
830 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
831 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
832 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
833 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
834 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
835 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
836 DEFINE_ACTION("seek-end", _("Seek to End"));
838 DEFINE_ACTION("action-group_add", _("Add group"));
840 DEFINE_ACTION("canvas-new", _("New Canvas"));
842 DEFINE_ACTION("amount-inc", _("Increase Amount"));
843 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
848 // Set up synfigapp actions
850 synfigapp::Action::Book::iterator iter;
852 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
854 Gtk::StockID stock_id;
856 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
858 //Gtk::Image* image(manage(new Gtk::Image()));
859 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
860 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
861 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
862 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
863 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
864 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
865 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
866 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
867 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
868 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
870 actions_action_group->add(Gtk::Action::create(
871 "action-"+iter->second.name,
873 iter->second.local_name,iter->second.local_name
881 Glib::ustring ui_info =
883 " <popup name='menu-toolbox' action='menu-toolbox'>"
884 " <menu action='menu-file'>"
887 " <popup name='menu-main' action='menu-main'>"
888 " <menu action='menu-file'>"
889 " <menuitem action='new' />"
890 " <menuitem action='open' />"
891 " <menuitem action='save' />"
892 " <menuitem action='save-as' />"
893 " <menuitem action='revert' />"
894 " <separator name='bleh01'/>"
895 " <menuitem action='cvs-add' />"
896 " <menuitem action='cvs-update' />"
897 " <menuitem action='cvs-commit' />"
898 " <menuitem action='cvs-revert' />"
899 " <separator name='bleh02'/>"
900 " <menuitem action='import' />"
901 " <separator name='bleh03'/>"
902 " <menuitem action='render' />"
903 " <menuitem action='preview' />"
904 " <menuitem action='sound' />"
905 " <separator name='bleh04'/>"
906 " <menuitem action='options' />"
907 " <menuitem action='close' />"
908 " <menuitem action='close-document' />"
909 " <menuitem action='quit' />"
911 " <menu action='menu-edit'>"
912 " <menuitem action='undo'/>"
913 " <menuitem action='redo'/>"
914 " <separator name='bleh05'/>"
915 " <menuitem action='cut'/>"
916 " <menuitem action='copy'/>"
917 " <menuitem action='paste'/>"
918 " <separator name='bleh06'/>"
919 " <menuitem action='select-all-layers'/>"
920 " <menuitem action='unselect-all-layers'/>"
921 " <menuitem action='select-all-ducks'/>"
922 " <menuitem action='unselect-all-ducks'/>"
923 " <separator name='bleh07'/>"
924 " <menuitem action='properties'/>"
926 " <menu action='menu-view'>"
927 " <menu action='menu-duck-mask'>"
928 " <menuitem action='mask-position-ducks' />"
929 " <menuitem action='mask-vertex-ducks' />"
930 " <menuitem action='mask-tangent-ducks' />"
931 " <menuitem action='mask-radius-ducks' />"
932 " <menuitem action='mask-width-ducks' />"
933 " <menuitem action='mask-angle-ducks' />"
935 " <menu action='menu-preview-quality'>"
936 " <menuitem action='quality-00' />"
937 " <menuitem action='quality-01' />"
938 " <menuitem action='quality-02' />"
939 " <menuitem action='quality-03' />"
940 " <menuitem action='quality-04' />"
941 " <menuitem action='quality-05' />"
942 " <menuitem action='quality-06' />"
943 " <menuitem action='quality-07' />"
944 " <menuitem action='quality-08' />"
945 " <menuitem action='quality-09' />"
946 " <menuitem action='quality-10' />"
948 " <menu action='menu-lowres-pixel'>"
949 " <menuitem action='decrease-low-res-pixel-size'/>"
950 " <menuitem action='increase-low-res-pixel-size'/>"
951 " <separator name='pixel-size-separator'/>"
954 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
955 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
959 " <separator name='bleh08'/>"
960 " <menuitem action='play'/>"
961 //" <menuitem action='pause'/>"
962 " <menuitem action='stop'/>"
963 " <menuitem action='dialog-flipbook'/>"
964 " <separator name='bleh09'/>"
965 " <menuitem action='toggle-grid-show'/>"
966 " <menuitem action='toggle-grid-snap'/>"
967 " <menuitem action='toggle-guide-show'/>"
968 " <menuitem action='toggle-low-res'/>"
969 " <menuitem action='toggle-onion-skin'/>"
970 " <separator name='bleh10'/>"
971 " <menuitem action='canvas-zoom-in'/>"
972 " <menuitem action='canvas-zoom-out'/>"
973 " <menuitem action='canvas-zoom-fit'/>"
974 " <menuitem action='canvas-zoom-100'/>"
975 " <separator name='bleh11'/>"
976 " <menuitem action='time-zoom-in'/>"
977 " <menuitem action='time-zoom-out'/>"
978 " <separator name='bleh12'/>"
979 " <menuitem action='jump-next-keyframe'/>"
980 " <menuitem action='jump-prev-keyframe'/>"
981 " <menuitem action='seek-next-frame'/>"
982 " <menuitem action='seek-prev-frame'/>"
983 " <menuitem action='seek-next-second'/>"
984 " <menuitem action='seek-prev-second'/>"
985 " <menuitem action='seek-begin'/>"
986 " <menuitem action='seek-end'/>"
988 " <menu action='menu-canvas'>"
989 " <menuitem action='canvas-new'/>"
991 " <menu name='menu-state' action='menu-state'>"
993 " <menu action='menu-group'>"
994 " <menuitem action='action-group_add'/>"
996 " <menu action='menu-layer'>"
997 //" <menuitem action='cut'/>"
998 //" <menuitem action='copy'/>"
999 //" <menuitem action='paste'/>"
1000 //" <separator name='bleh06'/>"
1001 " <menu action='menu-layer-new'></menu>"
1002 " <menuitem action='amount-inc'/>"
1003 " <menuitem action='amount-dec'/>"
1005 " <menu action='menu-keyframe'>"
1006 " <menuitem action='keyframe-properties'/>"
1013 " <menubar name='MenuBar'>"
1014 " <menu action='MenuFile'>"
1015 " <menuitem action='New'/>"
1016 " <menuitem action='Open'/>"
1018 " <menuitem action='Quit'/>"
1020 " <menu action='MenuEdit'>"
1021 " <menuitem action='Cut'/>"
1022 " <menuitem action='Copy'/>"
1023 " <menuitem action='Paste'/>"
1026 " <toolbar name='ToolBar'>"
1027 " <toolitem action='Open'/>"
1028 " <toolitem action='Quit'/>"
1034 actions_action_group->set_sensitive(false);
1035 App::ui_manager()->set_add_tearoffs(true);
1036 App::ui_manager()->insert_action_group(menus_action_group,1);
1037 App::ui_manager()->insert_action_group(actions_action_group,1);
1038 App::ui_manager()->add_ui_from_string(ui_info);
1040 //App::ui_manager()->get_accel_group()->unlock();
1042 catch(const Glib::Error& ex)
1044 synfig::error("building menus and toolbars failed: " + ex.what());
1047 // Add default keyboard accelerators
1048 #define ACCEL(accel,path) \
1050 Gtk::AccelKey accel_key(accel,path); \
1051 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1054 #define ACCEL2(accel) \
1056 Gtk::AccelKey accel_key(accel); \
1057 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1061 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1062 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1063 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1064 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1065 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1066 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1067 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1068 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1069 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1070 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1071 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1072 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1073 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1074 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1075 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1076 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1077 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1078 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1081 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1082 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1083 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1084 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1085 ACCEL("F9", "<Actions>/canvasview/render" );
1086 ACCEL("F11", "<Actions>/canvasview/preview" );
1087 ACCEL("F8", "<Actions>/canvasview/properties" );
1088 ACCEL("F12", "<Actions>/canvasview/options" );
1089 ACCEL("<control>i", "<Actions>/canvasview/import" );
1090 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1091 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1092 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1093 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1094 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1095 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1096 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1097 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1098 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1099 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1100 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1101 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1102 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1103 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1104 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1105 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1106 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1107 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1108 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1109 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1110 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1111 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1112 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1113 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1114 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1115 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1116 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1117 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1118 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1119 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1120 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1121 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1122 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1123 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1124 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1125 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1126 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1127 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1128 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1129 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1130 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1131 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1132 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1133 ACCEL("End", "<Actions>/canvasview/seek-end" );
1139 #define mkdir(x,y) mkdir(x)
1142 /* === M E T H O D S ======================================================= */
1144 App::App(int *argc, char ***argv):
1145 Gtk::Main(argc,argv),
1146 IconController(etl::dirname((*argv)[0]))
1148 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1151 ui_interface_=new GlobalUIInterface();
1155 // don't call thread_init() if threads are already initialized
1156 // on some machines bonobo_init() initialized threads before we get here
1157 if (!g_thread_supported())
1158 Glib::thread_init();
1160 distance_system=Distance::SYSTEM_UNITS;
1162 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1165 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1169 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1175 if(!SYNFIG_CHECK_VERSION())
1177 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1178 dialog_error_blocking("Synfig Studio",
1179 "This copy of Synfig Studio was compiled against a\n"
1180 "different version of libsynfig than what is currently\n"
1181 "installed. Synfig Studio will now abort. Try downloading\n"
1182 "the latest version from the Synfig website at\n"
1183 "http://synfig.org/Download"
1187 Glib::set_application_name(_("Synfig Studio"));
1189 Splash splash_screen;
1190 splash_screen.show();
1192 shutdown_in_progress=false;
1193 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1194 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1196 // Initialize the Synfig library
1197 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1198 catch(std::runtime_error x)
1200 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1205 get_ui_interface()->error(_("Failed to initialize synfig!"));
1209 // add the preferences to the settings
1210 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1214 studio_init_cb.task(_("Init UI Manager..."));
1215 App::ui_manager_=studio::UIManager::create();
1218 studio_init_cb.task(_("Init Dock Manager..."));
1219 dock_manager=new studio::DockManager();
1221 studio_init_cb.task(_("Init State Manager..."));
1222 state_manager=new StateManager();
1224 studio_init_cb.task(_("Init Toolbox..."));
1225 toolbox=new studio::Toolbox();
1227 studio_init_cb.task(_("Init About Dialog..."));
1228 about=new studio::About();
1230 studio_init_cb.task(_("Init Tool Options..."));
1231 dialog_tool_options=new studio::Dialog_ToolOptions();
1232 dock_manager->register_dockable(*dialog_tool_options);
1234 studio_init_cb.task(_("Init History..."));
1235 dock_history=new studio::Dock_History();
1236 dock_manager->register_dockable(*dock_history);
1238 studio_init_cb.task(_("Init Canvases..."));
1239 dock_canvases=new studio::Dock_Canvases();
1240 dock_manager->register_dockable(*dock_canvases);
1242 studio_init_cb.task(_("Init Keyframes..."));
1243 dock_keyframes=new studio::Dock_Keyframes();
1244 dock_manager->register_dockable(*dock_keyframes);
1246 studio_init_cb.task(_("Init Layers..."));
1247 dock_layers=new studio::Dock_Layers();
1248 dock_manager->register_dockable(*dock_layers);
1250 studio_init_cb.task(_("Init Params..."));
1251 dock_params=new studio::Dock_Params();
1252 dock_manager->register_dockable(*dock_params);
1254 studio_init_cb.task(_("Init MetaData..."));
1255 dock_meta_data=new studio::Dock_MetaData();
1256 dock_manager->register_dockable(*dock_meta_data);
1258 studio_init_cb.task(_("Init Children..."));
1259 dock_children=new studio::Dock_Children();
1260 dock_manager->register_dockable(*dock_children);
1262 studio_init_cb.task(_("Init Info..."));
1263 dock_info = new studio::Dock_Info();
1264 dock_manager->register_dockable(*dock_info);
1266 studio_init_cb.task(_("Init Navigator..."));
1267 dock_navigator = new studio::Dock_Navigator();
1268 dock_manager->register_dockable(*dock_navigator);
1270 studio_init_cb.task(_("Init Timetrack..."));
1271 dock_timetrack = new studio::Dock_Timetrack();
1272 dock_manager->register_dockable(*dock_timetrack);
1274 studio_init_cb.task(_("Init Curve Editor..."));
1275 dock_curves = new studio::Dock_Curves();
1276 dock_manager->register_dockable(*dock_curves);
1278 studio_init_cb.task(_("Init Layer Groups..."));
1279 dock_layer_groups = new studio::Dock_LayerGroups();
1280 dock_manager->register_dockable(*dock_layer_groups);
1283 studio_init_cb.task(_("Init Color Dialog..."));
1284 dialog_color=new studio::Dialog_Color();
1286 studio_init_cb.task(_("Init Gradient Dialog..."));
1287 dialog_gradient=new studio::Dialog_Gradient();
1289 studio_init_cb.task(_("Init DeviceTracker..."));
1290 device_tracker=new studio::DeviceTracker();
1292 studio_init_cb.task(_("Init Tools..."));
1295 state_manager->add_state(&state_normal);
1296 state_manager->add_state(&state_smooth_move);
1297 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1298 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1301 state_manager->add_state(&state_bline);
1302 state_manager->add_state(&state_circle);
1303 state_manager->add_state(&state_rectangle);
1304 state_manager->add_state(&state_star);
1305 state_manager->add_state(&state_gradient);
1306 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1307 state_manager->add_state(&state_text);
1308 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1312 state_manager->add_state(&state_fill);
1313 state_manager->add_state(&state_eyedrop);
1314 state_manager->add_state(&state_zoom);
1315 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1317 studio_init_cb.task(_("Init ModPalette..."));
1318 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1320 studio_init_cb.task(_("Init Setup Dialog..."));
1321 dialog_setup=new studio::Dialog_Setup();
1323 studio_init_cb.task(_("Init Input Dialog..."));
1324 dialog_input=new Gtk::InputDialog();
1325 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1326 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1328 studio_init_cb.task(_("Init auto recovery..."));
1329 auto_recover=new AutoRecover();
1331 studio_init_cb.amount_complete(9250,10000);
1332 studio_init_cb.task(_("Loading Settings..."));
1334 device_tracker->load_preferences();
1336 studio_init_cb.task(_("Checking auto-recover..."));
1338 studio_init_cb.amount_complete(9900,10000);
1340 bool opened_any = false;
1341 if(auto_recover->recovery_needed())
1343 splash_screen.hide();
1344 if (get_ui_interface()->confirmation("Crash Recovery",
1345 _("Auto recovery file found"),
1346 _("Synfig Studio seems to have crashed\n"
1347 "before you could save all your files.\n"
1348 "Recover unsaved changes?"),
1349 _("Recover"), _("Ignore"))
1350 == synfigapp::UIInterface::RESPONSE_OK)
1352 int number_recovered;
1353 if(!auto_recover->recover(number_recovered))
1354 if (number_recovered)
1355 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1357 get_ui_interface()->error(_("Unable to recover from previous crash"));
1359 get_ui_interface()->error(
1360 _("Synfig Studio has attempted to recover\n"
1361 "from a previous crash. The files that it has\n"
1362 "recovered are NOT YET SAVED. It would be a good\n"
1363 "idea to review them and save them now."));
1365 if (number_recovered)
1368 splash_screen.show();
1371 // Look for any files given on the command line,
1372 // and load them if found.
1373 for(;*argc>=1;(*argc)--)
1374 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1376 studio_init_cb.task(_("Loading files..."));
1377 splash_screen.hide();
1378 open((*argv)[*argc]);
1380 splash_screen.show();
1383 // if no file was specified to be opened, create a new document to help new users get started more easily
1384 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1387 studio_init_cb.task(_("Done."));
1388 studio_init_cb.amount_complete(10000,10000);
1394 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1398 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1402 StateManager* App::get_state_manager() { return state_manager; }
1406 shutdown_in_progress=true;
1410 synfigapp::Main::settings().remove_domain("pref");
1412 selected_instance=0;
1414 // Unload all of the modules
1415 for(;!module_list_.empty();module_list_.pop_back())
1418 delete state_manager;
1422 delete auto_recover;
1428 // studio::App::iteration(false);
1432 // studio::App::iteration(false);
1434 // studio::App::iteration(false);
1436 delete dialog_setup;
1438 delete dialog_gradient;
1440 delete dialog_color;
1442 delete dialog_input;
1444 delete dock_manager;
1446 instance_list.clear();
1448 // studio::App::iteration(false);
1452 App::get_user_app_directory()
1454 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1456 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1458 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1463 App::get_config_file(const synfig::String& file)
1465 return Glib::build_filename(get_user_app_directory(),file);
1468 #define SCALE_FACTOR (1280)
1469 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1471 App::set_recent_file_window_size(etl::handle<Instance> instance)
1473 int screen_w(Gdk::screen_width());
1474 int screen_h(Gdk::screen_height());
1476 const std::string &canvas_window_size = *recent_files_window_size.begin();
1478 if(canvas_window_size.empty())
1481 synfig::String::size_type current=0;
1482 bool seen_root(false), shown_non_root(false);
1484 while(current != synfig::String::npos)
1486 // find end of first field (canvas) or return
1487 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1488 if(separator == synfig::String::npos) break;
1491 synfig::Canvas::Handle canvas;
1494 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1496 catch(Exception::IDNotFound) {
1497 // can't find the canvas; skip to the next canvas or return
1498 separator = canvas_window_size.find_first_of('\t', current);
1499 if(separator == synfig::String::npos) return;
1500 current = separator+1;
1504 if (canvas->is_root())
1507 shown_non_root = true;
1509 // check that we have the tab character the ends this canvas' data or return
1510 current = separator+1;
1511 separator = canvas_window_size.find_first_of('\t', current);
1512 if(separator == synfig::String::npos) return;
1515 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1517 current = separator+1;
1521 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1522 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1523 x=x*screen_w/SCALE_FACTOR;
1524 y=y*screen_h/SCALE_FACTOR;
1525 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1526 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1527 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1528 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1530 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1531 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1533 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1534 canvasview->move(x,y);
1535 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1536 canvasview->present();
1538 current = separator+1;
1541 if (shown_non_root && !seen_root)
1542 instance->find_canvas_view(instance->get_canvas())->hide();
1546 App::add_recent_file(const etl::handle<Instance> instance)
1548 int screen_w(Gdk::screen_width());
1549 int screen_h(Gdk::screen_height());
1551 std::string canvas_window_size;
1553 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1554 Instance::CanvasViewList::const_iterator iter;
1556 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1558 if( !((*iter)->is_visible()) )
1561 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1562 int x_pos, y_pos, x_size, y_size;
1563 (*iter)->get_position(x_pos,y_pos);
1564 (*iter)->get_size(x_size,y_size);
1566 canvas_window_size += strprintf("%s %d %d %d %d\t",
1567 canvas->get_relative_id(canvas->get_root()).c_str(),
1568 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1569 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1572 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1577 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1579 std::string filename(file_name);
1581 assert(!filename.empty());
1583 if(filename.empty())
1586 // Toss out any "hidden" files
1587 if(basename(filename)[0]=='.')
1590 // If we aren't an absolute path, turn ourselves into one
1591 if(!is_absolute_path(filename))
1592 filename=absolute_path(filename);
1594 std::string old_window_size;
1596 list<string>::iterator iter;
1597 list<string>::iterator iter_wsize;
1598 // Check to see if the file is already on the list.
1599 // If it is, then remove it from the list
1600 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1603 recent_files.erase(iter);
1604 old_window_size = *iter_wsize;
1605 recent_files_window_size.erase(iter_wsize);
1610 // Push the filename to the front of the list
1611 recent_files.push_front(filename);
1612 if(window_size.empty())
1613 recent_files_window_size.push_front(old_window_size);
1615 recent_files_window_size.push_front(window_size);
1617 // Clean out the files at the end of the list.
1618 while(recent_files.size()>(unsigned)get_max_recent_files())
1620 recent_files.pop_back();
1621 recent_files_window_size.pop_back();
1624 signal_recent_files_changed_();
1629 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1632 App::get_time_format()
1634 return _App_time_format;
1638 App::set_time_format(synfig::Time::Format x)
1645 App::save_settings()
1650 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1651 setlocale(LC_NUMERIC, "C");
1653 std::string filename=get_config_file("accelrc");
1654 Gtk::AccelMap::save(filename);
1657 std::string filename=get_config_file("recentfiles");
1659 std::ofstream file(filename.c_str());
1663 synfig::warning("Unable to save %s",filename.c_str());
1667 list<string>::reverse_iterator iter;
1669 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1673 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1675 std::ofstream file(filename.c_str());
1679 synfig::warning("Unable to save %s",filename.c_str());
1683 list<string>::reverse_iterator iter;
1685 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1689 std::string filename=get_config_file("settings");
1690 synfigapp::Main::settings().save_to_file(filename);
1691 setlocale(LC_NUMERIC,old_locale);
1695 synfig::warning("Caught exception when attempting to save settings.");
1700 App::load_settings()
1705 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1706 setlocale(LC_NUMERIC, "C");
1708 std::string filename=get_config_file("accelrc");
1709 Gtk::AccelMap::load(filename);
1712 bool window_size_broken = false;
1714 std::string filename=get_config_file("recentfiles");
1715 std::string filename_window_size=filename+std::string("_window_size");
1717 std::ifstream file(filename.c_str());
1718 std::ifstream file_window_size(filename_window_size.c_str());
1720 if(!file_window_size)
1721 window_size_broken = true;
1725 std::string recent_file;
1726 std::string recent_file_window_size;
1727 getline(file,recent_file);
1728 if(!window_size_broken)
1729 getline(file_window_size,recent_file_window_size);
1730 if(!recent_file.empty())
1732 if(!window_size_broken && !file_window_size)
1733 window_size_broken = true;
1734 if (std::ifstream(recent_file.c_str()))
1736 if(!window_size_broken)
1737 add_recent_file(recent_file,recent_file_window_size);
1739 add_recent_file(recent_file);
1743 if(!window_size_broken && file_window_size)
1744 window_size_broken = true;
1746 if(window_size_broken)
1748 recent_files_window_size.clear();
1749 recent_files_window_size.resize(recent_files.size());
1752 std::string filename=get_config_file("settings");
1753 if(!synfigapp::Main::settings().load_from_file(filename))
1755 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1756 //if(!synfigapp::Main::settings().load_from_file(filename))
1758 gamma.set_gamma(1.0/2.2);
1759 reset_initial_window_configuration();
1762 setlocale(LC_NUMERIC,old_locale);
1766 synfig::warning("Caught exception when attempting to load settings.");
1771 App::reset_initial_window_configuration()
1773 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1774 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1775 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1776 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1777 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1778 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1779 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1780 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1781 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1782 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1783 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1784 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1785 #ifdef SINGLE_THREADED
1786 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1788 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1789 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1790 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1791 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1792 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1793 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1794 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1795 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1796 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1800 App::shutdown_request(GdkEventAny*)
1804 //return !shutdown_in_progress;
1810 if(shutdown_in_progress)return;
1813 get_ui_interface()->task(_("Quit Request"));
1816 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1820 std::list<etl::handle<Instance> >::iterator iter;
1821 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1823 if(!(*iter)->safe_close())
1827 if((*iter)->synfigapp::Instance::get_action_count())
1829 handle<synfigapp::UIInterface> uim;
1830 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1832 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1833 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1835 case synfigapp::UIInterface::RESPONSE_NO:
1837 case synfigapp::UIInterface::RESPONSE_YES:
1840 case synfigapp::UIInterface::RESPONSE_CANCEL:
1849 if((*iter)->synfigapp::Instance::is_modified())
1851 handle<synfigapp::UIInterface> uim;
1852 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1854 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() );
1855 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1857 case synfigapp::UIInterface::RESPONSE_NO:
1859 case synfigapp::UIInterface::RESPONSE_YES:
1860 (*iter)->dialog_cvs_commit();
1862 case synfigapp::UIInterface::RESPONSE_CANCEL:
1871 // This next line causes things to crash for some reason
1875 shutdown_in_progress=true;
1877 instance_list.clear();
1879 while(studio::App::events_pending())studio::App::iteration(false);
1882 auto_recover->normal_shutdown();
1884 get_ui_interface()->task(_("Quit Request sent"));
1890 dialog_setup->refresh();
1891 dialog_setup->show();
1894 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1895 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1898 //#define USE_WIN32_FILE_DIALOGS 1
1901 #ifdef USE_WIN32_FILE_DIALOGS
1902 static OPENFILENAME ofn={};
1906 #include <gdk/gdkwin32.h>
1910 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1912 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1914 #ifdef USE_WIN32_FILE_DIALOGS
1915 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1917 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1918 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1919 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1921 ofn.lStructSize=sizeof(OPENFILENAME);
1922 ofn.hwndOwner = hWnd;
1923 ofn.hInstance = hInstance;
1924 ofn.lpstrFilter = szFilter;
1925 // ofn.lpstrCustomFilter=NULL;
1926 // ofn.nMaxCustFilter=0;
1927 // ofn.nFilterIndex=0;
1928 // ofn.lpstrFile=NULL;
1929 ofn.nMaxFile=MAX_PATH;
1930 // ofn.lpstrFileTitle=NULL;
1931 // ofn.lpstrInitialDir=NULL;
1932 // ofn.lpstrTitle=NULL;
1933 ofn.Flags=OFN_HIDEREADONLY;
1934 // ofn.nFileOffset=0;
1935 // ofn.nFileExtension=0;
1936 ofn.lpstrDefExt=TEXT("sif");
1937 // ofn.lCustData = 0l;
1939 // ofn.lpTemplateName=NULL;
1941 CHAR szFilename[MAX_PATH];
1943 strcpy(szFilename,filename.c_str());
1944 strcpy(szTitle,title.c_str());
1946 ofn.lpstrFile=szFilename;
1947 ofn.lpstrFileTitle=szTitle;
1949 if(GetOpenFileName(&ofn))
1951 filename=szFilename;
1957 synfig::String prev_path;
1959 if(!_preferences.get_value(preference, prev_path))
1962 prev_path = absolute_path(prev_path);
1964 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1966 dialog->set_current_folder(prev_path);
1967 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1968 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1970 if (filename.empty())
1971 dialog->set_filename(prev_path);
1972 else if (is_absolute_path(filename))
1973 dialog->set_filename(filename);
1975 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1977 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1978 filename = dialog->get_filename();
1979 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1980 _preferences.set_value(preference, dirname(filename));
1994 GtkWidget *fileselection;
1995 fileselection = gtk_file_selection_new(title.c_str());
1998 if(basename(filename)==filename)
2000 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
2003 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
2005 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
2007 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
2008 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
2010 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
2011 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
2013 gtk_widget_show(fileselection);
2021 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
2022 _preferences.set_value(preference,dirname(filename));
2026 gtk_widget_destroy(fileselection);
2029 gtk_widget_destroy(fileselection);
2036 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2038 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2040 #if USE_WIN32_FILE_DIALOGS
2041 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2043 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2044 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2045 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2047 ofn.lStructSize=sizeof(OPENFILENAME);
2048 ofn.hwndOwner = hWnd;
2049 ofn.hInstance = hInstance;
2050 ofn.lpstrFilter = szFilter;
2051 // ofn.lpstrCustomFilter=NULL;
2052 // ofn.nMaxCustFilter=0;
2053 // ofn.nFilterIndex=0;
2054 // ofn.lpstrFile=NULL;
2055 ofn.nMaxFile=MAX_PATH;
2056 // ofn.lpstrFileTitle=NULL;
2057 // ofn.lpstrInitialDir=NULL;
2058 // ofn.lpstrTitle=NULL;
2059 ofn.Flags=OFN_OVERWRITEPROMPT;
2060 // ofn.nFileOffset=0;
2061 // ofn.nFileExtension=0;
2062 ofn.lpstrDefExt=TEXT("sif");
2063 // ofn.lCustData = 0l;
2065 // ofn.lpTemplateName=NULL;
2067 CHAR szFilename[MAX_PATH];
2069 strcpy(szFilename,filename.c_str());
2070 strcpy(szTitle,title.c_str());
2072 ofn.lpstrFile=szFilename;
2073 ofn.lpstrFileTitle=szTitle;
2075 if(GetSaveFileName(&ofn))
2077 filename=szFilename;
2078 _preferences.set_value(preference,dirname(filename));
2083 synfig::String prev_path;
2085 if(!_preferences.get_value(preference, prev_path))
2088 prev_path = absolute_path(prev_path);
2090 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2092 dialog->set_current_folder(prev_path);
2093 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2094 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2096 Widget_Enum *file_type_enum = 0;
2097 if (preference == ANIMATION_DIR_PREFERENCE)
2099 file_type_enum = manage(new Widget_Enum());
2100 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2101 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2102 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2103 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2104 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2105 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2107 Gtk::HBox *hbox = manage(new Gtk::HBox);
2108 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2109 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2112 dialog->set_extra_widget(*hbox);
2115 if (filename.empty())
2116 dialog->set_filename(prev_path);
2119 std::string full_path;
2120 if (is_absolute_path(filename))
2121 full_path = filename;
2123 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2125 // select the file if it exists
2126 dialog->set_filename(full_path);
2128 // if the file doesn't exist, put its name into the filename box
2130 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2131 dialog->set_current_name(basename(filename));
2134 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2135 if (preference == ANIMATION_DIR_PREFERENCE)
2136 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2137 filename = dialog->get_filename();
2138 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2139 _preferences.set_value(preference, dirname(filename));
2150 App::dialog_error_blocking(const std::string &title, const std::string &message)
2152 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2153 dialog.set_title(title);
2159 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2161 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2162 dialog.set_title(title);
2168 App::dialog_yes_no(const std::string &title, const std::string &message)
2173 true // use_separator
2175 Gtk::Label label(message);
2178 dialog.get_vbox()->pack_start(label);
2179 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2180 dialog.add_button(Gtk::StockID("gtk-no"),0);
2182 return dialog.run();
2186 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2191 true // use_separator
2193 Gtk::Label label(message);
2196 dialog.get_vbox()->pack_start(label);
2197 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2198 dialog.add_button(Gtk::StockID("gtk-no"),0);
2199 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2201 return dialog.run();
2205 App::dialog_not_implemented()
2207 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2208 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2213 try_open_url(const std::string &url)
2216 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2218 std::vector<std::string> command_line;
2219 std::vector<std::string> browsers;
2220 browsers.reserve(23);
2222 // Browser wrapper scripts
2223 #ifdef USE_OPEN_FOR_URLS
2224 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2226 browsers.push_back("xdg-open"); // XDG wrapper
2227 browsers.push_back("sensible-browser"); // Debian wrapper
2228 browsers.push_back("gnome-open"); // GNOME wrapper
2229 browsers.push_back("kfmclient"); // KDE wrapper
2230 browsers.push_back("exo-open"); // XFCE wrapper
2232 // Alternatives system
2233 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2234 browsers.push_back("x-www-browser"); // Debian GUI alternative
2236 // Individual browsers
2237 browsers.push_back("firefox");
2238 browsers.push_back("epiphany-browser");
2239 browsers.push_back("epiphany");
2240 browsers.push_back("konqueror");
2241 browsers.push_back("iceweasel");
2242 browsers.push_back("mozilla");
2243 browsers.push_back("netscape");
2244 browsers.push_back("icecat");
2245 browsers.push_back("galeon");
2246 browsers.push_back("midori");
2247 browsers.push_back("safari");
2248 browsers.push_back("opera");
2249 browsers.push_back("amaya");
2250 browsers.push_back("netsurf");
2251 browsers.push_back("dillo");
2253 // Try the user-specified browser first
2254 command_line.push_back(App::browser_command);
2255 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2256 command_line.push_back(url);
2258 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2259 catch( Glib::SpawnError& exception ){
2261 while ( !browsers.empty() )
2263 // Skip the browser if we already tried it
2264 if( browsers[0] == App::browser_command )
2267 // Construct the command line
2268 command_line.clear();
2269 command_line.push_back(browsers[0]);
2270 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2271 command_line.push_back(url);
2273 // Remove the browser from the list
2274 browsers.erase(browsers.begin());
2276 // Try to spawn the browser
2277 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2278 // Failed, move on to the next one
2279 catch(Glib::SpawnError& exception){ continue; }
2280 return true; // No exception means we succeeded!
2291 if (!try_open_url("http://synfig.org/Documentation"))
2293 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2294 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2295 dialog.set_title(_("Help"));
2301 App::open_url(const std::string &url)
2303 if(!try_open_url(url))
2305 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2306 dialog.set_secondary_text(url);
2307 dialog.set_title(_("No browser found"));
2313 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2318 true); // use_separator
2320 Gtk::Label label(message);
2322 dialog.get_vbox()->pack_start(label);
2325 entry.set_text(text);
2327 entry.set_activates_default(true);
2329 dialog.get_vbox()->pack_start(entry);
2331 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2332 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2333 dialog.set_default_response(Gtk::RESPONSE_OK);
2335 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2338 if(dialog.run()!=Gtk::RESPONSE_OK)
2341 text=entry.get_text();
2347 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2352 true); // use_separator
2354 Gtk::Label label(message);
2356 dialog.get_vbox()->pack_start(label);
2358 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2359 text_buffer->set_text(text);
2360 Gtk::TextView text_view(text_buffer);
2363 dialog.get_vbox()->pack_start(text_view);
2365 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2366 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2367 dialog.set_default_response(Gtk::RESPONSE_OK);
2369 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2372 if(dialog.run()!=Gtk::RESPONSE_OK)
2375 text=text_buffer->get_text();
2381 App::open(std::string filename)
2383 return open_as(filename,filename);
2386 // this is called from autorecover.cpp:
2387 // App::open_as(get_shadow_file_name(filename),filename)
2388 // other than that, 'filename' and 'as' are the same
2390 App::open_as(std::string filename,std::string as)
2393 char long_name[1024];
2394 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2395 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2396 // don't use it if that's the case
2397 if (long_name[0] != '\0')
2403 OneMoment one_moment;
2404 String errors, warnings;
2406 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2407 if(canvas && get_instance(canvas))
2409 get_instance(canvas)->find_canvas_view(canvas)->present();
2410 info("%s is already open", filename.c_str());
2411 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2416 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2419 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2421 if (as.find(custom_filename_prefix.c_str()) != 0)
2422 add_recent_file(as);
2424 handle<Instance> instance(Instance::create(canvas));
2427 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2429 set_recent_file_window_size(instance);
2433 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)")))
2434 instance->dialog_cvs_update();
2439 dialog_error_blocking(_("Error"), x);
2442 catch(runtime_error x)
2444 dialog_error_blocking(_("Error"), x.what());
2449 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2460 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2462 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2463 canvas->set_name(file_name);
2464 file_name += ".sifz";
2466 canvas->rend_desc().set_frame_rate(preferred_fps);
2467 canvas->rend_desc().set_time_start(0.0);
2468 canvas->rend_desc().set_time_end(5.0);
2469 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2470 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2471 // The top left and botton right positions are expressed in units
2472 // Original convention is that 1 unit = 60 pixels
2473 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2474 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2475 canvas->rend_desc().set_w(preferred_x_size);
2476 canvas->rend_desc().set_h(preferred_y_size);
2477 canvas->rend_desc().set_antialias(1);
2478 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2479 canvas->set_file_name(file_name);
2481 handle<Instance> instance = Instance::create(canvas);
2483 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2484 instance->find_canvas_view(canvas)->canvas_properties.present();
2488 App::dialog_open(string filename)
2490 if (filename.empty())
2493 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2495 // If the filename still has wildcards, then we should
2496 // continue looking for the file we want
2497 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2503 get_ui_interface()->error(_("Unable to open file"));
2508 App::set_selected_instance(etl::loose_handle<Instance> instance)
2510 /* if(get_selected_instance()==instance)
2512 selected_instance=instance;
2513 signal_instance_selected()(instance);
2519 selected_instance=instance;
2520 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2524 instance->focus(instance->get_canvas());
2527 set_selected_canvas_view(0);
2529 signal_instance_selected()(instance);
2533 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2535 selected_canvas_view=canvas_view;
2536 signal_canvas_view_focus()(selected_canvas_view);
2539 selected_instance=canvas_view->get_instance();
2540 signal_instance_selected()(canvas_view->get_instance());
2543 if(get_selected_canvas_view()==canvas_view)
2545 signal_canvas_view_focus()(selected_canvas_view);
2546 signal_instance_selected()(canvas_view->get_instance());
2549 selected_canvas_view=canvas_view;
2550 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2551 set_selected_instance(canvas_view->get_instance());
2552 signal_canvas_view_focus()(selected_canvas_view);
2556 etl::loose_handle<Instance>
2557 App::get_instance(etl::handle<synfig::Canvas> canvas)
2559 if(!canvas) return 0;
2560 canvas=canvas->get_root();
2562 std::list<etl::handle<Instance> >::iterator iter;
2563 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2565 if((*iter)->get_canvas()==canvas)
2581 if(selected_instance)
2582 selected_instance->undo();
2588 if(selected_instance)
2589 selected_instance->redo();
2593 studio::App::get_base_path()
2595 return app_base_path_;