1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2008 Gerald Young
11 ** Copyright (c) 2008 Carlos López
12 ** Copyright (c) 2009 Nikita Kitaev
14 ** This package is free software; you can redistribute it and/or
15 ** modify it under the terms of the GNU General Public License as
16 ** published by the Free Software Foundation; either version 2 of
17 ** the License, or (at your option) any later version.
19 ** This package is distributed in the hope that it will be useful,
20 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 ** General Public License for more details.
25 /* ========================================================================= */
27 /* === H E A D E R S ======================================================= */
46 #ifdef HAVE_SYS_ERRNO_H
47 #include <sys/errno.h>
49 #include <gtkmm/fileselection.h>
50 #include <gtkmm/dialog.h>
51 #include <gtkmm/messagedialog.h>
52 #include <gtkmm/label.h>
53 #include <gtkmm/stock.h>
54 #include <gtkmm/stockitem.h>
55 #include <gtkmm/iconsource.h>
56 #include <gtkmm/inputdialog.h>
57 #include <gtkmm/accelmap.h>
58 #include <gtkmm/uimanager.h>
59 #include <gtkmm/textview.h>
63 #include <gdkmm/general.h>
65 #include <synfig/loadcanvas.h>
66 #include <synfig/savecanvas.h>
72 #include "canvasview.h"
73 #include "dialog_setup.h"
74 #include "dialog_gradient.h"
75 #include "dialog_color.h"
77 #include "onemoment.h"
79 #include "dockmanager.h"
81 #include "state_eyedrop.h"
82 #include "state_normal.h"
83 #include "state_draw.h"
84 #include "state_fill.h"
85 #include "state_bline.h"
86 #include "state_polygon.h"
87 #include "state_sketch.h"
88 #include "state_gradient.h"
89 #include "state_circle.h"
90 #include "state_rectangle.h"
91 #include "state_smoothmove.h"
92 #include "state_scale.h"
93 #include "state_star.h"
94 #include "state_text.h"
95 #include "state_width.h"
96 #include "state_rotate.h"
97 #include "state_zoom.h"
99 #include "devicetracker.h"
100 #include "dialog_tooloptions.h"
101 #include "widget_enum.h"
103 #include "autorecover.h"
105 #include <synfigapp/settings.h>
106 #include "dock_history.h"
107 #include "dock_canvases.h"
108 #include "dock_keyframes.h"
109 #include "dock_layers.h"
110 #include "dock_params.h"
111 #include "dock_metadata.h"
112 #include "dock_children.h"
113 #include "dock_info.h"
114 #include "dock_navigator.h"
115 #include "dock_layergroups.h"
116 #include "dock_timetrack.h"
117 #include "dock_curves.h"
119 #include "mod_palette/mod_palette.h"
120 #include "mod_mirror/mod_mirror.h"
122 #include <sys/stat.h>
128 #include "statemanager.h"
134 #include <gtkmm/accelmap.h>
135 #include <gtkmm/filechooser.h>
136 #include <gtkmm/filechooserdialog.h>
142 /* === U S I N G =========================================================== */
146 using namespace synfig;
147 using namespace studio;
149 /* === M A C R O S ========================================================= */
151 #ifndef SYNFIG_USER_APP_DIR
153 #define SYNFIG_USER_APP_DIR "Library/Synfig"
154 #elif defined(_WIN32)
155 #define SYNFIG_USER_APP_DIR "Synfig"
157 #define SYNFIG_USER_APP_DIR ".synfig"
162 #define DPM2DPI(x) (float(x)/39.3700787402f)
163 #define DPI2DPM(x) (float(x)*39.3700787402f)
169 # define IMAGE_DIR "share\\pixmaps"
174 # define IMAGE_DIR "/usr/local/share/pixmaps"
178 # define IMAGE_EXT "tif"
181 #include <synfigapp/main.h>
183 /* === S I G N A L S ======================================================= */
185 static sigc::signal<void> signal_present_all_;
187 App::signal_present_all() { return signal_present_all_; }
189 static sigc::signal<void> signal_recent_files_changed_;
191 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
193 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
194 sigc::signal<void,etl::loose_handle<CanvasView> >&
195 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_selected() { return signal_instance_selected_; }
201 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
202 sigc::signal<void,etl::handle<Instance> >&
203 App::signal_instance_created() { return signal_instance_created_; }
205 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
206 sigc::signal<void,etl::handle<Instance> >&
207 App::signal_instance_deleted() { return signal_instance_deleted_; }
209 /* === G L O B A L S ======================================================= */
211 static std::list<std::string> recent_files;
212 const std::list<std::string>& App::get_recent_files() { return recent_files; }
214 static std::list<std::string> recent_files_window_size;
216 int App::Busy::count;
217 bool App::shutdown_in_progress;
219 synfig::Gamma App::gamma;
221 Glib::RefPtr<studio::UIManager> App::ui_manager_;
223 synfig::Distance::System App::distance_system;
225 studio::Dialog_Setup* App::dialog_setup;
227 etl::handle< studio::ModPalette > mod_palette_;
228 //studio::Dialog_Palette* App::dialog_palette;
230 std::list<etl::handle<Instance> > App::instance_list;
232 static etl::handle<synfigapp::UIInterface> ui_interface_;
233 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
235 etl::handle<Instance> App::selected_instance;
236 etl::handle<CanvasView> App::selected_canvas_view;
238 studio::About *studio::App::about=NULL;
240 studio::Toolbox *studio::App::toolbox=NULL;
242 studio::AutoRecover *studio::App::auto_recover=NULL;
244 studio::IPC *ipc=NULL;
246 studio::DockManager* studio::App::dock_manager=0;
248 studio::DeviceTracker* studio::App::device_tracker=0;
250 studio::Dialog_Gradient* studio::App::dialog_gradient;
252 studio::Dialog_Color* studio::App::dialog_color;
254 Gtk::InputDialog* studio::App::dialog_input;
256 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
258 studio::Dock_History* dock_history;
259 studio::Dock_Canvases* dock_canvases;
260 studio::Dock_Keyframes* dock_keyframes;
261 studio::Dock_Layers* dock_layers;
262 studio::Dock_Params* dock_params;
263 studio::Dock_MetaData* dock_meta_data;
264 studio::Dock_Children* dock_children;
265 studio::Dock_Info* dock_info;
266 studio::Dock_LayerGroups* dock_layer_groups;
267 studio::Dock_Navigator* dock_navigator;
268 studio::Dock_Timetrack* dock_timetrack;
269 studio::Dock_Curves* dock_curves;
271 std::list< etl::handle< studio::Module > > module_list_;
273 bool studio::App::use_colorspace_gamma=true;
274 #ifdef SINGLE_THREADED
275 bool studio::App::single_threaded=false;
277 bool studio::App::restrict_radius_ducks=false;
278 bool studio::App::resize_imported_images=false;
279 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
280 int studio::App::preferred_x_size=480;
281 int studio::App::preferred_y_size=270;
282 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
283 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
284 float studio::App::preferred_fps=24.0;
285 #ifdef USE_OPEN_FOR_URLS
286 String studio::App::browser_command("open"); // MacOS only
288 String studio::App::browser_command("xdg-open"); // Linux XDG standard
291 static int max_recent_files_=25;
292 int studio::App::get_max_recent_files() { return max_recent_files_; }
293 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
295 static synfig::String app_base_path_;
300 really_delete_widget(Gtk::Widget *widget)
302 // synfig::info("really delete %p", (void*)widget);
307 // nasty workaround - when we've finished with a popup menu, we want to delete it
308 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
309 // so schedule the real delete to happen in 50ms, giving the action a chance to run
311 delete_widget(Gtk::Widget *widget)
313 // synfig::info("delete %p", (void*)widget);
314 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
317 }; // END of namespace studio
318 studio::StateManager* state_manager;
323 class GlobalUIInterface : public synfigapp::UIInterface
327 virtual Response confirmation(const std::string &title,
328 const std::string &primaryText,
329 const std::string &secondaryText,
330 const std::string &confirmPhrase,
331 const std::string &cancelPhrase,
332 Response defaultResponse)
334 Gtk::MessageDialog dialog(
335 primaryText, // Message
337 Gtk::MESSAGE_WARNING, // Type
338 Gtk::BUTTONS_NONE, // Buttons
343 dialog.set_title(title);
344 if (! secondaryText.empty())
345 dialog.set_secondary_text(secondaryText);
347 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
348 dialog.add_button(confirmPhrase, RESPONSE_OK);
349 dialog.set_default_response(defaultResponse);
352 return (Response) dialog.run();
355 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
360 true // use_separator
362 Gtk::Label label(message);
365 dialog.get_vbox()->pack_start(label);
366 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
367 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
369 dialog.set_default_response(dflt);
371 return (Response)dialog.run();
373 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
378 true // use_separator
380 Gtk::Label label(message);
383 dialog.get_vbox()->pack_start(label);
384 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
385 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
386 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
388 dialog.set_default_response(dflt);
390 return (Response)dialog.run();
392 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
397 true // use_separator
399 Gtk::Label label(message);
402 dialog.get_vbox()->pack_start(label);
403 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
404 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
406 dialog.set_default_response(dflt);
408 return (Response)dialog.run();
412 task(const std::string &task)
414 std::cerr<<task<<std::endl;
415 while(studio::App::events_pending())studio::App::iteration(false);
420 error(const std::string &err)
422 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
429 warning(const std::string &err)
431 std::cerr<<"warning: "<<err<<std::endl;
432 while(studio::App::events_pending())studio::App::iteration(false);
437 amount_complete(int /*current*/, int /*total*/)
439 while(studio::App::events_pending())studio::App::iteration(false);
444 /* === P R O C E D U R E S ================================================= */
448 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
450 action_group_list.push_back(action_group);
451 Gtk::UIManager::insert_action_group(action_group, pos);
455 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
457 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
458 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
459 if(*iter==action_group)
461 action_group_list.erase(iter);
462 Gtk::UIManager::remove_action_group(action_group);
465 synfig::error("Unable to find action group");
469 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
471 ui_manager->insert_action_group(group,0);
473 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
474 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
476 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
478 if(*iter && (*iter)->get_name()!="menus")
480 synfig::info("Removing action group "+(*iter)->get_name());
481 ui_manager->remove_action_group(*iter);
484 ui_manager->insert_action_group(group,0);
486 for(;!prev_groups.empty();prev_groups.pop_front())
488 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
489 ui_manager->insert_action_group(prev_groups.front(),1);
493 class Preferences : public synfigapp::Settings
496 virtual bool get_value(const synfig::String& key, synfig::String& value)const
500 value=strprintf("%f %f %f %f",
501 App::gamma.get_gamma_r(),
502 App::gamma.get_gamma_g(),
503 App::gamma.get_gamma_b(),
504 App::gamma.get_black_level()
508 if(key=="time_format")
510 value=strprintf("%i",App::get_time_format());
513 if(key=="file_history.size")
515 value=strprintf("%i",App::get_max_recent_files());
518 if(key=="use_colorspace_gamma")
520 value=strprintf("%i",(int)App::use_colorspace_gamma);
523 if(key=="distance_system")
525 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
528 #ifdef SINGLE_THREADED
529 if(key=="single_threaded")
531 value=strprintf("%i",(int)App::single_threaded);
535 if(key=="auto_recover_backup_interval")
537 value=strprintf("%i",App::auto_recover->get_timeout());
540 if(key=="restrict_radius_ducks")
542 value=strprintf("%i",(int)App::restrict_radius_ducks);
545 if(key=="resize_imported_images")
547 value=strprintf("%i",(int)App::resize_imported_images);
550 if(key=="browser_command")
552 value=App::browser_command;
555 if(key=="custom_filename_prefix")
557 value=App::custom_filename_prefix;
560 if(key=="preferred_x_size")
562 value=strprintf("%i",App::preferred_x_size);
565 if(key=="preferred_y_size")
567 value=strprintf("%i",App::preferred_y_size);
570 if(key=="predefined_size")
572 value=strprintf("%s",App::predefined_size.c_str());
575 if(key=="preferred_fps")
577 value=strprintf("%f",App::preferred_fps);
580 if(key=="predefined_fps")
582 value=strprintf("%s",App::predefined_fps.c_str());
586 return synfigapp::Settings::get_value(key,value);
589 virtual bool set_value(const synfig::String& key,const synfig::String& value)
595 strscanf(value,"%f %f %f %f",
602 App::gamma.set_all(r,g,b,blk);
606 if(key=="time_format")
608 int i(atoi(value.c_str()));
609 App::set_time_format(static_cast<synfig::Time::Format>(i));
612 if(key=="auto_recover_backup_interval")
614 int i(atoi(value.c_str()));
615 App::auto_recover->set_timeout(i);
618 if(key=="file_history.size")
620 int i(atoi(value.c_str()));
621 App::set_max_recent_files(i);
624 if(key=="use_colorspace_gamma")
626 int i(atoi(value.c_str()));
627 App::use_colorspace_gamma=i;
630 if(key=="distance_system")
632 App::distance_system=Distance::ident_system(value);;
635 #ifdef SINGLE_THREADED
636 if(key=="single_threaded")
638 int i(atoi(value.c_str()));
639 App::single_threaded=i;
643 if(key=="restrict_radius_ducks")
645 int i(atoi(value.c_str()));
646 App::restrict_radius_ducks=i;
649 if(key=="resize_imported_images")
651 int i(atoi(value.c_str()));
652 App::resize_imported_images=i;
655 if(key=="browser_command")
657 App::browser_command=value;
660 if(key=="custom_filename_prefix")
662 App::custom_filename_prefix=value;
665 if(key=="preferred_x_size")
667 int i(atoi(value.c_str()));
668 App::preferred_x_size=i;
671 if(key=="preferred_y_size")
673 int i(atoi(value.c_str()));
674 App::preferred_y_size=i;
677 if(key=="predefined_size")
679 App::predefined_size=value;
682 if(key=="preferred_fps")
684 float i(atof(value.c_str()));
685 App::preferred_fps=i;
688 if(key=="predefined_fps")
690 App::predefined_fps=value;
694 return synfigapp::Settings::set_value(key,value);
697 virtual KeyList get_key_list()const
699 KeyList ret(synfigapp::Settings::get_key_list());
700 ret.push_back("gamma");
701 ret.push_back("time_format");
702 ret.push_back("distance_system");
703 ret.push_back("file_history.size");
704 ret.push_back("use_colorspace_gamma");
705 #ifdef SINGLE_THREADED
706 ret.push_back("single_threaded");
708 ret.push_back("auto_recover_backup_interval");
709 ret.push_back("restrict_radius_ducks");
710 ret.push_back("resize_imported_images");
711 ret.push_back("browser_command");
712 ret.push_back("custom_filename_prefix");
713 ret.push_back("preferred_x_size");
714 ret.push_back("preferred_y_size");
715 ret.push_back("predefined_size");
716 ret.push_back("preferred_fps");
717 ret.push_back("predefined_fps");
722 static ::Preferences _preferences;
727 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
729 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
731 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
733 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
734 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
735 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
736 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
737 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
738 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
739 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
740 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
741 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
742 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
743 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
744 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
745 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
747 // Add the synfigapp actions...
748 synfigapp::Action::Book::iterator iter;
749 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
751 actions_action_group->add(Gtk::Action::create(
752 "action-"+iter->second.name,
753 get_action_stock_id(iter->second),
754 iter->second.local_name,iter->second.local_name
758 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
759 #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); }
760 #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); }
762 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
763 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
764 DEFINE_ACTION("new", Gtk::Stock::NEW);
765 DEFINE_ACTION("open", Gtk::Stock::OPEN);
766 DEFINE_ACTION("save", Gtk::Stock::SAVE);
767 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
768 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
769 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
770 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
771 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
772 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
773 DEFINE_ACTION("import", _("Import"));
774 DEFINE_ACTION("render", _("Render"));
775 DEFINE_ACTION("preview", _("Preview"));
776 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
777 DEFINE_ACTION("sound", _("Sound File"));
778 DEFINE_ACTION("options", _("Options"));
779 DEFINE_ACTION("close", _("Close View"));
780 DEFINE_ACTION("close-document", _("Close Document"));
781 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
784 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
785 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
786 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
787 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
788 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
789 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
790 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
791 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
792 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
793 DEFINE_ACTION("properties", _("Properties"));
795 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
796 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
797 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
798 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
799 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
800 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
801 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
802 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
803 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
804 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
805 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
806 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
807 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
808 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
809 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
810 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
811 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
812 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
813 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
814 DEFINE_ACTION("play", _("Play"));
815 // DEFINE_ACTION("pause", _("Pause"));
816 DEFINE_ACTION("stop", _("Stop"));
817 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
818 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
819 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
820 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
821 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
822 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
823 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
824 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
825 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
826 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
827 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
828 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
829 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
830 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
831 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
832 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
833 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
834 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
835 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
836 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
837 DEFINE_ACTION("seek-end", _("Seek to End"));
839 DEFINE_ACTION("action-group_add", _("Add group"));
841 DEFINE_ACTION("canvas-new", _("New Canvas"));
843 DEFINE_ACTION("amount-inc", _("Increase Amount"));
844 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
847 #undef DEFINE_ACTION_2
848 #undef DEFINE_ACTION_SIG
850 // Set up synfigapp actions
852 synfigapp::Action::Book::iterator iter;
854 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
856 Gtk::StockID stock_id;
858 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
860 //Gtk::Image* image(manage(new Gtk::Image()));
861 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
862 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
863 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
864 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
865 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
866 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
867 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
868 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
869 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
870 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
872 actions_action_group->add(Gtk::Action::create(
873 "action-"+iter->second.name,
875 iter->second.local_name,iter->second.local_name
883 Glib::ustring ui_info =
885 " <popup name='menu-toolbox' action='menu-toolbox'>"
886 " <menu action='menu-file'>"
889 " <popup name='menu-main' action='menu-main'>"
890 " <menu action='menu-file'>"
891 " <menuitem action='new' />"
892 " <menuitem action='open' />"
893 " <menuitem action='save' />"
894 " <menuitem action='save-as' />"
895 " <menuitem action='revert' />"
896 " <separator name='bleh01'/>"
897 " <menuitem action='cvs-add' />"
898 " <menuitem action='cvs-update' />"
899 " <menuitem action='cvs-commit' />"
900 " <menuitem action='cvs-revert' />"
901 " <separator name='bleh02'/>"
902 " <menuitem action='import' />"
903 " <separator name='bleh03'/>"
904 " <menuitem action='render' />"
905 " <menuitem action='preview' />"
906 " <menuitem action='sound' />"
907 " <separator name='bleh04'/>"
908 " <menuitem action='options' />"
909 " <menuitem action='close' />"
910 " <menuitem action='close-document' />"
911 " <menuitem action='quit' />"
913 " <menu action='menu-edit'>"
914 " <menuitem action='undo'/>"
915 " <menuitem action='redo'/>"
916 " <separator name='bleh05'/>"
917 " <menuitem action='cut'/>"
918 " <menuitem action='copy'/>"
919 " <menuitem action='paste'/>"
920 " <separator name='bleh06'/>"
921 " <menuitem action='select-all-layers'/>"
922 " <menuitem action='unselect-all-layers'/>"
923 " <menuitem action='select-all-ducks'/>"
924 " <menuitem action='unselect-all-ducks'/>"
925 " <separator name='bleh07'/>"
926 " <menuitem action='properties'/>"
928 " <menu action='menu-view'>"
929 " <menu action='menu-duck-mask'>"
930 " <menuitem action='mask-position-ducks' />"
931 " <menuitem action='mask-vertex-ducks' />"
932 " <menuitem action='mask-tangent-ducks' />"
933 " <menuitem action='mask-radius-ducks' />"
934 " <menuitem action='mask-width-ducks' />"
935 " <menuitem action='mask-angle-ducks' />"
937 " <menu action='menu-preview-quality'>"
938 " <menuitem action='quality-00' />"
939 " <menuitem action='quality-01' />"
940 " <menuitem action='quality-02' />"
941 " <menuitem action='quality-03' />"
942 " <menuitem action='quality-04' />"
943 " <menuitem action='quality-05' />"
944 " <menuitem action='quality-06' />"
945 " <menuitem action='quality-07' />"
946 " <menuitem action='quality-08' />"
947 " <menuitem action='quality-09' />"
948 " <menuitem action='quality-10' />"
950 " <menu action='menu-lowres-pixel'>"
951 " <menuitem action='decrease-low-res-pixel-size'/>"
952 " <menuitem action='increase-low-res-pixel-size'/>"
953 " <separator name='pixel-size-separator'/>"
956 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
957 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
961 " <separator name='bleh08'/>"
962 " <menuitem action='play'/>"
963 //" <menuitem action='pause'/>"
964 " <menuitem action='stop'/>"
965 " <menuitem action='dialog-flipbook'/>"
966 " <separator name='bleh09'/>"
967 " <menuitem action='toggle-grid-show'/>"
968 " <menuitem action='toggle-grid-snap'/>"
969 " <menuitem action='toggle-guide-show'/>"
970 " <menuitem action='toggle-low-res'/>"
971 " <menuitem action='toggle-onion-skin'/>"
972 " <separator name='bleh10'/>"
973 " <menuitem action='canvas-zoom-in'/>"
974 " <menuitem action='canvas-zoom-out'/>"
975 " <menuitem action='canvas-zoom-fit'/>"
976 " <menuitem action='canvas-zoom-100'/>"
977 " <separator name='bleh11'/>"
978 " <menuitem action='time-zoom-in'/>"
979 " <menuitem action='time-zoom-out'/>"
980 " <separator name='bleh12'/>"
981 " <menuitem action='jump-next-keyframe'/>"
982 " <menuitem action='jump-prev-keyframe'/>"
983 " <menuitem action='seek-next-frame'/>"
984 " <menuitem action='seek-prev-frame'/>"
985 " <menuitem action='seek-next-second'/>"
986 " <menuitem action='seek-prev-second'/>"
987 " <menuitem action='seek-begin'/>"
988 " <menuitem action='seek-end'/>"
990 " <menu action='menu-canvas'>"
991 " <menuitem action='canvas-new'/>"
993 " <menu name='menu-state' action='menu-state'>"
995 " <menu action='menu-group'>"
996 " <menuitem action='action-group_add'/>"
998 " <menu action='menu-layer'>"
999 //" <menuitem action='cut'/>"
1000 //" <menuitem action='copy'/>"
1001 //" <menuitem action='paste'/>"
1002 //" <separator name='bleh06'/>"
1003 " <menu action='menu-layer-new'></menu>"
1004 " <menuitem action='amount-inc'/>"
1005 " <menuitem action='amount-dec'/>"
1007 " <menu action='menu-keyframe'>"
1008 " <menuitem action='keyframe-properties'/>"
1015 " <menubar name='MenuBar'>"
1016 " <menu action='MenuFile'>"
1017 " <menuitem action='New'/>"
1018 " <menuitem action='Open'/>"
1020 " <menuitem action='Quit'/>"
1022 " <menu action='MenuEdit'>"
1023 " <menuitem action='Cut'/>"
1024 " <menuitem action='Copy'/>"
1025 " <menuitem action='Paste'/>"
1028 " <toolbar name='ToolBar'>"
1029 " <toolitem action='Open'/>"
1030 " <toolitem action='Quit'/>"
1036 actions_action_group->set_sensitive(false);
1037 App::ui_manager()->set_add_tearoffs(true);
1038 App::ui_manager()->insert_action_group(menus_action_group,1);
1039 App::ui_manager()->insert_action_group(actions_action_group,1);
1040 App::ui_manager()->add_ui_from_string(ui_info);
1042 //App::ui_manager()->get_accel_group()->unlock();
1044 catch(const Glib::Error& ex)
1046 synfig::error("building menus and toolbars failed: " + ex.what());
1049 // Add default keyboard accelerators
1050 #define ACCEL(accel,path) \
1052 Gtk::AccelKey accel_key(accel,path); \
1053 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1056 #define ACCEL2(accel) \
1058 Gtk::AccelKey accel_key(accel); \
1059 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1063 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1064 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1065 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1066 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1067 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1068 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1069 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1070 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1071 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1072 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1073 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1074 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1075 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1076 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1077 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1078 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1079 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1080 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1083 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1084 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1085 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1086 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1087 ACCEL("F9", "<Actions>/canvasview/render" );
1088 ACCEL("F11", "<Actions>/canvasview/preview" );
1089 ACCEL("F8", "<Actions>/canvasview/properties" );
1090 ACCEL("F12", "<Actions>/canvasview/options" );
1091 ACCEL("<control>i", "<Actions>/canvasview/import" );
1092 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1093 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1094 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1095 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1096 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1097 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1098 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1099 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1100 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1101 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1102 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1103 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1104 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1105 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1106 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1107 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1108 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1109 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1110 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1111 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1112 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1113 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1114 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1115 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1116 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1117 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1118 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1119 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1120 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1121 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1122 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1123 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1124 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1125 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1126 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1127 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1128 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1129 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1130 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1131 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1132 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1133 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1134 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1135 ACCEL("End", "<Actions>/canvasview/seek-end" );
1142 #define mkdir(x,y) mkdir(x)
1145 /* === M E T H O D S ======================================================= */
1147 App::App(int *argc, char ***argv):
1148 Gtk::Main(argc,argv),
1149 IconController(etl::dirname((*argv)[0]))
1151 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1154 ui_interface_=new GlobalUIInterface();
1158 // don't call thread_init() if threads are already initialized
1159 // on some machines bonobo_init() initialized threads before we get here
1160 if (!g_thread_supported())
1161 Glib::thread_init();
1163 distance_system=Distance::SYSTEM_UNITS;
1165 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1168 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1172 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1178 if(!SYNFIG_CHECK_VERSION())
1180 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1181 dialog_error_blocking("Synfig Studio",
1182 "This copy of Synfig Studio was compiled against a\n"
1183 "different version of libsynfig than what is currently\n"
1184 "installed. Synfig Studio will now abort. Try downloading\n"
1185 "the latest version from the Synfig website at\n"
1186 "http://synfig.org/Download"
1190 Glib::set_application_name(_("Synfig Studio"));
1192 Splash splash_screen;
1193 splash_screen.show();
1195 shutdown_in_progress=false;
1196 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1197 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1199 // Initialize the Synfig library
1200 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1201 catch(std::runtime_error x)
1203 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1208 get_ui_interface()->error(_("Failed to initialize synfig!"));
1212 // add the preferences to the settings
1213 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1217 studio_init_cb.task(_("Init UI Manager..."));
1218 App::ui_manager_=studio::UIManager::create();
1221 studio_init_cb.task(_("Init Dock Manager..."));
1222 dock_manager=new studio::DockManager();
1224 studio_init_cb.task(_("Init State Manager..."));
1225 state_manager=new StateManager();
1227 studio_init_cb.task(_("Init Toolbox..."));
1228 toolbox=new studio::Toolbox();
1230 studio_init_cb.task(_("Init About Dialog..."));
1231 about=new studio::About();
1233 studio_init_cb.task(_("Init Tool Options..."));
1234 dialog_tool_options=new studio::Dialog_ToolOptions();
1235 dock_manager->register_dockable(*dialog_tool_options);
1237 studio_init_cb.task(_("Init History..."));
1238 dock_history=new studio::Dock_History();
1239 dock_manager->register_dockable(*dock_history);
1241 studio_init_cb.task(_("Init Canvases..."));
1242 dock_canvases=new studio::Dock_Canvases();
1243 dock_manager->register_dockable(*dock_canvases);
1245 studio_init_cb.task(_("Init Keyframes..."));
1246 dock_keyframes=new studio::Dock_Keyframes();
1247 dock_manager->register_dockable(*dock_keyframes);
1249 studio_init_cb.task(_("Init Layers..."));
1250 dock_layers=new studio::Dock_Layers();
1251 dock_manager->register_dockable(*dock_layers);
1253 studio_init_cb.task(_("Init Params..."));
1254 dock_params=new studio::Dock_Params();
1255 dock_manager->register_dockable(*dock_params);
1257 studio_init_cb.task(_("Init MetaData..."));
1258 dock_meta_data=new studio::Dock_MetaData();
1259 dock_manager->register_dockable(*dock_meta_data);
1261 studio_init_cb.task(_("Init Children..."));
1262 dock_children=new studio::Dock_Children();
1263 dock_manager->register_dockable(*dock_children);
1265 studio_init_cb.task(_("Init Info..."));
1266 dock_info = new studio::Dock_Info();
1267 dock_manager->register_dockable(*dock_info);
1269 studio_init_cb.task(_("Init Navigator..."));
1270 dock_navigator = new studio::Dock_Navigator();
1271 dock_manager->register_dockable(*dock_navigator);
1273 studio_init_cb.task(_("Init Timetrack..."));
1274 dock_timetrack = new studio::Dock_Timetrack();
1275 dock_manager->register_dockable(*dock_timetrack);
1277 studio_init_cb.task(_("Init Curve Editor..."));
1278 dock_curves = new studio::Dock_Curves();
1279 dock_manager->register_dockable(*dock_curves);
1281 studio_init_cb.task(_("Init Layer Groups..."));
1282 dock_layer_groups = new studio::Dock_LayerGroups();
1283 dock_manager->register_dockable(*dock_layer_groups);
1286 studio_init_cb.task(_("Init Color Dialog..."));
1287 dialog_color=new studio::Dialog_Color();
1289 studio_init_cb.task(_("Init Gradient Dialog..."));
1290 dialog_gradient=new studio::Dialog_Gradient();
1292 studio_init_cb.task(_("Init DeviceTracker..."));
1293 device_tracker=new studio::DeviceTracker();
1295 studio_init_cb.task(_("Init Tools..."));
1298 state_manager->add_state(&state_normal);
1299 state_manager->add_state(&state_smooth_move);
1300 state_manager->add_state(&state_scale);
1301 state_manager->add_state(&state_rotate);
1302 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1303 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1306 state_manager->add_state(&state_circle);
1307 state_manager->add_state(&state_rectangle);
1308 state_manager->add_state(&state_star);
1309 state_manager->add_state(&state_gradient);
1310 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1311 state_manager->add_state(&state_text);
1312 state_manager->add_state(&state_bline);
1313 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1316 state_manager->add_state(&state_fill);
1317 state_manager->add_state(&state_eyedrop);
1318 state_manager->add_state(&state_zoom);
1319 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1321 studio_init_cb.task(_("Init ModPalette..."));
1322 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1324 studio_init_cb.task(_("Init Setup Dialog..."));
1325 dialog_setup=new studio::Dialog_Setup();
1327 studio_init_cb.task(_("Init Input Dialog..."));
1328 dialog_input=new Gtk::InputDialog();
1329 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1330 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1332 studio_init_cb.task(_("Init auto recovery..."));
1333 auto_recover=new AutoRecover();
1335 studio_init_cb.amount_complete(9250,10000);
1336 studio_init_cb.task(_("Loading Settings..."));
1338 device_tracker->load_preferences();
1340 studio_init_cb.task(_("Checking auto-recover..."));
1342 studio_init_cb.amount_complete(9900,10000);
1344 bool opened_any = false;
1345 if(auto_recover->recovery_needed())
1347 splash_screen.hide();
1348 if (get_ui_interface()->confirmation("Crash Recovery",
1349 _("Auto recovery file found"),
1350 _("Synfig Studio seems to have crashed\n"
1351 "before you could save all your files.\n"
1352 "Recover unsaved changes?"),
1353 _("Recover"), _("Ignore"))
1354 == synfigapp::UIInterface::RESPONSE_OK)
1356 int number_recovered;
1357 if(!auto_recover->recover(number_recovered))
1358 if (number_recovered)
1359 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1361 get_ui_interface()->error(_("Unable to recover from previous crash"));
1363 get_ui_interface()->error(
1364 _("Synfig Studio has attempted to recover\n"
1365 "from a previous crash. The files that it has\n"
1366 "recovered are NOT YET SAVED. It would be a good\n"
1367 "idea to review them and save them now."));
1369 if (number_recovered)
1372 splash_screen.show();
1375 // Look for any files given on the command line,
1376 // and load them if found.
1377 for(;*argc>=1;(*argc)--)
1378 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1380 studio_init_cb.task(_("Loading files..."));
1381 splash_screen.hide();
1382 open((*argv)[*argc]);
1384 splash_screen.show();
1387 // if no file was specified to be opened, create a new document to help new users get started more easily
1388 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1391 studio_init_cb.task(_("Done."));
1392 studio_init_cb.amount_complete(10000,10000);
1398 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1402 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1406 StateManager* App::get_state_manager() { return state_manager; }
1410 shutdown_in_progress=true;
1414 synfigapp::Main::settings().remove_domain("pref");
1416 selected_instance=0;
1418 // Unload all of the modules
1419 for(;!module_list_.empty();module_list_.pop_back())
1422 delete state_manager;
1426 delete auto_recover;
1434 delete dialog_setup;
1436 delete dialog_gradient;
1438 delete dialog_color;
1440 delete dialog_input;
1442 delete dock_manager;
1444 instance_list.clear();
1448 App::get_user_app_directory()
1450 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1452 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1454 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1459 App::get_config_file(const synfig::String& file)
1461 return Glib::build_filename(get_user_app_directory(),file);
1464 #define SCALE_FACTOR (1280)
1465 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1467 App::set_recent_file_window_size(etl::handle<Instance> instance)
1469 int screen_w(Gdk::screen_width());
1470 int screen_h(Gdk::screen_height());
1472 const std::string &canvas_window_size = *recent_files_window_size.begin();
1474 if(canvas_window_size.empty())
1477 synfig::String::size_type current=0;
1478 bool seen_root(false), shown_non_root(false);
1480 while(current != synfig::String::npos)
1482 // find end of first field (canvas) or return
1483 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1484 if(separator == synfig::String::npos) break;
1487 synfig::Canvas::Handle canvas;
1490 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1492 catch(Exception::IDNotFound) {
1493 // can't find the canvas; skip to the next canvas or return
1494 separator = canvas_window_size.find_first_of('\t', current);
1495 if(separator == synfig::String::npos) return;
1496 current = separator+1;
1500 if (canvas->is_root())
1503 shown_non_root = true;
1505 // check that we have the tab character the ends this canvas' data or return
1506 current = separator+1;
1507 separator = canvas_window_size.find_first_of('\t', current);
1508 if(separator == synfig::String::npos) return;
1511 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1513 current = separator+1;
1517 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1518 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1519 x=x*screen_w/SCALE_FACTOR;
1520 y=y*screen_h/SCALE_FACTOR;
1521 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1522 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1523 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1524 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1526 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1527 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1529 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1530 canvasview->move(x,y);
1531 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1532 canvasview->present();
1534 current = separator+1;
1537 if (shown_non_root && !seen_root)
1538 instance->find_canvas_view(instance->get_canvas())->hide();
1542 App::add_recent_file(const etl::handle<Instance> instance)
1544 int screen_w(Gdk::screen_width());
1545 int screen_h(Gdk::screen_height());
1547 std::string canvas_window_size;
1549 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1550 Instance::CanvasViewList::const_iterator iter;
1552 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1554 if( !((*iter)->is_visible()) )
1557 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1558 int x_pos, y_pos, x_size, y_size;
1559 (*iter)->get_position(x_pos,y_pos);
1560 (*iter)->get_size(x_size,y_size);
1562 canvas_window_size += strprintf("%s %d %d %d %d\t",
1563 canvas->get_relative_id(canvas->get_root()).c_str(),
1564 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1565 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1568 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1573 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1575 std::string filename(file_name);
1577 assert(!filename.empty());
1579 if(filename.empty())
1582 // Toss out any "hidden" files
1583 if(basename(filename)[0]=='.')
1586 // If we aren't an absolute path, turn ourselves into one
1587 if(!is_absolute_path(filename))
1588 filename=absolute_path(filename);
1590 std::string old_window_size;
1592 list<string>::iterator iter;
1593 list<string>::iterator iter_wsize;
1594 // Check to see if the file is already on the list.
1595 // If it is, then remove it from the list
1596 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1599 recent_files.erase(iter);
1600 old_window_size = *iter_wsize;
1601 recent_files_window_size.erase(iter_wsize);
1606 // Push the filename to the front of the list
1607 recent_files.push_front(filename);
1608 if(window_size.empty())
1609 recent_files_window_size.push_front(old_window_size);
1611 recent_files_window_size.push_front(window_size);
1613 // Clean out the files at the end of the list.
1614 while(recent_files.size()>(unsigned)get_max_recent_files())
1616 recent_files.pop_back();
1617 recent_files_window_size.pop_back();
1620 signal_recent_files_changed_();
1625 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1628 App::get_time_format()
1630 return _App_time_format;
1634 App::set_time_format(synfig::Time::Format x)
1641 App::save_settings()
1646 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1647 setlocale(LC_NUMERIC, "C");
1649 std::string filename=get_config_file("accelrc");
1650 Gtk::AccelMap::save(filename);
1653 std::string filename=get_config_file("recentfiles");
1655 std::ofstream file(filename.c_str());
1659 synfig::warning("Unable to save %s",filename.c_str());
1663 list<string>::reverse_iterator iter;
1665 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1669 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1671 std::ofstream file(filename.c_str());
1675 synfig::warning("Unable to save %s",filename.c_str());
1679 list<string>::reverse_iterator iter;
1681 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1685 std::string filename=get_config_file("settings");
1686 synfigapp::Main::settings().save_to_file(filename);
1687 setlocale(LC_NUMERIC,old_locale);
1691 synfig::warning("Caught exception when attempting to save settings.");
1696 App::load_settings()
1701 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1702 setlocale(LC_NUMERIC, "C");
1704 std::string filename=get_config_file("accelrc");
1705 Gtk::AccelMap::load(filename);
1708 bool window_size_broken = false;
1710 std::string filename=get_config_file("recentfiles");
1711 std::string filename_window_size=filename+std::string("_window_size");
1713 std::ifstream file(filename.c_str());
1714 std::ifstream file_window_size(filename_window_size.c_str());
1716 if(!file_window_size)
1717 window_size_broken = true;
1721 std::string recent_file;
1722 std::string recent_file_window_size;
1723 getline(file,recent_file);
1724 if(!window_size_broken)
1725 getline(file_window_size,recent_file_window_size);
1726 if(!recent_file.empty())
1728 if(!window_size_broken && !file_window_size)
1729 window_size_broken = true;
1730 if (std::ifstream(recent_file.c_str()))
1732 if(!window_size_broken)
1733 add_recent_file(recent_file,recent_file_window_size);
1735 add_recent_file(recent_file);
1739 if(!window_size_broken && file_window_size)
1740 window_size_broken = true;
1742 if(window_size_broken)
1744 recent_files_window_size.clear();
1745 recent_files_window_size.resize(recent_files.size());
1748 std::string filename=get_config_file("settings");
1749 if(!synfigapp::Main::settings().load_from_file(filename))
1751 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1752 //if(!synfigapp::Main::settings().load_from_file(filename))
1754 gamma.set_gamma(1.0/2.2);
1755 reset_initial_window_configuration();
1758 setlocale(LC_NUMERIC,old_locale);
1762 synfig::warning("Caught exception when attempting to load settings.");
1767 App::reset_initial_window_configuration()
1769 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1770 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1771 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1772 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1773 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1774 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1775 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1776 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1777 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1778 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1779 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1780 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1781 #ifdef SINGLE_THREADED
1782 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1784 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1785 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1786 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1787 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1788 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1789 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1790 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1791 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1792 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1796 App::shutdown_request(GdkEventAny*)
1800 //return !shutdown_in_progress;
1806 if(shutdown_in_progress)return;
1809 get_ui_interface()->task(_("Quit Request"));
1812 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1816 std::list<etl::handle<Instance> >::iterator iter;
1817 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1819 if(!(*iter)->safe_close())
1823 if((*iter)->synfigapp::Instance::get_action_count())
1825 handle<synfigapp::UIInterface> uim;
1826 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1828 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1829 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1831 case synfigapp::UIInterface::RESPONSE_NO:
1833 case synfigapp::UIInterface::RESPONSE_YES:
1836 case synfigapp::UIInterface::RESPONSE_CANCEL:
1845 if((*iter)->synfigapp::Instance::is_modified())
1847 handle<synfigapp::UIInterface> uim;
1848 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1850 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() );
1851 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1853 case synfigapp::UIInterface::RESPONSE_NO:
1855 case synfigapp::UIInterface::RESPONSE_YES:
1856 (*iter)->dialog_cvs_commit();
1858 case synfigapp::UIInterface::RESPONSE_CANCEL:
1867 // This next line causes things to crash for some reason
1871 shutdown_in_progress=true;
1873 instance_list.clear();
1875 while(studio::App::events_pending())studio::App::iteration(false);
1878 auto_recover->normal_shutdown();
1880 get_ui_interface()->task(_("Quit Request sent"));
1886 dialog_setup->refresh();
1887 dialog_setup->show();
1890 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1891 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1894 //#define USE_WIN32_FILE_DIALOGS 1
1897 #ifdef USE_WIN32_FILE_DIALOGS
1898 static OPENFILENAME ofn={};
1902 #include <gdk/gdkwin32.h>
1906 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1908 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1910 #ifdef USE_WIN32_FILE_DIALOGS
1911 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1913 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1914 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1915 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1917 ofn.lStructSize=sizeof(OPENFILENAME);
1918 ofn.hwndOwner = hWnd;
1919 ofn.hInstance = hInstance;
1920 ofn.lpstrFilter = szFilter;
1921 // ofn.lpstrCustomFilter=NULL;
1922 // ofn.nMaxCustFilter=0;
1923 // ofn.nFilterIndex=0;
1924 // ofn.lpstrFile=NULL;
1925 ofn.nMaxFile=MAX_PATH;
1926 // ofn.lpstrFileTitle=NULL;
1927 // ofn.lpstrInitialDir=NULL;
1928 // ofn.lpstrTitle=NULL;
1929 ofn.Flags=OFN_HIDEREADONLY;
1930 // ofn.nFileOffset=0;
1931 // ofn.nFileExtension=0;
1932 ofn.lpstrDefExt=TEXT("sif");
1933 // ofn.lCustData = 0l;
1935 // ofn.lpTemplateName=NULL;
1937 CHAR szFilename[MAX_PATH];
1939 strcpy(szFilename,filename.c_str());
1940 strcpy(szTitle,title.c_str());
1942 ofn.lpstrFile=szFilename;
1943 ofn.lpstrFileTitle=szTitle;
1945 if(GetOpenFileName(&ofn))
1947 filename=szFilename;
1952 #else // not USE_WIN32_FILE_DIALOGS
1953 synfig::String prev_path;
1955 if(!_preferences.get_value(preference, prev_path))
1958 prev_path = absolute_path(prev_path);
1960 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1962 dialog->set_current_folder(prev_path);
1963 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1964 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1966 if (filename.empty())
1967 dialog->set_filename(prev_path);
1968 else if (is_absolute_path(filename))
1969 dialog->set_filename(filename);
1971 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1973 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1974 filename = dialog->get_filename();
1975 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1976 _preferences.set_value(preference, dirname(filename));
1983 #endif // not USE_WIN32_FILE_DIALOGS
1987 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1989 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1991 #if USE_WIN32_FILE_DIALOGS
1992 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1994 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1995 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1996 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1998 ofn.lStructSize=sizeof(OPENFILENAME);
1999 ofn.hwndOwner = hWnd;
2000 ofn.hInstance = hInstance;
2001 ofn.lpstrFilter = szFilter;
2002 // ofn.lpstrCustomFilter=NULL;
2003 // ofn.nMaxCustFilter=0;
2004 // ofn.nFilterIndex=0;
2005 // ofn.lpstrFile=NULL;
2006 ofn.nMaxFile=MAX_PATH;
2007 // ofn.lpstrFileTitle=NULL;
2008 // ofn.lpstrInitialDir=NULL;
2009 // ofn.lpstrTitle=NULL;
2010 ofn.Flags=OFN_OVERWRITEPROMPT;
2011 // ofn.nFileOffset=0;
2012 // ofn.nFileExtension=0;
2013 ofn.lpstrDefExt=TEXT("sif");
2014 // ofn.lCustData = 0l;
2016 // ofn.lpTemplateName=NULL;
2018 CHAR szFilename[MAX_PATH];
2020 strcpy(szFilename,filename.c_str());
2021 strcpy(szTitle,title.c_str());
2023 ofn.lpstrFile=szFilename;
2024 ofn.lpstrFileTitle=szTitle;
2026 if(GetSaveFileName(&ofn))
2028 filename=szFilename;
2029 _preferences.set_value(preference,dirname(filename));
2034 synfig::String prev_path;
2036 if(!_preferences.get_value(preference, prev_path))
2039 prev_path = absolute_path(prev_path);
2041 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2043 dialog->set_current_folder(prev_path);
2044 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2045 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2047 Widget_Enum *file_type_enum = 0;
2048 if (preference == ANIMATION_DIR_PREFERENCE)
2050 file_type_enum = manage(new Widget_Enum());
2051 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2052 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", strprintf("0.62.00 (%s)", _("current")))
2053 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2054 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2055 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2056 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2057 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2059 Gtk::HBox *hbox = manage(new Gtk::HBox);
2060 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2061 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2064 dialog->set_extra_widget(*hbox);
2067 if (filename.empty())
2068 dialog->set_filename(prev_path);
2071 std::string full_path;
2072 if (is_absolute_path(filename))
2073 full_path = filename;
2075 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2077 // select the file if it exists
2078 dialog->set_filename(full_path);
2080 // if the file doesn't exist, put its name into the filename box
2082 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2083 dialog->set_current_name(basename(filename));
2086 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2087 if (preference == ANIMATION_DIR_PREFERENCE)
2088 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2089 filename = dialog->get_filename();
2090 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2091 _preferences.set_value(preference, dirname(filename));
2102 App::dialog_error_blocking(const std::string &title, const std::string &message)
2104 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2105 dialog.set_title(title);
2111 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2113 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2114 dialog.set_title(title);
2120 App::dialog_yes_no(const std::string &title, const std::string &message)
2125 true // use_separator
2127 Gtk::Label label(message);
2130 dialog.get_vbox()->pack_start(label);
2131 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2132 dialog.add_button(Gtk::StockID("gtk-no"),0);
2134 return dialog.run();
2138 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2143 true // use_separator
2145 Gtk::Label label(message);
2148 dialog.get_vbox()->pack_start(label);
2149 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2150 dialog.add_button(Gtk::StockID("gtk-no"),0);
2151 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2153 return dialog.run();
2157 App::dialog_not_implemented()
2159 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2160 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2165 try_open_url(const std::string &url)
2168 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2170 std::vector<std::string> command_line;
2171 std::vector<std::string> browsers;
2172 browsers.reserve(23);
2174 // Browser wrapper scripts
2175 #ifdef USE_OPEN_FOR_URLS
2176 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2178 browsers.push_back("xdg-open"); // XDG wrapper
2179 browsers.push_back("sensible-browser"); // Debian wrapper
2180 browsers.push_back("gnome-open"); // GNOME wrapper
2181 browsers.push_back("kfmclient"); // KDE wrapper
2182 browsers.push_back("exo-open"); // XFCE wrapper
2184 // Alternatives system
2185 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2186 browsers.push_back("x-www-browser"); // Debian GUI alternative
2188 // Individual browsers
2189 browsers.push_back("firefox");
2190 browsers.push_back("epiphany-browser");
2191 browsers.push_back("epiphany");
2192 browsers.push_back("konqueror");
2193 browsers.push_back("iceweasel");
2194 browsers.push_back("mozilla");
2195 browsers.push_back("netscape");
2196 browsers.push_back("icecat");
2197 browsers.push_back("galeon");
2198 browsers.push_back("midori");
2199 browsers.push_back("safari");
2200 browsers.push_back("opera");
2201 browsers.push_back("amaya");
2202 browsers.push_back("netsurf");
2203 browsers.push_back("dillo");
2205 // Try the user-specified browser first
2206 command_line.push_back(App::browser_command);
2207 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2208 command_line.push_back(url);
2210 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2211 catch( Glib::SpawnError& exception ){
2213 while ( !browsers.empty() )
2215 // Skip the browser if we already tried it
2216 if( browsers[0] == App::browser_command )
2219 // Construct the command line
2220 command_line.clear();
2221 command_line.push_back(browsers[0]);
2222 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2223 command_line.push_back(url);
2225 // Remove the browser from the list
2226 browsers.erase(browsers.begin());
2228 // Try to spawn the browser
2229 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2230 // Failed, move on to the next one
2231 catch(Glib::SpawnError& exception){ continue; }
2232 return true; // No exception means we succeeded!
2243 if (!try_open_url("http://synfig.org/Documentation"))
2245 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2246 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2247 dialog.set_title(_("Help"));
2253 App::open_url(const std::string &url)
2255 if(!try_open_url(url))
2257 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2258 dialog.set_secondary_text(url);
2259 dialog.set_title(_("No browser found"));
2265 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2270 true); // use_separator
2272 Gtk::Label label(message);
2274 dialog.get_vbox()->pack_start(label);
2277 entry.set_text(text);
2279 entry.set_activates_default(true);
2281 dialog.get_vbox()->pack_start(entry);
2283 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2284 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2285 dialog.set_default_response(Gtk::RESPONSE_OK);
2287 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2290 if(dialog.run()!=Gtk::RESPONSE_OK)
2293 text=entry.get_text();
2299 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2304 true); // use_separator
2306 Gtk::Label label(message);
2308 dialog.get_vbox()->pack_start(label);
2310 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2311 text_buffer->set_text(text);
2312 Gtk::TextView text_view(text_buffer);
2315 dialog.get_vbox()->pack_start(text_view);
2317 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2318 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2319 dialog.set_default_response(Gtk::RESPONSE_OK);
2321 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2324 if(dialog.run()!=Gtk::RESPONSE_OK)
2327 text=text_buffer->get_text();
2333 App::open(std::string filename)
2335 return open_as(filename,filename);
2338 // this is called from autorecover.cpp:
2339 // App::open_as(get_shadow_file_name(filename),filename)
2340 // other than that, 'filename' and 'as' are the same
2342 App::open_as(std::string filename,std::string as)
2345 char long_name[1024];
2346 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2347 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2348 // don't use it if that's the case
2349 if (long_name[0] != '\0')
2355 OneMoment one_moment;
2356 String errors, warnings;
2358 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2359 if(canvas && get_instance(canvas))
2361 get_instance(canvas)->find_canvas_view(canvas)->present();
2362 info("%s is already open", filename.c_str());
2363 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2368 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2371 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2373 if (as.find(custom_filename_prefix.c_str()) != 0)
2374 add_recent_file(as);
2376 handle<Instance> instance(Instance::create(canvas));
2379 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2381 set_recent_file_window_size(instance);
2385 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)")))
2386 instance->dialog_cvs_update();
2391 dialog_error_blocking(_("Error"), x);
2394 catch(runtime_error x)
2396 dialog_error_blocking(_("Error"), x.what());
2401 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2412 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2414 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2415 canvas->set_name(file_name);
2416 file_name += ".sifz";
2418 canvas->rend_desc().set_frame_rate(preferred_fps);
2419 canvas->rend_desc().set_time_start(0.0);
2420 canvas->rend_desc().set_time_end(5.0);
2421 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2422 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2423 // The top left and botton right positions are expressed in units
2424 // Original convention is that 1 unit = 60 pixels
2425 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2426 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2427 canvas->rend_desc().set_w(preferred_x_size);
2428 canvas->rend_desc().set_h(preferred_y_size);
2429 canvas->rend_desc().set_antialias(1);
2430 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2431 canvas->set_file_name(file_name);
2433 handle<Instance> instance = Instance::create(canvas);
2435 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2436 instance->find_canvas_view(canvas)->canvas_properties.present();
2440 App::dialog_open(string filename)
2442 if (filename.empty())
2445 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2447 // If the filename still has wildcards, then we should
2448 // continue looking for the file we want
2449 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2455 get_ui_interface()->error(_("Unable to open file"));
2460 App::set_selected_instance(etl::loose_handle<Instance> instance)
2462 /* if(get_selected_instance()==instance)
2464 selected_instance=instance;
2465 signal_instance_selected()(instance);
2471 selected_instance=instance;
2472 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2476 instance->focus(instance->get_canvas());
2479 set_selected_canvas_view(0);
2481 signal_instance_selected()(instance);
2485 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2487 selected_canvas_view=canvas_view;
2488 signal_canvas_view_focus()(selected_canvas_view);
2491 selected_instance=canvas_view->get_instance();
2492 signal_instance_selected()(canvas_view->get_instance());
2495 if(get_selected_canvas_view()==canvas_view)
2497 signal_canvas_view_focus()(selected_canvas_view);
2498 signal_instance_selected()(canvas_view->get_instance());
2501 selected_canvas_view=canvas_view;
2502 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2503 set_selected_instance(canvas_view->get_instance());
2504 signal_canvas_view_focus()(selected_canvas_view);
2508 etl::loose_handle<Instance>
2509 App::get_instance(etl::handle<synfig::Canvas> canvas)
2511 if(!canvas) return 0;
2512 canvas=canvas->get_root();
2514 std::list<etl::handle<Instance> >::iterator iter;
2515 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2517 if((*iter)->get_canvas()==canvas)
2533 if(selected_instance)
2534 selected_instance->undo();
2540 if(selected_instance)
2541 selected_instance->redo();
2545 studio::App::get_base_path()
2547 return app_base_path_;