1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2008 Gerald Young
11 ** Copyright (c) 2008 Carlos López
12 ** Copyright (c) 2009 Nikita Kitaev
14 ** This package is free software; you can redistribute it and/or
15 ** modify it under the terms of the GNU General Public License as
16 ** published by the Free Software Foundation; either version 2 of
17 ** the License, or (at your option) any later version.
19 ** This package is distributed in the hope that it will be useful,
20 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 ** General Public License for more details.
25 /* ========================================================================= */
27 /* === H E A D E R S ======================================================= */
46 #ifdef HAVE_SYS_ERRNO_H
47 #include <sys/errno.h>
49 #include <gtkmm/fileselection.h>
50 #include <gtkmm/dialog.h>
51 #include <gtkmm/messagedialog.h>
52 #include <gtkmm/label.h>
53 #include <gtkmm/stock.h>
54 #include <gtkmm/stockitem.h>
55 #include <gtkmm/iconsource.h>
56 #include <gtkmm/inputdialog.h>
57 #include <gtkmm/accelmap.h>
58 #include <gtkmm/uimanager.h>
59 #include <gtkmm/textview.h>
63 #include <gdkmm/general.h>
65 #include <synfig/loadcanvas.h>
66 #include <synfig/savecanvas.h>
69 #include "dialogs/about.h"
72 #include "canvasview.h"
73 #include "dialogs/dialog_setup.h"
74 #include "dialogs/dialog_gradient.h"
75 #include "dialogs/dialog_color.h"
77 #include "onemoment.h"
79 #include "docks/dockmanager.h"
81 #include "states/state_eyedrop.h"
82 #include "states/state_normal.h"
83 #include "states/state_mirror.h"
84 #include "states/state_draw.h"
85 #include "states/state_fill.h"
86 #include "states/state_bline.h"
87 #include "states/state_polygon.h"
88 #include "states/state_sketch.h"
89 #include "states/state_gradient.h"
90 #include "states/state_circle.h"
91 #include "states/state_rectangle.h"
92 #include "states/state_smoothmove.h"
93 #include "states/state_scale.h"
94 #include "states/state_star.h"
95 #include "states/state_text.h"
96 #include "states/state_width.h"
97 #include "states/state_rotate.h"
98 #include "states/state_zoom.h"
100 #include "devicetracker.h"
101 #include "docks/dialog_tooloptions.h"
102 #include "widgets/widget_enum.h"
104 #include "autorecover.h"
106 #include <synfigapp/settings.h>
107 #include "docks/dock_history.h"
108 #include "docks/dock_canvases.h"
109 #include "docks/dock_keyframes.h"
110 #include "docks/dock_layers.h"
111 #include "docks/dock_params.h"
112 #include "docks/dock_metadata.h"
113 #include "docks/dock_children.h"
114 #include "docks/dock_info.h"
115 #include "docks/dock_navigator.h"
116 #include "docks/dock_layergroups.h"
117 #include "docks/dock_timetrack.h"
118 #include "docks/dock_curves.h"
120 #include "modules/module.h"
121 #include "modules/mod_palette/mod_palette.h"
123 #include <sys/stat.h>
127 #include "statemanager.h"
133 #include <gtkmm/accelmap.h>
134 #include <gtkmm/filechooser.h>
135 #include <gtkmm/filechooserdialog.h>
141 /* === U S I N G =========================================================== */
145 using namespace synfig;
146 using namespace studio;
148 /* === M A C R O S ========================================================= */
150 #ifndef SYNFIG_USER_APP_DIR
152 #define SYNFIG_USER_APP_DIR "Library/Synfig"
153 #elif defined(_WIN32)
154 #define SYNFIG_USER_APP_DIR "Synfig"
156 #define SYNFIG_USER_APP_DIR ".synfig"
161 #define DPM2DPI(x) (float(x)/39.3700787402f)
162 #define DPI2DPM(x) (float(x)*39.3700787402f)
168 # define IMAGE_DIR "share\\pixmaps"
173 # define IMAGE_DIR "/usr/local/share/pixmaps"
177 # define IMAGE_EXT "tif"
180 #include <synfigapp/main.h>
182 /* === S I G N A L S ======================================================= */
184 static sigc::signal<void> signal_present_all_;
186 App::signal_present_all() { return signal_present_all_; }
188 static sigc::signal<void> signal_recent_files_changed_;
190 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
192 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
193 sigc::signal<void,etl::loose_handle<CanvasView> >&
194 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
196 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
197 sigc::signal<void,etl::handle<Instance> >&
198 App::signal_instance_selected() { return signal_instance_selected_; }
200 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
201 sigc::signal<void,etl::handle<Instance> >&
202 App::signal_instance_created() { return signal_instance_created_; }
204 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
205 sigc::signal<void,etl::handle<Instance> >&
206 App::signal_instance_deleted() { return signal_instance_deleted_; }
208 /* === G L O B A L S ======================================================= */
210 static std::list<std::string> recent_files;
211 const std::list<std::string>& App::get_recent_files() { return recent_files; }
213 static std::list<std::string> recent_files_window_size;
215 int App::Busy::count;
216 bool App::shutdown_in_progress;
218 synfig::Gamma App::gamma;
220 Glib::RefPtr<studio::UIManager> App::ui_manager_;
222 synfig::Distance::System App::distance_system;
224 studio::Dialog_Setup* App::dialog_setup;
226 etl::handle< studio::ModPalette > mod_palette_;
227 //studio::Dialog_Palette* App::dialog_palette;
229 std::list<etl::handle<Instance> > App::instance_list;
231 static etl::handle<synfigapp::UIInterface> ui_interface_;
232 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
234 etl::handle<Instance> App::selected_instance;
235 etl::handle<CanvasView> App::selected_canvas_view;
237 studio::About *studio::App::about=NULL;
239 studio::Toolbox *studio::App::toolbox=NULL;
241 studio::AutoRecover *studio::App::auto_recover=NULL;
243 studio::IPC *ipc=NULL;
245 studio::DockManager* studio::App::dock_manager=0;
247 studio::DeviceTracker* studio::App::device_tracker=0;
249 studio::Dialog_Gradient* studio::App::dialog_gradient;
251 studio::Dialog_Color* studio::App::dialog_color;
253 Gtk::InputDialog* studio::App::dialog_input;
255 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
257 studio::Dock_History* dock_history;
258 studio::Dock_Canvases* dock_canvases;
259 studio::Dock_Keyframes* dock_keyframes;
260 studio::Dock_Layers* dock_layers;
261 studio::Dock_Params* dock_params;
262 studio::Dock_MetaData* dock_meta_data;
263 studio::Dock_Children* dock_children;
264 studio::Dock_Info* dock_info;
265 studio::Dock_LayerGroups* dock_layer_groups;
266 studio::Dock_Navigator* dock_navigator;
267 studio::Dock_Timetrack* dock_timetrack;
268 studio::Dock_Curves* dock_curves;
270 std::list< etl::handle< studio::Module > > module_list_;
272 bool studio::App::use_colorspace_gamma=true;
273 #ifdef SINGLE_THREADED
275 bool studio::App::single_threaded=true;
277 bool studio::App::single_threaded=false;
279 #endif // SINGLE THREADED
280 bool studio::App::restrict_radius_ducks=false;
281 bool studio::App::resize_imported_images=false;
282 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
283 int studio::App::preferred_x_size=480;
284 int studio::App::preferred_y_size=270;
285 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
286 String studio::App::predefined_fps(DEFAULT_PREDEFINED_FPS);
287 float studio::App::preferred_fps=24.0;
288 #ifdef USE_OPEN_FOR_URLS
289 String studio::App::browser_command("open"); // MacOS only
291 String studio::App::browser_command("xdg-open"); // Linux XDG standard
294 static int max_recent_files_=25;
295 int studio::App::get_max_recent_files() { return max_recent_files_; }
296 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
298 static synfig::String app_base_path_;
303 really_delete_widget(Gtk::Widget *widget)
305 // synfig::info("really delete %p", (void*)widget);
310 // nasty workaround - when we've finished with a popup menu, we want to delete it
311 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
312 // so schedule the real delete to happen in 50ms, giving the action a chance to run
314 delete_widget(Gtk::Widget *widget)
316 // synfig::info("delete %p", (void*)widget);
317 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
320 }; // END of namespace studio
321 studio::StateManager* state_manager;
326 class GlobalUIInterface : public synfigapp::UIInterface
330 virtual Response confirmation(const std::string &title,
331 const std::string &primaryText,
332 const std::string &secondaryText,
333 const std::string &confirmPhrase,
334 const std::string &cancelPhrase,
335 Response defaultResponse)
337 Gtk::MessageDialog dialog(
338 primaryText, // Message
340 Gtk::MESSAGE_WARNING, // Type
341 Gtk::BUTTONS_NONE, // Buttons
346 dialog.set_title(title);
347 if (! secondaryText.empty())
348 dialog.set_secondary_text(secondaryText);
350 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
351 dialog.add_button(confirmPhrase, RESPONSE_OK);
352 dialog.set_default_response(defaultResponse);
355 return (Response) dialog.run();
358 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
363 true // use_separator
365 Gtk::Label label(message);
368 dialog.get_vbox()->pack_start(label);
369 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
370 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
372 dialog.set_default_response(dflt);
374 return (Response)dialog.run();
376 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
381 true // use_separator
383 Gtk::Label label(message);
386 dialog.get_vbox()->pack_start(label);
387 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
388 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
389 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
391 dialog.set_default_response(dflt);
393 return (Response)dialog.run();
395 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
400 true // use_separator
402 Gtk::Label label(message);
405 dialog.get_vbox()->pack_start(label);
406 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
407 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
409 dialog.set_default_response(dflt);
411 return (Response)dialog.run();
415 task(const std::string &task)
417 std::cerr<<task<<std::endl;
418 while(studio::App::events_pending())studio::App::iteration(false);
423 error(const std::string &err)
425 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
432 warning(const std::string &err)
434 std::cerr<<"warning: "<<err<<std::endl;
435 while(studio::App::events_pending())studio::App::iteration(false);
440 amount_complete(int /*current*/, int /*total*/)
442 while(studio::App::events_pending())studio::App::iteration(false);
447 /* === P R O C E D U R E S ================================================= */
451 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
453 action_group_list.push_back(action_group);
454 Gtk::UIManager::insert_action_group(action_group, pos);
458 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
460 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
461 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
462 if(*iter==action_group)
464 action_group_list.erase(iter);
465 Gtk::UIManager::remove_action_group(action_group);
468 synfig::error("Unable to find action group");
472 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
474 ui_manager->insert_action_group(group,0);
476 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
477 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
479 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
481 if(*iter && (*iter)->get_name()!="menus")
483 synfig::info("Removing action group "+(*iter)->get_name());
484 ui_manager->remove_action_group(*iter);
487 ui_manager->insert_action_group(group,0);
489 for(;!prev_groups.empty();prev_groups.pop_front())
491 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
492 ui_manager->insert_action_group(prev_groups.front(),1);
496 class Preferences : public synfigapp::Settings
499 virtual bool get_value(const synfig::String& key, synfig::String& value)const
503 value=strprintf("%f %f %f %f",
504 App::gamma.get_gamma_r(),
505 App::gamma.get_gamma_g(),
506 App::gamma.get_gamma_b(),
507 App::gamma.get_black_level()
511 if(key=="time_format")
513 value=strprintf("%i",App::get_time_format());
516 if(key=="file_history.size")
518 value=strprintf("%i",App::get_max_recent_files());
521 if(key=="use_colorspace_gamma")
523 value=strprintf("%i",(int)App::use_colorspace_gamma);
526 if(key=="distance_system")
528 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
531 #ifdef SINGLE_THREADED
532 if(key=="single_threaded")
534 value=strprintf("%i",(int)App::single_threaded);
538 if(key=="auto_recover_backup_interval")
540 value=strprintf("%i",App::auto_recover->get_timeout());
543 if(key=="restrict_radius_ducks")
545 value=strprintf("%i",(int)App::restrict_radius_ducks);
548 if(key=="resize_imported_images")
550 value=strprintf("%i",(int)App::resize_imported_images);
553 if(key=="browser_command")
555 value=App::browser_command;
558 if(key=="custom_filename_prefix")
560 value=App::custom_filename_prefix;
563 if(key=="preferred_x_size")
565 value=strprintf("%i",App::preferred_x_size);
568 if(key=="preferred_y_size")
570 value=strprintf("%i",App::preferred_y_size);
573 if(key=="predefined_size")
575 value=strprintf("%s",App::predefined_size.c_str());
578 if(key=="preferred_fps")
580 value=strprintf("%f",App::preferred_fps);
583 if(key=="predefined_fps")
585 value=strprintf("%s",App::predefined_fps.c_str());
589 return synfigapp::Settings::get_value(key,value);
592 virtual bool set_value(const synfig::String& key,const synfig::String& value)
598 strscanf(value,"%f %f %f %f",
605 App::gamma.set_all(r,g,b,blk);
609 if(key=="time_format")
611 int i(atoi(value.c_str()));
612 App::set_time_format(static_cast<synfig::Time::Format>(i));
615 if(key=="auto_recover_backup_interval")
617 int i(atoi(value.c_str()));
618 App::auto_recover->set_timeout(i);
621 if(key=="file_history.size")
623 int i(atoi(value.c_str()));
624 App::set_max_recent_files(i);
627 if(key=="use_colorspace_gamma")
629 int i(atoi(value.c_str()));
630 App::use_colorspace_gamma=i;
633 if(key=="distance_system")
635 App::distance_system=Distance::ident_system(value);;
638 #ifdef SINGLE_THREADED
639 if(key=="single_threaded")
641 int i(atoi(value.c_str()));
642 App::single_threaded=i;
646 if(key=="restrict_radius_ducks")
648 int i(atoi(value.c_str()));
649 App::restrict_radius_ducks=i;
652 if(key=="resize_imported_images")
654 int i(atoi(value.c_str()));
655 App::resize_imported_images=i;
658 if(key=="browser_command")
660 App::browser_command=value;
663 if(key=="custom_filename_prefix")
665 App::custom_filename_prefix=value;
668 if(key=="preferred_x_size")
670 int i(atoi(value.c_str()));
671 App::preferred_x_size=i;
674 if(key=="preferred_y_size")
676 int i(atoi(value.c_str()));
677 App::preferred_y_size=i;
680 if(key=="predefined_size")
682 App::predefined_size=value;
685 if(key=="preferred_fps")
687 float i(atof(value.c_str()));
688 App::preferred_fps=i;
691 if(key=="predefined_fps")
693 App::predefined_fps=value;
697 return synfigapp::Settings::set_value(key,value);
700 virtual KeyList get_key_list()const
702 KeyList ret(synfigapp::Settings::get_key_list());
703 ret.push_back("gamma");
704 ret.push_back("time_format");
705 ret.push_back("distance_system");
706 ret.push_back("file_history.size");
707 ret.push_back("use_colorspace_gamma");
708 #ifdef SINGLE_THREADED
709 ret.push_back("single_threaded");
711 ret.push_back("auto_recover_backup_interval");
712 ret.push_back("restrict_radius_ducks");
713 ret.push_back("resize_imported_images");
714 ret.push_back("browser_command");
715 ret.push_back("custom_filename_prefix");
716 ret.push_back("preferred_x_size");
717 ret.push_back("preferred_y_size");
718 ret.push_back("predefined_size");
719 ret.push_back("preferred_fps");
720 ret.push_back("predefined_fps");
725 static ::Preferences _preferences;
730 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
732 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
734 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create("actions");
736 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
737 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
738 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
739 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
740 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
741 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
742 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
743 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
744 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
745 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
746 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
747 menus_action_group->add( Gtk::Action::create("menu-state", _("Tool")) );
748 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
750 // Add the synfigapp actions...
751 synfigapp::Action::Book::iterator iter;
752 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
754 actions_action_group->add(Gtk::Action::create(
755 "action-"+iter->second.name,
756 get_action_stock_id(iter->second),
757 iter->second.local_name,iter->second.local_name
761 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); actions_action_group->add(action); }
762 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); actions_action_group->add(action); }
763 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); group->add(action,sig); }
765 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
766 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
767 DEFINE_ACTION("new", Gtk::Stock::NEW);
768 DEFINE_ACTION("open", Gtk::Stock::OPEN);
769 DEFINE_ACTION("save", Gtk::Stock::SAVE);
770 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
771 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
772 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
773 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
774 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
775 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
776 DEFINE_ACTION("import", _("Import"));
777 DEFINE_ACTION("render", _("Render"));
778 DEFINE_ACTION("preview", _("Preview"));
779 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
780 DEFINE_ACTION("sound", _("Sound File"));
781 DEFINE_ACTION("options", _("Options"));
782 DEFINE_ACTION("close", _("Close View"));
783 DEFINE_ACTION("close-document", _("Close Document"));
784 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
787 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
788 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
789 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
790 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
791 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
792 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
793 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
794 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
795 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
796 DEFINE_ACTION("properties", _("Properties"));
798 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
799 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
800 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
801 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
802 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
803 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
804 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
805 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
806 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
807 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
808 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
809 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
810 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
811 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
812 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
813 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
814 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
815 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
816 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
817 DEFINE_ACTION("play", _("Play"));
818 // DEFINE_ACTION("pause", _("Pause"));
819 DEFINE_ACTION("stop", _("Stop"));
820 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
821 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
822 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
823 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
824 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
825 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
826 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
827 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
828 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
829 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
830 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
831 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
832 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
833 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
834 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
835 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
836 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
837 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
838 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
839 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
840 DEFINE_ACTION("seek-end", _("Seek to End"));
842 DEFINE_ACTION("action-group_add", _("Add group"));
844 DEFINE_ACTION("canvas-new", _("New Canvas"));
846 DEFINE_ACTION("amount-inc", _("Increase Amount"));
847 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
850 #undef DEFINE_ACTION_2
851 #undef DEFINE_ACTION_SIG
853 Glib::ustring ui_info =
855 " <popup name='menu-toolbox' action='menu-toolbox'>"
856 " <menu action='menu-file'>"
859 " <popup name='menu-main' action='menu-main'>"
860 " <menu action='menu-file'>"
861 " <menuitem action='new' />"
862 " <menuitem action='open' />"
863 " <menuitem action='save' />"
864 " <menuitem action='save-as' />"
865 " <menuitem action='revert' />"
866 " <separator name='bleh01'/>"
867 " <menuitem action='cvs-add' />"
868 " <menuitem action='cvs-update' />"
869 " <menuitem action='cvs-commit' />"
870 " <menuitem action='cvs-revert' />"
871 " <separator name='bleh02'/>"
872 " <menuitem action='import' />"
873 " <separator name='bleh03'/>"
874 " <menuitem action='render' />"
875 " <menuitem action='preview' />"
876 " <menuitem action='sound' />"
877 " <separator name='bleh04'/>"
878 " <menuitem action='options' />"
879 " <menuitem action='close' />"
880 " <menuitem action='close-document' />"
881 " <menuitem action='quit' />"
883 " <menu action='menu-edit'>"
884 " <menuitem action='undo'/>"
885 " <menuitem action='redo'/>"
886 " <separator name='bleh05'/>"
887 " <menuitem action='cut'/>"
888 " <menuitem action='copy'/>"
889 " <menuitem action='paste'/>"
890 " <separator name='bleh06'/>"
891 " <menuitem action='select-all-layers'/>"
892 " <menuitem action='unselect-all-layers'/>"
893 " <menuitem action='select-all-ducks'/>"
894 " <menuitem action='unselect-all-ducks'/>"
895 " <separator name='bleh07'/>"
896 " <menuitem action='properties'/>"
898 " <menu action='menu-view'>"
899 " <menu action='menu-duck-mask'>"
900 " <menuitem action='mask-position-ducks' />"
901 " <menuitem action='mask-vertex-ducks' />"
902 " <menuitem action='mask-tangent-ducks' />"
903 " <menuitem action='mask-radius-ducks' />"
904 " <menuitem action='mask-width-ducks' />"
905 " <menuitem action='mask-angle-ducks' />"
907 " <menu action='menu-preview-quality'>"
908 " <menuitem action='quality-00' />"
909 " <menuitem action='quality-01' />"
910 " <menuitem action='quality-02' />"
911 " <menuitem action='quality-03' />"
912 " <menuitem action='quality-04' />"
913 " <menuitem action='quality-05' />"
914 " <menuitem action='quality-06' />"
915 " <menuitem action='quality-07' />"
916 " <menuitem action='quality-08' />"
917 " <menuitem action='quality-09' />"
918 " <menuitem action='quality-10' />"
920 " <menu action='menu-lowres-pixel'>"
921 " <menuitem action='decrease-low-res-pixel-size'/>"
922 " <menuitem action='increase-low-res-pixel-size'/>"
923 " <separator name='pixel-size-separator'/>"
926 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
927 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
931 " <separator name='bleh08'/>"
932 " <menuitem action='play'/>"
933 //" <menuitem action='pause'/>"
934 " <menuitem action='stop'/>"
935 " <menuitem action='dialog-flipbook'/>"
936 " <separator name='bleh09'/>"
937 " <menuitem action='toggle-grid-show'/>"
938 " <menuitem action='toggle-grid-snap'/>"
939 " <menuitem action='toggle-guide-show'/>"
940 " <menuitem action='toggle-low-res'/>"
941 " <menuitem action='toggle-onion-skin'/>"
942 " <separator name='bleh10'/>"
943 " <menuitem action='canvas-zoom-in'/>"
944 " <menuitem action='canvas-zoom-out'/>"
945 " <menuitem action='canvas-zoom-fit'/>"
946 " <menuitem action='canvas-zoom-100'/>"
947 " <separator name='bleh11'/>"
948 " <menuitem action='time-zoom-in'/>"
949 " <menuitem action='time-zoom-out'/>"
950 " <separator name='bleh12'/>"
951 " <menuitem action='jump-next-keyframe'/>"
952 " <menuitem action='jump-prev-keyframe'/>"
953 " <menuitem action='seek-next-frame'/>"
954 " <menuitem action='seek-prev-frame'/>"
955 " <menuitem action='seek-next-second'/>"
956 " <menuitem action='seek-prev-second'/>"
957 " <menuitem action='seek-begin'/>"
958 " <menuitem action='seek-end'/>"
960 " <menu action='menu-canvas'>"
961 " <menuitem action='canvas-new'/>"
963 " <menu name='menu-state' action='menu-state'>"
965 " <menu action='menu-group'>"
966 " <menuitem action='action-group_add'/>"
968 " <menu action='menu-layer'>"
969 //" <menuitem action='cut'/>"
970 //" <menuitem action='copy'/>"
971 //" <menuitem action='paste'/>"
972 //" <separator name='bleh06'/>"
973 " <menu action='menu-layer-new'></menu>"
974 " <menuitem action='amount-inc'/>"
975 " <menuitem action='amount-dec'/>"
977 " <menu action='menu-keyframe'>"
978 " <menuitem action='keyframe-properties'/>"
985 " <menubar name='MenuBar'>"
986 " <menu action='MenuFile'>"
987 " <menuitem action='New'/>"
988 " <menuitem action='Open'/>"
990 " <menuitem action='Quit'/>"
992 " <menu action='MenuEdit'>"
993 " <menuitem action='Cut'/>"
994 " <menuitem action='Copy'/>"
995 " <menuitem action='Paste'/>"
998 " <toolbar name='ToolBar'>"
999 " <toolitem action='Open'/>"
1000 " <toolitem action='Quit'/>"
1006 actions_action_group->set_sensitive(false);
1007 App::ui_manager()->set_add_tearoffs(true);
1008 App::ui_manager()->insert_action_group(menus_action_group,1);
1009 App::ui_manager()->insert_action_group(actions_action_group,1);
1010 App::ui_manager()->add_ui_from_string(ui_info);
1012 //App::ui_manager()->get_accel_group()->unlock();
1014 catch(const Glib::Error& ex)
1016 synfig::error("building menus and toolbars failed: " + ex.what());
1019 // Add default keyboard accelerators
1020 #define ACCEL(accel,path) \
1022 Gtk::AccelKey accel_key(accel,path); \
1023 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1026 #define ACCEL2(accel) \
1028 Gtk::AccelKey accel_key(accel); \
1029 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1033 ACCEL("<Mod1>a", "<Actions>/action_group_state_manager/state-normal" );
1034 ACCEL("<Mod1>v", "<Actions>/action_group_state_manager/state-smooth_move" );
1035 ACCEL("<Mod1>s", "<Actions>/action_group_state_manager/state-scale" );
1036 ACCEL("<Mod1>t", "<Actions>/action_group_state_manager/state-rotate" );
1037 ACCEL("<Mod1>m", "<Actions>/action_group_state_manager/state-mirror" );
1038 ACCEL("<Mod1>c", "<Actions>/action_group_state_manager/state-circle" );
1039 ACCEL("<Mod1>r", "<Actions>/action_group_state_manager/state-rectangle" );
1040 ACCEL("<Mod1>q", "<Actions>/action_group_state_manager/state-star" );
1041 ACCEL("<Mod1>g", "<Actions>/action_group_state_manager/state-gradient" );
1042 ACCEL("<Mod1>p", "<Actions>/action_group_state_manager/state-polygon" );
1043 ACCEL("<Mod1>b", "<Actions>/action_group_state_manager/state-bline" );
1044 ACCEL("<Mod1>x", "<Actions>/action_group_state_manager/state-text" );
1045 ACCEL("<Mod1>f", "<Actions>/action_group_state_manager/state-fill" );
1046 ACCEL("<Mod1>e", "<Actions>/action_group_state_manager/state-eyedrop" );
1047 ACCEL("<Mod1>z", "<Actions>/action_group_state_manager/state-zoom" );
1048 ACCEL("<Mod1>d", "<Actions>/action_group_state_manager/state-draw" );
1049 ACCEL("<Mod1>k", "<Actions>/action_group_state_manager/state-sketch" );
1050 ACCEL("<Mod1>w", "<Actions>/action_group_state_manager/state-width" );
1053 ACCEL("<Control>a", "<Actions>/canvasview/select-all-ducks" );
1054 ACCEL("<Control>d", "<Actions>/canvasview/unselect-all-ducks" );
1055 ACCEL("<Control><Shift>a", "<Actions>/canvasview/select-all-layers" );
1056 ACCEL("<Control><Shift>d", "<Actions>/canvasview/unselect-all-layers" );
1057 ACCEL("F9", "<Actions>/canvasview/render" );
1058 ACCEL("F11", "<Actions>/canvasview/preview" );
1059 ACCEL("F8", "<Actions>/canvasview/properties" );
1060 ACCEL("F12", "<Actions>/canvasview/options" );
1061 ACCEL("<control>i", "<Actions>/canvasview/import" );
1062 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>/canvasview/stop" ));
1063 ACCEL("<Control>g", "<Actions>/canvasview/toggle-grid-show" );
1064 ACCEL("<Control>l", "<Actions>/canvasview/toggle-grid-snap" );
1065 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>/canvasview/toggle-low-res" ));
1066 ACCEL("<Mod1>1", "<Actions>/canvasview/mask-position-ducks" );
1067 ACCEL("<Mod1>2", "<Actions>/canvasview/mask-vertex-ducks" );
1068 ACCEL("<Mod1>3", "<Actions>/canvasview/mask-tangent-ducks" );
1069 ACCEL("<Mod1>4", "<Actions>/canvasview/mask-radius-ducks" );
1070 ACCEL("<Mod1>5", "<Actions>/canvasview/mask-width-ducks" );
1071 ACCEL("<Mod1>6", "<Actions>/canvasview/mask-angle-ducks" );
1072 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRaise" ));
1073 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>/action_group_layer_action_manager/action-LayerLower" ));
1074 ACCEL("<Control>1", "<Actions>/canvasview/quality-01" );
1075 ACCEL("<Control>2", "<Actions>/canvasview/quality-02" );
1076 ACCEL("<Control>3", "<Actions>/canvasview/quality-03" );
1077 ACCEL("<Control>4", "<Actions>/canvasview/quality-04" );
1078 ACCEL("<Control>5", "<Actions>/canvasview/quality-05" );
1079 ACCEL("<Control>6", "<Actions>/canvasview/quality-06" );
1080 ACCEL("<Control>7", "<Actions>/canvasview/quality-07" );
1081 ACCEL("<Control>8", "<Actions>/canvasview/quality-08" );
1082 ACCEL("<Control>9", "<Actions>/canvasview/quality-09" );
1083 ACCEL("<Control>0", "<Actions>/canvasview/quality-10" );
1084 ACCEL("<Control>z", "<Actions>/action_group_dock_history/undo" );
1085 ACCEL("<Control>r", "<Actions>/action_group_dock_history/redo" );
1086 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/action-LayerRemove" ));
1087 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>/canvasview/decrease-low-res-pixel-size" ));
1088 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>/canvasview/increase-low-res-pixel-size" ));
1089 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-dec" ));
1090 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>/action_group_layer_action_manager/amount-inc" ));
1091 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-next-keyframe" ));
1092 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>/canvasview/jump-prev-keyframe" ));
1093 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-in" ));
1094 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>/canvasview/canvas-zoom-out" ));
1095 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-in" ));
1096 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>/canvasview/time-zoom-out" ));
1097 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-frame" ));
1098 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-frame" ));
1099 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-next-second" ));
1100 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>/canvasview/seek-prev-second" ));
1101 ACCEL("<Mod1>o", "<Actions>/canvasview/toggle-onion-skin" );
1102 ACCEL("<Control><Shift>z", "<Actions>/canvasview/canvas-zoom-fit" );
1103 ACCEL("<Control>p", "<Actions>/canvasview/play" );
1104 ACCEL("Home", "<Actions>/canvasview/seek-begin" );
1105 ACCEL("End", "<Actions>/canvasview/seek-end" );
1112 #define mkdir(x,y) mkdir(x)
1115 /* === M E T H O D S ======================================================= */
1117 App::App(int *argc, char ***argv):
1118 Gtk::Main(argc,argv),
1119 IconController(etl::dirname((*argv)[0]))
1121 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1124 ui_interface_=new GlobalUIInterface();
1128 // don't call thread_init() if threads are already initialized
1129 // on some machines bonobo_init() initialized threads before we get here
1130 if (!g_thread_supported())
1131 Glib::thread_init();
1133 distance_system=Distance::SYSTEM_UNITS;
1135 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1138 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1142 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1148 if(!SYNFIG_CHECK_VERSION())
1150 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1151 dialog_error_blocking("Synfig Studio",
1152 "This copy of Synfig Studio was compiled against a\n"
1153 "different version of libsynfig than what is currently\n"
1154 "installed. Synfig Studio will now abort. Try downloading\n"
1155 "the latest version from the Synfig website at\n"
1156 "http://synfig.org/en/current-release"
1160 Glib::set_application_name(_("Synfig Studio"));
1162 Splash splash_screen;
1163 splash_screen.show();
1165 shutdown_in_progress=false;
1166 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1167 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1169 // Initialize the Synfig library
1170 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1171 catch(std::runtime_error x)
1173 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1178 get_ui_interface()->error(_("Failed to initialize synfig!"));
1182 // add the preferences to the settings
1183 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1187 studio_init_cb.task(_("Init UI Manager..."));
1188 App::ui_manager_=studio::UIManager::create();
1191 studio_init_cb.task(_("Init Dock Manager..."));
1192 dock_manager=new studio::DockManager();
1194 studio_init_cb.task(_("Init State Manager..."));
1195 state_manager=new StateManager();
1197 studio_init_cb.task(_("Init Toolbox..."));
1198 toolbox=new studio::Toolbox();
1200 studio_init_cb.task(_("Init About Dialog..."));
1201 about=new studio::About();
1203 studio_init_cb.task(_("Init Tool Options..."));
1204 dialog_tool_options=new studio::Dialog_ToolOptions();
1205 dock_manager->register_dockable(*dialog_tool_options);
1207 studio_init_cb.task(_("Init History..."));
1208 dock_history=new studio::Dock_History();
1209 dock_manager->register_dockable(*dock_history);
1211 studio_init_cb.task(_("Init Canvases..."));
1212 dock_canvases=new studio::Dock_Canvases();
1213 dock_manager->register_dockable(*dock_canvases);
1215 studio_init_cb.task(_("Init Keyframes..."));
1216 dock_keyframes=new studio::Dock_Keyframes();
1217 dock_manager->register_dockable(*dock_keyframes);
1219 studio_init_cb.task(_("Init Layers..."));
1220 dock_layers=new studio::Dock_Layers();
1221 dock_manager->register_dockable(*dock_layers);
1223 studio_init_cb.task(_("Init Params..."));
1224 dock_params=new studio::Dock_Params();
1225 dock_manager->register_dockable(*dock_params);
1227 studio_init_cb.task(_("Init MetaData..."));
1228 dock_meta_data=new studio::Dock_MetaData();
1229 dock_manager->register_dockable(*dock_meta_data);
1231 studio_init_cb.task(_("Init Children..."));
1232 dock_children=new studio::Dock_Children();
1233 dock_manager->register_dockable(*dock_children);
1235 studio_init_cb.task(_("Init Info..."));
1236 dock_info = new studio::Dock_Info();
1237 dock_manager->register_dockable(*dock_info);
1239 studio_init_cb.task(_("Init Navigator..."));
1240 dock_navigator = new studio::Dock_Navigator();
1241 dock_manager->register_dockable(*dock_navigator);
1243 studio_init_cb.task(_("Init Timetrack..."));
1244 dock_timetrack = new studio::Dock_Timetrack();
1245 dock_manager->register_dockable(*dock_timetrack);
1247 studio_init_cb.task(_("Init Curve Editor..."));
1248 dock_curves = new studio::Dock_Curves();
1249 dock_manager->register_dockable(*dock_curves);
1251 studio_init_cb.task(_("Init Layer Groups..."));
1252 dock_layer_groups = new studio::Dock_LayerGroups();
1253 dock_manager->register_dockable(*dock_layer_groups);
1256 studio_init_cb.task(_("Init Color Dialog..."));
1257 dialog_color=new studio::Dialog_Color();
1259 studio_init_cb.task(_("Init Gradient Dialog..."));
1260 dialog_gradient=new studio::Dialog_Gradient();
1262 studio_init_cb.task(_("Init DeviceTracker..."));
1263 device_tracker=new studio::DeviceTracker();
1265 studio_init_cb.task(_("Init Tools..."));
1268 state_manager->add_state(&state_normal);
1269 state_manager->add_state(&state_smooth_move);
1270 state_manager->add_state(&state_scale);
1271 state_manager->add_state(&state_rotate);
1272 state_manager->add_state(&state_mirror);
1275 state_manager->add_state(&state_circle);
1276 state_manager->add_state(&state_rectangle);
1277 state_manager->add_state(&state_star);
1278 state_manager->add_state(&state_gradient);
1279 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1282 state_manager->add_state(&state_bline);
1283 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1284 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1285 state_manager->add_state(&state_fill);
1286 state_manager->add_state(&state_eyedrop);
1289 state_manager->add_state(&state_text);
1290 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1291 state_manager->add_state(&state_zoom);
1293 studio_init_cb.task(_("Init ModPalette..."));
1294 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1296 studio_init_cb.task(_("Init Setup Dialog..."));
1297 dialog_setup=new studio::Dialog_Setup();
1299 studio_init_cb.task(_("Init Input Dialog..."));
1300 dialog_input=new Gtk::InputDialog();
1301 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1302 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1304 studio_init_cb.task(_("Init auto recovery..."));
1305 auto_recover=new AutoRecover();
1307 studio_init_cb.amount_complete(9250,10000);
1308 studio_init_cb.task(_("Loading Settings..."));
1310 device_tracker->load_preferences();
1312 studio_init_cb.task(_("Checking auto-recover..."));
1314 studio_init_cb.amount_complete(9900,10000);
1316 bool opened_any = false;
1317 if(auto_recover->recovery_needed())
1319 splash_screen.hide();
1320 if (get_ui_interface()->confirmation(_("Crash Recovery"),
1321 _("Auto recovery file found"),
1322 _("Synfig Studio seems to have crashed before you could save all your files. "
1323 "Recover unsaved changes?"),
1324 _("Recover"), _("Ignore"))
1325 == synfigapp::UIInterface::RESPONSE_OK)
1327 int number_recovered;
1328 if(!auto_recover->recover(number_recovered))
1329 if (number_recovered)
1330 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1332 get_ui_interface()->error(_("Unable to recover from previous crash"));
1334 dialog_warning_blocking(_("Warning"),
1335 _("Synfig Studio has attempted to recover from a previous crash. "
1336 "The files that it has recovered are NOT YET SAVED. It would be a "
1337 "good idea to review them and save them now."));
1339 if (number_recovered)
1342 splash_screen.show();
1345 // Look for any files given on the command line,
1346 // and load them if found.
1347 for(;*argc>=1;(*argc)--)
1348 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1350 studio_init_cb.task(_("Loading files..."));
1351 splash_screen.hide();
1352 open((*argv)[*argc]);
1354 splash_screen.show();
1357 // if no file was specified to be opened, create a new document to help new users get started more easily
1358 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1361 studio_init_cb.task(_("Done."));
1362 studio_init_cb.amount_complete(10000,10000);
1364 // To avoid problems with some window managers and gtk >= 2.18
1365 // we should show dock dialogs after the settings load.
1366 // If dock dialogs are shown before the settings are loaded,
1367 // the windows manager can act over it.
1368 // See discussions here:
1369 // * http://synfig.org/forums/viewtopic.php?f=1&t=1131&st=0&sk=t&sd=a&start=30
1370 // * http://synfig.org/forums/viewtopic.php?f=15&t=1062
1371 dock_manager->show_all_dock_dialogs();
1377 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1381 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1385 StateManager* App::get_state_manager() { return state_manager; }
1389 shutdown_in_progress=true;
1393 synfigapp::Main::settings().remove_domain("pref");
1395 selected_instance=0;
1397 // Unload all of the modules
1398 for(;!module_list_.empty();module_list_.pop_back())
1401 delete state_manager;
1405 delete auto_recover;
1413 delete dialog_setup;
1415 delete dialog_gradient;
1417 delete dialog_color;
1419 delete dialog_input;
1421 delete dock_manager;
1423 instance_list.clear();
1427 App::get_user_app_directory()
1429 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1431 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1433 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1438 App::get_config_file(const synfig::String& file)
1440 return Glib::build_filename(get_user_app_directory(),file);
1443 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1445 App::set_recent_file_window_size(etl::handle<Instance> instance)
1448 const std::string &canvas_window_size = *recent_files_window_size.begin();
1450 if(canvas_window_size.empty())
1453 synfig::String::size_type current=0;
1454 bool seen_root(false), shown_non_root(false);
1456 while(current != synfig::String::npos)
1458 // find end of first field (canvas) or return
1459 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1460 if(separator == synfig::String::npos) break;
1463 synfig::Canvas::Handle canvas;
1466 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1468 catch(Exception::IDNotFound) {
1469 // can't find the canvas; skip to the next canvas or return
1470 separator = canvas_window_size.find_first_of('\t', current);
1471 if(separator == synfig::String::npos) return;
1472 current = separator+1;
1476 if (canvas->is_root())
1479 shown_non_root = true;
1481 // check that we have the tab character the ends this canvas' data or return
1482 current = separator+1;
1483 separator = canvas_window_size.find_first_of('\t', current);
1484 if(separator == synfig::String::npos) return;
1487 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1489 current = separator+1;
1492 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1493 canvasview->move(x,y);
1494 canvasview->resize(w,h);
1495 canvasview->present();
1497 current = separator+1;
1500 if (shown_non_root && !seen_root)
1501 instance->find_canvas_view(instance->get_canvas())->hide();
1505 App::add_recent_file(const etl::handle<Instance> instance)
1508 std::string canvas_window_size;
1510 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1511 Instance::CanvasViewList::const_iterator iter;
1513 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1515 if( !((*iter)->is_visible()) )
1518 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1519 int x_pos, y_pos, x_size, y_size;
1520 (*iter)->get_position(x_pos,y_pos);
1521 (*iter)->get_size(x_size,y_size);
1523 canvas_window_size += strprintf("%s %d %d %d %d\t",
1524 canvas->get_relative_id(canvas->get_root()).c_str(),
1529 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1533 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1535 std::string filename(file_name);
1537 assert(!filename.empty());
1539 if(filename.empty())
1542 // Toss out any "hidden" files
1543 if(basename(filename)[0]=='.')
1546 // If we aren't an absolute path, turn ourselves into one
1547 if(!is_absolute_path(filename))
1548 filename=absolute_path(filename);
1550 std::string old_window_size;
1552 list<string>::iterator iter;
1553 list<string>::iterator iter_wsize;
1554 // Check to see if the file is already on the list.
1555 // If it is, then remove it from the list
1556 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1559 recent_files.erase(iter);
1560 old_window_size = *iter_wsize;
1561 recent_files_window_size.erase(iter_wsize);
1566 // Push the filename to the front of the list
1567 recent_files.push_front(filename);
1568 if(window_size.empty())
1569 recent_files_window_size.push_front(old_window_size);
1571 recent_files_window_size.push_front(window_size);
1573 // Clean out the files at the end of the list.
1574 while(recent_files.size()>(unsigned)get_max_recent_files())
1576 recent_files.pop_back();
1577 recent_files_window_size.pop_back();
1580 signal_recent_files_changed_();
1585 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1588 App::get_time_format()
1590 return _App_time_format;
1594 App::set_time_format(synfig::Time::Format x)
1601 App::save_settings()
1606 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1607 setlocale(LC_NUMERIC, "C");
1609 std::string filename=get_config_file("accelrc");
1610 Gtk::AccelMap::save(filename);
1613 std::string filename=get_config_file("recentfiles");
1615 std::ofstream file(filename.c_str());
1619 synfig::warning("Unable to save %s",filename.c_str());
1623 list<string>::reverse_iterator iter;
1625 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1629 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1631 std::ofstream file(filename.c_str());
1635 synfig::warning("Unable to save %s",filename.c_str());
1639 list<string>::reverse_iterator iter;
1641 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1645 std::string filename=get_config_file("settings");
1646 synfigapp::Main::settings().save_to_file(filename);
1647 setlocale(LC_NUMERIC,old_locale);
1651 synfig::warning("Caught exception when attempting to save settings.");
1656 App::load_settings()
1661 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1662 setlocale(LC_NUMERIC, "C");
1664 std::string filename=get_config_file("accelrc");
1665 Gtk::AccelMap::load(filename);
1668 bool window_size_broken = false;
1670 std::string filename=get_config_file("recentfiles");
1671 std::string filename_window_size=filename+std::string("_window_size");
1673 std::ifstream file(filename.c_str());
1674 std::ifstream file_window_size(filename_window_size.c_str());
1676 if(!file_window_size)
1677 window_size_broken = true;
1681 std::string recent_file;
1682 std::string recent_file_window_size;
1683 getline(file,recent_file);
1684 if(!window_size_broken)
1685 getline(file_window_size,recent_file_window_size);
1686 if(!recent_file.empty())
1688 if(!window_size_broken && !file_window_size)
1689 window_size_broken = true;
1690 if (std::ifstream(recent_file.c_str()))
1692 if(!window_size_broken)
1693 add_recent_file(recent_file,recent_file_window_size);
1695 add_recent_file(recent_file);
1699 if(!window_size_broken && file_window_size)
1700 window_size_broken = true;
1702 if(window_size_broken)
1704 recent_files_window_size.clear();
1705 recent_files_window_size.resize(recent_files.size());
1708 std::string filename=get_config_file("settings");
1709 if(!synfigapp::Main::settings().load_from_file(filename))
1711 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1712 //if(!synfigapp::Main::settings().load_from_file(filename))
1714 gamma.set_gamma(1.0/2.2);
1715 reset_initial_window_configuration();
1718 setlocale(LC_NUMERIC,old_locale);
1722 synfig::warning("Caught exception when attempting to load settings.");
1727 App::reset_initial_window_configuration()
1729 Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
1730 Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
1731 Gdk::Rectangle rect;
1732 // A proper way to obtain the primary monitor is to use the
1733 // Gdk::Screen::get_primary_monitor () const member. But as it
1734 // was introduced in gtkmm 2.20 I assume that the monitor 0 is the
1736 screen->get_monitor_geometry(0,rect);
1737 #define hpanel_width 79.0f
1738 #define hpanel_height 25.0f
1739 #define vpanel_width 20.0f
1740 #define vpanel_height 100.0f
1744 /* percentages referred to width or height of the screen
1745 *---------------------------------------------------------------------*
1760 *-----hdock%----------------------------------------------|------------
1765 * --------------------------------------------------------------------*
1768 int v_xpos=rect.get_x() + rect.get_width()*(1.0-vpanel_width/100.0);
1769 int v_xsize=rect.get_width()*vpanel_width/100.0;
1770 int v_ypos=rect.get_y();
1771 int v_ysize=rect.get_height()*vpanel_height/100.0;
1772 std::string v_pos(strprintf("%d %d", v_xpos, v_ypos));
1773 std::string v_size(strprintf("%d %d", v_xsize, v_ysize));
1775 int h_xpos=rect.get_x();
1776 int h_xsize=rect.get_width()*hpanel_width/100.0;
1777 int h_ypos=rect.get_y()+ rect.get_height()*(1.0-hpanel_height/100.0);;
1778 int h_ysize=rect.get_height()*hpanel_height/100.0;
1779 std::string h_pos(strprintf("%d %d", h_xpos, h_ypos));
1780 std::string h_size(strprintf("%d %d", h_xsize, h_ysize));
1781 int v_dock1 = rect.get_height()*vdock*0.8/100.0;
1782 int v_dock2 = rect.get_height()*vdock*0.6/100.0;
1783 int v_dock3 = rect.get_height()*vdock*1.1/100.0;
1784 int h_dock = rect.get_width()*hdock/100.0;
1786 std::string v_contents(strprintf("%d %d %d", v_dock1, v_dock2, v_dock3));
1787 std::string h_contents(strprintf("%d", h_dock));
1788 // Tool Box position
1789 std::string tbox_pos(strprintf("%d %d", rect.get_x(), rect.get_y()));
1791 synfig::info("tool box pos: %s", tbox_pos.c_str());
1792 synfig::info("v_contents sizes: %s", v_contents.c_str());
1793 synfig::info("v_pos: %s", v_pos.c_str());
1794 synfig::info("v_sizes: %s", v_size.c_str());
1795 synfig::info("h_contents sizes: %s", h_contents.c_str());
1796 synfig::info("h_pos: %s", h_pos.c_str());
1797 synfig::info("h_sizes: %s", h_size.c_str());
1799 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1800 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1801 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size",v_contents);
1802 synfigapp::Main::settings().set_value("dock.dialog.1.size",v_size);
1803 synfigapp::Main::settings().set_value("dock.dialog.1.pos",v_pos);
1804 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1805 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1806 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size",h_contents);
1807 synfigapp::Main::settings().set_value("dock.dialog.2.size",h_size);
1808 synfigapp::Main::settings().set_value("dock.dialog.2.pos",h_pos);
1809 synfigapp::Main::settings().set_value("window.toolbox.pos",tbox_pos);
1811 dock_manager->show_all_dock_dialogs();
1815 App::reset_initial_preferences()
1817 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1818 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1819 #ifdef SINGLE_THREADED
1820 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1822 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1823 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1824 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1825 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1826 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1827 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1828 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1829 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1834 App::shutdown_request(GdkEventAny*)
1838 //return !shutdown_in_progress;
1844 if(shutdown_in_progress)return;
1847 get_ui_interface()->task(_("Quit Request"));
1850 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1854 std::list<etl::handle<Instance> >::iterator iter;
1855 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1857 if(!(*iter)->safe_close())
1861 if((*iter)->synfigapp::Instance::get_action_count())
1863 handle<synfigapp::UIInterface> uim;
1864 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1866 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1867 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1869 case synfigapp::UIInterface::RESPONSE_NO:
1871 case synfigapp::UIInterface::RESPONSE_YES:
1874 case synfigapp::UIInterface::RESPONSE_CANCEL:
1883 if((*iter)->synfigapp::Instance::is_modified())
1885 handle<synfigapp::UIInterface> uim;
1886 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1888 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() );
1889 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1891 case synfigapp::UIInterface::RESPONSE_NO:
1893 case synfigapp::UIInterface::RESPONSE_YES:
1894 (*iter)->dialog_cvs_commit();
1896 case synfigapp::UIInterface::RESPONSE_CANCEL:
1905 // This next line causes things to crash for some reason
1909 shutdown_in_progress=true;
1911 instance_list.clear();
1913 while(studio::App::events_pending())studio::App::iteration(false);
1916 auto_recover->normal_shutdown();
1918 get_ui_interface()->task(_("Quit Request sent"));
1924 dialog_setup->refresh();
1925 dialog_setup->show();
1928 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1929 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1932 //#define USE_WIN32_FILE_DIALOGS 1
1935 #ifdef USE_WIN32_FILE_DIALOGS
1936 static OPENFILENAME ofn={};
1940 #include <gdk/gdkwin32.h>
1944 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1946 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1948 #ifdef USE_WIN32_FILE_DIALOGS
1949 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1951 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1952 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1953 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1955 ofn.lStructSize=sizeof(OPENFILENAME);
1956 ofn.hwndOwner = hWnd;
1957 ofn.hInstance = hInstance;
1958 ofn.lpstrFilter = szFilter;
1959 // ofn.lpstrCustomFilter=NULL;
1960 // ofn.nMaxCustFilter=0;
1961 // ofn.nFilterIndex=0;
1962 // ofn.lpstrFile=NULL;
1963 ofn.nMaxFile=MAX_PATH;
1964 // ofn.lpstrFileTitle=NULL;
1965 // ofn.lpstrInitialDir=NULL;
1966 // ofn.lpstrTitle=NULL;
1967 ofn.Flags=OFN_HIDEREADONLY;
1968 // ofn.nFileOffset=0;
1969 // ofn.nFileExtension=0;
1970 ofn.lpstrDefExt=TEXT("sif");
1971 // ofn.lCustData = 0l;
1973 // ofn.lpTemplateName=NULL;
1975 CHAR szFilename[MAX_PATH];
1977 strcpy(szFilename,filename.c_str());
1978 strcpy(szTitle,title.c_str());
1980 ofn.lpstrFile=szFilename;
1981 ofn.lpstrFileTitle=szTitle;
1983 if(GetOpenFileName(&ofn))
1985 filename=szFilename;
1990 #else // not USE_WIN32_FILE_DIALOGS
1991 synfig::String prev_path;
1993 if(!_preferences.get_value(preference, prev_path))
1996 prev_path = absolute_path(prev_path);
1998 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2000 dialog->set_current_folder(prev_path);
2001 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2002 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
2004 if (filename.empty())
2005 dialog->set_filename(prev_path);
2006 else if (is_absolute_path(filename))
2007 dialog->set_filename(filename);
2009 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2011 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2012 filename = dialog->get_filename();
2013 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
2014 _preferences.set_value(preference, dirname(filename));
2021 #endif // not USE_WIN32_FILE_DIALOGS
2025 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2027 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2029 #if USE_WIN32_FILE_DIALOGS
2030 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2032 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2033 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2034 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2036 ofn.lStructSize=sizeof(OPENFILENAME);
2037 ofn.hwndOwner = hWnd;
2038 ofn.hInstance = hInstance;
2039 ofn.lpstrFilter = szFilter;
2040 // ofn.lpstrCustomFilter=NULL;
2041 // ofn.nMaxCustFilter=0;
2042 // ofn.nFilterIndex=0;
2043 // ofn.lpstrFile=NULL;
2044 ofn.nMaxFile=MAX_PATH;
2045 // ofn.lpstrFileTitle=NULL;
2046 // ofn.lpstrInitialDir=NULL;
2047 // ofn.lpstrTitle=NULL;
2048 ofn.Flags=OFN_OVERWRITEPROMPT;
2049 // ofn.nFileOffset=0;
2050 // ofn.nFileExtension=0;
2051 ofn.lpstrDefExt=TEXT("sif");
2052 // ofn.lCustData = 0l;
2054 // ofn.lpTemplateName=NULL;
2056 CHAR szFilename[MAX_PATH];
2058 strcpy(szFilename,filename.c_str());
2059 strcpy(szTitle,title.c_str());
2061 ofn.lpstrFile=szFilename;
2062 ofn.lpstrFileTitle=szTitle;
2064 if(GetSaveFileName(&ofn))
2066 filename=szFilename;
2067 _preferences.set_value(preference,dirname(filename));
2072 synfig::String prev_path;
2074 if(!_preferences.get_value(preference, prev_path))
2077 prev_path = absolute_path(prev_path);
2079 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2081 dialog->set_current_folder(prev_path);
2082 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2083 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2085 Widget_Enum *file_type_enum = 0;
2086 if (preference == ANIMATION_DIR_PREFERENCE)
2088 file_type_enum = manage(new Widget_Enum());
2089 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2090 .add_enum_value(synfig::RELEASE_VERSION_0_62_01, "0.62.01", strprintf("0.62.01 (%s)", _("current")))
2091 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", "0.61.00")
2092 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2093 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2094 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2095 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2096 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2098 Gtk::HBox *hbox = manage(new Gtk::HBox);
2099 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2100 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2103 dialog->set_extra_widget(*hbox);
2106 if (filename.empty())
2107 dialog->set_filename(prev_path);
2110 std::string full_path;
2111 if (is_absolute_path(filename))
2112 full_path = filename;
2114 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2116 // select the file if it exists
2117 dialog->set_filename(full_path);
2119 // if the file doesn't exist, put its name into the filename box
2121 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2122 dialog->set_current_name(basename(filename));
2125 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2126 if (preference == ANIMATION_DIR_PREFERENCE)
2127 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2128 filename = dialog->get_filename();
2129 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2130 _preferences.set_value(preference, dirname(filename));
2141 App::dialog_error_blocking(const std::string &title, const std::string &message)
2143 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2144 dialog.set_title(title);
2150 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2152 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2153 dialog.set_title(title);
2159 App::dialog_yes_no(const std::string &title, const std::string &message)
2164 true // use_separator
2166 Gtk::Label label(message);
2169 dialog.get_vbox()->pack_start(label);
2170 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2171 dialog.add_button(Gtk::StockID("gtk-no"),0);
2173 return dialog.run();
2177 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2182 true // use_separator
2184 Gtk::Label label(message);
2187 dialog.get_vbox()->pack_start(label);
2188 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2189 dialog.add_button(Gtk::StockID("gtk-no"),0);
2190 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2192 return dialog.run();
2196 App::dialog_not_implemented()
2198 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2199 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2204 try_open_url(const std::string &url)
2207 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2209 std::vector<std::string> command_line;
2210 std::vector<std::string> browsers;
2211 browsers.reserve(23);
2213 // Browser wrapper scripts
2214 #ifdef USE_OPEN_FOR_URLS
2215 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2217 browsers.push_back("xdg-open"); // XDG wrapper
2218 browsers.push_back("sensible-browser"); // Debian wrapper
2219 browsers.push_back("gnome-open"); // GNOME wrapper
2220 browsers.push_back("kfmclient"); // KDE wrapper
2221 browsers.push_back("exo-open"); // XFCE wrapper
2223 // Alternatives system
2224 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2225 browsers.push_back("x-www-browser"); // Debian GUI alternative
2227 // Individual browsers
2228 browsers.push_back("firefox");
2229 browsers.push_back("epiphany-browser");
2230 browsers.push_back("epiphany");
2231 browsers.push_back("konqueror");
2232 browsers.push_back("iceweasel");
2233 browsers.push_back("mozilla");
2234 browsers.push_back("netscape");
2235 browsers.push_back("icecat");
2236 browsers.push_back("galeon");
2237 browsers.push_back("midori");
2238 browsers.push_back("safari");
2239 browsers.push_back("opera");
2240 browsers.push_back("amaya");
2241 browsers.push_back("netsurf");
2242 browsers.push_back("dillo");
2244 // Try the user-specified browser first
2245 command_line.push_back(App::browser_command);
2246 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2247 command_line.push_back(url);
2249 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2250 catch( Glib::SpawnError& exception ){
2252 while ( !browsers.empty() )
2254 // Skip the browser if we already tried it
2255 if( browsers[0] == App::browser_command )
2258 // Construct the command line
2259 command_line.clear();
2260 command_line.push_back(browsers[0]);
2261 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2262 command_line.push_back(url);
2264 // Remove the browser from the list
2265 browsers.erase(browsers.begin());
2267 // Try to spawn the browser
2268 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2269 // Failed, move on to the next one
2270 catch(Glib::SpawnError& exception){ continue; }
2271 return true; // No exception means we succeeded!
2282 if (!try_open_url("http://synfig.org/wiki/Category:Manual"))
2284 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2285 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://synfig.org/wiki/Category:Manual"));
2286 dialog.set_title(_("Help"));
2292 App::open_url(const std::string &url)
2294 if(!try_open_url(url))
2296 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2297 dialog.set_secondary_text(url);
2298 dialog.set_title(_("No browser found"));
2304 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2309 true); // use_separator
2311 Gtk::Label label(message);
2313 dialog.get_vbox()->pack_start(label);
2316 entry.set_text(text);
2318 entry.set_activates_default(true);
2320 dialog.get_vbox()->pack_start(entry);
2322 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2323 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2324 dialog.set_default_response(Gtk::RESPONSE_OK);
2326 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2329 if(dialog.run()!=Gtk::RESPONSE_OK)
2332 text=entry.get_text();
2338 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2343 true); // use_separator
2345 Gtk::Label label(message);
2347 dialog.get_vbox()->pack_start(label);
2349 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2350 text_buffer->set_text(text);
2351 Gtk::TextView text_view(text_buffer);
2354 dialog.get_vbox()->pack_start(text_view);
2356 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2357 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2358 dialog.set_default_response(Gtk::RESPONSE_OK);
2360 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2363 if(dialog.run()!=Gtk::RESPONSE_OK)
2366 text=text_buffer->get_text();
2372 App::open(std::string filename)
2374 return open_as(filename,filename);
2377 // this is called from autorecover.cpp:
2378 // App::open_as(get_shadow_file_name(filename),filename)
2379 // other than that, 'filename' and 'as' are the same
2381 App::open_as(std::string filename,std::string as)
2384 char long_name[1024];
2385 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2386 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2387 // don't use it if that's the case
2388 if (long_name[0] != '\0')
2394 OneMoment one_moment;
2395 String errors, warnings;
2397 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2398 if(canvas && get_instance(canvas))
2400 get_instance(canvas)->find_canvas_view(canvas)->present();
2401 info("%s is already open", filename.c_str());
2402 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2407 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2410 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2412 if (as.find(custom_filename_prefix.c_str()) != 0)
2413 add_recent_file(as);
2415 handle<Instance> instance(Instance::create(canvas));
2418 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2420 set_recent_file_window_size(instance);
2424 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)")))
2425 instance->dialog_cvs_update();
2430 dialog_error_blocking(_("Error"), x);
2433 catch(runtime_error x)
2435 dialog_error_blocking(_("Error"), x.what());
2440 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2451 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2453 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2454 canvas->set_name(file_name);
2455 file_name += ".sifz";
2457 canvas->rend_desc().set_frame_rate(preferred_fps);
2458 canvas->rend_desc().set_time_start(0.0);
2459 canvas->rend_desc().set_time_end(5.0);
2460 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2461 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2462 // The top left and botton right positions are expressed in units
2463 // Original convention is that 1 unit = 60 pixels
2464 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2465 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2466 canvas->rend_desc().set_w(preferred_x_size);
2467 canvas->rend_desc().set_h(preferred_y_size);
2468 canvas->rend_desc().set_antialias(1);
2469 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2470 canvas->set_file_name(file_name);
2472 handle<Instance> instance = Instance::create(canvas);
2474 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2475 instance->find_canvas_view(canvas)->canvas_properties.present();
2479 App::dialog_open(string filename)
2481 if (filename.empty())
2484 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2486 // If the filename still has wildcards, then we should
2487 // continue looking for the file we want
2488 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2494 get_ui_interface()->error(_("Unable to open file"));
2499 App::set_selected_instance(etl::loose_handle<Instance> instance)
2501 /* if(get_selected_instance()==instance)
2503 selected_instance=instance;
2504 signal_instance_selected()(instance);
2510 selected_instance=instance;
2511 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2515 instance->focus(instance->get_canvas());
2518 set_selected_canvas_view(0);
2520 signal_instance_selected()(instance);
2524 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2526 selected_canvas_view=canvas_view;
2527 signal_canvas_view_focus()(selected_canvas_view);
2530 selected_instance=canvas_view->get_instance();
2531 signal_instance_selected()(canvas_view->get_instance());
2534 if(get_selected_canvas_view()==canvas_view)
2536 signal_canvas_view_focus()(selected_canvas_view);
2537 signal_instance_selected()(canvas_view->get_instance());
2540 selected_canvas_view=canvas_view;
2541 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2542 set_selected_instance(canvas_view->get_instance());
2543 signal_canvas_view_focus()(selected_canvas_view);
2547 etl::loose_handle<Instance>
2548 App::get_instance(etl::handle<synfig::Canvas> canvas)
2550 if(!canvas) return 0;
2551 canvas=canvas->get_root();
2553 std::list<etl::handle<Instance> >::iterator iter;
2554 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2556 if((*iter)->get_canvas()==canvas)
2572 if(selected_instance)
2573 selected_instance->undo();
2579 if(selected_instance)
2580 selected_instance->redo();
2584 studio::App::get_base_path()
2586 return app_base_path_;