1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2008 Gerald Young
11 ** Copyright (c) 2008 Carlos López
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
24 /* ========================================================================= */
26 /* === H E A D E R S ======================================================= */
45 #ifdef HAVE_SYS_ERRNO_H
46 #include <sys/errno.h>
48 #include <gtkmm/fileselection.h>
49 #include <gtkmm/dialog.h>
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/label.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/stockitem.h>
54 #include <gtkmm/iconsource.h>
55 #include <gtkmm/inputdialog.h>
56 #include <gtkmm/accelmap.h>
57 #include <gtkmm/uimanager.h>
58 #include <gtkmm/textview.h>
62 #include <gdkmm/general.h>
64 #include <synfig/loadcanvas.h>
65 #include <synfig/savecanvas.h>
71 #include "canvasview.h"
72 #include "dialog_setup.h"
73 #include "dialog_gradient.h"
74 #include "dialog_color.h"
77 #include "onemoment.h"
79 #include "dockmanager.h"
81 #include "state_eyedrop.h"
82 #include "state_normal.h"
83 #include "state_draw.h"
84 #include "state_fill.h"
85 #include "state_bline.h"
86 #include "state_polygon.h"
87 #include "state_sketch.h"
88 #include "state_gradient.h"
89 #include "state_circle.h"
90 #include "state_rectangle.h"
91 #include "state_smoothmove.h"
92 #include "state_star.h"
93 #include "state_text.h"
94 #include "state_width.h"
95 #include "state_zoom.h"
97 #include "devicetracker.h"
98 #include "dialog_tooloptions.h"
99 #include "widget_enum.h"
101 #include "autorecover.h"
103 #include <synfigapp/settings.h>
104 #include "dock_history.h"
105 #include "dock_canvases.h"
106 #include "dock_keyframes.h"
107 #include "dock_layers.h"
108 #include "dock_params.h"
109 #include "dock_metadata.h"
110 #include "dock_children.h"
111 #include "dock_info.h"
112 #include "dock_navigator.h"
113 #include "dock_layergroups.h"
114 #include "dock_timetrack.h"
115 #include "dock_curves.h"
117 #include "mod_palette/mod_palette.h"
118 #include "mod_mirror/mod_mirror.h"
120 #include <sys/stat.h>
126 #include "statemanager.h"
132 #include <gtkmm/accelmap.h>
133 #include <gtkmm/filechooser.h>
134 #include <gtkmm/filechooserdialog.h>
140 /* === U S I N G =========================================================== */
144 using namespace synfig;
145 using namespace studio;
147 /* === M A C R O S ========================================================= */
149 #ifndef SYNFIG_USER_APP_DIR
151 #define SYNFIG_USER_APP_DIR "Library/Synfig"
152 #elif defined(_WIN32)
153 #define SYNFIG_USER_APP_DIR "Synfig"
155 #define SYNFIG_USER_APP_DIR ".synfig"
160 #define DPM2DPI(x) (float(x)/39.3700787402f)
161 #define DPI2DPM(x) (float(x)*39.3700787402f)
167 # define IMAGE_DIR "share\\pixmaps"
172 # define IMAGE_DIR "/usr/local/share/pixmaps"
176 # define IMAGE_EXT "tif"
179 #include <synfigapp/main.h>
181 /* === S I G N A L S ======================================================= */
183 static sigc::signal<void> signal_present_all_;
185 App::signal_present_all() { return signal_present_all_; }
187 static sigc::signal<void> signal_recent_files_changed_;
189 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
191 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
192 sigc::signal<void,etl::loose_handle<CanvasView> >&
193 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
195 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
196 sigc::signal<void,etl::handle<Instance> >&
197 App::signal_instance_selected() { return signal_instance_selected_; }
199 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
200 sigc::signal<void,etl::handle<Instance> >&
201 App::signal_instance_created() { return signal_instance_created_; }
203 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
204 sigc::signal<void,etl::handle<Instance> >&
205 App::signal_instance_deleted() { return signal_instance_deleted_; }
207 /* === G L O B A L S ======================================================= */
209 static std::list<std::string> recent_files;
210 const std::list<std::string>& App::get_recent_files() { return recent_files; }
212 static std::list<std::string> recent_files_window_size;
214 int App::Busy::count;
215 bool App::shutdown_in_progress;
217 synfig::Gamma App::gamma;
219 Glib::RefPtr<studio::UIManager> App::ui_manager_;
221 synfig::Distance::System App::distance_system;
223 studio::Dialog_Setup* App::dialog_setup;
225 etl::handle< studio::ModPalette > mod_palette_;
226 //studio::Dialog_Palette* App::dialog_palette;
228 std::list<etl::handle<Instance> > App::instance_list;
230 static etl::handle<synfigapp::UIInterface> ui_interface_;
231 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
233 etl::handle<Instance> App::selected_instance;
234 etl::handle<CanvasView> App::selected_canvas_view;
236 studio::About *studio::App::about=NULL;
238 studio::Toolbox *studio::App::toolbox=NULL;
240 studio::AutoRecover *studio::App::auto_recover=NULL;
242 studio::IPC *ipc=NULL;
244 studio::DockManager* studio::App::dock_manager=0;
246 studio::DeviceTracker* studio::App::device_tracker=0;
248 studio::Dialog_Gradient* studio::App::dialog_gradient;
250 studio::Dialog_Color* studio::App::dialog_color;
252 Gtk::InputDialog* studio::App::dialog_input;
254 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
256 studio::Dock_History* dock_history;
257 studio::Dock_Canvases* dock_canvases;
258 studio::Dock_Keyframes* dock_keyframes;
259 studio::Dock_Layers* dock_layers;
260 studio::Dock_Params* dock_params;
261 studio::Dock_MetaData* dock_meta_data;
262 studio::Dock_Children* dock_children;
263 studio::Dock_Info* dock_info;
264 studio::Dock_LayerGroups* dock_layer_groups;
265 studio::Dock_Navigator* dock_navigator;
266 studio::Dock_Timetrack* dock_timetrack;
267 studio::Dock_Curves* dock_curves;
269 std::list< etl::handle< studio::Module > > module_list_;
271 bool studio::App::use_colorspace_gamma=true;
272 #ifdef SINGLE_THREADED
273 bool studio::App::single_threaded=false;
275 bool studio::App::restrict_radius_ducks=false;
276 bool studio::App::resize_imported_images=false;
277 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
278 int studio::App::preferred_x_size=480;
279 int studio::App::preferred_y_size=270;
280 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
281 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
282 float studio::App::preferred_fps=24.0;
283 #ifdef USE_OPEN_FOR_URLS
284 String studio::App::browser_command("open"); // MacOS only
286 String studio::App::browser_command("xdg-open"); // Linux XDG standard
289 static int max_recent_files_=25;
290 int studio::App::get_max_recent_files() { return max_recent_files_; }
291 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
293 static synfig::String app_base_path_;
298 really_delete_widget(Gtk::Widget *widget)
300 // synfig::info("really delete %p", (void*)widget);
305 // nasty workaround - when we've finished with a popup menu, we want to delete it
306 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
307 // so schedule the real delete to happen in 50ms, giving the action a chance to run
309 delete_widget(Gtk::Widget *widget)
311 // synfig::info("delete %p", (void*)widget);
312 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
315 }; // END of namespace studio
316 studio::StateManager* state_manager;
321 class GlobalUIInterface : public synfigapp::UIInterface
325 virtual Response confirmation(const std::string &title,
326 const std::string &primaryText,
327 const std::string &secondaryText,
328 const std::string &confirmPhrase,
329 const std::string &cancelPhrase,
330 Response defaultResponse)
332 Gtk::MessageDialog dialog(
333 primaryText, // Message
335 Gtk::MESSAGE_WARNING, // Type
336 Gtk::BUTTONS_NONE, // Buttons
341 dialog.set_title(title);
342 if (! secondaryText.empty())
343 dialog.set_secondary_text(secondaryText);
345 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
346 dialog.add_button(confirmPhrase, RESPONSE_OK);
347 dialog.set_default_response(defaultResponse);
350 return (Response) dialog.run();
353 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
358 true // use_separator
360 Gtk::Label label(message);
363 dialog.get_vbox()->pack_start(label);
364 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
365 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
367 dialog.set_default_response(dflt);
369 return (Response)dialog.run();
371 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
376 true // use_separator
378 Gtk::Label label(message);
381 dialog.get_vbox()->pack_start(label);
382 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
383 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
384 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
386 dialog.set_default_response(dflt);
388 return (Response)dialog.run();
390 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
395 true // use_separator
397 Gtk::Label label(message);
400 dialog.get_vbox()->pack_start(label);
401 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
402 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
404 dialog.set_default_response(dflt);
406 return (Response)dialog.run();
410 task(const std::string &task)
412 std::cerr<<task<<std::endl;
413 while(studio::App::events_pending())studio::App::iteration(false);
418 error(const std::string &err)
420 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
427 warning(const std::string &err)
429 std::cerr<<"warning: "<<err<<std::endl;
430 while(studio::App::events_pending())studio::App::iteration(false);
435 amount_complete(int /*current*/, int /*total*/)
437 while(studio::App::events_pending())studio::App::iteration(false);
442 /* === P R O C E D U R E S ================================================= */
446 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
448 action_group_list.push_back(action_group);
449 Gtk::UIManager::insert_action_group(action_group, pos);
453 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
455 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
456 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
457 if(*iter==action_group)
459 action_group_list.erase(iter);
460 Gtk::UIManager::remove_action_group(action_group);
463 synfig::error("Unable to find action group");
467 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
469 ui_manager->insert_action_group(group,0);
471 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
472 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
474 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
476 if(*iter && (*iter)->get_name()!="menus")
478 synfig::info("Removing action group "+(*iter)->get_name());
479 ui_manager->remove_action_group(*iter);
482 ui_manager->insert_action_group(group,0);
484 for(;!prev_groups.empty();prev_groups.pop_front())
486 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
487 ui_manager->insert_action_group(prev_groups.front(),1);
491 class Preferences : public synfigapp::Settings
494 virtual bool get_value(const synfig::String& key, synfig::String& value)const
498 value=strprintf("%f %f %f %f",
499 App::gamma.get_gamma_r(),
500 App::gamma.get_gamma_g(),
501 App::gamma.get_gamma_b(),
502 App::gamma.get_black_level()
506 if(key=="time_format")
508 value=strprintf("%i",App::get_time_format());
511 if(key=="file_history.size")
513 value=strprintf("%i",App::get_max_recent_files());
516 if(key=="use_colorspace_gamma")
518 value=strprintf("%i",(int)App::use_colorspace_gamma);
521 if(key=="distance_system")
523 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
526 #ifdef SINGLE_THREADED
527 if(key=="single_threaded")
529 value=strprintf("%i",(int)App::single_threaded);
533 if(key=="auto_recover_backup_interval")
535 value=strprintf("%i",App::auto_recover->get_timeout());
538 if(key=="restrict_radius_ducks")
540 value=strprintf("%i",(int)App::restrict_radius_ducks);
543 if(key=="resize_imported_images")
545 value=strprintf("%i",(int)App::resize_imported_images);
548 if(key=="browser_command")
550 value=App::browser_command;
553 if(key=="custom_filename_prefix")
555 value=App::custom_filename_prefix;
558 if(key=="preferred_x_size")
560 value=strprintf("%i",App::preferred_x_size);
563 if(key=="preferred_y_size")
565 value=strprintf("%i",App::preferred_y_size);
568 if(key=="predefined_size")
570 value=strprintf("%s",App::predefined_size.c_str());
573 if(key=="preferred_fps")
575 value=strprintf("%f",App::preferred_fps);
578 if(key=="predefined_fps")
580 value=strprintf("%s",App::predefined_fps.c_str());
584 return synfigapp::Settings::get_value(key,value);
587 virtual bool set_value(const synfig::String& key,const synfig::String& value)
593 strscanf(value,"%f %f %f %f",
600 App::gamma.set_all(r,g,b,blk);
604 if(key=="time_format")
606 int i(atoi(value.c_str()));
607 App::set_time_format(static_cast<synfig::Time::Format>(i));
610 if(key=="auto_recover_backup_interval")
612 int i(atoi(value.c_str()));
613 App::auto_recover->set_timeout(i);
616 if(key=="file_history.size")
618 int i(atoi(value.c_str()));
619 App::set_max_recent_files(i);
622 if(key=="use_colorspace_gamma")
624 int i(atoi(value.c_str()));
625 App::use_colorspace_gamma=i;
628 if(key=="distance_system")
630 App::distance_system=Distance::ident_system(value);;
633 #ifdef SINGLE_THREADED
634 if(key=="single_threaded")
636 int i(atoi(value.c_str()));
637 App::single_threaded=i;
641 if(key=="restrict_radius_ducks")
643 int i(atoi(value.c_str()));
644 App::restrict_radius_ducks=i;
647 if(key=="resize_imported_images")
649 int i(atoi(value.c_str()));
650 App::resize_imported_images=i;
653 if(key=="browser_command")
655 App::browser_command=value;
658 if(key=="custom_filename_prefix")
660 App::custom_filename_prefix=value;
663 if(key=="preferred_x_size")
665 int i(atoi(value.c_str()));
666 App::preferred_x_size=i;
669 if(key=="preferred_y_size")
671 int i(atoi(value.c_str()));
672 App::preferred_y_size=i;
675 if(key=="predefined_size")
677 App::predefined_size=value;
680 if(key=="preferred_fps")
682 float i(atof(value.c_str()));
683 App::preferred_fps=i;
686 if(key=="predefined_fps")
688 App::predefined_fps=value;
692 return synfigapp::Settings::set_value(key,value);
695 virtual KeyList get_key_list()const
697 KeyList ret(synfigapp::Settings::get_key_list());
698 ret.push_back("gamma");
699 ret.push_back("time_format");
700 ret.push_back("distance_system");
701 ret.push_back("file_history.size");
702 ret.push_back("use_colorspace_gamma");
703 #ifdef SINGLE_THREADED
704 ret.push_back("single_threaded");
706 ret.push_back("auto_recover_backup_interval");
707 ret.push_back("restrict_radius_ducks");
708 ret.push_back("resize_imported_images");
709 ret.push_back("browser_command");
710 ret.push_back("custom_filename_prefix");
711 ret.push_back("preferred_x_size");
712 ret.push_back("preferred_y_size");
713 ret.push_back("predefined_size");
714 ret.push_back("preferred_fps");
715 ret.push_back("predefined_fps");
720 static ::Preferences _preferences;
725 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
727 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
729 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
731 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
732 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
733 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
734 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
735 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
736 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
737 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
738 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
739 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
740 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
741 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
742 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
743 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
745 // Add the synfigapp actions...
746 synfigapp::Action::Book::iterator iter;
747 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
749 actions_action_group->add(Gtk::Action::create(
750 "action-"+iter->second.name,
751 get_action_stock_id(iter->second),
752 iter->second.local_name,iter->second.local_name
756 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
757 #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); }
758 #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); }
760 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
761 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
762 DEFINE_ACTION("new", Gtk::Stock::NEW);
763 DEFINE_ACTION("open", Gtk::Stock::OPEN);
764 DEFINE_ACTION("save", Gtk::Stock::SAVE);
765 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
766 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
767 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
768 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
769 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
770 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
771 DEFINE_ACTION("import", _("Import"));
772 DEFINE_ACTION("render", _("Render"));
773 DEFINE_ACTION("preview", _("Preview"));
774 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
775 DEFINE_ACTION("sound", _("Sound File"));
776 DEFINE_ACTION("options", _("Options"));
777 DEFINE_ACTION("close", _("Close View"));
778 DEFINE_ACTION("close-document", _("Close Document"));
779 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
782 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
783 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
784 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
785 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
786 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
787 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
788 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
789 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
790 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
791 DEFINE_ACTION("properties", _("Properties"));
793 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
794 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
795 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
796 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
797 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
798 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
799 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
800 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
801 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
802 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
803 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
804 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
805 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
806 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
807 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
808 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
809 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
810 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
811 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
812 DEFINE_ACTION("play", _("Play"));
813 // DEFINE_ACTION("pause", _("Pause"));
814 DEFINE_ACTION("stop", _("Stop"));
815 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
816 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
817 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
818 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
819 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
820 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
821 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
822 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
823 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
824 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
825 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
826 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
827 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
828 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
829 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
830 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
831 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
832 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
833 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
834 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
835 DEFINE_ACTION("seek-end", _("Seek to End"));
837 DEFINE_ACTION("action-group_add", _("Add group"));
839 DEFINE_ACTION("canvas-new", _("New Canvas"));
841 DEFINE_ACTION("amount-inc", _("Increase Amount"));
842 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
847 // Set up synfigapp actions
849 synfigapp::Action::Book::iterator iter;
851 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
853 Gtk::StockID stock_id;
855 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
857 //Gtk::Image* image(manage(new Gtk::Image()));
858 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
859 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
860 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
861 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
862 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
863 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
864 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
865 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
866 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
867 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
869 actions_action_group->add(Gtk::Action::create(
870 "action-"+iter->second.name,
872 iter->second.local_name,iter->second.local_name
880 Glib::ustring ui_info =
882 " <popup name='menu-toolbox' action='menu-toolbox'>"
883 " <menu action='menu-file'>"
886 " <popup name='menu-main' action='menu-main'>"
887 " <menu action='menu-file'>"
888 " <menuitem action='new' />"
889 " <menuitem action='open' />"
890 " <menuitem action='save' />"
891 " <menuitem action='save-as' />"
892 " <menuitem action='revert' />"
893 " <separator name='bleh01'/>"
894 " <menuitem action='cvs-add' />"
895 " <menuitem action='cvs-update' />"
896 " <menuitem action='cvs-commit' />"
897 " <menuitem action='cvs-revert' />"
898 " <separator name='bleh02'/>"
899 " <menuitem action='import' />"
900 " <separator name='bleh03'/>"
901 " <menuitem action='render' />"
902 " <menuitem action='preview' />"
903 " <menuitem action='sound' />"
904 " <separator name='bleh04'/>"
905 " <menuitem action='options' />"
906 " <menuitem action='close' />"
907 " <menuitem action='close-document' />"
908 " <menuitem action='quit' />"
910 " <menu action='menu-edit'>"
911 " <menuitem action='undo'/>"
912 " <menuitem action='redo'/>"
913 " <separator name='bleh05'/>"
914 " <menuitem action='cut'/>"
915 " <menuitem action='copy'/>"
916 " <menuitem action='paste'/>"
917 " <separator name='bleh06'/>"
918 " <menuitem action='select-all-layers'/>"
919 " <menuitem action='unselect-all-layers'/>"
920 " <menuitem action='select-all-ducks'/>"
921 " <menuitem action='unselect-all-ducks'/>"
922 " <separator name='bleh07'/>"
923 " <menuitem action='properties'/>"
925 " <menu action='menu-view'>"
926 " <menu action='menu-duck-mask'>"
927 " <menuitem action='mask-position-ducks' />"
928 " <menuitem action='mask-vertex-ducks' />"
929 " <menuitem action='mask-tangent-ducks' />"
930 " <menuitem action='mask-radius-ducks' />"
931 " <menuitem action='mask-width-ducks' />"
932 " <menuitem action='mask-angle-ducks' />"
934 " <menu action='menu-preview-quality'>"
935 " <menuitem action='quality-00' />"
936 " <menuitem action='quality-01' />"
937 " <menuitem action='quality-02' />"
938 " <menuitem action='quality-03' />"
939 " <menuitem action='quality-04' />"
940 " <menuitem action='quality-05' />"
941 " <menuitem action='quality-06' />"
942 " <menuitem action='quality-07' />"
943 " <menuitem action='quality-08' />"
944 " <menuitem action='quality-09' />"
945 " <menuitem action='quality-10' />"
947 " <menu action='menu-lowres-pixel'>"
948 " <menuitem action='decrease-low-res-pixel-size'/>"
949 " <menuitem action='increase-low-res-pixel-size'/>"
950 " <separator name='pixel-size-separator'/>"
953 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
954 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
958 " <separator name='bleh08'/>"
959 " <menuitem action='play'/>"
960 //" <menuitem action='pause'/>"
961 " <menuitem action='stop'/>"
962 " <menuitem action='dialog-flipbook'/>"
963 " <separator name='bleh09'/>"
964 " <menuitem action='toggle-grid-show'/>"
965 " <menuitem action='toggle-grid-snap'/>"
966 " <menuitem action='toggle-guide-show'/>"
967 " <menuitem action='toggle-low-res'/>"
968 " <menuitem action='toggle-onion-skin'/>"
969 " <separator name='bleh10'/>"
970 " <menuitem action='canvas-zoom-in'/>"
971 " <menuitem action='canvas-zoom-out'/>"
972 " <menuitem action='canvas-zoom-fit'/>"
973 " <menuitem action='canvas-zoom-100'/>"
974 " <separator name='bleh11'/>"
975 " <menuitem action='time-zoom-in'/>"
976 " <menuitem action='time-zoom-out'/>"
977 " <separator name='bleh12'/>"
978 " <menuitem action='jump-next-keyframe'/>"
979 " <menuitem action='jump-prev-keyframe'/>"
980 " <menuitem action='seek-next-frame'/>"
981 " <menuitem action='seek-prev-frame'/>"
982 " <menuitem action='seek-next-second'/>"
983 " <menuitem action='seek-prev-second'/>"
984 " <menuitem action='seek-begin'/>"
985 " <menuitem action='seek-end'/>"
987 " <menu action='menu-canvas'>"
988 " <menuitem action='canvas-new'/>"
990 " <menu name='menu-state' action='menu-state'>"
992 " <menu action='menu-group'>"
993 " <menuitem action='action-group_add'/>"
995 " <menu action='menu-layer'>"
996 //" <menuitem action='cut'/>"
997 //" <menuitem action='copy'/>"
998 //" <menuitem action='paste'/>"
999 //" <separator name='bleh06'/>"
1000 " <menu action='menu-layer-new'></menu>"
1001 " <menuitem action='amount-inc'/>"
1002 " <menuitem action='amount-dec'/>"
1004 " <menu action='menu-keyframe'>"
1005 " <menuitem action='keyframe-properties'/>"
1012 " <menubar name='MenuBar'>"
1013 " <menu action='MenuFile'>"
1014 " <menuitem action='New'/>"
1015 " <menuitem action='Open'/>"
1017 " <menuitem action='Quit'/>"
1019 " <menu action='MenuEdit'>"
1020 " <menuitem action='Cut'/>"
1021 " <menuitem action='Copy'/>"
1022 " <menuitem action='Paste'/>"
1025 " <toolbar name='ToolBar'>"
1026 " <toolitem action='Open'/>"
1027 " <toolitem action='Quit'/>"
1033 actions_action_group->set_sensitive(false);
1034 App::ui_manager()->set_add_tearoffs(true);
1035 App::ui_manager()->insert_action_group(menus_action_group,1);
1036 App::ui_manager()->insert_action_group(actions_action_group,1);
1037 App::ui_manager()->add_ui_from_string(ui_info);
1039 //App::ui_manager()->get_accel_group()->unlock();
1041 catch(const Glib::Error& ex)
1043 synfig::error("building menus and toolbars failed: " + ex.what());
1046 // Add default keyboard accelerators
1047 #define ACCEL(accel,path) \
1049 Gtk::AccelKey accel_key(accel,path); \
1050 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1053 #define ACCEL2(accel) \
1055 Gtk::AccelKey accel_key(accel); \
1056 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1060 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1061 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1062 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1063 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1064 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1065 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1066 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1067 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1068 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1069 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1070 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1071 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1072 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1073 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1074 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1075 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1076 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1077 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1080 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1081 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1082 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1083 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1084 ACCEL("F9", "<Actions>/canvasview/render" );
1085 ACCEL("F11", "<Actions>/canvasview/preview" );
1086 ACCEL("F8", "<Actions>/canvasview/properties" );
1087 ACCEL("F12", "<Actions>/canvasview/options" );
1088 ACCEL("<control>i", "<Actions>/canvasview/import" );
1089 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1090 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1091 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1092 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1093 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1094 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1095 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1096 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1097 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1098 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1099 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1100 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1101 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1102 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1103 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1104 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1105 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1106 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1107 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1108 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1109 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1110 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1111 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1112 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1113 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1114 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1115 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1116 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1117 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1118 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1119 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1120 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1121 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1122 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1123 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1124 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1125 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1126 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1127 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1128 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1129 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1130 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1131 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1132 ACCEL("End", "<Actions>/canvasview/seek-end" );
1138 #define mkdir(x,y) mkdir(x)
1141 /* === M E T H O D S ======================================================= */
1143 App::App(int *argc, char ***argv):
1144 Gtk::Main(argc,argv),
1145 IconController(etl::dirname((*argv)[0]))
1147 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1150 ui_interface_=new GlobalUIInterface();
1154 // don't call thread_init() if threads are already initialized
1155 // on some machines bonobo_init() initialized threads before we get here
1156 if (!g_thread_supported())
1157 Glib::thread_init();
1159 distance_system=Distance::SYSTEM_UNITS;
1161 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1164 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1168 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1174 if(!SYNFIG_CHECK_VERSION())
1176 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1177 dialog_error_blocking("Synfig Studio",
1178 "This copy of Synfig Studio was compiled against a\n"
1179 "different version of libsynfig than what is currently\n"
1180 "installed. Synfig Studio will now abort. Try downloading\n"
1181 "the latest version from the Synfig website at\n"
1182 "http://synfig.org/Download"
1186 Glib::set_application_name(_("Synfig Studio"));
1188 Splash splash_screen;
1189 splash_screen.show();
1191 shutdown_in_progress=false;
1192 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1193 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1195 // Initialize the Synfig library
1196 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1197 catch(std::runtime_error x)
1199 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1204 get_ui_interface()->error(_("Failed to initialize synfig!"));
1208 // add the preferences to the settings
1209 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1213 studio_init_cb.task(_("Init UI Manager..."));
1214 App::ui_manager_=studio::UIManager::create();
1217 studio_init_cb.task(_("Init Dock Manager..."));
1218 dock_manager=new studio::DockManager();
1220 studio_init_cb.task(_("Init State Manager..."));
1221 state_manager=new StateManager();
1223 studio_init_cb.task(_("Init Toolbox..."));
1224 toolbox=new studio::Toolbox();
1226 studio_init_cb.task(_("Init About Dialog..."));
1227 about=new studio::About();
1229 studio_init_cb.task(_("Init Tool Options..."));
1230 dialog_tool_options=new studio::Dialog_ToolOptions();
1231 dock_manager->register_dockable(*dialog_tool_options);
1233 studio_init_cb.task(_("Init History..."));
1234 dock_history=new studio::Dock_History();
1235 dock_manager->register_dockable(*dock_history);
1237 studio_init_cb.task(_("Init Canvases..."));
1238 dock_canvases=new studio::Dock_Canvases();
1239 dock_manager->register_dockable(*dock_canvases);
1241 studio_init_cb.task(_("Init Keyframes..."));
1242 dock_keyframes=new studio::Dock_Keyframes();
1243 dock_manager->register_dockable(*dock_keyframes);
1245 studio_init_cb.task(_("Init Layers..."));
1246 dock_layers=new studio::Dock_Layers();
1247 dock_manager->register_dockable(*dock_layers);
1249 studio_init_cb.task(_("Init Params..."));
1250 dock_params=new studio::Dock_Params();
1251 dock_manager->register_dockable(*dock_params);
1253 studio_init_cb.task(_("Init MetaData..."));
1254 dock_meta_data=new studio::Dock_MetaData();
1255 dock_manager->register_dockable(*dock_meta_data);
1257 studio_init_cb.task(_("Init Children..."));
1258 dock_children=new studio::Dock_Children();
1259 dock_manager->register_dockable(*dock_children);
1261 studio_init_cb.task(_("Init Info..."));
1262 dock_info = new studio::Dock_Info();
1263 dock_manager->register_dockable(*dock_info);
1265 studio_init_cb.task(_("Init Navigator..."));
1266 dock_navigator = new studio::Dock_Navigator();
1267 dock_manager->register_dockable(*dock_navigator);
1269 studio_init_cb.task(_("Init Timetrack..."));
1270 dock_timetrack = new studio::Dock_Timetrack();
1271 dock_manager->register_dockable(*dock_timetrack);
1273 studio_init_cb.task(_("Init Curve Editor..."));
1274 dock_curves = new studio::Dock_Curves();
1275 dock_manager->register_dockable(*dock_curves);
1277 studio_init_cb.task(_("Init Layer Groups..."));
1278 dock_layer_groups = new studio::Dock_LayerGroups();
1279 dock_manager->register_dockable(*dock_layer_groups);
1282 studio_init_cb.task(_("Init Color Dialog..."));
1283 dialog_color=new studio::Dialog_Color();
1285 studio_init_cb.task(_("Init Gradient Dialog..."));
1286 dialog_gradient=new studio::Dialog_Gradient();
1288 studio_init_cb.task(_("Init DeviceTracker..."));
1289 device_tracker=new studio::DeviceTracker();
1291 studio_init_cb.task(_("Init Tools..."));
1294 state_manager->add_state(&state_normal);
1295 state_manager->add_state(&state_smooth_move);
1296 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1297 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1300 state_manager->add_state(&state_bline);
1301 state_manager->add_state(&state_circle);
1302 state_manager->add_state(&state_rectangle);
1303 state_manager->add_state(&state_star);
1304 state_manager->add_state(&state_gradient);
1305 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1306 state_manager->add_state(&state_text);
1307 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1311 state_manager->add_state(&state_fill);
1312 state_manager->add_state(&state_eyedrop);
1313 state_manager->add_state(&state_zoom);
1314 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1316 studio_init_cb.task(_("Init ModPalette..."));
1317 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1319 studio_init_cb.task(_("Init Setup Dialog..."));
1320 dialog_setup=new studio::Dialog_Setup();
1322 studio_init_cb.task(_("Init Input Dialog..."));
1323 dialog_input=new Gtk::InputDialog();
1324 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1325 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1327 studio_init_cb.task(_("Init auto recovery..."));
1328 auto_recover=new AutoRecover();
1330 studio_init_cb.amount_complete(9250,10000);
1331 studio_init_cb.task(_("Loading Settings..."));
1333 device_tracker->load_preferences();
1335 studio_init_cb.task(_("Checking auto-recover..."));
1337 studio_init_cb.amount_complete(9900,10000);
1339 bool opened_any = false;
1340 if(auto_recover->recovery_needed())
1342 splash_screen.hide();
1343 if (get_ui_interface()->confirmation("Crash Recovery",
1344 _("Auto recovery file found"),
1345 _("Synfig Studio seems to have crashed\n"
1346 "before you could save all your files.\n"
1347 "Recover unsaved changes?"),
1348 _("Recover"), _("Ignore"))
1349 == synfigapp::UIInterface::RESPONSE_OK)
1351 int number_recovered;
1352 if(!auto_recover->recover(number_recovered))
1353 if (number_recovered)
1354 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1356 get_ui_interface()->error(_("Unable to recover from previous crash"));
1358 get_ui_interface()->error(
1359 _("Synfig Studio has attempted to recover\n"
1360 "from a previous crash. The files that it has\n"
1361 "recovered are NOT YET SAVED. It would be a good\n"
1362 "idea to review them and save them now."));
1364 if (number_recovered)
1367 splash_screen.show();
1370 // Look for any files given on the command line,
1371 // and load them if found.
1372 for(;*argc>=1;(*argc)--)
1373 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1375 studio_init_cb.task(_("Loading files..."));
1376 splash_screen.hide();
1377 open((*argv)[*argc]);
1379 splash_screen.show();
1382 // if no file was specified to be opened, create a new document to help new users get started more easily
1383 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1386 studio_init_cb.task(_("Done."));
1387 studio_init_cb.amount_complete(10000,10000);
1393 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1397 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1401 StateManager* App::get_state_manager() { return state_manager; }
1405 shutdown_in_progress=true;
1409 synfigapp::Main::settings().remove_domain("pref");
1411 selected_instance=0;
1413 // Unload all of the modules
1414 for(;!module_list_.empty();module_list_.pop_back())
1417 delete state_manager;
1421 delete auto_recover;
1427 // studio::App::iteration(false);
1431 // studio::App::iteration(false);
1433 // studio::App::iteration(false);
1435 delete dialog_setup;
1437 delete dialog_gradient;
1439 delete dialog_color;
1441 delete dialog_input;
1443 delete dock_manager;
1445 instance_list.clear();
1447 // studio::App::iteration(false);
1451 App::get_user_app_directory()
1453 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1455 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1457 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1462 App::get_config_file(const synfig::String& file)
1464 return Glib::build_filename(get_user_app_directory(),file);
1467 #define SCALE_FACTOR (1280)
1468 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1470 App::set_recent_file_window_size(etl::handle<Instance> instance)
1472 int screen_w(Gdk::screen_width());
1473 int screen_h(Gdk::screen_height());
1475 const std::string &canvas_window_size = *recent_files_window_size.begin();
1477 if(canvas_window_size.empty())
1480 synfig::String::size_type current=0;
1481 bool seen_root(false), shown_non_root(false);
1483 while(current != synfig::String::npos)
1485 // find end of first field (canvas) or return
1486 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1487 if(separator == synfig::String::npos) break;
1490 synfig::Canvas::Handle canvas;
1493 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1495 catch(Exception::IDNotFound) {
1496 // can't find the canvas; skip to the next canvas or return
1497 separator = canvas_window_size.find_first_of('\t', current);
1498 if(separator == synfig::String::npos) return;
1499 current = separator+1;
1503 if (canvas->is_root())
1506 shown_non_root = true;
1508 // check that we have the tab character the ends this canvas' data or return
1509 current = separator+1;
1510 separator = canvas_window_size.find_first_of('\t', current);
1511 if(separator == synfig::String::npos) return;
1514 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1516 current = separator+1;
1520 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1521 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1522 x=x*screen_w/SCALE_FACTOR;
1523 y=y*screen_h/SCALE_FACTOR;
1524 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1525 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1526 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1527 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1529 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1530 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1532 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1533 canvasview->move(x,y);
1534 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1535 canvasview->present();
1537 current = separator+1;
1540 if (shown_non_root && !seen_root)
1541 instance->find_canvas_view(instance->get_canvas())->hide();
1545 App::add_recent_file(const etl::handle<Instance> instance)
1547 int screen_w(Gdk::screen_width());
1548 int screen_h(Gdk::screen_height());
1550 std::string canvas_window_size;
1552 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1553 Instance::CanvasViewList::const_iterator iter;
1555 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1557 if( !((*iter)->is_visible()) )
1560 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1561 int x_pos, y_pos, x_size, y_size;
1562 (*iter)->get_position(x_pos,y_pos);
1563 (*iter)->get_size(x_size,y_size);
1565 canvas_window_size += strprintf("%s %d %d %d %d\t",
1566 canvas->get_relative_id(canvas->get_root()).c_str(),
1567 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1568 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1571 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1576 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1578 std::string filename(file_name);
1580 assert(!filename.empty());
1582 if(filename.empty())
1585 // Toss out any "hidden" files
1586 if(basename(filename)[0]=='.')
1589 // If we aren't an absolute path, turn ourselves into one
1590 if(!is_absolute_path(filename))
1591 filename=absolute_path(filename);
1593 std::string old_window_size;
1595 list<string>::iterator iter;
1596 list<string>::iterator iter_wsize;
1597 // Check to see if the file is already on the list.
1598 // If it is, then remove it from the list
1599 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1602 recent_files.erase(iter);
1603 old_window_size = *iter_wsize;
1604 recent_files_window_size.erase(iter_wsize);
1609 // Push the filename to the front of the list
1610 recent_files.push_front(filename);
1611 if(window_size.empty())
1612 recent_files_window_size.push_front(old_window_size);
1614 recent_files_window_size.push_front(window_size);
1616 // Clean out the files at the end of the list.
1617 while(recent_files.size()>(unsigned)get_max_recent_files())
1619 recent_files.pop_back();
1620 recent_files_window_size.pop_back();
1623 signal_recent_files_changed_();
1628 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1631 App::get_time_format()
1633 return _App_time_format;
1637 App::set_time_format(synfig::Time::Format x)
1644 App::save_settings()
1649 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1650 setlocale(LC_NUMERIC, "C");
1652 std::string filename=get_config_file("accelrc");
1653 Gtk::AccelMap::save(filename);
1656 std::string filename=get_config_file("recentfiles");
1658 std::ofstream file(filename.c_str());
1662 synfig::warning("Unable to save %s",filename.c_str());
1666 list<string>::reverse_iterator iter;
1668 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1672 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1674 std::ofstream file(filename.c_str());
1678 synfig::warning("Unable to save %s",filename.c_str());
1682 list<string>::reverse_iterator iter;
1684 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1688 std::string filename=get_config_file("settings");
1689 synfigapp::Main::settings().save_to_file(filename);
1690 setlocale(LC_NUMERIC,old_locale);
1694 synfig::warning("Caught exception when attempting to save settings.");
1699 App::load_settings()
1704 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1705 setlocale(LC_NUMERIC, "C");
1707 std::string filename=get_config_file("accelrc");
1708 Gtk::AccelMap::load(filename);
1711 bool window_size_broken = false;
1713 std::string filename=get_config_file("recentfiles");
1714 std::string filename_window_size=filename+std::string("_window_size");
1716 std::ifstream file(filename.c_str());
1717 std::ifstream file_window_size(filename_window_size.c_str());
1719 if(!file_window_size)
1720 window_size_broken = true;
1724 std::string recent_file;
1725 std::string recent_file_window_size;
1726 getline(file,recent_file);
1727 if(!window_size_broken)
1728 getline(file_window_size,recent_file_window_size);
1729 if(!recent_file.empty())
1731 if(!window_size_broken && !file_window_size)
1732 window_size_broken = true;
1733 if (std::ifstream(recent_file.c_str()))
1735 if(!window_size_broken)
1736 add_recent_file(recent_file,recent_file_window_size);
1738 add_recent_file(recent_file);
1742 if(!window_size_broken && file_window_size)
1743 window_size_broken = true;
1745 if(window_size_broken)
1747 recent_files_window_size.clear();
1748 recent_files_window_size.resize(recent_files.size());
1751 std::string filename=get_config_file("settings");
1752 if(!synfigapp::Main::settings().load_from_file(filename))
1754 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1755 //if(!synfigapp::Main::settings().load_from_file(filename))
1757 gamma.set_gamma(1.0/2.2);
1758 reset_initial_window_configuration();
1761 setlocale(LC_NUMERIC,old_locale);
1765 synfig::warning("Caught exception when attempting to load settings.");
1770 App::reset_initial_window_configuration()
1772 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1773 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1774 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1775 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1776 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1777 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1778 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1779 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1780 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1781 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1782 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1783 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1784 #ifdef SINGLE_THREADED
1785 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1787 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1788 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1789 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1790 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1791 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1792 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1793 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1794 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1795 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1799 App::shutdown_request(GdkEventAny*)
1803 //return !shutdown_in_progress;
1809 if(shutdown_in_progress)return;
1812 get_ui_interface()->task(_("Quit Request"));
1815 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1819 std::list<etl::handle<Instance> >::iterator iter;
1820 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1822 if(!(*iter)->safe_close())
1826 if((*iter)->synfigapp::Instance::get_action_count())
1828 handle<synfigapp::UIInterface> uim;
1829 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1831 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1832 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1834 case synfigapp::UIInterface::RESPONSE_NO:
1836 case synfigapp::UIInterface::RESPONSE_YES:
1839 case synfigapp::UIInterface::RESPONSE_CANCEL:
1848 if((*iter)->synfigapp::Instance::is_modified())
1850 handle<synfigapp::UIInterface> uim;
1851 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1853 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() );
1854 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1856 case synfigapp::UIInterface::RESPONSE_NO:
1858 case synfigapp::UIInterface::RESPONSE_YES:
1859 (*iter)->dialog_cvs_commit();
1861 case synfigapp::UIInterface::RESPONSE_CANCEL:
1870 // This next line causes things to crash for some reason
1874 shutdown_in_progress=true;
1876 instance_list.clear();
1878 while(studio::App::events_pending())studio::App::iteration(false);
1881 auto_recover->normal_shutdown();
1883 get_ui_interface()->task(_("Quit Request sent"));
1889 dialog_setup->refresh();
1890 dialog_setup->show();
1893 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1894 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1897 //#define USE_WIN32_FILE_DIALOGS 1
1900 #ifdef USE_WIN32_FILE_DIALOGS
1901 static OPENFILENAME ofn={};
1905 #include <gdk/gdkwin32.h>
1909 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1911 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1913 #ifdef USE_WIN32_FILE_DIALOGS
1914 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1916 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1917 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1918 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1920 ofn.lStructSize=sizeof(OPENFILENAME);
1921 ofn.hwndOwner = hWnd;
1922 ofn.hInstance = hInstance;
1923 ofn.lpstrFilter = szFilter;
1924 // ofn.lpstrCustomFilter=NULL;
1925 // ofn.nMaxCustFilter=0;
1926 // ofn.nFilterIndex=0;
1927 // ofn.lpstrFile=NULL;
1928 ofn.nMaxFile=MAX_PATH;
1929 // ofn.lpstrFileTitle=NULL;
1930 // ofn.lpstrInitialDir=NULL;
1931 // ofn.lpstrTitle=NULL;
1932 ofn.Flags=OFN_HIDEREADONLY;
1933 // ofn.nFileOffset=0;
1934 // ofn.nFileExtension=0;
1935 ofn.lpstrDefExt=TEXT("sif");
1936 // ofn.lCustData = 0l;
1938 // ofn.lpTemplateName=NULL;
1940 CHAR szFilename[MAX_PATH];
1942 strcpy(szFilename,filename.c_str());
1943 strcpy(szTitle,title.c_str());
1945 ofn.lpstrFile=szFilename;
1946 ofn.lpstrFileTitle=szTitle;
1948 if(GetOpenFileName(&ofn))
1950 filename=szFilename;
1956 synfig::String prev_path;
1958 if(!_preferences.get_value(preference, prev_path))
1961 prev_path = absolute_path(prev_path);
1963 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1965 dialog->set_current_folder(prev_path);
1966 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1967 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1969 if (filename.empty())
1970 dialog->set_filename(prev_path);
1971 else if (is_absolute_path(filename))
1972 dialog->set_filename(filename);
1974 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1976 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1977 filename = dialog->get_filename();
1978 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1979 _preferences.set_value(preference, dirname(filename));
1993 GtkWidget *fileselection;
1994 fileselection = gtk_file_selection_new(title.c_str());
1997 if(basename(filename)==filename)
1999 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
2002 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
2004 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
2006 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
2007 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
2009 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
2010 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
2012 gtk_widget_show(fileselection);
2020 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
2021 _preferences.set_value(preference,dirname(filename));
2025 gtk_widget_destroy(fileselection);
2028 gtk_widget_destroy(fileselection);
2035 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2037 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2039 #if USE_WIN32_FILE_DIALOGS
2040 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2042 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2043 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2044 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2046 ofn.lStructSize=sizeof(OPENFILENAME);
2047 ofn.hwndOwner = hWnd;
2048 ofn.hInstance = hInstance;
2049 ofn.lpstrFilter = szFilter;
2050 // ofn.lpstrCustomFilter=NULL;
2051 // ofn.nMaxCustFilter=0;
2052 // ofn.nFilterIndex=0;
2053 // ofn.lpstrFile=NULL;
2054 ofn.nMaxFile=MAX_PATH;
2055 // ofn.lpstrFileTitle=NULL;
2056 // ofn.lpstrInitialDir=NULL;
2057 // ofn.lpstrTitle=NULL;
2058 ofn.Flags=OFN_OVERWRITEPROMPT;
2059 // ofn.nFileOffset=0;
2060 // ofn.nFileExtension=0;
2061 ofn.lpstrDefExt=TEXT("sif");
2062 // ofn.lCustData = 0l;
2064 // ofn.lpTemplateName=NULL;
2066 CHAR szFilename[MAX_PATH];
2068 strcpy(szFilename,filename.c_str());
2069 strcpy(szTitle,title.c_str());
2071 ofn.lpstrFile=szFilename;
2072 ofn.lpstrFileTitle=szTitle;
2074 if(GetSaveFileName(&ofn))
2076 filename=szFilename;
2077 _preferences.set_value(preference,dirname(filename));
2082 synfig::String prev_path;
2084 if(!_preferences.get_value(preference, prev_path))
2087 prev_path = absolute_path(prev_path);
2089 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2091 dialog->set_current_folder(prev_path);
2092 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2093 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2095 Widget_Enum *file_type_enum = 0;
2096 if (preference == ANIMATION_DIR_PREFERENCE)
2098 file_type_enum = manage(new Widget_Enum());
2099 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2100 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2101 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2102 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2103 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2104 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2106 Gtk::HBox *hbox = manage(new Gtk::HBox);
2107 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2108 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2111 dialog->set_extra_widget(*hbox);
2114 if (filename.empty())
2115 dialog->set_filename(prev_path);
2118 std::string full_path;
2119 if (is_absolute_path(filename))
2120 full_path = filename;
2122 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2124 // select the file if it exists
2125 dialog->set_filename(full_path);
2127 // if the file doesn't exist, put its name into the filename box
2129 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2130 dialog->set_current_name(basename(filename));
2133 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2134 if (preference == ANIMATION_DIR_PREFERENCE)
2135 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2136 filename = dialog->get_filename();
2137 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2138 _preferences.set_value(preference, dirname(filename));
2149 App::dialog_error_blocking(const std::string &title, const std::string &message)
2151 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2152 dialog.set_title(title);
2158 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2160 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2161 dialog.set_title(title);
2167 App::dialog_yes_no(const std::string &title, const std::string &message)
2172 true // use_separator
2174 Gtk::Label label(message);
2177 dialog.get_vbox()->pack_start(label);
2178 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2179 dialog.add_button(Gtk::StockID("gtk-no"),0);
2181 return dialog.run();
2185 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2190 true // use_separator
2192 Gtk::Label label(message);
2195 dialog.get_vbox()->pack_start(label);
2196 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2197 dialog.add_button(Gtk::StockID("gtk-no"),0);
2198 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2200 return dialog.run();
2204 App::dialog_not_implemented()
2206 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2207 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2212 try_open_url(const std::string &url)
2215 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2217 std::vector<std::string> command_line;
2218 std::vector<std::string> browsers;
2219 browsers.reserve(23);
2221 // Browser wrapper scripts
2222 #ifdef USE_OPEN_FOR_URLS
2223 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2225 browsers.push_back("xdg-open"); // XDG wrapper
2226 browsers.push_back("sensible-browser"); // Debian wrapper
2227 browsers.push_back("gnome-open"); // GNOME wrapper
2228 browsers.push_back("kfmclient"); // KDE wrapper
2229 browsers.push_back("exo-open"); // XFCE wrapper
2231 // Alternatives system
2232 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2233 browsers.push_back("x-www-browser"); // Debian GUI alternative
2235 // Individual browsers
2236 browsers.push_back("firefox");
2237 browsers.push_back("epiphany-browser");
2238 browsers.push_back("epiphany");
2239 browsers.push_back("konqueror");
2240 browsers.push_back("iceweasel");
2241 browsers.push_back("mozilla");
2242 browsers.push_back("netscape");
2243 browsers.push_back("icecat");
2244 browsers.push_back("galeon");
2245 browsers.push_back("midori");
2246 browsers.push_back("safari");
2247 browsers.push_back("opera");
2248 browsers.push_back("amaya");
2249 browsers.push_back("netsurf");
2250 browsers.push_back("dillo");
2252 // Try the user-specified browser first
2253 command_line.push_back(App::browser_command);
2254 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2255 command_line.push_back(url);
2257 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2258 catch( Glib::SpawnError& exception ){
2260 while ( !browsers.empty() )
2262 // Skip the browser if we already tried it
2263 if( browsers[0] == App::browser_command )
2266 // Construct the command line
2267 command_line.clear();
2268 command_line.push_back(browsers[0]);
2269 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2270 command_line.push_back(url);
2272 // Remove the browser from the list
2273 browsers.erase(browsers.begin());
2275 // Try to spawn the browser
2276 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2277 // Failed, move on to the next one
2278 catch(Glib::SpawnError& exception){ continue; }
2279 return true; // No exception means we succeeded!
2290 if (!try_open_url("http://synfig.org/Documentation"))
2292 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2293 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2294 dialog.set_title(_("Help"));
2300 App::open_url(const std::string &url)
2302 if(!try_open_url(url))
2304 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2305 dialog.set_secondary_text(url);
2306 dialog.set_title(_("No browser found"));
2312 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2317 true); // use_separator
2319 Gtk::Label label(message);
2321 dialog.get_vbox()->pack_start(label);
2324 entry.set_text(text);
2326 entry.set_activates_default(true);
2328 dialog.get_vbox()->pack_start(entry);
2330 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2331 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2332 dialog.set_default_response(Gtk::RESPONSE_OK);
2334 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2337 if(dialog.run()!=Gtk::RESPONSE_OK)
2340 text=entry.get_text();
2346 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2351 true); // use_separator
2353 Gtk::Label label(message);
2355 dialog.get_vbox()->pack_start(label);
2357 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2358 text_buffer->set_text(text);
2359 Gtk::TextView text_view(text_buffer);
2362 dialog.get_vbox()->pack_start(text_view);
2364 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2365 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2366 dialog.set_default_response(Gtk::RESPONSE_OK);
2368 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2371 if(dialog.run()!=Gtk::RESPONSE_OK)
2374 text=text_buffer->get_text();
2380 App::open(std::string filename)
2382 return open_as(filename,filename);
2385 // this is called from autorecover.cpp:
2386 // App::open_as(get_shadow_file_name(filename),filename)
2387 // other than that, 'filename' and 'as' are the same
2389 App::open_as(std::string filename,std::string as)
2392 char long_name[1024];
2393 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2394 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2395 // don't use it if that's the case
2396 if (long_name[0] != '\0')
2402 OneMoment one_moment;
2403 String errors, warnings;
2405 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2406 if(canvas && get_instance(canvas))
2408 get_instance(canvas)->find_canvas_view(canvas)->present();
2409 info("%s is already open", filename.c_str());
2410 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2415 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2418 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2420 if (as.find(custom_filename_prefix.c_str()) != 0)
2421 add_recent_file(as);
2423 handle<Instance> instance(Instance::create(canvas));
2426 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2428 set_recent_file_window_size(instance);
2432 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)")))
2433 instance->dialog_cvs_update();
2438 dialog_error_blocking(_("Error"), x);
2441 catch(runtime_error x)
2443 dialog_error_blocking(_("Error"), x.what());
2448 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2459 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2461 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2462 canvas->set_name(file_name);
2463 file_name += ".sifz";
2465 canvas->rend_desc().set_frame_rate(preferred_fps);
2466 canvas->rend_desc().set_time_start(0.0);
2467 canvas->rend_desc().set_time_end(5.0);
2468 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2469 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2470 // The top left and botton right positions are expressed in units
2471 // Original convention is that 1 unit = 60 pixels
2472 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2473 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2474 canvas->rend_desc().set_w(preferred_x_size);
2475 canvas->rend_desc().set_h(preferred_y_size);
2476 canvas->rend_desc().set_antialias(1);
2477 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2478 canvas->set_file_name(file_name);
2480 handle<Instance> instance = Instance::create(canvas);
2482 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2483 instance->find_canvas_view(canvas)->canvas_properties.present();
2487 App::dialog_open(string filename)
2489 if (filename.empty())
2492 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2494 // If the filename still has wildcards, then we should
2495 // continue looking for the file we want
2496 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2502 get_ui_interface()->error(_("Unable to open file"));
2507 App::set_selected_instance(etl::loose_handle<Instance> instance)
2509 /* if(get_selected_instance()==instance)
2511 selected_instance=instance;
2512 signal_instance_selected()(instance);
2518 selected_instance=instance;
2519 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2523 instance->focus(instance->get_canvas());
2526 set_selected_canvas_view(0);
2528 signal_instance_selected()(instance);
2532 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2534 selected_canvas_view=canvas_view;
2535 signal_canvas_view_focus()(selected_canvas_view);
2538 selected_instance=canvas_view->get_instance();
2539 signal_instance_selected()(canvas_view->get_instance());
2542 if(get_selected_canvas_view()==canvas_view)
2544 signal_canvas_view_focus()(selected_canvas_view);
2545 signal_instance_selected()(canvas_view->get_instance());
2548 selected_canvas_view=canvas_view;
2549 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2550 set_selected_instance(canvas_view->get_instance());
2551 signal_canvas_view_focus()(selected_canvas_view);
2555 etl::loose_handle<Instance>
2556 App::get_instance(etl::handle<synfig::Canvas> canvas)
2558 if(!canvas) return 0;
2559 canvas=canvas->get_root();
2561 std::list<etl::handle<Instance> >::iterator iter;
2562 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2564 if((*iter)->get_canvas()==canvas)
2580 if(selected_instance)
2581 selected_instance->undo();
2587 if(selected_instance)
2588 selected_instance->redo();
2592 studio::App::get_base_path()
2594 return app_base_path_;