1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2008 Gerald Young
11 ** Copyright (c) 2008 Carlos López
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
24 /* ========================================================================= */
26 /* === H E A D E R S ======================================================= */
45 #ifdef HAVE_SYS_ERRNO_H
46 #include <sys/errno.h>
48 #include <gtkmm/fileselection.h>
49 #include <gtkmm/dialog.h>
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/label.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/stockitem.h>
54 #include <gtkmm/iconsource.h>
55 #include <gtkmm/inputdialog.h>
56 #include <gtkmm/accelmap.h>
57 #include <gtkmm/uimanager.h>
58 #include <gtkmm/textview.h>
62 #include <gdkmm/general.h>
64 #include <synfig/loadcanvas.h>
65 #include <synfig/savecanvas.h>
71 #include "canvasview.h"
72 #include "dialog_setup.h"
73 #include "dialog_gradient.h"
74 #include "dialog_color.h"
77 #include "onemoment.h"
79 #include "dockmanager.h"
81 #include "state_eyedrop.h"
82 #include "state_normal.h"
83 #include "state_draw.h"
84 #include "state_fill.h"
85 #include "state_bline.h"
86 #include "state_polygon.h"
87 #include "state_sketch.h"
88 #include "state_gradient.h"
89 #include "state_circle.h"
90 #include "state_rectangle.h"
91 #include "state_smoothmove.h"
92 #include "state_scale.h"
93 #include "state_star.h"
94 #include "state_text.h"
95 #include "state_width.h"
96 #include "state_rotate.h"
97 #include "state_zoom.h"
99 #include "devicetracker.h"
100 #include "dialog_tooloptions.h"
101 #include "widget_enum.h"
103 #include "autorecover.h"
105 #include <synfigapp/settings.h>
106 #include "dock_history.h"
107 #include "dock_canvases.h"
108 #include "dock_keyframes.h"
109 #include "dock_layers.h"
110 #include "dock_params.h"
111 #include "dock_metadata.h"
112 #include "dock_children.h"
113 #include "dock_info.h"
114 #include "dock_navigator.h"
115 #include "dock_layergroups.h"
116 #include "dock_timetrack.h"
117 #include "dock_curves.h"
119 #include "mod_palette/mod_palette.h"
120 #include "mod_mirror/mod_mirror.h"
122 #include <sys/stat.h>
128 #include "statemanager.h"
134 #include <gtkmm/accelmap.h>
135 #include <gtkmm/filechooser.h>
136 #include <gtkmm/filechooserdialog.h>
142 /* === U S I N G =========================================================== */
146 using namespace synfig;
147 using namespace studio;
149 /* === M A C R O S ========================================================= */
151 #ifndef SYNFIG_USER_APP_DIR
153 #define SYNFIG_USER_APP_DIR "Library/Synfig"
154 #elif defined(_WIN32)
155 #define SYNFIG_USER_APP_DIR "Synfig"
157 #define SYNFIG_USER_APP_DIR ".synfig"
162 #define DPM2DPI(x) (float(x)/39.3700787402f)
163 #define DPI2DPM(x) (float(x)*39.3700787402f)
169 # define IMAGE_DIR "share\\pixmaps"
174 # define IMAGE_DIR "/usr/local/share/pixmaps"
178 # define IMAGE_EXT "tif"
181 #include <synfigapp/main.h>
183 /* === S I G N A L S ======================================================= */
185 static sigc::signal<void> signal_present_all_;
187 App::signal_present_all() { return signal_present_all_; }
189 static sigc::signal<void> signal_recent_files_changed_;
191 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
193 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
194 sigc::signal<void,etl::loose_handle<CanvasView> >&
195 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_selected() { return signal_instance_selected_; }
201 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
202 sigc::signal<void,etl::handle<Instance> >&
203 App::signal_instance_created() { return signal_instance_created_; }
205 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
206 sigc::signal<void,etl::handle<Instance> >&
207 App::signal_instance_deleted() { return signal_instance_deleted_; }
209 /* === G L O B A L S ======================================================= */
211 static std::list<std::string> recent_files;
212 const std::list<std::string>& App::get_recent_files() { return recent_files; }
214 static std::list<std::string> recent_files_window_size;
216 int App::Busy::count;
217 bool App::shutdown_in_progress;
219 synfig::Gamma App::gamma;
221 Glib::RefPtr<studio::UIManager> App::ui_manager_;
223 synfig::Distance::System App::distance_system;
225 studio::Dialog_Setup* App::dialog_setup;
227 etl::handle< studio::ModPalette > mod_palette_;
228 //studio::Dialog_Palette* App::dialog_palette;
230 std::list<etl::handle<Instance> > App::instance_list;
232 static etl::handle<synfigapp::UIInterface> ui_interface_;
233 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
235 etl::handle<Instance> App::selected_instance;
236 etl::handle<CanvasView> App::selected_canvas_view;
238 studio::About *studio::App::about=NULL;
240 studio::Toolbox *studio::App::toolbox=NULL;
242 studio::AutoRecover *studio::App::auto_recover=NULL;
244 studio::IPC *ipc=NULL;
246 studio::DockManager* studio::App::dock_manager=0;
248 studio::DeviceTracker* studio::App::device_tracker=0;
250 studio::Dialog_Gradient* studio::App::dialog_gradient;
252 studio::Dialog_Color* studio::App::dialog_color;
254 Gtk::InputDialog* studio::App::dialog_input;
256 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
258 studio::Dock_History* dock_history;
259 studio::Dock_Canvases* dock_canvases;
260 studio::Dock_Keyframes* dock_keyframes;
261 studio::Dock_Layers* dock_layers;
262 studio::Dock_Params* dock_params;
263 studio::Dock_MetaData* dock_meta_data;
264 studio::Dock_Children* dock_children;
265 studio::Dock_Info* dock_info;
266 studio::Dock_LayerGroups* dock_layer_groups;
267 studio::Dock_Navigator* dock_navigator;
268 studio::Dock_Timetrack* dock_timetrack;
269 studio::Dock_Curves* dock_curves;
271 std::list< etl::handle< studio::Module > > module_list_;
273 bool studio::App::use_colorspace_gamma=true;
274 #ifdef SINGLE_THREADED
275 bool studio::App::single_threaded=false;
277 bool studio::App::restrict_radius_ducks=false;
278 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"));
849 // Set up synfigapp actions
851 synfigapp::Action::Book::iterator iter;
853 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
855 Gtk::StockID stock_id;
857 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
859 //Gtk::Image* image(manage(new Gtk::Image()));
860 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
861 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
862 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
863 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
864 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
865 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
866 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
867 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
868 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
869 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
871 actions_action_group->add(Gtk::Action::create(
872 "action-"+iter->second.name,
874 iter->second.local_name,iter->second.local_name
882 Glib::ustring ui_info =
884 " <popup name='menu-toolbox' action='menu-toolbox'>"
885 " <menu action='menu-file'>"
888 " <popup name='menu-main' action='menu-main'>"
889 " <menu action='menu-file'>"
890 " <menuitem action='new' />"
891 " <menuitem action='open' />"
892 " <menuitem action='save' />"
893 " <menuitem action='save-as' />"
894 " <menuitem action='revert' />"
895 " <separator name='bleh01'/>"
896 " <menuitem action='cvs-add' />"
897 " <menuitem action='cvs-update' />"
898 " <menuitem action='cvs-commit' />"
899 " <menuitem action='cvs-revert' />"
900 " <separator name='bleh02'/>"
901 " <menuitem action='import' />"
902 " <separator name='bleh03'/>"
903 " <menuitem action='render' />"
904 " <menuitem action='preview' />"
905 " <menuitem action='sound' />"
906 " <separator name='bleh04'/>"
907 " <menuitem action='options' />"
908 " <menuitem action='close' />"
909 " <menuitem action='close-document' />"
910 " <menuitem action='quit' />"
912 " <menu action='menu-edit'>"
913 " <menuitem action='undo'/>"
914 " <menuitem action='redo'/>"
915 " <separator name='bleh05'/>"
916 " <menuitem action='cut'/>"
917 " <menuitem action='copy'/>"
918 " <menuitem action='paste'/>"
919 " <separator name='bleh06'/>"
920 " <menuitem action='select-all-layers'/>"
921 " <menuitem action='unselect-all-layers'/>"
922 " <menuitem action='select-all-ducks'/>"
923 " <menuitem action='unselect-all-ducks'/>"
924 " <separator name='bleh07'/>"
925 " <menuitem action='properties'/>"
927 " <menu action='menu-view'>"
928 " <menu action='menu-duck-mask'>"
929 " <menuitem action='mask-position-ducks' />"
930 " <menuitem action='mask-vertex-ducks' />"
931 " <menuitem action='mask-tangent-ducks' />"
932 " <menuitem action='mask-radius-ducks' />"
933 " <menuitem action='mask-width-ducks' />"
934 " <menuitem action='mask-angle-ducks' />"
936 " <menu action='menu-preview-quality'>"
937 " <menuitem action='quality-00' />"
938 " <menuitem action='quality-01' />"
939 " <menuitem action='quality-02' />"
940 " <menuitem action='quality-03' />"
941 " <menuitem action='quality-04' />"
942 " <menuitem action='quality-05' />"
943 " <menuitem action='quality-06' />"
944 " <menuitem action='quality-07' />"
945 " <menuitem action='quality-08' />"
946 " <menuitem action='quality-09' />"
947 " <menuitem action='quality-10' />"
949 " <menu action='menu-lowres-pixel'>"
950 " <menuitem action='decrease-low-res-pixel-size'/>"
951 " <menuitem action='increase-low-res-pixel-size'/>"
952 " <separator name='pixel-size-separator'/>"
955 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
956 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
960 " <separator name='bleh08'/>"
961 " <menuitem action='play'/>"
962 //" <menuitem action='pause'/>"
963 " <menuitem action='stop'/>"
964 " <menuitem action='dialog-flipbook'/>"
965 " <separator name='bleh09'/>"
966 " <menuitem action='toggle-grid-show'/>"
967 " <menuitem action='toggle-grid-snap'/>"
968 " <menuitem action='toggle-guide-show'/>"
969 " <menuitem action='toggle-low-res'/>"
970 " <menuitem action='toggle-onion-skin'/>"
971 " <separator name='bleh10'/>"
972 " <menuitem action='canvas-zoom-in'/>"
973 " <menuitem action='canvas-zoom-out'/>"
974 " <menuitem action='canvas-zoom-fit'/>"
975 " <menuitem action='canvas-zoom-100'/>"
976 " <separator name='bleh11'/>"
977 " <menuitem action='time-zoom-in'/>"
978 " <menuitem action='time-zoom-out'/>"
979 " <separator name='bleh12'/>"
980 " <menuitem action='jump-next-keyframe'/>"
981 " <menuitem action='jump-prev-keyframe'/>"
982 " <menuitem action='seek-next-frame'/>"
983 " <menuitem action='seek-prev-frame'/>"
984 " <menuitem action='seek-next-second'/>"
985 " <menuitem action='seek-prev-second'/>"
986 " <menuitem action='seek-begin'/>"
987 " <menuitem action='seek-end'/>"
989 " <menu action='menu-canvas'>"
990 " <menuitem action='canvas-new'/>"
992 " <menu name='menu-state' action='menu-state'>"
994 " <menu action='menu-group'>"
995 " <menuitem action='action-group_add'/>"
997 " <menu action='menu-layer'>"
998 //" <menuitem action='cut'/>"
999 //" <menuitem action='copy'/>"
1000 //" <menuitem action='paste'/>"
1001 //" <separator name='bleh06'/>"
1002 " <menu action='menu-layer-new'></menu>"
1003 " <menuitem action='amount-inc'/>"
1004 " <menuitem action='amount-dec'/>"
1006 " <menu action='menu-keyframe'>"
1007 " <menuitem action='keyframe-properties'/>"
1014 " <menubar name='MenuBar'>"
1015 " <menu action='MenuFile'>"
1016 " <menuitem action='New'/>"
1017 " <menuitem action='Open'/>"
1019 " <menuitem action='Quit'/>"
1021 " <menu action='MenuEdit'>"
1022 " <menuitem action='Cut'/>"
1023 " <menuitem action='Copy'/>"
1024 " <menuitem action='Paste'/>"
1027 " <toolbar name='ToolBar'>"
1028 " <toolitem action='Open'/>"
1029 " <toolitem action='Quit'/>"
1035 actions_action_group->set_sensitive(false);
1036 App::ui_manager()->set_add_tearoffs(true);
1037 App::ui_manager()->insert_action_group(menus_action_group,1);
1038 App::ui_manager()->insert_action_group(actions_action_group,1);
1039 App::ui_manager()->add_ui_from_string(ui_info);
1041 //App::ui_manager()->get_accel_group()->unlock();
1043 catch(const Glib::Error& ex)
1045 synfig::error("building menus and toolbars failed: " + ex.what());
1048 // Add default keyboard accelerators
1049 #define ACCEL(accel,path) \
1051 Gtk::AccelKey accel_key(accel,path); \
1052 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1055 #define ACCEL2(accel) \
1057 Gtk::AccelKey accel_key(accel); \
1058 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1062 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1063 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1064 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1065 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1066 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1067 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1068 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1069 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1070 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1071 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1072 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1073 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1074 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1075 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1076 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1077 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1078 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1079 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1082 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1083 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1084 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1085 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1086 ACCEL("F9", "<Actions>/canvasview/render" );
1087 ACCEL("F11", "<Actions>/canvasview/preview" );
1088 ACCEL("F8", "<Actions>/canvasview/properties" );
1089 ACCEL("F12", "<Actions>/canvasview/options" );
1090 ACCEL("<control>i", "<Actions>/canvasview/import" );
1091 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1092 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1093 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1094 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1095 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1096 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1097 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1098 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1099 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1100 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1101 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1102 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1103 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1104 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1105 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1106 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1107 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1108 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1109 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1110 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1111 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1112 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1113 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1114 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1115 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1116 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1117 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1118 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1119 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1120 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1121 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1122 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1123 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1124 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1125 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1126 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1127 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1128 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1129 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1130 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1131 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1132 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1133 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1134 ACCEL("End", "<Actions>/canvasview/seek-end" );
1140 #define mkdir(x,y) mkdir(x)
1143 /* === M E T H O D S ======================================================= */
1145 App::App(int *argc, char ***argv):
1146 Gtk::Main(argc,argv),
1147 IconController(etl::dirname((*argv)[0]))
1149 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1152 ui_interface_=new GlobalUIInterface();
1156 // don't call thread_init() if threads are already initialized
1157 // on some machines bonobo_init() initialized threads before we get here
1158 if (!g_thread_supported())
1159 Glib::thread_init();
1161 distance_system=Distance::SYSTEM_UNITS;
1163 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1166 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1170 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1176 if(!SYNFIG_CHECK_VERSION())
1178 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1179 dialog_error_blocking("Synfig Studio",
1180 "This copy of Synfig Studio was compiled against a\n"
1181 "different version of libsynfig than what is currently\n"
1182 "installed. Synfig Studio will now abort. Try downloading\n"
1183 "the latest version from the Synfig website at\n"
1184 "http://synfig.org/Download"
1188 Glib::set_application_name(_("Synfig Studio"));
1190 Splash splash_screen;
1191 splash_screen.show();
1193 shutdown_in_progress=false;
1194 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1195 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1197 // Initialize the Synfig library
1198 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1199 catch(std::runtime_error x)
1201 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1206 get_ui_interface()->error(_("Failed to initialize synfig!"));
1210 // add the preferences to the settings
1211 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1215 studio_init_cb.task(_("Init UI Manager..."));
1216 App::ui_manager_=studio::UIManager::create();
1219 studio_init_cb.task(_("Init Dock Manager..."));
1220 dock_manager=new studio::DockManager();
1222 studio_init_cb.task(_("Init State Manager..."));
1223 state_manager=new StateManager();
1225 studio_init_cb.task(_("Init Toolbox..."));
1226 toolbox=new studio::Toolbox();
1228 studio_init_cb.task(_("Init About Dialog..."));
1229 about=new studio::About();
1231 studio_init_cb.task(_("Init Tool Options..."));
1232 dialog_tool_options=new studio::Dialog_ToolOptions();
1233 dock_manager->register_dockable(*dialog_tool_options);
1235 studio_init_cb.task(_("Init History..."));
1236 dock_history=new studio::Dock_History();
1237 dock_manager->register_dockable(*dock_history);
1239 studio_init_cb.task(_("Init Canvases..."));
1240 dock_canvases=new studio::Dock_Canvases();
1241 dock_manager->register_dockable(*dock_canvases);
1243 studio_init_cb.task(_("Init Keyframes..."));
1244 dock_keyframes=new studio::Dock_Keyframes();
1245 dock_manager->register_dockable(*dock_keyframes);
1247 studio_init_cb.task(_("Init Layers..."));
1248 dock_layers=new studio::Dock_Layers();
1249 dock_manager->register_dockable(*dock_layers);
1251 studio_init_cb.task(_("Init Params..."));
1252 dock_params=new studio::Dock_Params();
1253 dock_manager->register_dockable(*dock_params);
1255 studio_init_cb.task(_("Init MetaData..."));
1256 dock_meta_data=new studio::Dock_MetaData();
1257 dock_manager->register_dockable(*dock_meta_data);
1259 studio_init_cb.task(_("Init Children..."));
1260 dock_children=new studio::Dock_Children();
1261 dock_manager->register_dockable(*dock_children);
1263 studio_init_cb.task(_("Init Info..."));
1264 dock_info = new studio::Dock_Info();
1265 dock_manager->register_dockable(*dock_info);
1267 studio_init_cb.task(_("Init Navigator..."));
1268 dock_navigator = new studio::Dock_Navigator();
1269 dock_manager->register_dockable(*dock_navigator);
1271 studio_init_cb.task(_("Init Timetrack..."));
1272 dock_timetrack = new studio::Dock_Timetrack();
1273 dock_manager->register_dockable(*dock_timetrack);
1275 studio_init_cb.task(_("Init Curve Editor..."));
1276 dock_curves = new studio::Dock_Curves();
1277 dock_manager->register_dockable(*dock_curves);
1279 studio_init_cb.task(_("Init Layer Groups..."));
1280 dock_layer_groups = new studio::Dock_LayerGroups();
1281 dock_manager->register_dockable(*dock_layer_groups);
1284 studio_init_cb.task(_("Init Color Dialog..."));
1285 dialog_color=new studio::Dialog_Color();
1287 studio_init_cb.task(_("Init Gradient Dialog..."));
1288 dialog_gradient=new studio::Dialog_Gradient();
1290 studio_init_cb.task(_("Init DeviceTracker..."));
1291 device_tracker=new studio::DeviceTracker();
1293 studio_init_cb.task(_("Init Tools..."));
1296 state_manager->add_state(&state_normal);
1297 state_manager->add_state(&state_smooth_move);
1298 state_manager->add_state(&state_scale);
1299 state_manager->add_state(&state_rotate);
1300 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
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
1310 state_manager->add_state(&state_bline);
1311 state_manager->add_state(&state_text);
1312 state_manager->add_state(&state_fill);
1313 state_manager->add_state(&state_eyedrop);
1314 state_manager->add_state(&state_zoom);
1316 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1317 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1318 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1320 studio_init_cb.task(_("Init ModPalette..."));
1321 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1323 studio_init_cb.task(_("Init Setup Dialog..."));
1324 dialog_setup=new studio::Dialog_Setup();
1326 studio_init_cb.task(_("Init Input Dialog..."));
1327 dialog_input=new Gtk::InputDialog();
1328 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1329 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1331 studio_init_cb.task(_("Init auto recovery..."));
1332 auto_recover=new AutoRecover();
1334 studio_init_cb.amount_complete(9250,10000);
1335 studio_init_cb.task(_("Loading Settings..."));
1337 device_tracker->load_preferences();
1339 studio_init_cb.task(_("Checking auto-recover..."));
1341 studio_init_cb.amount_complete(9900,10000);
1343 bool opened_any = false;
1344 if(auto_recover->recovery_needed())
1346 splash_screen.hide();
1347 if (get_ui_interface()->confirmation("Crash Recovery",
1348 _("Auto recovery file found"),
1349 _("Synfig Studio seems to have crashed\n"
1350 "before you could save all your files.\n"
1351 "Recover unsaved changes?"),
1352 _("Recover"), _("Ignore"))
1353 == synfigapp::UIInterface::RESPONSE_OK)
1355 int number_recovered;
1356 if(!auto_recover->recover(number_recovered))
1357 if (number_recovered)
1358 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1360 get_ui_interface()->error(_("Unable to recover from previous crash"));
1362 get_ui_interface()->error(
1363 _("Synfig Studio has attempted to recover\n"
1364 "from a previous crash. The files that it has\n"
1365 "recovered are NOT YET SAVED. It would be a good\n"
1366 "idea to review them and save them now."));
1368 if (number_recovered)
1371 splash_screen.show();
1374 // Look for any files given on the command line,
1375 // and load them if found.
1376 for(;*argc>=1;(*argc)--)
1377 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1379 studio_init_cb.task(_("Loading files..."));
1380 splash_screen.hide();
1381 open((*argv)[*argc]);
1383 splash_screen.show();
1386 // if no file was specified to be opened, create a new document to help new users get started more easily
1387 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1390 studio_init_cb.task(_("Done."));
1391 studio_init_cb.amount_complete(10000,10000);
1397 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1401 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1405 StateManager* App::get_state_manager() { return state_manager; }
1409 shutdown_in_progress=true;
1413 synfigapp::Main::settings().remove_domain("pref");
1415 selected_instance=0;
1417 // Unload all of the modules
1418 for(;!module_list_.empty();module_list_.pop_back())
1421 delete state_manager;
1425 delete auto_recover;
1431 // studio::App::iteration(false);
1435 // studio::App::iteration(false);
1437 // studio::App::iteration(false);
1439 delete dialog_setup;
1441 delete dialog_gradient;
1443 delete dialog_color;
1445 delete dialog_input;
1447 delete dock_manager;
1449 instance_list.clear();
1451 // studio::App::iteration(false);
1455 App::get_user_app_directory()
1457 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1459 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1461 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1466 App::get_config_file(const synfig::String& file)
1468 return Glib::build_filename(get_user_app_directory(),file);
1471 #define SCALE_FACTOR (1280)
1472 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1474 App::set_recent_file_window_size(etl::handle<Instance> instance)
1476 int screen_w(Gdk::screen_width());
1477 int screen_h(Gdk::screen_height());
1479 const std::string &canvas_window_size = *recent_files_window_size.begin();
1481 if(canvas_window_size.empty())
1484 synfig::String::size_type current=0;
1485 bool seen_root(false), shown_non_root(false);
1487 while(current != synfig::String::npos)
1489 // find end of first field (canvas) or return
1490 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1491 if(separator == synfig::String::npos) break;
1494 synfig::Canvas::Handle canvas;
1497 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1499 catch(Exception::IDNotFound) {
1500 // can't find the canvas; skip to the next canvas or return
1501 separator = canvas_window_size.find_first_of('\t', current);
1502 if(separator == synfig::String::npos) return;
1503 current = separator+1;
1507 if (canvas->is_root())
1510 shown_non_root = true;
1512 // check that we have the tab character the ends this canvas' data or return
1513 current = separator+1;
1514 separator = canvas_window_size.find_first_of('\t', current);
1515 if(separator == synfig::String::npos) return;
1518 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1520 current = separator+1;
1524 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1525 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1526 x=x*screen_w/SCALE_FACTOR;
1527 y=y*screen_h/SCALE_FACTOR;
1528 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1529 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1530 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1531 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1533 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1534 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1536 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1537 canvasview->move(x,y);
1538 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1539 canvasview->present();
1541 current = separator+1;
1544 if (shown_non_root && !seen_root)
1545 instance->find_canvas_view(instance->get_canvas())->hide();
1549 App::add_recent_file(const etl::handle<Instance> instance)
1551 int screen_w(Gdk::screen_width());
1552 int screen_h(Gdk::screen_height());
1554 std::string canvas_window_size;
1556 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1557 Instance::CanvasViewList::const_iterator iter;
1559 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1561 if( !((*iter)->is_visible()) )
1564 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1565 int x_pos, y_pos, x_size, y_size;
1566 (*iter)->get_position(x_pos,y_pos);
1567 (*iter)->get_size(x_size,y_size);
1569 canvas_window_size += strprintf("%s %d %d %d %d\t",
1570 canvas->get_relative_id(canvas->get_root()).c_str(),
1571 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1572 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1575 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1580 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1582 std::string filename(file_name);
1584 assert(!filename.empty());
1586 if(filename.empty())
1589 // Toss out any "hidden" files
1590 if(basename(filename)[0]=='.')
1593 // If we aren't an absolute path, turn ourselves into one
1594 if(!is_absolute_path(filename))
1595 filename=absolute_path(filename);
1597 std::string old_window_size;
1599 list<string>::iterator iter;
1600 list<string>::iterator iter_wsize;
1601 // Check to see if the file is already on the list.
1602 // If it is, then remove it from the list
1603 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1606 recent_files.erase(iter);
1607 old_window_size = *iter_wsize;
1608 recent_files_window_size.erase(iter_wsize);
1613 // Push the filename to the front of the list
1614 recent_files.push_front(filename);
1615 if(window_size.empty())
1616 recent_files_window_size.push_front(old_window_size);
1618 recent_files_window_size.push_front(window_size);
1620 // Clean out the files at the end of the list.
1621 while(recent_files.size()>(unsigned)get_max_recent_files())
1623 recent_files.pop_back();
1624 recent_files_window_size.pop_back();
1627 signal_recent_files_changed_();
1632 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1635 App::get_time_format()
1637 return _App_time_format;
1641 App::set_time_format(synfig::Time::Format x)
1648 App::save_settings()
1653 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1654 setlocale(LC_NUMERIC, "C");
1656 std::string filename=get_config_file("accelrc");
1657 Gtk::AccelMap::save(filename);
1660 std::string filename=get_config_file("recentfiles");
1662 std::ofstream file(filename.c_str());
1666 synfig::warning("Unable to save %s",filename.c_str());
1670 list<string>::reverse_iterator iter;
1672 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1676 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1678 std::ofstream file(filename.c_str());
1682 synfig::warning("Unable to save %s",filename.c_str());
1686 list<string>::reverse_iterator iter;
1688 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1692 std::string filename=get_config_file("settings");
1693 synfigapp::Main::settings().save_to_file(filename);
1694 setlocale(LC_NUMERIC,old_locale);
1698 synfig::warning("Caught exception when attempting to save settings.");
1703 App::load_settings()
1708 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1709 setlocale(LC_NUMERIC, "C");
1711 std::string filename=get_config_file("accelrc");
1712 Gtk::AccelMap::load(filename);
1715 bool window_size_broken = false;
1717 std::string filename=get_config_file("recentfiles");
1718 std::string filename_window_size=filename+std::string("_window_size");
1720 std::ifstream file(filename.c_str());
1721 std::ifstream file_window_size(filename_window_size.c_str());
1723 if(!file_window_size)
1724 window_size_broken = true;
1728 std::string recent_file;
1729 std::string recent_file_window_size;
1730 getline(file,recent_file);
1731 if(!window_size_broken)
1732 getline(file_window_size,recent_file_window_size);
1733 if(!recent_file.empty())
1735 if(!window_size_broken && !file_window_size)
1736 window_size_broken = true;
1737 if (std::ifstream(recent_file.c_str()))
1739 if(!window_size_broken)
1740 add_recent_file(recent_file,recent_file_window_size);
1742 add_recent_file(recent_file);
1746 if(!window_size_broken && file_window_size)
1747 window_size_broken = true;
1749 if(window_size_broken)
1751 recent_files_window_size.clear();
1752 recent_files_window_size.resize(recent_files.size());
1755 std::string filename=get_config_file("settings");
1756 if(!synfigapp::Main::settings().load_from_file(filename))
1758 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1759 //if(!synfigapp::Main::settings().load_from_file(filename))
1761 gamma.set_gamma(1.0/2.2);
1762 reset_initial_window_configuration();
1765 setlocale(LC_NUMERIC,old_locale);
1769 synfig::warning("Caught exception when attempting to load settings.");
1774 App::reset_initial_window_configuration()
1776 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1777 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1778 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1779 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1780 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1781 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1782 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1783 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1784 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1785 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1786 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1787 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1788 #ifdef SINGLE_THREADED
1789 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1791 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1792 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1793 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1794 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1795 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1796 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1797 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1798 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1799 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1803 App::shutdown_request(GdkEventAny*)
1807 //return !shutdown_in_progress;
1813 if(shutdown_in_progress)return;
1816 get_ui_interface()->task(_("Quit Request"));
1819 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1823 std::list<etl::handle<Instance> >::iterator iter;
1824 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1826 if(!(*iter)->safe_close())
1830 if((*iter)->synfigapp::Instance::get_action_count())
1832 handle<synfigapp::UIInterface> uim;
1833 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1835 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1836 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1838 case synfigapp::UIInterface::RESPONSE_NO:
1840 case synfigapp::UIInterface::RESPONSE_YES:
1843 case synfigapp::UIInterface::RESPONSE_CANCEL:
1852 if((*iter)->synfigapp::Instance::is_modified())
1854 handle<synfigapp::UIInterface> uim;
1855 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1857 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() );
1858 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1860 case synfigapp::UIInterface::RESPONSE_NO:
1862 case synfigapp::UIInterface::RESPONSE_YES:
1863 (*iter)->dialog_cvs_commit();
1865 case synfigapp::UIInterface::RESPONSE_CANCEL:
1874 // This next line causes things to crash for some reason
1878 shutdown_in_progress=true;
1880 instance_list.clear();
1882 while(studio::App::events_pending())studio::App::iteration(false);
1885 auto_recover->normal_shutdown();
1887 get_ui_interface()->task(_("Quit Request sent"));
1893 dialog_setup->refresh();
1894 dialog_setup->show();
1897 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1898 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1901 //#define USE_WIN32_FILE_DIALOGS 1
1904 #ifdef USE_WIN32_FILE_DIALOGS
1905 static OPENFILENAME ofn={};
1909 #include <gdk/gdkwin32.h>
1913 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1915 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1917 #ifdef USE_WIN32_FILE_DIALOGS
1918 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1920 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1921 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1922 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1924 ofn.lStructSize=sizeof(OPENFILENAME);
1925 ofn.hwndOwner = hWnd;
1926 ofn.hInstance = hInstance;
1927 ofn.lpstrFilter = szFilter;
1928 // ofn.lpstrCustomFilter=NULL;
1929 // ofn.nMaxCustFilter=0;
1930 // ofn.nFilterIndex=0;
1931 // ofn.lpstrFile=NULL;
1932 ofn.nMaxFile=MAX_PATH;
1933 // ofn.lpstrFileTitle=NULL;
1934 // ofn.lpstrInitialDir=NULL;
1935 // ofn.lpstrTitle=NULL;
1936 ofn.Flags=OFN_HIDEREADONLY;
1937 // ofn.nFileOffset=0;
1938 // ofn.nFileExtension=0;
1939 ofn.lpstrDefExt=TEXT("sif");
1940 // ofn.lCustData = 0l;
1942 // ofn.lpTemplateName=NULL;
1944 CHAR szFilename[MAX_PATH];
1946 strcpy(szFilename,filename.c_str());
1947 strcpy(szTitle,title.c_str());
1949 ofn.lpstrFile=szFilename;
1950 ofn.lpstrFileTitle=szTitle;
1952 if(GetOpenFileName(&ofn))
1954 filename=szFilename;
1960 synfig::String prev_path;
1962 if(!_preferences.get_value(preference, prev_path))
1965 prev_path = absolute_path(prev_path);
1967 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1969 dialog->set_current_folder(prev_path);
1970 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1971 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1973 if (filename.empty())
1974 dialog->set_filename(prev_path);
1975 else if (is_absolute_path(filename))
1976 dialog->set_filename(filename);
1978 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1980 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1981 filename = dialog->get_filename();
1982 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1983 _preferences.set_value(preference, dirname(filename));
1997 GtkWidget *fileselection;
1998 fileselection = gtk_file_selection_new(title.c_str());
2001 if(basename(filename)==filename)
2003 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
2006 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
2008 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
2010 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
2011 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
2013 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
2014 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
2016 gtk_widget_show(fileselection);
2024 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
2025 _preferences.set_value(preference,dirname(filename));
2029 gtk_widget_destroy(fileselection);
2032 gtk_widget_destroy(fileselection);
2039 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2041 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2043 #if USE_WIN32_FILE_DIALOGS
2044 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2046 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2047 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2048 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2050 ofn.lStructSize=sizeof(OPENFILENAME);
2051 ofn.hwndOwner = hWnd;
2052 ofn.hInstance = hInstance;
2053 ofn.lpstrFilter = szFilter;
2054 // ofn.lpstrCustomFilter=NULL;
2055 // ofn.nMaxCustFilter=0;
2056 // ofn.nFilterIndex=0;
2057 // ofn.lpstrFile=NULL;
2058 ofn.nMaxFile=MAX_PATH;
2059 // ofn.lpstrFileTitle=NULL;
2060 // ofn.lpstrInitialDir=NULL;
2061 // ofn.lpstrTitle=NULL;
2062 ofn.Flags=OFN_OVERWRITEPROMPT;
2063 // ofn.nFileOffset=0;
2064 // ofn.nFileExtension=0;
2065 ofn.lpstrDefExt=TEXT("sif");
2066 // ofn.lCustData = 0l;
2068 // ofn.lpTemplateName=NULL;
2070 CHAR szFilename[MAX_PATH];
2072 strcpy(szFilename,filename.c_str());
2073 strcpy(szTitle,title.c_str());
2075 ofn.lpstrFile=szFilename;
2076 ofn.lpstrFileTitle=szTitle;
2078 if(GetSaveFileName(&ofn))
2080 filename=szFilename;
2081 _preferences.set_value(preference,dirname(filename));
2086 synfig::String prev_path;
2088 if(!_preferences.get_value(preference, prev_path))
2091 prev_path = absolute_path(prev_path);
2093 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2095 dialog->set_current_folder(prev_path);
2096 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2097 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2099 Widget_Enum *file_type_enum = 0;
2100 if (preference == ANIMATION_DIR_PREFERENCE)
2102 file_type_enum = manage(new Widget_Enum());
2103 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2104 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2105 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2106 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2107 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2108 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2110 Gtk::HBox *hbox = manage(new Gtk::HBox);
2111 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2112 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2115 dialog->set_extra_widget(*hbox);
2118 if (filename.empty())
2119 dialog->set_filename(prev_path);
2122 std::string full_path;
2123 if (is_absolute_path(filename))
2124 full_path = filename;
2126 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2128 // select the file if it exists
2129 dialog->set_filename(full_path);
2131 // if the file doesn't exist, put its name into the filename box
2133 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2134 dialog->set_current_name(basename(filename));
2137 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2138 if (preference == ANIMATION_DIR_PREFERENCE)
2139 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2140 filename = dialog->get_filename();
2141 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2142 _preferences.set_value(preference, dirname(filename));
2153 App::dialog_error_blocking(const std::string &title, const std::string &message)
2155 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2156 dialog.set_title(title);
2162 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2164 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2165 dialog.set_title(title);
2171 App::dialog_yes_no(const std::string &title, const std::string &message)
2176 true // use_separator
2178 Gtk::Label label(message);
2181 dialog.get_vbox()->pack_start(label);
2182 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2183 dialog.add_button(Gtk::StockID("gtk-no"),0);
2185 return dialog.run();
2189 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2194 true // use_separator
2196 Gtk::Label label(message);
2199 dialog.get_vbox()->pack_start(label);
2200 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2201 dialog.add_button(Gtk::StockID("gtk-no"),0);
2202 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2204 return dialog.run();
2208 App::dialog_not_implemented()
2210 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2211 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2216 try_open_url(const std::string &url)
2219 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2221 std::vector<std::string> command_line;
2222 std::vector<std::string> browsers;
2223 browsers.reserve(23);
2225 // Browser wrapper scripts
2226 #ifdef USE_OPEN_FOR_URLS
2227 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2229 browsers.push_back("xdg-open"); // XDG wrapper
2230 browsers.push_back("sensible-browser"); // Debian wrapper
2231 browsers.push_back("gnome-open"); // GNOME wrapper
2232 browsers.push_back("kfmclient"); // KDE wrapper
2233 browsers.push_back("exo-open"); // XFCE wrapper
2235 // Alternatives system
2236 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2237 browsers.push_back("x-www-browser"); // Debian GUI alternative
2239 // Individual browsers
2240 browsers.push_back("firefox");
2241 browsers.push_back("epiphany-browser");
2242 browsers.push_back("epiphany");
2243 browsers.push_back("konqueror");
2244 browsers.push_back("iceweasel");
2245 browsers.push_back("mozilla");
2246 browsers.push_back("netscape");
2247 browsers.push_back("icecat");
2248 browsers.push_back("galeon");
2249 browsers.push_back("midori");
2250 browsers.push_back("safari");
2251 browsers.push_back("opera");
2252 browsers.push_back("amaya");
2253 browsers.push_back("netsurf");
2254 browsers.push_back("dillo");
2256 // Try the user-specified browser first
2257 command_line.push_back(App::browser_command);
2258 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2259 command_line.push_back(url);
2261 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2262 catch( Glib::SpawnError& exception ){
2264 while ( !browsers.empty() )
2266 // Skip the browser if we already tried it
2267 if( browsers[0] == App::browser_command )
2270 // Construct the command line
2271 command_line.clear();
2272 command_line.push_back(browsers[0]);
2273 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2274 command_line.push_back(url);
2276 // Remove the browser from the list
2277 browsers.erase(browsers.begin());
2279 // Try to spawn the browser
2280 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2281 // Failed, move on to the next one
2282 catch(Glib::SpawnError& exception){ continue; }
2283 return true; // No exception means we succeeded!
2294 if (!try_open_url("http://synfig.org/Documentation"))
2296 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2297 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2298 dialog.set_title(_("Help"));
2304 App::open_url(const std::string &url)
2306 if(!try_open_url(url))
2308 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2309 dialog.set_secondary_text(url);
2310 dialog.set_title(_("No browser found"));
2316 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2321 true); // use_separator
2323 Gtk::Label label(message);
2325 dialog.get_vbox()->pack_start(label);
2328 entry.set_text(text);
2330 entry.set_activates_default(true);
2332 dialog.get_vbox()->pack_start(entry);
2334 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2335 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2336 dialog.set_default_response(Gtk::RESPONSE_OK);
2338 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2341 if(dialog.run()!=Gtk::RESPONSE_OK)
2344 text=entry.get_text();
2350 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2355 true); // use_separator
2357 Gtk::Label label(message);
2359 dialog.get_vbox()->pack_start(label);
2361 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2362 text_buffer->set_text(text);
2363 Gtk::TextView text_view(text_buffer);
2366 dialog.get_vbox()->pack_start(text_view);
2368 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2369 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2370 dialog.set_default_response(Gtk::RESPONSE_OK);
2372 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2375 if(dialog.run()!=Gtk::RESPONSE_OK)
2378 text=text_buffer->get_text();
2384 App::open(std::string filename)
2386 return open_as(filename,filename);
2389 // this is called from autorecover.cpp:
2390 // App::open_as(get_shadow_file_name(filename),filename)
2391 // other than that, 'filename' and 'as' are the same
2393 App::open_as(std::string filename,std::string as)
2396 char long_name[1024];
2397 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2398 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2399 // don't use it if that's the case
2400 if (long_name[0] != '\0')
2406 OneMoment one_moment;
2407 String errors, warnings;
2409 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2410 if(canvas && get_instance(canvas))
2412 get_instance(canvas)->find_canvas_view(canvas)->present();
2413 info("%s is already open", filename.c_str());
2414 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2419 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2422 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2424 if (as.find(custom_filename_prefix.c_str()) != 0)
2425 add_recent_file(as);
2427 handle<Instance> instance(Instance::create(canvas));
2430 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2432 set_recent_file_window_size(instance);
2436 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)")))
2437 instance->dialog_cvs_update();
2442 dialog_error_blocking(_("Error"), x);
2445 catch(runtime_error x)
2447 dialog_error_blocking(_("Error"), x.what());
2452 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2463 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2465 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2466 canvas->set_name(file_name);
2467 file_name += ".sifz";
2469 canvas->rend_desc().set_frame_rate(preferred_fps);
2470 canvas->rend_desc().set_time_start(0.0);
2471 canvas->rend_desc().set_time_end(5.0);
2472 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2473 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2474 // The top left and botton right positions are expressed in units
2475 // Original convention is that 1 unit = 60 pixels
2476 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2477 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2478 canvas->rend_desc().set_w(preferred_x_size);
2479 canvas->rend_desc().set_h(preferred_y_size);
2480 canvas->rend_desc().set_antialias(1);
2481 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2482 canvas->set_file_name(file_name);
2484 handle<Instance> instance = Instance::create(canvas);
2486 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2487 instance->find_canvas_view(canvas)->canvas_properties.present();
2491 App::dialog_open(string filename)
2493 if (filename.empty())
2496 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2498 // If the filename still has wildcards, then we should
2499 // continue looking for the file we want
2500 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2506 get_ui_interface()->error(_("Unable to open file"));
2511 App::set_selected_instance(etl::loose_handle<Instance> instance)
2513 /* if(get_selected_instance()==instance)
2515 selected_instance=instance;
2516 signal_instance_selected()(instance);
2522 selected_instance=instance;
2523 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2527 instance->focus(instance->get_canvas());
2530 set_selected_canvas_view(0);
2532 signal_instance_selected()(instance);
2536 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2538 selected_canvas_view=canvas_view;
2539 signal_canvas_view_focus()(selected_canvas_view);
2542 selected_instance=canvas_view->get_instance();
2543 signal_instance_selected()(canvas_view->get_instance());
2546 if(get_selected_canvas_view()==canvas_view)
2548 signal_canvas_view_focus()(selected_canvas_view);
2549 signal_instance_selected()(canvas_view->get_instance());
2552 selected_canvas_view=canvas_view;
2553 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2554 set_selected_instance(canvas_view->get_instance());
2555 signal_canvas_view_focus()(selected_canvas_view);
2559 etl::loose_handle<Instance>
2560 App::get_instance(etl::handle<synfig::Canvas> canvas)
2562 if(!canvas) return 0;
2563 canvas=canvas->get_root();
2565 std::list<etl::handle<Instance> >::iterator iter;
2566 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2568 if((*iter)->get_canvas()==canvas)
2584 if(selected_instance)
2585 selected_instance->undo();
2591 if(selected_instance)
2592 selected_instance->redo();
2596 studio::App::get_base_path()
2598 return app_base_path_;