1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2008 Gerald Young
11 ** Copyright (c) 2008 Carlos López
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
24 /* ========================================================================= */
26 /* === H E A D E R S ======================================================= */
45 #ifdef HAVE_SYS_ERRNO_H
46 #include <sys/errno.h>
48 #include <gtkmm/fileselection.h>
49 #include <gtkmm/dialog.h>
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/label.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/stockitem.h>
54 #include <gtkmm/iconsource.h>
55 #include <gtkmm/inputdialog.h>
56 #include <gtkmm/accelmap.h>
57 #include <gtkmm/uimanager.h>
58 #include <gtkmm/textview.h>
62 #include <gdkmm/general.h>
64 #include <synfig/loadcanvas.h>
65 #include <synfig/savecanvas.h>
71 #include "canvasview.h"
72 #include "dialog_setup.h"
73 #include "dialog_gradient.h"
74 #include "dialog_color.h"
77 #include "onemoment.h"
79 #include "dockmanager.h"
81 #include "state_eyedrop.h"
82 #include "state_normal.h"
83 #include "state_draw.h"
84 #include "state_fill.h"
85 #include "state_bline.h"
86 #include "state_polygon.h"
87 #include "state_sketch.h"
88 #include "state_gradient.h"
89 #include "state_circle.h"
90 #include "state_rectangle.h"
91 #include "state_smoothmove.h"
92 #include "state_star.h"
93 #include "state_text.h"
94 #include "state_width.h"
95 #include "state_transform.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_transform);
1297 state_manager->add_state(&state_smooth_move);
1298 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1299 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1302 state_manager->add_state(&state_bline);
1303 state_manager->add_state(&state_circle);
1304 state_manager->add_state(&state_rectangle);
1305 state_manager->add_state(&state_star);
1306 state_manager->add_state(&state_gradient);
1307 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1308 state_manager->add_state(&state_text);
1309 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1313 state_manager->add_state(&state_fill);
1314 state_manager->add_state(&state_eyedrop);
1315 state_manager->add_state(&state_zoom);
1316 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1318 studio_init_cb.task(_("Init ModPalette..."));
1319 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1321 studio_init_cb.task(_("Init Setup Dialog..."));
1322 dialog_setup=new studio::Dialog_Setup();
1324 studio_init_cb.task(_("Init Input Dialog..."));
1325 dialog_input=new Gtk::InputDialog();
1326 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1327 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1329 studio_init_cb.task(_("Init auto recovery..."));
1330 auto_recover=new AutoRecover();
1332 studio_init_cb.amount_complete(9250,10000);
1333 studio_init_cb.task(_("Loading Settings..."));
1335 device_tracker->load_preferences();
1337 studio_init_cb.task(_("Checking auto-recover..."));
1339 studio_init_cb.amount_complete(9900,10000);
1341 bool opened_any = false;
1342 if(auto_recover->recovery_needed())
1344 splash_screen.hide();
1345 if (get_ui_interface()->confirmation("Crash Recovery",
1346 _("Auto recovery file found"),
1347 _("Synfig Studio seems to have crashed\n"
1348 "before you could save all your files.\n"
1349 "Recover unsaved changes?"),
1350 _("Recover"), _("Ignore"))
1351 == synfigapp::UIInterface::RESPONSE_OK)
1353 int number_recovered;
1354 if(!auto_recover->recover(number_recovered))
1355 if (number_recovered)
1356 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1358 get_ui_interface()->error(_("Unable to recover from previous crash"));
1360 get_ui_interface()->error(
1361 _("Synfig Studio has attempted to recover\n"
1362 "from a previous crash. The files that it has\n"
1363 "recovered are NOT YET SAVED. It would be a good\n"
1364 "idea to review them and save them now."));
1366 if (number_recovered)
1369 splash_screen.show();
1372 // Look for any files given on the command line,
1373 // and load them if found.
1374 for(;*argc>=1;(*argc)--)
1375 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1377 studio_init_cb.task(_("Loading files..."));
1378 splash_screen.hide();
1379 open((*argv)[*argc]);
1381 splash_screen.show();
1384 // if no file was specified to be opened, create a new document to help new users get started more easily
1385 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1388 studio_init_cb.task(_("Done."));
1389 studio_init_cb.amount_complete(10000,10000);
1395 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1399 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1403 StateManager* App::get_state_manager() { return state_manager; }
1407 shutdown_in_progress=true;
1411 synfigapp::Main::settings().remove_domain("pref");
1413 selected_instance=0;
1415 // Unload all of the modules
1416 for(;!module_list_.empty();module_list_.pop_back())
1419 delete state_manager;
1423 delete auto_recover;
1429 // studio::App::iteration(false);
1433 // studio::App::iteration(false);
1435 // studio::App::iteration(false);
1437 delete dialog_setup;
1439 delete dialog_gradient;
1441 delete dialog_color;
1443 delete dialog_input;
1445 delete dock_manager;
1447 instance_list.clear();
1449 // studio::App::iteration(false);
1453 App::get_user_app_directory()
1455 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1457 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1459 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1464 App::get_config_file(const synfig::String& file)
1466 return Glib::build_filename(get_user_app_directory(),file);
1469 #define SCALE_FACTOR (1280)
1470 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1472 App::set_recent_file_window_size(etl::handle<Instance> instance)
1474 int screen_w(Gdk::screen_width());
1475 int screen_h(Gdk::screen_height());
1477 const std::string &canvas_window_size = *recent_files_window_size.begin();
1479 if(canvas_window_size.empty())
1482 synfig::String::size_type current=0;
1483 bool seen_root(false), shown_non_root(false);
1485 while(current != synfig::String::npos)
1487 // find end of first field (canvas) or return
1488 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1489 if(separator == synfig::String::npos) break;
1492 synfig::Canvas::Handle canvas;
1495 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1497 catch(Exception::IDNotFound) {
1498 // can't find the canvas; skip to the next canvas or return
1499 separator = canvas_window_size.find_first_of('\t', current);
1500 if(separator == synfig::String::npos) return;
1501 current = separator+1;
1505 if (canvas->is_root())
1508 shown_non_root = true;
1510 // check that we have the tab character the ends this canvas' data or return
1511 current = separator+1;
1512 separator = canvas_window_size.find_first_of('\t', current);
1513 if(separator == synfig::String::npos) return;
1516 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1518 current = separator+1;
1522 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1523 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1524 x=x*screen_w/SCALE_FACTOR;
1525 y=y*screen_h/SCALE_FACTOR;
1526 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1527 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1528 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1529 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1531 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1532 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1534 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1535 canvasview->move(x,y);
1536 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1537 canvasview->present();
1539 current = separator+1;
1542 if (shown_non_root && !seen_root)
1543 instance->find_canvas_view(instance->get_canvas())->hide();
1547 App::add_recent_file(const etl::handle<Instance> instance)
1549 int screen_w(Gdk::screen_width());
1550 int screen_h(Gdk::screen_height());
1552 std::string canvas_window_size;
1554 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1555 Instance::CanvasViewList::const_iterator iter;
1557 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1559 if( !((*iter)->is_visible()) )
1562 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1563 int x_pos, y_pos, x_size, y_size;
1564 (*iter)->get_position(x_pos,y_pos);
1565 (*iter)->get_size(x_size,y_size);
1567 canvas_window_size += strprintf("%s %d %d %d %d\t",
1568 canvas->get_relative_id(canvas->get_root()).c_str(),
1569 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1570 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1573 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1578 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1580 std::string filename(file_name);
1582 assert(!filename.empty());
1584 if(filename.empty())
1587 // Toss out any "hidden" files
1588 if(basename(filename)[0]=='.')
1591 // If we aren't an absolute path, turn ourselves into one
1592 if(!is_absolute_path(filename))
1593 filename=absolute_path(filename);
1595 std::string old_window_size;
1597 list<string>::iterator iter;
1598 list<string>::iterator iter_wsize;
1599 // Check to see if the file is already on the list.
1600 // If it is, then remove it from the list
1601 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1604 recent_files.erase(iter);
1605 old_window_size = *iter_wsize;
1606 recent_files_window_size.erase(iter_wsize);
1611 // Push the filename to the front of the list
1612 recent_files.push_front(filename);
1613 if(window_size.empty())
1614 recent_files_window_size.push_front(old_window_size);
1616 recent_files_window_size.push_front(window_size);
1618 // Clean out the files at the end of the list.
1619 while(recent_files.size()>(unsigned)get_max_recent_files())
1621 recent_files.pop_back();
1622 recent_files_window_size.pop_back();
1625 signal_recent_files_changed_();
1630 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1633 App::get_time_format()
1635 return _App_time_format;
1639 App::set_time_format(synfig::Time::Format x)
1646 App::save_settings()
1651 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1652 setlocale(LC_NUMERIC, "C");
1654 std::string filename=get_config_file("accelrc");
1655 Gtk::AccelMap::save(filename);
1658 std::string filename=get_config_file("recentfiles");
1660 std::ofstream file(filename.c_str());
1664 synfig::warning("Unable to save %s",filename.c_str());
1668 list<string>::reverse_iterator iter;
1670 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1674 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1676 std::ofstream file(filename.c_str());
1680 synfig::warning("Unable to save %s",filename.c_str());
1684 list<string>::reverse_iterator iter;
1686 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1690 std::string filename=get_config_file("settings");
1691 synfigapp::Main::settings().save_to_file(filename);
1692 setlocale(LC_NUMERIC,old_locale);
1696 synfig::warning("Caught exception when attempting to save settings.");
1701 App::load_settings()
1706 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1707 setlocale(LC_NUMERIC, "C");
1709 std::string filename=get_config_file("accelrc");
1710 Gtk::AccelMap::load(filename);
1713 bool window_size_broken = false;
1715 std::string filename=get_config_file("recentfiles");
1716 std::string filename_window_size=filename+std::string("_window_size");
1718 std::ifstream file(filename.c_str());
1719 std::ifstream file_window_size(filename_window_size.c_str());
1721 if(!file_window_size)
1722 window_size_broken = true;
1726 std::string recent_file;
1727 std::string recent_file_window_size;
1728 getline(file,recent_file);
1729 if(!window_size_broken)
1730 getline(file_window_size,recent_file_window_size);
1731 if(!recent_file.empty())
1733 if(!window_size_broken && !file_window_size)
1734 window_size_broken = true;
1735 if (std::ifstream(recent_file.c_str()))
1737 if(!window_size_broken)
1738 add_recent_file(recent_file,recent_file_window_size);
1740 add_recent_file(recent_file);
1744 if(!window_size_broken && file_window_size)
1745 window_size_broken = true;
1747 if(window_size_broken)
1749 recent_files_window_size.clear();
1750 recent_files_window_size.resize(recent_files.size());
1753 std::string filename=get_config_file("settings");
1754 if(!synfigapp::Main::settings().load_from_file(filename))
1756 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1757 //if(!synfigapp::Main::settings().load_from_file(filename))
1759 gamma.set_gamma(1.0/2.2);
1760 reset_initial_window_configuration();
1763 setlocale(LC_NUMERIC,old_locale);
1767 synfig::warning("Caught exception when attempting to load settings.");
1772 App::reset_initial_window_configuration()
1774 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1775 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1776 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1777 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1778 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1779 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1780 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1781 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1782 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1783 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1784 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1785 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1786 #ifdef SINGLE_THREADED
1787 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1789 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1790 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1791 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1792 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1793 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1794 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1795 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1796 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1797 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1801 App::shutdown_request(GdkEventAny*)
1805 //return !shutdown_in_progress;
1811 if(shutdown_in_progress)return;
1814 get_ui_interface()->task(_("Quit Request"));
1817 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1821 std::list<etl::handle<Instance> >::iterator iter;
1822 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1824 if(!(*iter)->safe_close())
1828 if((*iter)->synfigapp::Instance::get_action_count())
1830 handle<synfigapp::UIInterface> uim;
1831 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1833 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1834 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1836 case synfigapp::UIInterface::RESPONSE_NO:
1838 case synfigapp::UIInterface::RESPONSE_YES:
1841 case synfigapp::UIInterface::RESPONSE_CANCEL:
1850 if((*iter)->synfigapp::Instance::is_modified())
1852 handle<synfigapp::UIInterface> uim;
1853 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1855 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() );
1856 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1858 case synfigapp::UIInterface::RESPONSE_NO:
1860 case synfigapp::UIInterface::RESPONSE_YES:
1861 (*iter)->dialog_cvs_commit();
1863 case synfigapp::UIInterface::RESPONSE_CANCEL:
1872 // This next line causes things to crash for some reason
1876 shutdown_in_progress=true;
1878 instance_list.clear();
1880 while(studio::App::events_pending())studio::App::iteration(false);
1883 auto_recover->normal_shutdown();
1885 get_ui_interface()->task(_("Quit Request sent"));
1891 dialog_setup->refresh();
1892 dialog_setup->show();
1895 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1896 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1899 //#define USE_WIN32_FILE_DIALOGS 1
1902 #ifdef USE_WIN32_FILE_DIALOGS
1903 static OPENFILENAME ofn={};
1907 #include <gdk/gdkwin32.h>
1911 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1913 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1915 #ifdef USE_WIN32_FILE_DIALOGS
1916 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1918 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1919 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1920 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1922 ofn.lStructSize=sizeof(OPENFILENAME);
1923 ofn.hwndOwner = hWnd;
1924 ofn.hInstance = hInstance;
1925 ofn.lpstrFilter = szFilter;
1926 // ofn.lpstrCustomFilter=NULL;
1927 // ofn.nMaxCustFilter=0;
1928 // ofn.nFilterIndex=0;
1929 // ofn.lpstrFile=NULL;
1930 ofn.nMaxFile=MAX_PATH;
1931 // ofn.lpstrFileTitle=NULL;
1932 // ofn.lpstrInitialDir=NULL;
1933 // ofn.lpstrTitle=NULL;
1934 ofn.Flags=OFN_HIDEREADONLY;
1935 // ofn.nFileOffset=0;
1936 // ofn.nFileExtension=0;
1937 ofn.lpstrDefExt=TEXT("sif");
1938 // ofn.lCustData = 0l;
1940 // ofn.lpTemplateName=NULL;
1942 CHAR szFilename[MAX_PATH];
1944 strcpy(szFilename,filename.c_str());
1945 strcpy(szTitle,title.c_str());
1947 ofn.lpstrFile=szFilename;
1948 ofn.lpstrFileTitle=szTitle;
1950 if(GetOpenFileName(&ofn))
1952 filename=szFilename;
1958 synfig::String prev_path;
1960 if(!_preferences.get_value(preference, prev_path))
1963 prev_path = absolute_path(prev_path);
1965 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1967 dialog->set_current_folder(prev_path);
1968 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1969 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1971 if (filename.empty())
1972 dialog->set_filename(prev_path);
1973 else if (is_absolute_path(filename))
1974 dialog->set_filename(filename);
1976 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1978 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1979 filename = dialog->get_filename();
1980 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1981 _preferences.set_value(preference, dirname(filename));
1995 GtkWidget *fileselection;
1996 fileselection = gtk_file_selection_new(title.c_str());
1999 if(basename(filename)==filename)
2001 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
2004 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
2006 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
2008 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
2009 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
2011 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
2012 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
2014 gtk_widget_show(fileselection);
2022 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
2023 _preferences.set_value(preference,dirname(filename));
2027 gtk_widget_destroy(fileselection);
2030 gtk_widget_destroy(fileselection);
2037 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2039 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2041 #if USE_WIN32_FILE_DIALOGS
2042 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2044 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2045 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2046 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2048 ofn.lStructSize=sizeof(OPENFILENAME);
2049 ofn.hwndOwner = hWnd;
2050 ofn.hInstance = hInstance;
2051 ofn.lpstrFilter = szFilter;
2052 // ofn.lpstrCustomFilter=NULL;
2053 // ofn.nMaxCustFilter=0;
2054 // ofn.nFilterIndex=0;
2055 // ofn.lpstrFile=NULL;
2056 ofn.nMaxFile=MAX_PATH;
2057 // ofn.lpstrFileTitle=NULL;
2058 // ofn.lpstrInitialDir=NULL;
2059 // ofn.lpstrTitle=NULL;
2060 ofn.Flags=OFN_OVERWRITEPROMPT;
2061 // ofn.nFileOffset=0;
2062 // ofn.nFileExtension=0;
2063 ofn.lpstrDefExt=TEXT("sif");
2064 // ofn.lCustData = 0l;
2066 // ofn.lpTemplateName=NULL;
2068 CHAR szFilename[MAX_PATH];
2070 strcpy(szFilename,filename.c_str());
2071 strcpy(szTitle,title.c_str());
2073 ofn.lpstrFile=szFilename;
2074 ofn.lpstrFileTitle=szTitle;
2076 if(GetSaveFileName(&ofn))
2078 filename=szFilename;
2079 _preferences.set_value(preference,dirname(filename));
2084 synfig::String prev_path;
2086 if(!_preferences.get_value(preference, prev_path))
2089 prev_path = absolute_path(prev_path);
2091 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2093 dialog->set_current_folder(prev_path);
2094 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2095 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2097 Widget_Enum *file_type_enum = 0;
2098 if (preference == ANIMATION_DIR_PREFERENCE)
2100 file_type_enum = manage(new Widget_Enum());
2101 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2102 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2103 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2104 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2105 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2106 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2108 Gtk::HBox *hbox = manage(new Gtk::HBox);
2109 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2110 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2113 dialog->set_extra_widget(*hbox);
2116 if (filename.empty())
2117 dialog->set_filename(prev_path);
2120 std::string full_path;
2121 if (is_absolute_path(filename))
2122 full_path = filename;
2124 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2126 // select the file if it exists
2127 dialog->set_filename(full_path);
2129 // if the file doesn't exist, put its name into the filename box
2131 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2132 dialog->set_current_name(basename(filename));
2135 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2136 if (preference == ANIMATION_DIR_PREFERENCE)
2137 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2138 filename = dialog->get_filename();
2139 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2140 _preferences.set_value(preference, dirname(filename));
2151 App::dialog_error_blocking(const std::string &title, const std::string &message)
2153 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2154 dialog.set_title(title);
2160 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2162 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2163 dialog.set_title(title);
2169 App::dialog_yes_no(const std::string &title, const std::string &message)
2174 true // use_separator
2176 Gtk::Label label(message);
2179 dialog.get_vbox()->pack_start(label);
2180 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2181 dialog.add_button(Gtk::StockID("gtk-no"),0);
2183 return dialog.run();
2187 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2192 true // use_separator
2194 Gtk::Label label(message);
2197 dialog.get_vbox()->pack_start(label);
2198 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2199 dialog.add_button(Gtk::StockID("gtk-no"),0);
2200 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2202 return dialog.run();
2206 App::dialog_not_implemented()
2208 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2209 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2214 try_open_url(const std::string &url)
2217 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2219 std::vector<std::string> command_line;
2220 std::vector<std::string> browsers;
2221 browsers.reserve(23);
2223 // Browser wrapper scripts
2224 #ifdef USE_OPEN_FOR_URLS
2225 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2227 browsers.push_back("xdg-open"); // XDG wrapper
2228 browsers.push_back("sensible-browser"); // Debian wrapper
2229 browsers.push_back("gnome-open"); // GNOME wrapper
2230 browsers.push_back("kfmclient"); // KDE wrapper
2231 browsers.push_back("exo-open"); // XFCE wrapper
2233 // Alternatives system
2234 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2235 browsers.push_back("x-www-browser"); // Debian GUI alternative
2237 // Individual browsers
2238 browsers.push_back("firefox");
2239 browsers.push_back("epiphany-browser");
2240 browsers.push_back("epiphany");
2241 browsers.push_back("konqueror");
2242 browsers.push_back("iceweasel");
2243 browsers.push_back("mozilla");
2244 browsers.push_back("netscape");
2245 browsers.push_back("icecat");
2246 browsers.push_back("galeon");
2247 browsers.push_back("midori");
2248 browsers.push_back("safari");
2249 browsers.push_back("opera");
2250 browsers.push_back("amaya");
2251 browsers.push_back("netsurf");
2252 browsers.push_back("dillo");
2254 // Try the user-specified browser first
2255 command_line.push_back(App::browser_command);
2256 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2257 command_line.push_back(url);
2259 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2260 catch( Glib::SpawnError& exception ){
2262 while ( !browsers.empty() )
2264 // Skip the browser if we already tried it
2265 if( browsers[0] == App::browser_command )
2268 // Construct the command line
2269 command_line.clear();
2270 command_line.push_back(browsers[0]);
2271 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2272 command_line.push_back(url);
2274 // Remove the browser from the list
2275 browsers.erase(browsers.begin());
2277 // Try to spawn the browser
2278 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2279 // Failed, move on to the next one
2280 catch(Glib::SpawnError& exception){ continue; }
2281 return true; // No exception means we succeeded!
2292 if (!try_open_url("http://synfig.org/Documentation"))
2294 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2295 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2296 dialog.set_title(_("Help"));
2302 App::open_url(const std::string &url)
2304 if(!try_open_url(url))
2306 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2307 dialog.set_secondary_text(url);
2308 dialog.set_title(_("No browser found"));
2314 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2319 true); // use_separator
2321 Gtk::Label label(message);
2323 dialog.get_vbox()->pack_start(label);
2326 entry.set_text(text);
2328 entry.set_activates_default(true);
2330 dialog.get_vbox()->pack_start(entry);
2332 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2333 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2334 dialog.set_default_response(Gtk::RESPONSE_OK);
2336 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2339 if(dialog.run()!=Gtk::RESPONSE_OK)
2342 text=entry.get_text();
2348 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2353 true); // use_separator
2355 Gtk::Label label(message);
2357 dialog.get_vbox()->pack_start(label);
2359 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2360 text_buffer->set_text(text);
2361 Gtk::TextView text_view(text_buffer);
2364 dialog.get_vbox()->pack_start(text_view);
2366 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2367 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2368 dialog.set_default_response(Gtk::RESPONSE_OK);
2370 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2373 if(dialog.run()!=Gtk::RESPONSE_OK)
2376 text=text_buffer->get_text();
2382 App::open(std::string filename)
2384 return open_as(filename,filename);
2387 // this is called from autorecover.cpp:
2388 // App::open_as(get_shadow_file_name(filename),filename)
2389 // other than that, 'filename' and 'as' are the same
2391 App::open_as(std::string filename,std::string as)
2394 char long_name[1024];
2395 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2396 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2397 // don't use it if that's the case
2398 if (long_name[0] != '\0')
2404 OneMoment one_moment;
2405 String errors, warnings;
2407 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2408 if(canvas && get_instance(canvas))
2410 get_instance(canvas)->find_canvas_view(canvas)->present();
2411 info("%s is already open", filename.c_str());
2412 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2417 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2420 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2422 if (as.find(custom_filename_prefix.c_str()) != 0)
2423 add_recent_file(as);
2425 handle<Instance> instance(Instance::create(canvas));
2428 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2430 set_recent_file_window_size(instance);
2434 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)")))
2435 instance->dialog_cvs_update();
2440 dialog_error_blocking(_("Error"), x);
2443 catch(runtime_error x)
2445 dialog_error_blocking(_("Error"), x.what());
2450 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2461 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2463 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2464 canvas->set_name(file_name);
2465 file_name += ".sifz";
2467 canvas->rend_desc().set_frame_rate(preferred_fps);
2468 canvas->rend_desc().set_time_start(0.0);
2469 canvas->rend_desc().set_time_end(5.0);
2470 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2471 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2472 // The top left and botton right positions are expressed in units
2473 // Original convention is that 1 unit = 60 pixels
2474 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2475 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2476 canvas->rend_desc().set_w(preferred_x_size);
2477 canvas->rend_desc().set_h(preferred_y_size);
2478 canvas->rend_desc().set_antialias(1);
2479 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2480 canvas->set_file_name(file_name);
2482 handle<Instance> instance = Instance::create(canvas);
2484 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2485 instance->find_canvas_view(canvas)->canvas_properties.present();
2489 App::dialog_open(string filename)
2491 if (filename.empty())
2494 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2496 // If the filename still has wildcards, then we should
2497 // continue looking for the file we want
2498 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2504 get_ui_interface()->error(_("Unable to open file"));
2509 App::set_selected_instance(etl::loose_handle<Instance> instance)
2511 /* if(get_selected_instance()==instance)
2513 selected_instance=instance;
2514 signal_instance_selected()(instance);
2520 selected_instance=instance;
2521 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2525 instance->focus(instance->get_canvas());
2528 set_selected_canvas_view(0);
2530 signal_instance_selected()(instance);
2534 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2536 selected_canvas_view=canvas_view;
2537 signal_canvas_view_focus()(selected_canvas_view);
2540 selected_instance=canvas_view->get_instance();
2541 signal_instance_selected()(canvas_view->get_instance());
2544 if(get_selected_canvas_view()==canvas_view)
2546 signal_canvas_view_focus()(selected_canvas_view);
2547 signal_instance_selected()(canvas_view->get_instance());
2550 selected_canvas_view=canvas_view;
2551 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2552 set_selected_instance(canvas_view->get_instance());
2553 signal_canvas_view_focus()(selected_canvas_view);
2557 etl::loose_handle<Instance>
2558 App::get_instance(etl::handle<synfig::Canvas> canvas)
2560 if(!canvas) return 0;
2561 canvas=canvas->get_root();
2563 std::list<etl::handle<Instance> >::iterator iter;
2564 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2566 if((*iter)->get_canvas()==canvas)
2582 if(selected_instance)
2583 selected_instance->undo();
2589 if(selected_instance)
2590 selected_instance->redo();
2594 studio::App::get_base_path()
2596 return app_base_path_;