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\n"
1323 "before you could save all your files.\n"
1324 "Recover unsaved changes?"),
1325 _("Recover"), _("Ignore"))
1326 == synfigapp::UIInterface::RESPONSE_OK)
1328 int number_recovered;
1329 if(!auto_recover->recover(number_recovered))
1330 if (number_recovered)
1331 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1333 get_ui_interface()->error(_("Unable to recover from previous crash"));
1335 get_ui_interface()->error(
1336 _("Synfig Studio has attempted to recover\n"
1337 "from a previous crash. The files that it has\n"
1338 "recovered are NOT YET SAVED. It would be a good\n"
1339 "idea to review them and save them now."));
1341 if (number_recovered)
1344 splash_screen.show();
1347 // Look for any files given on the command line,
1348 // and load them if found.
1349 for(;*argc>=1;(*argc)--)
1350 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1352 studio_init_cb.task(_("Loading files..."));
1353 splash_screen.hide();
1354 open((*argv)[*argc]);
1356 splash_screen.show();
1359 // if no file was specified to be opened, create a new document to help new users get started more easily
1360 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1363 studio_init_cb.task(_("Done."));
1364 studio_init_cb.amount_complete(10000,10000);
1366 // To avoid problems with some window managers and gtk >= 2.18
1367 // we should show dock dialogs after the settings load.
1368 // If dock dialogs are shown before the settings are loaded,
1369 // the windows manager can act over it.
1370 // See discussions here:
1371 // * http://synfig.org/forums/viewtopic.php?f=1&t=1131&st=0&sk=t&sd=a&start=30
1372 // * http://synfig.org/forums/viewtopic.php?f=15&t=1062
1373 dock_manager->show_all_dock_dialogs();
1379 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1383 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1387 StateManager* App::get_state_manager() { return state_manager; }
1391 shutdown_in_progress=true;
1395 synfigapp::Main::settings().remove_domain("pref");
1397 selected_instance=0;
1399 // Unload all of the modules
1400 for(;!module_list_.empty();module_list_.pop_back())
1403 delete state_manager;
1407 delete auto_recover;
1415 delete dialog_setup;
1417 delete dialog_gradient;
1419 delete dialog_color;
1421 delete dialog_input;
1423 delete dock_manager;
1425 instance_list.clear();
1429 App::get_user_app_directory()
1431 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1433 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1435 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1440 App::get_config_file(const synfig::String& file)
1442 return Glib::build_filename(get_user_app_directory(),file);
1445 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1447 App::set_recent_file_window_size(etl::handle<Instance> instance)
1450 const std::string &canvas_window_size = *recent_files_window_size.begin();
1452 if(canvas_window_size.empty())
1455 synfig::String::size_type current=0;
1456 bool seen_root(false), shown_non_root(false);
1458 while(current != synfig::String::npos)
1460 // find end of first field (canvas) or return
1461 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1462 if(separator == synfig::String::npos) break;
1465 synfig::Canvas::Handle canvas;
1468 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1470 catch(Exception::IDNotFound) {
1471 // can't find the canvas; skip to the next canvas or return
1472 separator = canvas_window_size.find_first_of('\t', current);
1473 if(separator == synfig::String::npos) return;
1474 current = separator+1;
1478 if (canvas->is_root())
1481 shown_non_root = true;
1483 // check that we have the tab character the ends this canvas' data or return
1484 current = separator+1;
1485 separator = canvas_window_size.find_first_of('\t', current);
1486 if(separator == synfig::String::npos) return;
1489 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1491 current = separator+1;
1494 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1495 canvasview->move(x,y);
1496 canvasview->resize(w,h);
1497 canvasview->present();
1499 current = separator+1;
1502 if (shown_non_root && !seen_root)
1503 instance->find_canvas_view(instance->get_canvas())->hide();
1507 App::add_recent_file(const etl::handle<Instance> instance)
1510 std::string canvas_window_size;
1512 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1513 Instance::CanvasViewList::const_iterator iter;
1515 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1517 if( !((*iter)->is_visible()) )
1520 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1521 int x_pos, y_pos, x_size, y_size;
1522 (*iter)->get_position(x_pos,y_pos);
1523 (*iter)->get_size(x_size,y_size);
1525 canvas_window_size += strprintf("%s %d %d %d %d\t",
1526 canvas->get_relative_id(canvas->get_root()).c_str(),
1531 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1535 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1537 std::string filename(file_name);
1539 assert(!filename.empty());
1541 if(filename.empty())
1544 // Toss out any "hidden" files
1545 if(basename(filename)[0]=='.')
1548 // If we aren't an absolute path, turn ourselves into one
1549 if(!is_absolute_path(filename))
1550 filename=absolute_path(filename);
1552 std::string old_window_size;
1554 list<string>::iterator iter;
1555 list<string>::iterator iter_wsize;
1556 // Check to see if the file is already on the list.
1557 // If it is, then remove it from the list
1558 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1561 recent_files.erase(iter);
1562 old_window_size = *iter_wsize;
1563 recent_files_window_size.erase(iter_wsize);
1568 // Push the filename to the front of the list
1569 recent_files.push_front(filename);
1570 if(window_size.empty())
1571 recent_files_window_size.push_front(old_window_size);
1573 recent_files_window_size.push_front(window_size);
1575 // Clean out the files at the end of the list.
1576 while(recent_files.size()>(unsigned)get_max_recent_files())
1578 recent_files.pop_back();
1579 recent_files_window_size.pop_back();
1582 signal_recent_files_changed_();
1587 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1590 App::get_time_format()
1592 return _App_time_format;
1596 App::set_time_format(synfig::Time::Format x)
1603 App::save_settings()
1608 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1609 setlocale(LC_NUMERIC, "C");
1611 std::string filename=get_config_file("accelrc");
1612 Gtk::AccelMap::save(filename);
1615 std::string filename=get_config_file("recentfiles");
1617 std::ofstream file(filename.c_str());
1621 synfig::warning("Unable to save %s",filename.c_str());
1625 list<string>::reverse_iterator iter;
1627 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1631 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1633 std::ofstream file(filename.c_str());
1637 synfig::warning("Unable to save %s",filename.c_str());
1641 list<string>::reverse_iterator iter;
1643 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1647 std::string filename=get_config_file("settings");
1648 synfigapp::Main::settings().save_to_file(filename);
1649 setlocale(LC_NUMERIC,old_locale);
1653 synfig::warning("Caught exception when attempting to save settings.");
1658 App::load_settings()
1663 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1664 setlocale(LC_NUMERIC, "C");
1666 std::string filename=get_config_file("accelrc");
1667 Gtk::AccelMap::load(filename);
1670 bool window_size_broken = false;
1672 std::string filename=get_config_file("recentfiles");
1673 std::string filename_window_size=filename+std::string("_window_size");
1675 std::ifstream file(filename.c_str());
1676 std::ifstream file_window_size(filename_window_size.c_str());
1678 if(!file_window_size)
1679 window_size_broken = true;
1683 std::string recent_file;
1684 std::string recent_file_window_size;
1685 getline(file,recent_file);
1686 if(!window_size_broken)
1687 getline(file_window_size,recent_file_window_size);
1688 if(!recent_file.empty())
1690 if(!window_size_broken && !file_window_size)
1691 window_size_broken = true;
1692 if (std::ifstream(recent_file.c_str()))
1694 if(!window_size_broken)
1695 add_recent_file(recent_file,recent_file_window_size);
1697 add_recent_file(recent_file);
1701 if(!window_size_broken && file_window_size)
1702 window_size_broken = true;
1704 if(window_size_broken)
1706 recent_files_window_size.clear();
1707 recent_files_window_size.resize(recent_files.size());
1710 std::string filename=get_config_file("settings");
1711 if(!synfigapp::Main::settings().load_from_file(filename))
1713 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1714 //if(!synfigapp::Main::settings().load_from_file(filename))
1716 gamma.set_gamma(1.0/2.2);
1717 reset_initial_window_configuration();
1720 setlocale(LC_NUMERIC,old_locale);
1724 synfig::warning("Caught exception when attempting to load settings.");
1729 App::reset_initial_window_configuration()
1731 Glib::RefPtr<Gdk::Display> display(Gdk::Display::get_default());
1732 Glib::RefPtr<const Gdk::Screen> screen(display->get_default_screen());
1733 Gdk::Rectangle rect;
1734 // A proper way to obtain the primary monitor is to use the
1735 // Gdk::Screen::get_primary_monitor () const member. But as it
1736 // was introduced in gtkmm 2.20 I assume that the monitor 0 is the
1738 screen->get_monitor_geometry(0,rect);
1739 #define hpanel_width 79.0f
1740 #define hpanel_height 25.0f
1741 #define vpanel_width 20.0f
1742 #define vpanel_height 100.0f
1746 /* percentages referred to width or height of the screen
1747 *---------------------------------------------------------------------*
1762 *-----hdock%----------------------------------------------|------------
1767 * --------------------------------------------------------------------*
1770 int v_xpos=rect.get_x() + rect.get_width()*(1.0-vpanel_width/100.0);
1771 int v_xsize=rect.get_width()*vpanel_width/100.0;
1772 int v_ypos=rect.get_y();
1773 int v_ysize=rect.get_height()*vpanel_height/100.0;
1774 std::string v_pos(strprintf("%d %d", v_xpos, v_ypos));
1775 std::string v_size(strprintf("%d %d", v_xsize, v_ysize));
1777 int h_xpos=rect.get_x();
1778 int h_xsize=rect.get_width()*hpanel_width/100.0;
1779 int h_ypos=rect.get_y()+ rect.get_height()*(1.0-hpanel_height/100.0);;
1780 int h_ysize=rect.get_height()*hpanel_height/100.0;
1781 std::string h_pos(strprintf("%d %d", h_xpos, h_ypos));
1782 std::string h_size(strprintf("%d %d", h_xsize, h_ysize));
1783 int v_dock1 = rect.get_height()*vdock*0.8/100.0;
1784 int v_dock2 = rect.get_height()*vdock*0.6/100.0;
1785 int v_dock3 = rect.get_height()*vdock*1.1/100.0;
1786 int h_dock = rect.get_width()*hdock/100.0;
1788 std::string v_contents(strprintf("%d %d %d", v_dock1, v_dock2, v_dock3));
1789 std::string h_contents(strprintf("%d", h_dock));
1790 // Tool Box position
1791 std::string tbox_pos(strprintf("%d %d", rect.get_x(), rect.get_y()));
1793 synfig::info("tool box pos: %s", tbox_pos.c_str());
1794 synfig::info("v_contents sizes: %s", v_contents.c_str());
1795 synfig::info("v_pos: %s", v_pos.c_str());
1796 synfig::info("v_sizes: %s", v_size.c_str());
1797 synfig::info("h_contents sizes: %s", h_contents.c_str());
1798 synfig::info("h_pos: %s", h_pos.c_str());
1799 synfig::info("h_sizes: %s", h_size.c_str());
1801 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1802 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1803 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size",v_contents);
1804 synfigapp::Main::settings().set_value("dock.dialog.1.size",v_size);
1805 synfigapp::Main::settings().set_value("dock.dialog.1.pos",v_pos);
1806 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1807 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1808 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size",h_contents);
1809 synfigapp::Main::settings().set_value("dock.dialog.2.size",h_size);
1810 synfigapp::Main::settings().set_value("dock.dialog.2.pos",h_pos);
1811 synfigapp::Main::settings().set_value("window.toolbox.pos",tbox_pos);
1813 dock_manager->show_all_dock_dialogs();
1817 App::reset_initial_preferences()
1819 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1820 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1821 #ifdef SINGLE_THREADED
1822 synfigapp::Main::settings().set_value("pref.single_threaded","1");
1824 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1825 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1826 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1827 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1828 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1829 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1830 synfigapp::Main::settings().set_value("pref.preferred_fps","24.0");
1831 synfigapp::Main::settings().set_value("pref.predefined_fps",DEFAULT_PREDEFINED_FPS);
1836 App::shutdown_request(GdkEventAny*)
1840 //return !shutdown_in_progress;
1846 if(shutdown_in_progress)return;
1849 get_ui_interface()->task(_("Quit Request"));
1852 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1856 std::list<etl::handle<Instance> >::iterator iter;
1857 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1859 if(!(*iter)->safe_close())
1863 if((*iter)->synfigapp::Instance::get_action_count())
1865 handle<synfigapp::UIInterface> uim;
1866 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1868 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1869 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1871 case synfigapp::UIInterface::RESPONSE_NO:
1873 case synfigapp::UIInterface::RESPONSE_YES:
1876 case synfigapp::UIInterface::RESPONSE_CANCEL:
1885 if((*iter)->synfigapp::Instance::is_modified())
1887 handle<synfigapp::UIInterface> uim;
1888 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1890 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() );
1891 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1893 case synfigapp::UIInterface::RESPONSE_NO:
1895 case synfigapp::UIInterface::RESPONSE_YES:
1896 (*iter)->dialog_cvs_commit();
1898 case synfigapp::UIInterface::RESPONSE_CANCEL:
1907 // This next line causes things to crash for some reason
1911 shutdown_in_progress=true;
1913 instance_list.clear();
1915 while(studio::App::events_pending())studio::App::iteration(false);
1918 auto_recover->normal_shutdown();
1920 get_ui_interface()->task(_("Quit Request sent"));
1926 dialog_setup->refresh();
1927 dialog_setup->show();
1930 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1931 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1934 //#define USE_WIN32_FILE_DIALOGS 1
1937 #ifdef USE_WIN32_FILE_DIALOGS
1938 static OPENFILENAME ofn={};
1942 #include <gdk/gdkwin32.h>
1946 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1948 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1950 #ifdef USE_WIN32_FILE_DIALOGS
1951 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1953 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1954 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1955 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1957 ofn.lStructSize=sizeof(OPENFILENAME);
1958 ofn.hwndOwner = hWnd;
1959 ofn.hInstance = hInstance;
1960 ofn.lpstrFilter = szFilter;
1961 // ofn.lpstrCustomFilter=NULL;
1962 // ofn.nMaxCustFilter=0;
1963 // ofn.nFilterIndex=0;
1964 // ofn.lpstrFile=NULL;
1965 ofn.nMaxFile=MAX_PATH;
1966 // ofn.lpstrFileTitle=NULL;
1967 // ofn.lpstrInitialDir=NULL;
1968 // ofn.lpstrTitle=NULL;
1969 ofn.Flags=OFN_HIDEREADONLY;
1970 // ofn.nFileOffset=0;
1971 // ofn.nFileExtension=0;
1972 ofn.lpstrDefExt=TEXT("sif");
1973 // ofn.lCustData = 0l;
1975 // ofn.lpTemplateName=NULL;
1977 CHAR szFilename[MAX_PATH];
1979 strcpy(szFilename,filename.c_str());
1980 strcpy(szTitle,title.c_str());
1982 ofn.lpstrFile=szFilename;
1983 ofn.lpstrFileTitle=szTitle;
1985 if(GetOpenFileName(&ofn))
1987 filename=szFilename;
1992 #else // not USE_WIN32_FILE_DIALOGS
1993 synfig::String prev_path;
1995 if(!_preferences.get_value(preference, prev_path))
1998 prev_path = absolute_path(prev_path);
2000 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
2002 dialog->set_current_folder(prev_path);
2003 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2004 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
2006 if (filename.empty())
2007 dialog->set_filename(prev_path);
2008 else if (is_absolute_path(filename))
2009 dialog->set_filename(filename);
2011 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
2013 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2014 filename = dialog->get_filename();
2015 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
2016 _preferences.set_value(preference, dirname(filename));
2023 #endif // not USE_WIN32_FILE_DIALOGS
2027 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2029 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2031 #if USE_WIN32_FILE_DIALOGS
2032 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2034 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2035 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2036 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2038 ofn.lStructSize=sizeof(OPENFILENAME);
2039 ofn.hwndOwner = hWnd;
2040 ofn.hInstance = hInstance;
2041 ofn.lpstrFilter = szFilter;
2042 // ofn.lpstrCustomFilter=NULL;
2043 // ofn.nMaxCustFilter=0;
2044 // ofn.nFilterIndex=0;
2045 // ofn.lpstrFile=NULL;
2046 ofn.nMaxFile=MAX_PATH;
2047 // ofn.lpstrFileTitle=NULL;
2048 // ofn.lpstrInitialDir=NULL;
2049 // ofn.lpstrTitle=NULL;
2050 ofn.Flags=OFN_OVERWRITEPROMPT;
2051 // ofn.nFileOffset=0;
2052 // ofn.nFileExtension=0;
2053 ofn.lpstrDefExt=TEXT("sif");
2054 // ofn.lCustData = 0l;
2056 // ofn.lpTemplateName=NULL;
2058 CHAR szFilename[MAX_PATH];
2060 strcpy(szFilename,filename.c_str());
2061 strcpy(szTitle,title.c_str());
2063 ofn.lpstrFile=szFilename;
2064 ofn.lpstrFileTitle=szTitle;
2066 if(GetSaveFileName(&ofn))
2068 filename=szFilename;
2069 _preferences.set_value(preference,dirname(filename));
2074 synfig::String prev_path;
2076 if(!_preferences.get_value(preference, prev_path))
2079 prev_path = absolute_path(prev_path);
2081 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2083 dialog->set_current_folder(prev_path);
2084 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2085 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2087 Widget_Enum *file_type_enum = 0;
2088 if (preference == ANIMATION_DIR_PREFERENCE)
2090 file_type_enum = manage(new Widget_Enum());
2091 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2092 .add_enum_value(synfig::RELEASE_VERSION_0_62_01, "0.62.01", strprintf("0.62.01 (%s)", _("current")))
2093 .add_enum_value(synfig::RELEASE_VERSION_0_62_00, "0.62.00", "0.61.00")
2094 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", "0.61.09")
2095 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2096 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2097 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2098 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2100 Gtk::HBox *hbox = manage(new Gtk::HBox);
2101 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2102 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2105 dialog->set_extra_widget(*hbox);
2108 if (filename.empty())
2109 dialog->set_filename(prev_path);
2112 std::string full_path;
2113 if (is_absolute_path(filename))
2114 full_path = filename;
2116 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2118 // select the file if it exists
2119 dialog->set_filename(full_path);
2121 // if the file doesn't exist, put its name into the filename box
2123 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2124 dialog->set_current_name(basename(filename));
2127 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2128 if (preference == ANIMATION_DIR_PREFERENCE)
2129 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2130 filename = dialog->get_filename();
2131 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2132 _preferences.set_value(preference, dirname(filename));
2143 App::dialog_error_blocking(const std::string &title, const std::string &message)
2145 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2146 dialog.set_title(title);
2152 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2154 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2155 dialog.set_title(title);
2161 App::dialog_yes_no(const std::string &title, const std::string &message)
2166 true // use_separator
2168 Gtk::Label label(message);
2171 dialog.get_vbox()->pack_start(label);
2172 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2173 dialog.add_button(Gtk::StockID("gtk-no"),0);
2175 return dialog.run();
2179 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2184 true // use_separator
2186 Gtk::Label label(message);
2189 dialog.get_vbox()->pack_start(label);
2190 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2191 dialog.add_button(Gtk::StockID("gtk-no"),0);
2192 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2194 return dialog.run();
2198 App::dialog_not_implemented()
2200 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2201 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2206 try_open_url(const std::string &url)
2209 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2211 std::vector<std::string> command_line;
2212 std::vector<std::string> browsers;
2213 browsers.reserve(23);
2215 // Browser wrapper scripts
2216 #ifdef USE_OPEN_FOR_URLS
2217 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2219 browsers.push_back("xdg-open"); // XDG wrapper
2220 browsers.push_back("sensible-browser"); // Debian wrapper
2221 browsers.push_back("gnome-open"); // GNOME wrapper
2222 browsers.push_back("kfmclient"); // KDE wrapper
2223 browsers.push_back("exo-open"); // XFCE wrapper
2225 // Alternatives system
2226 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2227 browsers.push_back("x-www-browser"); // Debian GUI alternative
2229 // Individual browsers
2230 browsers.push_back("firefox");
2231 browsers.push_back("epiphany-browser");
2232 browsers.push_back("epiphany");
2233 browsers.push_back("konqueror");
2234 browsers.push_back("iceweasel");
2235 browsers.push_back("mozilla");
2236 browsers.push_back("netscape");
2237 browsers.push_back("icecat");
2238 browsers.push_back("galeon");
2239 browsers.push_back("midori");
2240 browsers.push_back("safari");
2241 browsers.push_back("opera");
2242 browsers.push_back("amaya");
2243 browsers.push_back("netsurf");
2244 browsers.push_back("dillo");
2246 // Try the user-specified browser first
2247 command_line.push_back(App::browser_command);
2248 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2249 command_line.push_back(url);
2251 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2252 catch( Glib::SpawnError& exception ){
2254 while ( !browsers.empty() )
2256 // Skip the browser if we already tried it
2257 if( browsers[0] == App::browser_command )
2260 // Construct the command line
2261 command_line.clear();
2262 command_line.push_back(browsers[0]);
2263 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2264 command_line.push_back(url);
2266 // Remove the browser from the list
2267 browsers.erase(browsers.begin());
2269 // Try to spawn the browser
2270 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2271 // Failed, move on to the next one
2272 catch(Glib::SpawnError& exception){ continue; }
2273 return true; // No exception means we succeeded!
2284 if (!try_open_url("http://synfig.org/wiki/Category:Manual"))
2286 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2287 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://synfig.org/wiki/Category:Manual"));
2288 dialog.set_title(_("Help"));
2294 App::open_url(const std::string &url)
2296 if(!try_open_url(url))
2298 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2299 dialog.set_secondary_text(url);
2300 dialog.set_title(_("No browser found"));
2306 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2311 true); // use_separator
2313 Gtk::Label label(message);
2315 dialog.get_vbox()->pack_start(label);
2318 entry.set_text(text);
2320 entry.set_activates_default(true);
2322 dialog.get_vbox()->pack_start(entry);
2324 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2325 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2326 dialog.set_default_response(Gtk::RESPONSE_OK);
2328 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2331 if(dialog.run()!=Gtk::RESPONSE_OK)
2334 text=entry.get_text();
2340 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2345 true); // use_separator
2347 Gtk::Label label(message);
2349 dialog.get_vbox()->pack_start(label);
2351 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2352 text_buffer->set_text(text);
2353 Gtk::TextView text_view(text_buffer);
2356 dialog.get_vbox()->pack_start(text_view);
2358 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2359 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2360 dialog.set_default_response(Gtk::RESPONSE_OK);
2362 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2365 if(dialog.run()!=Gtk::RESPONSE_OK)
2368 text=text_buffer->get_text();
2374 App::open(std::string filename)
2376 return open_as(filename,filename);
2379 // this is called from autorecover.cpp:
2380 // App::open_as(get_shadow_file_name(filename),filename)
2381 // other than that, 'filename' and 'as' are the same
2383 App::open_as(std::string filename,std::string as)
2386 char long_name[1024];
2387 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2388 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2389 // don't use it if that's the case
2390 if (long_name[0] != '\0')
2396 OneMoment one_moment;
2397 String errors, warnings;
2399 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2400 if(canvas && get_instance(canvas))
2402 get_instance(canvas)->find_canvas_view(canvas)->present();
2403 info("%s is already open", filename.c_str());
2404 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2409 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2412 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2414 if (as.find(custom_filename_prefix.c_str()) != 0)
2415 add_recent_file(as);
2417 handle<Instance> instance(Instance::create(canvas));
2420 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2422 set_recent_file_window_size(instance);
2426 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)")))
2427 instance->dialog_cvs_update();
2432 dialog_error_blocking(_("Error"), x);
2435 catch(runtime_error x)
2437 dialog_error_blocking(_("Error"), x.what());
2442 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2453 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2455 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2456 canvas->set_name(file_name);
2457 file_name += ".sifz";
2459 canvas->rend_desc().set_frame_rate(preferred_fps);
2460 canvas->rend_desc().set_time_start(0.0);
2461 canvas->rend_desc().set_time_end(5.0);
2462 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2463 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2464 // The top left and botton right positions are expressed in units
2465 // Original convention is that 1 unit = 60 pixels
2466 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2467 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2468 canvas->rend_desc().set_w(preferred_x_size);
2469 canvas->rend_desc().set_h(preferred_y_size);
2470 canvas->rend_desc().set_antialias(1);
2471 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2472 canvas->set_file_name(file_name);
2474 handle<Instance> instance = Instance::create(canvas);
2476 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2477 instance->find_canvas_view(canvas)->canvas_properties.present();
2481 App::dialog_open(string filename)
2483 if (filename.empty())
2486 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2488 // If the filename still has wildcards, then we should
2489 // continue looking for the file we want
2490 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2496 get_ui_interface()->error(_("Unable to open file"));
2501 App::set_selected_instance(etl::loose_handle<Instance> instance)
2503 /* if(get_selected_instance()==instance)
2505 selected_instance=instance;
2506 signal_instance_selected()(instance);
2512 selected_instance=instance;
2513 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2517 instance->focus(instance->get_canvas());
2520 set_selected_canvas_view(0);
2522 signal_instance_selected()(instance);
2526 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2528 selected_canvas_view=canvas_view;
2529 signal_canvas_view_focus()(selected_canvas_view);
2532 selected_instance=canvas_view->get_instance();
2533 signal_instance_selected()(canvas_view->get_instance());
2536 if(get_selected_canvas_view()==canvas_view)
2538 signal_canvas_view_focus()(selected_canvas_view);
2539 signal_instance_selected()(canvas_view->get_instance());
2542 selected_canvas_view=canvas_view;
2543 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2544 set_selected_instance(canvas_view->get_instance());
2545 signal_canvas_view_focus()(selected_canvas_view);
2549 etl::loose_handle<Instance>
2550 App::get_instance(etl::handle<synfig::Canvas> canvas)
2552 if(!canvas) return 0;
2553 canvas=canvas->get_root();
2555 std::list<etl::handle<Instance> >::iterator iter;
2556 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2558 if((*iter)->get_canvas()==canvas)
2574 if(selected_instance)
2575 selected_instance->undo();
2581 if(selected_instance)
2582 selected_instance->redo();
2586 studio::App::get_base_path()
2588 return app_base_path_;