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
12 ** This package is free software; you can redistribute it and/or
13 ** modify it under the terms of the GNU General Public License as
14 ** published by the Free Software Foundation; either version 2 of
15 ** the License, or (at your option) any later version.
17 ** This package is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ** General Public License for more details.
23 /* ========================================================================= */
25 /* === H E A D E R S ======================================================= */
44 #ifdef HAVE_SYS_ERRNO_H
45 #include <sys/errno.h>
47 #include <gtkmm/fileselection.h>
48 #include <gtkmm/dialog.h>
49 #include <gtkmm/messagedialog.h>
50 #include <gtkmm/label.h>
51 #include <gtkmm/stock.h>
52 #include <gtkmm/stockitem.h>
53 #include <gtkmm/iconsource.h>
54 #include <gtkmm/inputdialog.h>
55 #include <gtkmm/accelmap.h>
56 #include <gtkmm/uimanager.h>
57 #include <gtkmm/textview.h>
61 #include <gdkmm/general.h>
63 #include <synfig/loadcanvas.h>
64 #include <synfig/savecanvas.h>
70 #include "canvasview.h"
71 #include "dialog_setup.h"
72 #include "dialog_gradient.h"
73 #include "dialog_color.h"
76 #include "onemoment.h"
78 #include "dockmanager.h"
80 #include "state_eyedrop.h"
81 #include "state_normal.h"
82 #include "state_draw.h"
83 #include "state_fill.h"
84 #include "state_bline.h"
85 #include "state_polygon.h"
86 #include "state_sketch.h"
87 #include "state_gradient.h"
88 #include "state_circle.h"
89 #include "state_rectangle.h"
90 #include "state_smoothmove.h"
91 #include "state_scale.h"
92 #include "state_star.h"
93 #include "state_text.h"
94 #include "state_width.h"
95 #include "state_rotate.h"
96 #include "state_zoom.h"
98 #include "devicetracker.h"
99 #include "dialog_tooloptions.h"
100 #include "widget_enum.h"
102 #include "autorecover.h"
104 #include <synfigapp/settings.h>
105 #include "dock_history.h"
106 #include "dock_canvases.h"
107 #include "dock_keyframes.h"
108 #include "dock_layers.h"
109 #include "dock_params.h"
110 #include "dock_metadata.h"
111 #include "dock_children.h"
112 #include "dock_info.h"
113 #include "dock_navigator.h"
114 #include "dock_layergroups.h"
115 #include "dock_timetrack.h"
116 #include "dock_curves.h"
118 #include "mod_palette/mod_palette.h"
119 #include "mod_mirror/mod_mirror.h"
121 #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
274 bool studio::App::single_threaded=false;
276 bool studio::App::restrict_radius_ducks=false;
277 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
278 int studio::App::preferred_x_size=480;
279 int studio::App::preferred_y_size=270;
280 #ifdef USE_OPEN_FOR_URLS
281 String studio::App::browser_command("open"); // MacOS only
283 String studio::App::browser_command("xdg-open"); // Linux XDG standard
286 static int max_recent_files_=25;
287 int studio::App::get_max_recent_files() { return max_recent_files_; }
288 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
290 static synfig::String app_base_path_;
295 really_delete_widget(Gtk::Widget *widget)
297 // synfig::info("really delete %p", (void*)widget);
302 // nasty workaround - when we've finished with a popup menu, we want to delete it
303 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
304 // so schedule the real delete to happen in 50ms, giving the action a chance to run
306 delete_widget(Gtk::Widget *widget)
308 // synfig::info("delete %p", (void*)widget);
309 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
312 }; // END of namespace studio
313 studio::StateManager* state_manager;
318 class GlobalUIInterface : public synfigapp::UIInterface
322 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
327 true // use_separator
329 Gtk::Label label(message);
332 dialog.get_vbox()->pack_start(label);
333 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
334 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
336 dialog.set_default_response(dflt);
338 return (Response)dialog.run();
340 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
345 true // use_separator
347 Gtk::Label label(message);
350 dialog.get_vbox()->pack_start(label);
351 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
352 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
353 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
355 dialog.set_default_response(dflt);
357 return (Response)dialog.run();
359 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
364 true // use_separator
366 Gtk::Label label(message);
369 dialog.get_vbox()->pack_start(label);
370 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
371 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
373 dialog.set_default_response(dflt);
375 return (Response)dialog.run();
379 task(const std::string &task)
381 std::cerr<<task<<std::endl;
382 while(studio::App::events_pending())studio::App::iteration(false);
387 error(const std::string &err)
389 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
396 warning(const std::string &err)
398 std::cerr<<"warning: "<<err<<std::endl;
399 while(studio::App::events_pending())studio::App::iteration(false);
404 amount_complete(int /*current*/, int /*total*/)
406 while(studio::App::events_pending())studio::App::iteration(false);
411 /* === P R O C E D U R E S ================================================= */
415 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
417 action_group_list.push_back(action_group);
418 Gtk::UIManager::insert_action_group(action_group, pos);
422 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
424 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
425 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
426 if(*iter==action_group)
428 action_group_list.erase(iter);
429 Gtk::UIManager::remove_action_group(action_group);
432 synfig::error("Unable to find action group");
436 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
438 ui_manager->insert_action_group(group,0);
440 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
441 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
443 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
445 if(*iter && (*iter)->get_name()!="menus")
447 synfig::info("Removing action group "+(*iter)->get_name());
448 ui_manager->remove_action_group(*iter);
451 ui_manager->insert_action_group(group,0);
453 for(;!prev_groups.empty();prev_groups.pop_front())
455 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
456 ui_manager->insert_action_group(prev_groups.front(),1);
460 class Preferences : public synfigapp::Settings
463 virtual bool get_value(const synfig::String& key, synfig::String& value)const
467 value=strprintf("%f %f %f %f",
468 App::gamma.get_gamma_r(),
469 App::gamma.get_gamma_g(),
470 App::gamma.get_gamma_b(),
471 App::gamma.get_black_level()
475 if(key=="time_format")
477 value=strprintf("%i",App::get_time_format());
480 if(key=="file_history.size")
482 value=strprintf("%i",App::get_max_recent_files());
485 if(key=="use_colorspace_gamma")
487 value=strprintf("%i",(int)App::use_colorspace_gamma);
490 if(key=="distance_system")
492 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
495 #ifdef SINGLE_THREADED
496 if(key=="single_threaded")
498 value=strprintf("%i",(int)App::single_threaded);
502 if(key=="auto_recover_backup_interval")
504 value=strprintf("%i",App::auto_recover->get_timeout());
507 if(key=="restrict_radius_ducks")
509 value=strprintf("%i",(int)App::restrict_radius_ducks);
512 if(key=="browser_command")
514 value=App::browser_command;
517 if(key=="custom_filename_prefix")
519 value=App::custom_filename_prefix;
522 if(key=="preferred_x_size")
524 value=strprintf("%i",App::preferred_x_size);
527 if(key=="preferred_y_size")
529 value=strprintf("%i",App::preferred_y_size);
532 return synfigapp::Settings::get_value(key,value);
535 virtual bool set_value(const synfig::String& key,const synfig::String& value)
541 strscanf(value,"%f %f %f %f",
548 App::gamma.set_all(r,g,b,blk);
552 if(key=="time_format")
554 int i(atoi(value.c_str()));
555 App::set_time_format(static_cast<synfig::Time::Format>(i));
558 if(key=="auto_recover_backup_interval")
560 int i(atoi(value.c_str()));
561 App::auto_recover->set_timeout(i);
564 if(key=="file_history.size")
566 int i(atoi(value.c_str()));
567 App::set_max_recent_files(i);
570 if(key=="use_colorspace_gamma")
572 int i(atoi(value.c_str()));
573 App::use_colorspace_gamma=i;
576 if(key=="distance_system")
578 App::distance_system=Distance::ident_system(value);;
581 #ifdef SINGLE_THREADED
582 if(key=="single_threaded")
584 int i(atoi(value.c_str()));
585 App::single_threaded=i;
589 if(key=="restrict_radius_ducks")
591 int i(atoi(value.c_str()));
592 App::restrict_radius_ducks=i;
595 if(key=="browser_command")
597 App::browser_command=value;
600 if(key=="custom_filename_prefix")
602 App::custom_filename_prefix=value;
605 if(key=="preferred_x_size")
607 int i(atoi(value.c_str()));
608 App::preferred_x_size=i;
611 if(key=="preferred_y_size")
613 int i(atoi(value.c_str()));
614 App::preferred_y_size=i;
617 return synfigapp::Settings::set_value(key,value);
620 virtual KeyList get_key_list()const
622 KeyList ret(synfigapp::Settings::get_key_list());
623 ret.push_back("gamma");
624 ret.push_back("time_format");
625 ret.push_back("distance_system");
626 ret.push_back("file_history.size");
627 ret.push_back("use_colorspace_gamma");
628 #ifdef SINGLE_THREADED
629 ret.push_back("single_threaded");
631 ret.push_back("auto_recover_backup_interval");
632 ret.push_back("restrict_radius_ducks");
633 ret.push_back("browser_command");
634 ret.push_back("custom_filename_prefix");
635 ret.push_back("preferred_x_size");
636 ret.push_back("preferred_y_size");
641 static ::Preferences _preferences;
646 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
648 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
650 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
652 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
653 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
654 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
655 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
656 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
657 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
658 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
659 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
660 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
661 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
662 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
663 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
664 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
666 // Add the synfigapp actions...
667 synfigapp::Action::Book::iterator iter;
668 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
670 actions_action_group->add(Gtk::Action::create(
671 "action-"+iter->second.name,
672 get_action_stock_id(iter->second),
673 iter->second.local_name,iter->second.local_name
677 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
678 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
679 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ group->add(action,sig); }
681 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
682 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
683 DEFINE_ACTION("new", Gtk::Stock::NEW);
684 DEFINE_ACTION("open", Gtk::Stock::OPEN);
685 DEFINE_ACTION("save", Gtk::Stock::SAVE);
686 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
687 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
688 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
689 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
690 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
691 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
692 DEFINE_ACTION("import", _("Import"));
693 DEFINE_ACTION("render", _("Render"));
694 DEFINE_ACTION("preview", _("Preview"));
695 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
696 DEFINE_ACTION("sound", _("Sound File"));
697 DEFINE_ACTION("options", _("Options"));
698 DEFINE_ACTION("close", _("Close View"));
699 DEFINE_ACTION("close-document", _("Close Document"));
700 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
703 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
704 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
705 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
706 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
707 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
708 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
709 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
710 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
711 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
712 DEFINE_ACTION("properties", _("Properties"));
714 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
715 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
716 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
717 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
718 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
719 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
720 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
721 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
722 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
723 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
724 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
725 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
726 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
727 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
728 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
729 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
730 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
731 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
732 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
733 DEFINE_ACTION("play", _("Play"));
734 // DEFINE_ACTION("pause", _("Pause"));
735 DEFINE_ACTION("stop", _("Stop"));
736 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
737 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
738 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
739 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
740 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
741 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
742 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
743 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
744 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
745 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
746 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
747 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
748 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
749 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
750 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
751 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
752 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
753 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
754 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
755 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
756 DEFINE_ACTION("seek-end", _("Seek to End"));
758 DEFINE_ACTION("action-group_add", _("Add group"));
760 DEFINE_ACTION("canvas-new", _("New Canvas"));
762 DEFINE_ACTION("amount-inc", _("Increase Amount"));
763 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
768 // Set up synfigapp actions
770 synfigapp::Action::Book::iterator iter;
772 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
774 Gtk::StockID stock_id;
776 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
778 //Gtk::Image* image(manage(new Gtk::Image()));
779 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
780 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
781 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
782 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
783 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
784 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
785 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
786 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
787 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
788 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
790 actions_action_group->add(Gtk::Action::create(
791 "action-"+iter->second.name,
793 iter->second.local_name,iter->second.local_name
801 Glib::ustring ui_info =
803 " <popup name='menu-toolbox' action='menu-toolbox'>"
804 " <menu action='menu-file'>"
807 " <popup name='menu-main' action='menu-main'>"
808 " <menu action='menu-file'>"
809 " <menuitem action='new' />"
810 " <menuitem action='open' />"
811 " <menuitem action='save' />"
812 " <menuitem action='save-as' />"
813 " <menuitem action='revert' />"
814 " <separator name='bleh01'/>"
815 " <menuitem action='cvs-add' />"
816 " <menuitem action='cvs-update' />"
817 " <menuitem action='cvs-commit' />"
818 " <menuitem action='cvs-revert' />"
819 " <separator name='bleh02'/>"
820 " <menuitem action='import' />"
821 " <separator name='bleh03'/>"
822 " <menuitem action='render' />"
823 " <menuitem action='preview' />"
824 " <menuitem action='sound' />"
825 " <separator name='bleh04'/>"
826 " <menuitem action='options' />"
827 " <menuitem action='close' />"
828 " <menuitem action='close-document' />"
829 " <menuitem action='quit' />"
831 " <menu action='menu-edit'>"
832 " <menuitem action='undo'/>"
833 " <menuitem action='redo'/>"
834 " <separator name='bleh05'/>"
835 " <menuitem action='cut'/>"
836 " <menuitem action='copy'/>"
837 " <menuitem action='paste'/>"
838 " <separator name='bleh06'/>"
839 " <menuitem action='select-all-layers'/>"
840 " <menuitem action='unselect-all-layers'/>"
841 " <menuitem action='select-all-ducks'/>"
842 " <menuitem action='unselect-all-ducks'/>"
843 " <separator name='bleh07'/>"
844 " <menuitem action='properties'/>"
846 " <menu action='menu-view'>"
847 " <menu action='menu-duck-mask'>"
848 " <menuitem action='mask-position-ducks' />"
849 " <menuitem action='mask-vertex-ducks' />"
850 " <menuitem action='mask-tangent-ducks' />"
851 " <menuitem action='mask-radius-ducks' />"
852 " <menuitem action='mask-width-ducks' />"
853 " <menuitem action='mask-angle-ducks' />"
855 " <menu action='menu-preview-quality'>"
856 " <menuitem action='quality-00' />"
857 " <menuitem action='quality-01' />"
858 " <menuitem action='quality-02' />"
859 " <menuitem action='quality-03' />"
860 " <menuitem action='quality-04' />"
861 " <menuitem action='quality-05' />"
862 " <menuitem action='quality-06' />"
863 " <menuitem action='quality-07' />"
864 " <menuitem action='quality-08' />"
865 " <menuitem action='quality-09' />"
866 " <menuitem action='quality-10' />"
868 " <menu action='menu-lowres-pixel'>"
869 " <menuitem action='decrease-low-res-pixel-size'/>"
870 " <menuitem action='increase-low-res-pixel-size'/>"
871 " <separator name='pixel-size-separator'/>"
874 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
875 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
879 " <separator name='bleh08'/>"
880 " <menuitem action='play'/>"
881 //" <menuitem action='pause'/>"
882 " <menuitem action='stop'/>"
883 " <menuitem action='dialog-flipbook'/>"
884 " <separator name='bleh09'/>"
885 " <menuitem action='toggle-grid-show'/>"
886 " <menuitem action='toggle-grid-snap'/>"
887 " <menuitem action='toggle-guide-show'/>"
888 " <menuitem action='toggle-low-res'/>"
889 " <menuitem action='toggle-onion-skin'/>"
890 " <separator name='bleh10'/>"
891 " <menuitem action='canvas-zoom-in'/>"
892 " <menuitem action='canvas-zoom-out'/>"
893 " <menuitem action='canvas-zoom-fit'/>"
894 " <menuitem action='canvas-zoom-100'/>"
895 " <separator name='bleh11'/>"
896 " <menuitem action='time-zoom-in'/>"
897 " <menuitem action='time-zoom-out'/>"
898 " <separator name='bleh12'/>"
899 " <menuitem action='jump-next-keyframe'/>"
900 " <menuitem action='jump-prev-keyframe'/>"
901 " <menuitem action='seek-next-frame'/>"
902 " <menuitem action='seek-prev-frame'/>"
903 " <menuitem action='seek-next-second'/>"
904 " <menuitem action='seek-prev-second'/>"
905 " <menuitem action='seek-begin'/>"
906 " <menuitem action='seek-end'/>"
908 " <menu action='menu-canvas'>"
909 " <menuitem action='canvas-new'/>"
911 " <menu name='menu-state' action='menu-state'>"
913 " <menu action='menu-group'>"
914 " <menuitem action='action-group_add'/>"
916 " <menu action='menu-layer'>"
917 //" <menuitem action='cut'/>"
918 //" <menuitem action='copy'/>"
919 //" <menuitem action='paste'/>"
920 //" <separator name='bleh06'/>"
921 " <menu action='menu-layer-new'></menu>"
922 " <menuitem action='amount-inc'/>"
923 " <menuitem action='amount-dec'/>"
925 " <menu action='menu-keyframe'>"
926 " <menuitem action='keyframe-properties'/>"
933 " <menubar name='MenuBar'>"
934 " <menu action='MenuFile'>"
935 " <menuitem action='New'/>"
936 " <menuitem action='Open'/>"
938 " <menuitem action='Quit'/>"
940 " <menu action='MenuEdit'>"
941 " <menuitem action='Cut'/>"
942 " <menuitem action='Copy'/>"
943 " <menuitem action='Paste'/>"
946 " <toolbar name='ToolBar'>"
947 " <toolitem action='Open'/>"
948 " <toolitem action='Quit'/>"
954 actions_action_group->set_sensitive(false);
955 App::ui_manager()->set_add_tearoffs(true);
956 App::ui_manager()->insert_action_group(menus_action_group,1);
957 App::ui_manager()->insert_action_group(actions_action_group,1);
958 App::ui_manager()->add_ui_from_string(ui_info);
960 //App::ui_manager()->get_accel_group()->unlock();
962 catch(const Glib::Error& ex)
964 synfig::error("building menus and toolbars failed: " + ex.what());
967 // Add default keyboard accelerators
968 #define ACCEL(path,accel) \
970 Gtk::AccelKey accel_key(accel,path); \
971 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
974 #define ACCEL2(accel) \
976 Gtk::AccelKey accel_key(accel); \
977 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
980 ACCEL("<Actions>//select-all-ducks","<Control>a");
981 ACCEL("<Actions>//unselect-all-ducks","<Control>d");
982 ACCEL("<Actions>//select-all-layers","<Control><Shift>a");
983 ACCEL("<Actions>//unselect-all-layers","<Control><Shift>d");
984 ACCEL("<Actions>//render","F9");
985 ACCEL("<Actions>//preview","F11");
986 ACCEL("<Actions>//properties","F8");
987 ACCEL("<Actions>//options","F12");
988 ACCEL("<Actions>//import","<control>i");
989 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
990 ACCEL("<Actions>//toggle-grid-show","<Control>g");
991 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
992 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
993 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
994 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
995 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
996 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
997 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
998 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1000 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1001 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1003 ACCEL("<Actions>//quality-01","<Control>1");
1004 ACCEL("<Actions>//quality-02","<Control>2");
1005 ACCEL("<Actions>//quality-03","<Control>3");
1006 ACCEL("<Actions>//quality-04","<Control>4");
1007 ACCEL("<Actions>//quality-05","<Control>5");
1008 ACCEL("<Actions>//quality-06","<Control>6");
1009 ACCEL("<Actions>//quality-07","<Control>7");
1010 ACCEL("<Actions>//quality-08","<Control>8");
1011 ACCEL("<Actions>//quality-09","<Control>9");
1012 ACCEL("<Actions>//quality-10","<Control>0");
1013 ACCEL("<Actions>//undo","<Control>z");
1014 ACCEL("<Actions>//redo","<Control>r");
1015 ACCEL("<Actions>//action-layer_remove","Delete");
1017 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1018 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1019 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1020 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1021 ACCEL("<Actions>//time-zoom-in","+");
1022 ACCEL("<Actions>//time-zoom-out","_");
1024 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
1025 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
1027 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1028 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1030 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1031 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1032 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1033 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1034 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1035 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1036 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1037 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1038 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1039 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1040 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
1041 ACCEL("<Actions>//play", "<Control>p");
1042 ACCEL("<Actions>//seek-begin","Home");
1043 ACCEL("<Actions>//seek-end","End");
1045 ACCEL("<Actions>//state-normal", "<Mod1>a");
1046 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1047 ACCEL("<Actions>//state-scale", "<Mod1>s");
1048 ACCEL("<Actions>//state-rotate", "<Mod1>t");
1049 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1051 ACCEL("<Actions>//state-circle", "<Mod1>c");
1052 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1053 ACCEL("<Actions>//state-star", "<Mod1>q");
1054 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1055 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1057 ACCEL("<Actions>//state-bline", "<Mod1>b");
1058 ACCEL("<Actions>//state-text", "<Mod1>x");
1059 ACCEL("<Actions>//state-fill", "<Mod1>f");
1060 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1061 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1063 ACCEL("<Actions>//state-draw", "<Mod1>d");
1064 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1065 ACCEL("<Actions>//state-width", "<Mod1>w");
1067 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1073 #define mkdir(x,y) mkdir(x)
1076 /* === M E T H O D S ======================================================= */
1078 App::App(int *argc, char ***argv):
1079 Gtk::Main(argc,argv),
1080 IconController(etl::dirname((*argv)[0]))
1082 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1085 ui_interface_=new GlobalUIInterface();
1089 // don't call thread_init() if threads are already initialized
1090 // on some machines bonobo_init() initialized threads before we get here
1091 if (!g_thread_supported())
1092 Glib::thread_init();
1094 distance_system=Distance::SYSTEM_UNITS;
1096 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1099 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1103 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1109 if(!SYNFIG_CHECK_VERSION())
1111 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1112 dialog_error_blocking("Synfig Studio",
1113 "This copy of Synfig Studio was compiled against a\n"
1114 "different version of libsynfig than what is currently\n"
1115 "installed. Synfig Studio will now abort. Try downloading\n"
1116 "the latest version from the Synfig website at\n"
1117 "http://synfig.org/Download"
1121 Glib::set_application_name(_("Synfig Studio"));
1123 Splash splash_screen;
1124 splash_screen.show();
1126 shutdown_in_progress=false;
1127 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1128 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1130 // Initialize the Synfig library
1131 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1134 get_ui_interface()->error(_("Failed to initialize synfig!"));
1138 // add the preferences to the settings
1139 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1143 studio_init_cb.task(_("Init UI Manager..."));
1144 App::ui_manager_=studio::UIManager::create();
1147 studio_init_cb.task(_("Init Dock Manager..."));
1148 dock_manager=new studio::DockManager();
1150 studio_init_cb.task(_("Init State Manager..."));
1151 state_manager=new StateManager();
1153 studio_init_cb.task(_("Init Toolbox..."));
1154 toolbox=new studio::Toolbox();
1156 studio_init_cb.task(_("Init About Dialog..."));
1157 about=new studio::About();
1159 studio_init_cb.task(_("Init Tool Options..."));
1160 dialog_tool_options=new studio::Dialog_ToolOptions();
1161 dock_manager->register_dockable(*dialog_tool_options);
1163 studio_init_cb.task(_("Init History..."));
1164 dock_history=new studio::Dock_History();
1165 dock_manager->register_dockable(*dock_history);
1167 studio_init_cb.task(_("Init Canvases..."));
1168 dock_canvases=new studio::Dock_Canvases();
1169 dock_manager->register_dockable(*dock_canvases);
1171 studio_init_cb.task(_("Init Keyframes..."));
1172 dock_keyframes=new studio::Dock_Keyframes();
1173 dock_manager->register_dockable(*dock_keyframes);
1175 studio_init_cb.task(_("Init Layers..."));
1176 dock_layers=new studio::Dock_Layers();
1177 dock_manager->register_dockable(*dock_layers);
1179 studio_init_cb.task(_("Init Params..."));
1180 dock_params=new studio::Dock_Params();
1181 dock_manager->register_dockable(*dock_params);
1183 studio_init_cb.task(_("Init MetaData..."));
1184 dock_meta_data=new studio::Dock_MetaData();
1185 dock_manager->register_dockable(*dock_meta_data);
1187 studio_init_cb.task(_("Init Children..."));
1188 dock_children=new studio::Dock_Children();
1189 dock_manager->register_dockable(*dock_children);
1191 studio_init_cb.task(_("Init Info..."));
1192 dock_info = new studio::Dock_Info();
1193 dock_manager->register_dockable(*dock_info);
1195 studio_init_cb.task(_("Init Navigator..."));
1196 dock_navigator = new studio::Dock_Navigator();
1197 dock_manager->register_dockable(*dock_navigator);
1199 studio_init_cb.task(_("Init Timetrack..."));
1200 dock_timetrack = new studio::Dock_Timetrack();
1201 dock_manager->register_dockable(*dock_timetrack);
1203 studio_init_cb.task(_("Init Curve Editor..."));
1204 dock_curves = new studio::Dock_Curves();
1205 dock_manager->register_dockable(*dock_curves);
1207 studio_init_cb.task(_("Init Layer Groups..."));
1208 dock_layer_groups = new studio::Dock_LayerGroups();
1209 dock_manager->register_dockable(*dock_layer_groups);
1212 studio_init_cb.task(_("Init Color Dialog..."));
1213 dialog_color=new studio::Dialog_Color();
1215 studio_init_cb.task(_("Init Gradient Dialog..."));
1216 dialog_gradient=new studio::Dialog_Gradient();
1218 studio_init_cb.task(_("Init DeviceTracker..."));
1219 device_tracker=new studio::DeviceTracker();
1221 studio_init_cb.task(_("Init Tools..."));
1224 state_manager->add_state(&state_normal);
1225 state_manager->add_state(&state_smooth_move);
1226 state_manager->add_state(&state_scale);
1227 state_manager->add_state(&state_rotate);
1228 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1231 state_manager->add_state(&state_circle);
1232 state_manager->add_state(&state_rectangle);
1233 state_manager->add_state(&state_star);
1234 state_manager->add_state(&state_gradient);
1235 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1238 state_manager->add_state(&state_bline);
1239 state_manager->add_state(&state_text);
1240 state_manager->add_state(&state_fill);
1241 state_manager->add_state(&state_eyedrop);
1242 state_manager->add_state(&state_zoom);
1244 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1245 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1247 // Disabled by default - it doesn't work properly?
1248 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1250 studio_init_cb.task(_("Init ModPalette..."));
1251 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1253 studio_init_cb.task(_("Init Setup Dialog..."));
1254 dialog_setup=new studio::Dialog_Setup();
1256 studio_init_cb.task(_("Init Input Dialog..."));
1257 dialog_input=new Gtk::InputDialog();
1258 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1259 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1261 studio_init_cb.task(_("Init auto recovery..."));
1262 auto_recover=new AutoRecover();
1264 studio_init_cb.amount_complete(9250,10000);
1265 studio_init_cb.task(_("Loading Settings..."));
1267 studio_init_cb.task(_("Checking auto-recover..."));
1269 studio_init_cb.amount_complete(9900,10000);
1271 bool opened_any = false;
1272 if(auto_recover->recovery_needed())
1274 splash_screen.hide();
1275 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1276 _("Synfig Studio seems to have crashed\n"
1277 "before you could save all your files.\n"
1278 "Would you like to re-open those files\n"
1279 "and recover your unsaved changes?")) ==
1280 synfigapp::UIInterface::RESPONSE_YES)
1282 int number_recovered;
1283 if(!auto_recover->recover(number_recovered))
1284 if (number_recovered)
1285 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1287 get_ui_interface()->error(_("Unable to recover from previous crash"));
1289 get_ui_interface()->error(
1290 _("Synfig Studio has attempted to recover\n"
1291 "from a previous crash. The files that it has\n"
1292 "recovered are NOT YET SAVED. It would be a good\n"
1293 "idea to review them and save them now."));
1295 if (number_recovered)
1298 splash_screen.show();
1301 // Look for any files given on the command line,
1302 // and load them if found.
1303 for(;*argc>=1;(*argc)--)
1304 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1306 studio_init_cb.task(_("Loading files..."));
1307 splash_screen.hide();
1308 open((*argv)[*argc]);
1310 splash_screen.show();
1313 // if no file was specified to be opened, create a new document to help new users get started more easily
1314 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1317 studio_init_cb.task(_("Done."));
1318 studio_init_cb.amount_complete(10000,10000);
1324 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1328 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1332 StateManager* App::get_state_manager() { return state_manager; }
1336 shutdown_in_progress=true;
1340 synfigapp::Main::settings().remove_domain("pref");
1342 selected_instance=0;
1344 // Unload all of the modules
1345 for(;!module_list_.empty();module_list_.pop_back())
1348 delete state_manager;
1352 delete auto_recover;
1358 // studio::App::iteration(false);
1362 // studio::App::iteration(false);
1364 // studio::App::iteration(false);
1366 delete dialog_setup;
1368 delete dialog_gradient;
1370 delete dialog_color;
1372 delete dialog_input;
1374 delete dock_manager;
1376 instance_list.clear();
1378 // studio::App::iteration(false);
1382 App::get_user_app_directory()
1384 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1386 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1388 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1393 App::get_config_file(const synfig::String& file)
1395 return Glib::build_filename(get_user_app_directory(),file);
1398 #define SCALE_FACTOR (1280)
1399 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1401 App::set_recent_file_window_size(etl::handle<Instance> instance)
1403 int screen_w(Gdk::screen_width());
1404 int screen_h(Gdk::screen_height());
1406 const std::string &canvas_window_size = *recent_files_window_size.begin();
1408 if(canvas_window_size.empty())
1411 synfig::String::size_type current=0;
1412 bool seen_root(false), shown_non_root(false);
1414 while(current != synfig::String::npos)
1416 // find end of first field (canvas) or return
1417 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1418 if(separator == synfig::String::npos) break;
1421 synfig::Canvas::Handle canvas;
1423 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1425 catch(Exception::IDNotFound) {
1426 // can't find the canvas; skip to the next canvas or return
1427 separator = canvas_window_size.find_first_of('\t', current);
1428 if(separator == synfig::String::npos) return;
1429 current = separator+1;
1433 if (canvas->is_root())
1436 shown_non_root = true;
1438 // check that we have the tab character the ends this canvas' data or return
1439 current = separator+1;
1440 separator = canvas_window_size.find_first_of('\t', current);
1441 if(separator == synfig::String::npos) return;
1444 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1446 current = separator+1;
1450 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1451 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1452 x=x*screen_w/SCALE_FACTOR;
1453 y=y*screen_h/SCALE_FACTOR;
1454 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1455 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1456 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1457 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1459 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1460 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1462 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1463 canvasview->move(x,y);
1464 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1465 canvasview->present();
1467 current = separator+1;
1470 if (shown_non_root && !seen_root)
1471 instance->find_canvas_view(instance->get_canvas())->hide();
1475 App::add_recent_file(const etl::handle<Instance> instance)
1477 int screen_w(Gdk::screen_width());
1478 int screen_h(Gdk::screen_height());
1480 std::string canvas_window_size;
1482 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1483 Instance::CanvasViewList::const_iterator iter;
1485 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1487 if( !((*iter)->is_visible()) )
1490 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1491 int x_pos, y_pos, x_size, y_size;
1492 (*iter)->get_position(x_pos,y_pos);
1493 (*iter)->get_size(x_size,y_size);
1495 canvas_window_size += strprintf("%s %d %d %d %d\t",
1496 canvas->get_relative_id(canvas->get_root()).c_str(),
1497 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1498 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1501 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1506 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1508 std::string filename(file_name);
1510 assert(!filename.empty());
1512 if(filename.empty())
1515 // Toss out any "hidden" files
1516 if(basename(filename)[0]=='.')
1519 // If we aren't an absolute path, turn ourselves into one
1520 if(!is_absolute_path(filename))
1521 filename=absolute_path(filename);
1523 std::string old_window_size;
1525 list<string>::iterator iter;
1526 list<string>::iterator iter_wsize;
1527 // Check to see if the file is already on the list.
1528 // If it is, then remove it from the list
1529 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1532 recent_files.erase(iter);
1533 old_window_size = *iter_wsize;
1534 recent_files_window_size.erase(iter_wsize);
1539 // Push the filename to the front of the list
1540 recent_files.push_front(filename);
1541 if(window_size.empty())
1542 recent_files_window_size.push_front(old_window_size);
1544 recent_files_window_size.push_front(window_size);
1546 // Clean out the files at the end of the list.
1547 while(recent_files.size()>(unsigned)get_max_recent_files())
1549 recent_files.pop_back();
1550 recent_files_window_size.pop_back();
1553 signal_recent_files_changed_();
1558 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1561 App::get_time_format()
1563 return _App_time_format;
1567 App::set_time_format(synfig::Time::Format x)
1574 App::save_settings()
1579 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1580 setlocale(LC_NUMERIC, "C");
1582 std::string filename=get_config_file("accelrc");
1583 Gtk::AccelMap::save(filename);
1586 std::string filename=get_config_file("recentfiles");
1588 std::ofstream file(filename.c_str());
1592 synfig::warning("Unable to save %s",filename.c_str());
1596 list<string>::reverse_iterator iter;
1598 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1602 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1604 std::ofstream file(filename.c_str());
1608 synfig::warning("Unable to save %s",filename.c_str());
1612 list<string>::reverse_iterator iter;
1614 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1618 std::string filename=get_config_file("settings");
1619 synfigapp::Main::settings().save_to_file(filename);
1620 setlocale(LC_NUMERIC,old_locale);
1624 synfig::warning("Caught exception when attempting to save settings.");
1629 App::load_settings()
1634 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1635 setlocale(LC_NUMERIC, "C");
1637 std::string filename=get_config_file("accelrc");
1638 Gtk::AccelMap::load(filename);
1641 bool window_size_broken = false;
1643 std::string filename=get_config_file("recentfiles");
1644 std::string filename_window_size=filename+std::string("_window_size");
1646 std::ifstream file(filename.c_str());
1647 std::ifstream file_window_size(filename_window_size.c_str());
1649 if(!file_window_size)
1650 window_size_broken = true;
1654 std::string recent_file;
1655 std::string recent_file_window_size;
1656 getline(file,recent_file);
1657 if(!window_size_broken)
1658 getline(file_window_size,recent_file_window_size);
1659 if(!recent_file.empty())
1661 if(!window_size_broken && !file_window_size)
1662 window_size_broken = true;
1663 if (std::ifstream(recent_file.c_str()))
1665 if(!window_size_broken)
1666 add_recent_file(recent_file,recent_file_window_size);
1668 add_recent_file(recent_file);
1672 if(!window_size_broken && file_window_size)
1673 window_size_broken = true;
1675 if(window_size_broken)
1677 recent_files_window_size.clear();
1678 recent_files_window_size.resize(recent_files.size());
1681 std::string filename=get_config_file("settings");
1682 if(!synfigapp::Main::settings().load_from_file(filename))
1684 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1685 //if(!synfigapp::Main::settings().load_from_file(filename))
1687 gamma.set_gamma(1.0/2.2);
1688 reset_initial_window_configuration();
1691 setlocale(LC_NUMERIC,old_locale);
1695 synfig::warning("Caught exception when attempting to load settings.");
1700 App::reset_initial_window_configuration()
1702 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1703 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1704 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1705 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1706 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1707 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1708 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1709 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1710 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1711 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1712 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1713 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1714 #ifdef SINGLE_THREADED
1715 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1717 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1718 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1719 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1720 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1721 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1725 App::shutdown_request(GdkEventAny*)
1729 //return !shutdown_in_progress;
1735 if(shutdown_in_progress)return;
1738 get_ui_interface()->task(_("Quit Request"));
1741 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1745 std::list<etl::handle<Instance> >::iterator iter;
1746 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1748 if(!(*iter)->safe_close())
1752 if((*iter)->synfigapp::Instance::get_action_count())
1754 handle<synfigapp::UIInterface> uim;
1755 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1757 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1758 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1760 case synfigapp::UIInterface::RESPONSE_NO:
1762 case synfigapp::UIInterface::RESPONSE_YES:
1765 case synfigapp::UIInterface::RESPONSE_CANCEL:
1774 if((*iter)->synfigapp::Instance::is_modified())
1776 handle<synfigapp::UIInterface> uim;
1777 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1779 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() );
1780 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1782 case synfigapp::UIInterface::RESPONSE_NO:
1784 case synfigapp::UIInterface::RESPONSE_YES:
1785 (*iter)->dialog_cvs_commit();
1787 case synfigapp::UIInterface::RESPONSE_CANCEL:
1796 // This next line causes things to crash for some reason
1800 shutdown_in_progress=true;
1802 instance_list.clear();
1804 while(studio::App::events_pending())studio::App::iteration(false);
1807 auto_recover->normal_shutdown();
1809 get_ui_interface()->task(_("Quit Request sent"));
1815 dialog_setup->refresh();
1816 dialog_setup->show();
1819 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1820 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1823 //#define USE_WIN32_FILE_DIALOGS 1
1826 #ifdef USE_WIN32_FILE_DIALOGS
1827 static OPENFILENAME ofn={};
1831 #include <gdk/gdkwin32.h>
1835 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1837 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1839 #ifdef USE_WIN32_FILE_DIALOGS
1840 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1842 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1843 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1844 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1846 ofn.lStructSize=sizeof(OPENFILENAME);
1847 ofn.hwndOwner = hWnd;
1848 ofn.hInstance = hInstance;
1849 ofn.lpstrFilter = szFilter;
1850 // ofn.lpstrCustomFilter=NULL;
1851 // ofn.nMaxCustFilter=0;
1852 // ofn.nFilterIndex=0;
1853 // ofn.lpstrFile=NULL;
1854 ofn.nMaxFile=MAX_PATH;
1855 // ofn.lpstrFileTitle=NULL;
1856 // ofn.lpstrInitialDir=NULL;
1857 // ofn.lpstrTitle=NULL;
1858 ofn.Flags=OFN_HIDEREADONLY;
1859 // ofn.nFileOffset=0;
1860 // ofn.nFileExtension=0;
1861 ofn.lpstrDefExt=TEXT("sif");
1862 // ofn.lCustData = 0l;
1864 // ofn.lpTemplateName=NULL;
1866 CHAR szFilename[MAX_PATH];
1868 strcpy(szFilename,filename.c_str());
1869 strcpy(szTitle,title.c_str());
1871 ofn.lpstrFile=szFilename;
1872 ofn.lpstrFileTitle=szTitle;
1874 if(GetOpenFileName(&ofn))
1876 filename=szFilename;
1882 synfig::String prev_path;
1884 if(!_preferences.get_value(preference, prev_path))
1887 prev_path = absolute_path(prev_path);
1889 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1891 dialog->set_current_folder(prev_path);
1892 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1893 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1895 if (filename.empty())
1896 dialog->set_filename(prev_path);
1897 else if (is_absolute_path(filename))
1898 dialog->set_filename(filename);
1900 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1902 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1903 filename = dialog->get_filename();
1904 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1905 _preferences.set_value(preference, dirname(filename));
1919 GtkWidget *fileselection;
1920 fileselection = gtk_file_selection_new(title.c_str());
1923 if(basename(filename)==filename)
1925 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1928 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1930 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1932 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1933 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1935 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1936 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1938 gtk_widget_show(fileselection);
1946 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1947 _preferences.set_value(preference,dirname(filename));
1951 gtk_widget_destroy(fileselection);
1954 gtk_widget_destroy(fileselection);
1961 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1963 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1965 #if USE_WIN32_FILE_DIALOGS
1966 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1968 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1969 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1970 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1972 ofn.lStructSize=sizeof(OPENFILENAME);
1973 ofn.hwndOwner = hWnd;
1974 ofn.hInstance = hInstance;
1975 ofn.lpstrFilter = szFilter;
1976 // ofn.lpstrCustomFilter=NULL;
1977 // ofn.nMaxCustFilter=0;
1978 // ofn.nFilterIndex=0;
1979 // ofn.lpstrFile=NULL;
1980 ofn.nMaxFile=MAX_PATH;
1981 // ofn.lpstrFileTitle=NULL;
1982 // ofn.lpstrInitialDir=NULL;
1983 // ofn.lpstrTitle=NULL;
1984 ofn.Flags=OFN_OVERWRITEPROMPT;
1985 // ofn.nFileOffset=0;
1986 // ofn.nFileExtension=0;
1987 ofn.lpstrDefExt=TEXT("sif");
1988 // ofn.lCustData = 0l;
1990 // ofn.lpTemplateName=NULL;
1992 CHAR szFilename[MAX_PATH];
1994 strcpy(szFilename,filename.c_str());
1995 strcpy(szTitle,title.c_str());
1997 ofn.lpstrFile=szFilename;
1998 ofn.lpstrFileTitle=szTitle;
2000 if(GetSaveFileName(&ofn))
2002 filename=szFilename;
2003 _preferences.set_value(preference,dirname(filename));
2008 synfig::String prev_path;
2010 if(!_preferences.get_value(preference, prev_path))
2013 prev_path = absolute_path(prev_path);
2015 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2017 dialog->set_current_folder(prev_path);
2018 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2019 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2021 Widget_Enum *file_type_enum = 0;
2022 if (preference == ANIMATION_DIR_PREFERENCE)
2024 file_type_enum = manage(new Widget_Enum());
2025 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2026 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2027 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2028 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2029 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2030 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2032 Gtk::HBox *hbox = manage(new Gtk::HBox);
2033 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2034 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2037 dialog->set_extra_widget(*hbox);
2040 if (filename.empty())
2041 dialog->set_filename(prev_path);
2044 std::string full_path;
2045 if (is_absolute_path(filename))
2046 full_path = filename;
2048 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2050 // select the file if it exists
2051 dialog->set_filename(full_path);
2053 // if the file doesn't exist, put its name into the filename box
2055 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2056 dialog->set_current_name(basename(filename));
2059 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2060 if (preference == ANIMATION_DIR_PREFERENCE)
2061 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2062 filename = dialog->get_filename();
2063 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2064 _preferences.set_value(preference, dirname(filename));
2075 App::dialog_error_blocking(const std::string &title, const std::string &message)
2077 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2078 dialog.set_title(title);
2084 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2086 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2087 dialog.set_title(title);
2093 App::dialog_yes_no(const std::string &title, const std::string &message)
2098 true // use_separator
2100 Gtk::Label label(message);
2103 dialog.get_vbox()->pack_start(label);
2104 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2105 dialog.add_button(Gtk::StockID("gtk-no"),0);
2107 return dialog.run();
2111 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2116 true // use_separator
2118 Gtk::Label label(message);
2121 dialog.get_vbox()->pack_start(label);
2122 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2123 dialog.add_button(Gtk::StockID("gtk-no"),0);
2124 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2126 return dialog.run();
2130 App::dialog_not_implemented()
2132 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2133 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2138 try_open_url(const std::string &url)
2141 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2143 std::vector<std::string> command_line;
2144 std::vector<std::string> browsers;
2145 browsers.reserve(23);
2147 // Browser wrapper scripts
2148 #ifdef USE_OPEN_FOR_URLS
2149 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2151 browsers.push_back("xdg-open"); // XDG wrapper
2152 browsers.push_back("sensible-browser"); // Debian wrapper
2153 browsers.push_back("gnome-open"); // GNOME wrapper
2154 browsers.push_back("kfmclient"); // KDE wrapper
2155 browsers.push_back("exo-open"); // XFCE wrapper
2157 // Alternatives system
2158 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2159 browsers.push_back("x-www-browser"); // Debian GUI alternative
2161 // Individual browsers
2162 browsers.push_back("firefox");
2163 browsers.push_back("epiphany-browser");
2164 browsers.push_back("epiphany");
2165 browsers.push_back("konqueror");
2166 browsers.push_back("iceweasel");
2167 browsers.push_back("mozilla");
2168 browsers.push_back("netscape");
2169 browsers.push_back("icecat");
2170 browsers.push_back("galeon");
2171 browsers.push_back("midori");
2172 browsers.push_back("safari");
2173 browsers.push_back("opera");
2174 browsers.push_back("amaya");
2175 browsers.push_back("netsurf");
2176 browsers.push_back("dillo");
2178 // Try the user-specified browser first
2179 command_line.push_back(App::browser_command);
2180 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2181 command_line.push_back(url);
2183 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2184 catch( Glib::SpawnError& exception ){
2186 while ( !browsers.empty() )
2188 // Skip the browser if we already tried it
2189 if( browsers[0] == App::browser_command )
2192 // Construct the command line
2193 command_line.clear();
2194 command_line.push_back(browsers[0]);
2195 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2196 command_line.push_back(url);
2198 // Remove the browser from the list
2199 browsers.erase(browsers.begin());
2201 // Try to spawn the browser
2202 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2203 // Failed, move on to the next one
2204 catch(Glib::SpawnError& exception){ continue; }
2205 return true; // No exception means we succeeded!
2216 if (!try_open_url("http://synfig.org/Documentation"))
2218 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2219 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2220 dialog.set_title(_("Help"));
2226 App::open_url(const std::string &url)
2228 if(!try_open_url(url))
2230 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2231 dialog.set_secondary_text(url);
2232 dialog.set_title(_("No browser found"));
2238 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2243 true); // use_separator
2245 Gtk::Label label(message);
2247 dialog.get_vbox()->pack_start(label);
2250 entry.set_text(text);
2252 entry.set_activates_default(true);
2254 dialog.get_vbox()->pack_start(entry);
2256 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2257 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2258 dialog.set_default_response(Gtk::RESPONSE_OK);
2260 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2263 if(dialog.run()!=Gtk::RESPONSE_OK)
2266 text=entry.get_text();
2272 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2277 true); // use_separator
2279 Gtk::Label label(message);
2281 dialog.get_vbox()->pack_start(label);
2283 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2284 text_buffer->set_text(text);
2285 Gtk::TextView text_view(text_buffer);
2288 dialog.get_vbox()->pack_start(text_view);
2290 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2291 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2292 dialog.set_default_response(Gtk::RESPONSE_OK);
2294 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2297 if(dialog.run()!=Gtk::RESPONSE_OK)
2300 text=text_buffer->get_text();
2306 App::open(std::string filename)
2308 return open_as(filename,filename);
2311 // this is called from autorecover.cpp:
2312 // App::open_as(get_shadow_file_name(filename),filename)
2313 // other than that, 'filename' and 'as' are the same
2315 App::open_as(std::string filename,std::string as)
2318 char long_name[1024];
2319 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2320 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2321 // don't use it if that's the case
2322 if (long_name[0] != '\0')
2328 OneMoment one_moment;
2330 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2331 if(canvas && get_instance(canvas))
2333 get_instance(canvas)->find_canvas_view(canvas)->present();
2334 info("%s is already open", filename.c_str());
2335 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2340 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2342 if (as.find(custom_filename_prefix.c_str()) != 0)
2343 add_recent_file(as);
2345 handle<Instance> instance(Instance::create(canvas));
2348 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2350 set_recent_file_window_size(instance);
2354 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)")))
2355 instance->dialog_cvs_update();
2360 dialog_error_blocking(_("Error"), x);
2365 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2376 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2378 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2379 canvas->set_name(file_name);
2380 file_name += ".sifz";
2382 canvas->rend_desc().set_frame_rate(24.0);
2383 canvas->rend_desc().set_time_start(0.0);
2384 canvas->rend_desc().set_time_end(5.0);
2385 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2386 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2387 canvas->rend_desc().set_tl(Vector(-4,2.25));
2388 canvas->rend_desc().set_br(Vector(4,-2.25));
2389 canvas->rend_desc().set_w(preferred_x_size);
2390 canvas->rend_desc().set_h(preferred_y_size);
2391 canvas->rend_desc().set_antialias(1);
2392 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2393 canvas->set_file_name(file_name);
2395 handle<Instance> instance = Instance::create(canvas);
2397 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2398 instance->find_canvas_view(canvas)->canvas_properties.present();
2402 App::dialog_open(string filename)
2404 if (filename.empty())
2407 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2409 // If the filename still has wildcards, then we should
2410 // continue looking for the file we want
2411 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2417 get_ui_interface()->error(_("Unable to open file"));
2422 App::set_selected_instance(etl::loose_handle<Instance> instance)
2424 /* if(get_selected_instance()==instance)
2426 selected_instance=instance;
2427 signal_instance_selected()(instance);
2433 selected_instance=instance;
2434 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2438 instance->focus(instance->get_canvas());
2441 set_selected_canvas_view(0);
2443 signal_instance_selected()(instance);
2447 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2449 selected_canvas_view=canvas_view;
2450 signal_canvas_view_focus()(selected_canvas_view);
2453 selected_instance=canvas_view->get_instance();
2454 signal_instance_selected()(canvas_view->get_instance());
2457 if(get_selected_canvas_view()==canvas_view)
2459 signal_canvas_view_focus()(selected_canvas_view);
2460 signal_instance_selected()(canvas_view->get_instance());
2463 selected_canvas_view=canvas_view;
2464 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2465 set_selected_instance(canvas_view->get_instance());
2466 signal_canvas_view_focus()(selected_canvas_view);
2470 etl::loose_handle<Instance>
2471 App::get_instance(etl::handle<synfig::Canvas> canvas)
2473 if(!canvas) return 0;
2474 canvas=canvas->get_root();
2476 std::list<etl::handle<Instance> >::iterator iter;
2477 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2479 if((*iter)->get_canvas()==canvas)
2495 if(selected_instance)
2496 selected_instance->undo();
2502 if(selected_instance)
2503 selected_instance->redo();
2507 studio::App::get_base_path()
2509 return app_base_path_;