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
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
38 #ifdef HAVE_SYS_ERRNO_H
39 #include <sys/errno.h>
41 #include <gtkmm/fileselection.h>
42 #include <gtkmm/dialog.h>
43 #include <gtkmm/messagedialog.h>
44 #include <gtkmm/label.h>
45 #include <gtkmm/stock.h>
46 #include <gtkmm/stockitem.h>
47 #include <gtkmm/iconsource.h>
48 #include <gtkmm/inputdialog.h>
49 #include <gtkmm/accelmap.h>
50 #include <gtkmm/uimanager.h>
54 #include <synfig/loadcanvas.h>
55 #include <synfig/savecanvas.h>
61 #include "canvasview.h"
62 #include "dialog_setup.h"
63 #include "dialog_gradient.h"
64 #include "dialog_color.h"
67 #include "onemoment.h"
69 #include "dockmanager.h"
71 #include "state_eyedrop.h"
72 #include "state_normal.h"
73 #include "state_draw.h"
74 #include "state_fill.h"
75 #include "state_bline.h"
76 #include "state_polygon.h"
77 #include "state_sketch.h"
78 #include "state_gradient.h"
79 #include "state_circle.h"
80 #include "state_rectangle.h"
81 #include "state_smoothmove.h"
82 #include "state_scale.h"
83 #include "state_width.h"
84 #include "state_rotate.h"
85 #include "state_zoom.h"
87 #include "devicetracker.h"
88 #include "dialog_tooloptions.h"
89 #include "widget_enum.h"
91 #include "autorecover.h"
93 #include <synfigapp/settings.h>
94 #include "dock_history.h"
95 #include "dock_canvases.h"
96 #include "dock_keyframes.h"
97 #include "dock_layers.h"
98 #include "dock_params.h"
99 #include "dock_metadata.h"
100 #include "dock_children.h"
101 #include "dock_info.h"
102 #include "dock_navigator.h"
103 #include "dock_layergroups.h"
104 #include "dock_timetrack.h"
105 #include "dock_curves.h"
107 #include "mod_palette/mod_palette.h"
108 #include "mod_mirror/mod_mirror.h"
110 #include <sys/stat.h>
116 #include "statemanager.h"
123 #define _WIN32_WINNT 0x0500
126 #include <gtkmm/accelmap.h>
127 #include <gtkmm/filechooser.h>
128 #include <gtkmm/filechooserdialog.h>
134 /* === U S I N G =========================================================== */
138 using namespace synfig;
139 using namespace studio;
141 /* === M A C R O S ========================================================= */
143 #ifndef SYNFIG_USER_APP_DIR
145 #define SYNFIG_USER_APP_DIR "Library/Synfig"
146 #elif defined(_WIN32)
147 #define SYNFIG_USER_APP_DIR "Synfig"
149 #define SYNFIG_USER_APP_DIR ".synfig"
154 #define DPM2DPI(x) (float(x)/39.3700787402f)
155 #define DPI2DPM(x) (float(x)*39.3700787402f)
161 # define IMAGE_DIR "share\\pixmaps"
166 # define IMAGE_DIR "/usr/local/share/pixmaps"
170 # define IMAGE_EXT "tif"
173 #include <synfigapp/main.h>
175 /* === S I G N A L S ======================================================= */
177 static sigc::signal<void> signal_present_all_;
179 App::signal_present_all() { return signal_present_all_; }
181 static sigc::signal<void> signal_recent_files_changed_;
183 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
185 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
186 sigc::signal<void,etl::loose_handle<CanvasView> >&
187 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
189 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
190 sigc::signal<void,etl::handle<Instance> >&
191 App::signal_instance_selected() { return signal_instance_selected_; }
193 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
194 sigc::signal<void,etl::handle<Instance> >&
195 App::signal_instance_created() { return signal_instance_created_; }
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_deleted() { return signal_instance_deleted_; }
201 /* === G L O B A L S ======================================================= */
203 static std::list<std::string> recent_files;
204 const std::list<std::string>& App::get_recent_files() { return recent_files; }
206 int App::Busy::count;
207 bool App::shutdown_in_progress;
209 synfig::Gamma App::gamma;
211 Glib::RefPtr<studio::UIManager> App::ui_manager_;
213 synfig::Distance::System App::distance_system;
215 studio::Dialog_Setup* App::dialog_setup;
217 etl::handle< studio::ModPalette > mod_palette_;
218 //studio::Dialog_Palette* App::dialog_palette;
220 std::list<etl::handle<Instance> > App::instance_list;
222 static etl::handle<synfigapp::UIInterface> ui_interface_;
223 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
225 etl::handle<Instance> App::selected_instance;
226 etl::handle<CanvasView> App::selected_canvas_view;
228 studio::About *studio::App::about=NULL;
230 studio::Toolbox *studio::App::toolbox=NULL;
232 studio::AutoRecover *studio::App::auto_recover=NULL;
234 studio::IPC *ipc=NULL;
236 studio::DockManager* studio::App::dock_manager=0;
238 studio::DeviceTracker* studio::App::device_tracker=0;
240 studio::Dialog_Gradient* studio::App::dialog_gradient;
242 studio::Dialog_Color* studio::App::dialog_color;
244 Gtk::InputDialog* studio::App::dialog_input;
246 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
248 studio::Dock_History* dock_history;
249 studio::Dock_Canvases* dock_canvases;
250 studio::Dock_Keyframes* dock_keyframes;
251 studio::Dock_Layers* dock_layers;
252 studio::Dock_Params* dock_params;
253 studio::Dock_MetaData* dock_meta_data;
254 studio::Dock_Children* dock_children;
255 studio::Dock_Info* dock_info;
256 studio::Dock_LayerGroups* dock_layer_groups;
257 studio::Dock_Navigator* dock_navigator;
258 studio::Dock_Timetrack* dock_timetrack;
259 studio::Dock_Curves* dock_curves;
261 std::list< etl::handle< studio::Module > > module_list_;
263 bool studio::App::use_colorspace_gamma=true;
264 bool studio::App::single_threaded=false;
265 bool studio::App::restrict_radius_ducks=false;
266 String studio::App::browser_command("firefox");
268 static int max_recent_files_=25;
269 int studio::App::get_max_recent_files() { return max_recent_files_; }
270 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
272 static synfig::String app_base_path_;
277 really_delete_widget(Gtk::Widget *widget)
279 // synfig::info("really delete %p", (void*)widget);
284 // nasty workaround - when we've finished with a popup menu, we want to delete it
285 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
286 // so schedule the real delete to happen in 50ms, giving the action a chance to run
288 delete_widget(Gtk::Widget *widget)
290 // synfig::info("delete %p", (void*)widget);
291 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
294 }; // END of namespace studio
295 studio::StateManager* state_manager;
300 class GlobalUIInterface : public synfigapp::UIInterface
304 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
309 true // use_separator
311 Gtk::Label label(message);
314 dialog.get_vbox()->pack_start(label);
315 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
316 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
318 dialog.set_default_response(dflt);
320 return (Response)dialog.run();
322 virtual Response yes_no_cancel(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);
335 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
337 dialog.set_default_response(dflt);
339 return (Response)dialog.run();
341 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
346 true // use_separator
348 Gtk::Label label(message);
351 dialog.get_vbox()->pack_start(label);
352 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
353 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
355 dialog.set_default_response(dflt);
357 return (Response)dialog.run();
361 task(const std::string &task)
363 std::cerr<<task<<std::endl;
364 while(studio::App::events_pending())studio::App::iteration(false);
369 error(const std::string &err)
371 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
378 warning(const std::string &err)
380 std::cerr<<"warning: "<<err<<std::endl;
381 while(studio::App::events_pending())studio::App::iteration(false);
386 amount_complete(int /*current*/, int /*total*/)
388 while(studio::App::events_pending())studio::App::iteration(false);
393 /* === P R O C E D U R E S ================================================= */
397 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
399 action_group_list.push_back(action_group);
400 Gtk::UIManager::insert_action_group(action_group, pos);
404 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
406 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
407 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
408 if(*iter==action_group)
410 action_group_list.erase(iter);
411 Gtk::UIManager::remove_action_group(action_group);
414 synfig::error("Unable to find action group");
418 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
420 ui_manager->insert_action_group(group,0);
422 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
423 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
425 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
427 if(*iter && (*iter)->get_name()!="menus")
429 synfig::info("Removing action group "+(*iter)->get_name());
430 ui_manager->remove_action_group(*iter);
433 ui_manager->insert_action_group(group,0);
435 for(;!prev_groups.empty();prev_groups.pop_front())
437 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
438 ui_manager->insert_action_group(prev_groups.front(),1);
442 class Preferences : public synfigapp::Settings
445 virtual bool get_value(const synfig::String& key, synfig::String& value)const
449 value=strprintf("%f %f %f %f",
450 App::gamma.get_gamma_r(),
451 App::gamma.get_gamma_g(),
452 App::gamma.get_gamma_b(),
453 App::gamma.get_black_level()
457 if(key=="time_format")
459 value=strprintf("%i",App::get_time_format());
462 if(key=="file_history.size")
464 value=strprintf("%i",App::get_max_recent_files());
467 if(key=="use_colorspace_gamma")
469 value=strprintf("%i",(int)App::use_colorspace_gamma);
472 if(key=="distance_system")
474 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
477 if(key=="single_threaded")
479 value=strprintf("%i",(int)App::single_threaded);
482 if(key=="auto_recover_backup_interval")
484 value=strprintf("%i",App::auto_recover->get_timeout());
487 if(key=="restrict_radius_ducks")
489 value=strprintf("%i",(int)App::restrict_radius_ducks);
492 if(key=="browser_command")
494 value=App::browser_command;
498 return synfigapp::Settings::get_value(key,value);
501 virtual bool set_value(const synfig::String& key,const synfig::String& value)
507 strscanf(value,"%f %f %f %f",
514 App::gamma.set_all(r,g,b,blk);
518 if(key=="time_format")
520 int i(atoi(value.c_str()));
521 App::set_time_format(static_cast<synfig::Time::Format>(i));
524 if(key=="auto_recover_backup_interval")
526 int i(atoi(value.c_str()));
527 App::auto_recover->set_timeout(i);
530 if(key=="file_history.size")
532 int i(atoi(value.c_str()));
533 App::set_max_recent_files(i);
536 if(key=="use_colorspace_gamma")
538 int i(atoi(value.c_str()));
539 App::use_colorspace_gamma=i;
542 if(key=="distance_system")
544 App::distance_system=Distance::ident_system(value);;
547 if(key=="single_threaded")
549 int i(atoi(value.c_str()));
550 App::single_threaded=i;
553 if(key=="restrict_radius_ducks")
555 int i(atoi(value.c_str()));
556 App::restrict_radius_ducks=i;
559 if(key=="browser_command")
561 App::browser_command=value;
565 return synfigapp::Settings::set_value(key,value);
568 virtual KeyList get_key_list()const
570 KeyList ret(synfigapp::Settings::get_key_list());
571 ret.push_back("gamma");
572 ret.push_back("time_format");
573 ret.push_back("distance_system");
574 ret.push_back("file_history.size");
575 ret.push_back("use_colorspace_gamma");
576 ret.push_back("single_threaded");
577 ret.push_back("auto_recover_backup_interval");
578 ret.push_back("restrict_radius_ducks");
579 ret.push_back("browser_command");
584 static ::Preferences _preferences;
589 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
591 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
593 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
595 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
596 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
597 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
598 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
599 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
600 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
601 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
602 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
603 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
604 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
605 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
606 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
607 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
609 // Add the synfigapp actions...
610 synfigapp::Action::Book::iterator iter;
611 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
613 actions_action_group->add(Gtk::Action::create(
614 "action-"+iter->second.name,
615 get_action_stock_id(iter->second),
616 iter->second.local_name,iter->second.local_name
620 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
621 #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); }
622 #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); }
624 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
625 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
626 DEFINE_ACTION("new", Gtk::Stock::NEW);
627 DEFINE_ACTION("open", Gtk::Stock::OPEN);
628 DEFINE_ACTION("save", Gtk::Stock::SAVE);
629 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
630 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
631 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
632 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
633 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
634 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
635 DEFINE_ACTION("import", _("Import"));
636 DEFINE_ACTION("render", _("Render"));
637 DEFINE_ACTION("preview", _("Preview"));
638 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
639 DEFINE_ACTION("sound", _("Sound File"));
640 DEFINE_ACTION("options", _("Options"));
641 DEFINE_ACTION("close", _("Close View"));
642 DEFINE_ACTION("close-document", _("Close Document"));
643 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
646 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
647 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
648 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
649 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
650 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
651 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
652 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
653 DEFINE_ACTION("properties", _("Properties"));
655 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
656 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
657 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
658 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
659 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
660 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
661 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
662 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
663 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
664 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
665 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
666 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
667 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
668 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
669 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
670 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
671 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
672 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
673 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
674 DEFINE_ACTION("play", _("Play"));
675 // DEFINE_ACTION("pause", _("Pause"));
676 DEFINE_ACTION("stop", _("Stop"));
677 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
678 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
679 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
680 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
681 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
682 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
683 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
684 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
685 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
686 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
687 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
688 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
689 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
690 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
691 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
692 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
693 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
694 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
695 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
696 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
697 DEFINE_ACTION("seek-end", _("Seek to End"));
699 DEFINE_ACTION("action-group_add", _("Add group"));
701 DEFINE_ACTION("canvas-new", _("New Canvas"));
703 DEFINE_ACTION("amount-inc", _("Increase Amount"));
704 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
709 // Set up synfigapp actions
711 synfigapp::Action::Book::iterator iter;
713 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
715 Gtk::StockID stock_id;
717 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
719 //Gtk::Image* image(manage(new Gtk::Image()));
720 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
721 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
722 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
723 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
724 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
725 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
726 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
727 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
728 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
729 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
731 actions_action_group->add(Gtk::Action::create(
732 "action-"+iter->second.name,
734 iter->second.local_name,iter->second.local_name
742 Glib::ustring ui_info =
744 " <popup name='menu-toolbox' action='menu-toolbox'>"
745 " <menu action='menu-file'>"
748 " <popup name='menu-main' action='menu-main'>"
749 " <menu action='menu-file'>"
750 " <menuitem action='new' />"
751 " <menuitem action='open' />"
752 " <menuitem action='save' />"
753 " <menuitem action='save-as' />"
754 " <menuitem action='revert' />"
755 " <separator name='bleh01'/>"
756 " <menuitem action='cvs-add' />"
757 " <menuitem action='cvs-update' />"
758 " <menuitem action='cvs-commit' />"
759 " <menuitem action='cvs-revert' />"
760 " <separator name='bleh02'/>"
761 " <menuitem action='import' />"
762 " <separator name='bleh03'/>"
763 " <menuitem action='render' />"
764 " <menuitem action='preview' />"
765 " <menuitem action='sound' />"
766 " <separator name='bleh04'/>"
767 " <menuitem action='options' />"
768 " <menuitem action='close' />"
769 " <menuitem action='close-document' />"
770 " <menuitem action='quit' />"
772 " <menu action='menu-edit'>"
773 " <menuitem action='undo'/>"
774 " <menuitem action='redo'/>"
775 " <separator name='bleh05'/>"
776 " <menuitem action='cut'/>"
777 " <menuitem action='copy'/>"
778 " <menuitem action='paste'/>"
779 " <separator name='bleh06'/>"
780 " <menuitem action='select-all-ducks'/>"
781 " <menuitem action='unselect-all-layers'/>"
782 " <separator name='bleh07'/>"
783 " <menuitem action='properties'/>"
785 " <menu action='menu-view'>"
786 " <menu action='menu-duck-mask'>"
787 " <menuitem action='mask-position-ducks' />"
788 " <menuitem action='mask-vertex-ducks' />"
789 " <menuitem action='mask-tangent-ducks' />"
790 " <menuitem action='mask-radius-ducks' />"
791 " <menuitem action='mask-width-ducks' />"
792 " <menuitem action='mask-angle-ducks' />"
794 " <menu action='menu-preview-quality'>"
795 " <menuitem action='quality-00' />"
796 " <menuitem action='quality-01' />"
797 " <menuitem action='quality-02' />"
798 " <menuitem action='quality-03' />"
799 " <menuitem action='quality-04' />"
800 " <menuitem action='quality-05' />"
801 " <menuitem action='quality-06' />"
802 " <menuitem action='quality-07' />"
803 " <menuitem action='quality-08' />"
804 " <menuitem action='quality-09' />"
805 " <menuitem action='quality-10' />"
807 " <menu action='menu-lowres-pixel'>"
808 " <menuitem action='decrease-low-res-pixel-size'/>"
809 " <menuitem action='increase-low-res-pixel-size'/>"
810 " <separator name='pixel-size-separator'/>"
813 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
814 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
818 " <separator name='bleh08'/>"
819 " <menuitem action='play'/>"
820 //" <menuitem action='pause'/>"
821 " <menuitem action='stop'/>"
822 " <menuitem action='dialog-flipbook'/>"
823 " <separator name='bleh09'/>"
824 " <menuitem action='toggle-grid-show'/>"
825 " <menuitem action='toggle-grid-snap'/>"
826 " <menuitem action='toggle-guide-show'/>"
827 " <menuitem action='toggle-low-res'/>"
828 " <menuitem action='toggle-onion-skin'/>"
829 " <separator name='bleh10'/>"
830 " <menuitem action='canvas-zoom-in'/>"
831 " <menuitem action='canvas-zoom-out'/>"
832 " <menuitem action='canvas-zoom-fit'/>"
833 " <menuitem action='canvas-zoom-100'/>"
834 " <separator name='bleh11'/>"
835 " <menuitem action='time-zoom-in'/>"
836 " <menuitem action='time-zoom-out'/>"
837 " <separator name='bleh12'/>"
838 " <menuitem action='jump-next-keyframe'/>"
839 " <menuitem action='jump-prev-keyframe'/>"
840 " <menuitem action='seek-next-frame'/>"
841 " <menuitem action='seek-prev-frame'/>"
842 " <menuitem action='seek-next-second'/>"
843 " <menuitem action='seek-prev-second'/>"
844 " <menuitem action='seek-begin'/>"
845 " <menuitem action='seek-end'/>"
847 " <menu action='menu-canvas'>"
848 " <menuitem action='canvas-new'/>"
850 " <menu name='menu-state' action='menu-state'>"
852 " <menu action='menu-group'>"
853 " <menuitem action='action-group_add'/>"
855 " <menu action='menu-layer'>"
856 //" <menuitem action='cut'/>"
857 //" <menuitem action='copy'/>"
858 //" <menuitem action='paste'/>"
859 //" <separator name='bleh06'/>"
860 " <menu action='menu-layer-new'></menu>"
861 " <menuitem action='amount-inc'/>"
862 " <menuitem action='amount-dec'/>"
864 " <menu action='menu-keyframe'>"
865 " <menuitem action='keyframe-properties'/>"
872 " <menubar name='MenuBar'>"
873 " <menu action='MenuFile'>"
874 " <menuitem action='New'/>"
875 " <menuitem action='Open'/>"
877 " <menuitem action='Quit'/>"
879 " <menu action='MenuEdit'>"
880 " <menuitem action='Cut'/>"
881 " <menuitem action='Copy'/>"
882 " <menuitem action='Paste'/>"
885 " <toolbar name='ToolBar'>"
886 " <toolitem action='Open'/>"
887 " <toolitem action='Quit'/>"
893 actions_action_group->set_sensitive(false);
894 App::ui_manager()->set_add_tearoffs(true);
895 App::ui_manager()->insert_action_group(menus_action_group,1);
896 App::ui_manager()->insert_action_group(actions_action_group,1);
897 App::ui_manager()->add_ui_from_string(ui_info);
899 //App::ui_manager()->get_accel_group()->unlock();
901 catch(const Glib::Error& ex)
903 synfig::error("building menus and toolbars failed: " + ex.what());
906 // Add default keyboard accelerators
907 #define ACCEL(path,accel) \
909 Gtk::AccelKey accel_key(accel,path); \
910 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
913 #define ACCEL2(accel) \
915 Gtk::AccelKey accel_key(accel); \
916 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
919 ACCEL("<Actions>//select-all-ducks","<Control>a");
920 ACCEL("<Actions>//unselect-all-layers","<Control>d");
921 ACCEL("<Actions>//render","F9");
922 ACCEL("<Actions>//preview","F11");
923 ACCEL("<Actions>//properties","F8");
924 ACCEL("<Actions>//options","F12");
925 ACCEL("<Actions>//import","<control>i");
926 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
927 ACCEL("<Actions>//toggle-grid-show","<Control>g");
928 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
929 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
930 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
931 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
932 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
933 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
934 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
935 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
937 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
938 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
940 ACCEL("<Actions>//quality-01","<Control>1");
941 ACCEL("<Actions>//quality-02","<Control>2");
942 ACCEL("<Actions>//quality-03","<Control>3");
943 ACCEL("<Actions>//quality-04","<Control>4");
944 ACCEL("<Actions>//quality-05","<Control>5");
945 ACCEL("<Actions>//quality-06","<Control>6");
946 ACCEL("<Actions>//quality-07","<Control>7");
947 ACCEL("<Actions>//quality-08","<Control>8");
948 ACCEL("<Actions>//quality-09","<Control>9");
949 ACCEL("<Actions>//quality-10","<Control>0");
950 ACCEL("<Actions>//undo","<Control>z");
951 ACCEL("<Actions>//redo","<Control>r");
952 ACCEL("<Actions>//action-layer_remove","Delete");
954 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
955 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
956 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
957 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
958 ACCEL("<Actions>//time-zoom-in","+");
959 ACCEL("<Actions>//time-zoom-out","_");
961 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
962 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
964 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
965 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
967 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
968 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
969 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
970 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
971 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
972 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
973 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
974 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
975 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
976 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
977 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
978 ACCEL("<Actions>//play", "<Control>p");
979 ACCEL("<Actions>//seek-begin","Home");
980 ACCEL("<Actions>//seek-end","End");
982 ACCEL("<Actions>//state-normal", "<Mod1>a");
983 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
984 ACCEL("<Actions>//state-scale", "<Mod1>d");
985 ACCEL("<Actions>//state-rotate", "<Mod1>s");
987 ACCEL("<Actions>//state-bline", "<Mod1>b");
988 ACCEL("<Actions>//state-circle", "<Mod1>c");
989 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
990 ACCEL("<Actions>//state-gradient", "<Mod1>g");
992 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
993 ACCEL("<Actions>//state-fill", "<Mod1>f");
994 ACCEL("<Actions>//state-zoom", "<Mod1>z");
995 ACCEL("<Actions>//state-polygon", "<Mod1>p");
997 ACCEL("<Actions>//state-draw", "<Mod1>w");
998 ACCEL("<Actions>//state-sketch", "<Mod1>k");
999 ACCEL("<Actions>//state-width", "<Mod1>t");
1000 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1002 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1008 #define mkdir(x,y) mkdir(x)
1011 /* === M E T H O D S ======================================================= */
1013 App::App(int *argc, char ***argv):
1014 Gtk::Main(argc,argv),
1015 IconController(etl::dirname((*argv)[0]))
1017 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1020 ui_interface_=new GlobalUIInterface();
1024 // don't call thread_init() if threads are already initialized
1025 // on some machines bonobo_init() initialized threads before we get here
1026 if (!g_thread_supported())
1027 Glib::thread_init();
1029 distance_system=Distance::SYSTEM_UNITS;
1031 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1034 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1038 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1044 if(!SYNFIG_CHECK_VERSION())
1046 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1047 dialog_error_blocking("Synfig Studio",
1048 "This copy of Synfig Studio was compiled against a\n"
1049 "different version of libsynfig than what is currently\n"
1050 "installed. Synfig Studio will now abort. Try downloading\n"
1051 "the latest version from the Synfig website at\n"
1052 "http://synfig.org/Download"
1056 Glib::set_application_name(_("Synfig Studio"));
1058 Splash splash_screen;
1059 splash_screen.set_can_self_destruct(false);
1060 splash_screen.show();
1062 shutdown_in_progress=false;
1063 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1064 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1066 // Initialize the Synfig library
1067 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1070 get_ui_interface()->error(_("Failed to initialize synfig!"));
1074 // add the preferences to the settings
1075 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1079 studio_init_cb.task(_("Init UI Manager..."));
1080 App::ui_manager_=studio::UIManager::create();
1083 studio_init_cb.task(_("Init Dock Manager..."));
1084 dock_manager=new studio::DockManager();
1086 studio_init_cb.task(_("Init State Manager..."));
1087 state_manager=new StateManager();
1089 studio_init_cb.task(_("Init Toolbox..."));
1090 toolbox=new studio::Toolbox();
1092 studio_init_cb.task(_("Init About Dialog..."));
1093 about=new studio::About();
1095 studio_init_cb.task(_("Init Tool Options..."));
1096 dialog_tool_options=new studio::Dialog_ToolOptions();
1097 dock_manager->register_dockable(*dialog_tool_options);
1099 studio_init_cb.task(_("Init History..."));
1100 dock_history=new studio::Dock_History();
1101 dock_manager->register_dockable(*dock_history);
1103 studio_init_cb.task(_("Init Canvases..."));
1104 dock_canvases=new studio::Dock_Canvases();
1105 dock_manager->register_dockable(*dock_canvases);
1107 studio_init_cb.task(_("Init Keyframes..."));
1108 dock_keyframes=new studio::Dock_Keyframes();
1109 dock_manager->register_dockable(*dock_keyframes);
1111 studio_init_cb.task(_("Init Layers..."));
1112 dock_layers=new studio::Dock_Layers();
1113 dock_manager->register_dockable(*dock_layers);
1115 studio_init_cb.task(_("Init Params..."));
1116 dock_params=new studio::Dock_Params();
1117 dock_manager->register_dockable(*dock_params);
1119 studio_init_cb.task(_("Init MetaData..."));
1120 dock_meta_data=new studio::Dock_MetaData();
1121 dock_manager->register_dockable(*dock_meta_data);
1123 studio_init_cb.task(_("Init Children..."));
1124 dock_children=new studio::Dock_Children();
1125 dock_manager->register_dockable(*dock_children);
1127 studio_init_cb.task(_("Init Info..."));
1128 dock_info = new studio::Dock_Info();
1129 dock_manager->register_dockable(*dock_info);
1131 studio_init_cb.task(_("Init Navigator..."));
1132 dock_navigator = new studio::Dock_Navigator();
1133 dock_manager->register_dockable(*dock_navigator);
1135 studio_init_cb.task(_("Init Timetrack..."));
1136 dock_timetrack = new studio::Dock_Timetrack();
1137 dock_manager->register_dockable(*dock_timetrack);
1139 studio_init_cb.task(_("Init Curve Editor..."));
1140 dock_curves = new studio::Dock_Curves();
1141 dock_manager->register_dockable(*dock_curves);
1143 studio_init_cb.task(_("Init Layer Groups..."));
1144 dock_layer_groups = new studio::Dock_LayerGroups();
1145 dock_manager->register_dockable(*dock_layer_groups);
1148 studio_init_cb.task(_("Init Color Dialog..."));
1149 dialog_color=new studio::Dialog_Color();
1151 studio_init_cb.task(_("Init Gradient Dialog..."));
1152 dialog_gradient=new studio::Dialog_Gradient();
1154 studio_init_cb.task(_("Init DeviceTracker..."));
1155 device_tracker=new studio::DeviceTracker();
1157 studio_init_cb.task(_("Init Tools..."));
1160 state_manager->add_state(&state_normal);
1161 state_manager->add_state(&state_smooth_move);
1162 state_manager->add_state(&state_scale);
1163 state_manager->add_state(&state_rotate);
1164 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1167 state_manager->add_state(&state_bline);
1168 state_manager->add_state(&state_circle);
1169 state_manager->add_state(&state_rectangle);
1170 state_manager->add_state(&state_gradient);
1171 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1174 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1175 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1176 state_manager->add_state(&state_fill);
1177 state_manager->add_state(&state_eyedrop);
1178 state_manager->add_state(&state_zoom);
1180 // Disabled by default - it doesn't work properly?
1181 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1183 studio_init_cb.task(_("Init ModPalette..."));
1184 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1186 studio_init_cb.task(_("Init Setup Dialog..."));
1187 dialog_setup=new studio::Dialog_Setup();
1189 studio_init_cb.task(_("Init Input Dialog..."));
1190 dialog_input=new Gtk::InputDialog();
1191 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1192 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1194 studio_init_cb.task(_("Init auto recovery..."));
1195 auto_recover=new AutoRecover();
1197 studio_init_cb.amount_complete(9250,10000);
1198 studio_init_cb.task(_("Loading Settings..."));
1200 studio_init_cb.task(_("Checking auto-recover..."));
1202 studio_init_cb.amount_complete(9900,10000);
1204 bool opened_any = false;
1205 if(auto_recover->recovery_needed())
1207 splash_screen.hide();
1208 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1209 _("Synfig Studio seems to have crashed\n"
1210 "before you could save all your files.\n"
1211 "Would you like to re-open those files\n"
1212 "and recover your unsaved changes?")) ==
1213 synfigapp::UIInterface::RESPONSE_YES)
1215 int number_recovered;
1216 if(!auto_recover->recover(number_recovered))
1217 if (number_recovered)
1218 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1220 get_ui_interface()->error(_("Unable to recover from previous crash"));
1222 get_ui_interface()->error(
1223 _("Synfig Studio has attempted to recover\n"
1224 "from a previous crash. The files that it has\n"
1225 "recovered are NOT YET SAVED. It would be a good\n"
1226 "idea to review them and save them now."));
1228 if (number_recovered)
1231 splash_screen.show();
1234 // Look for any files given on the command line,
1235 // and load them if found.
1236 for(;*argc>=1;(*argc)--)
1237 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1239 studio_init_cb.task(_("Loading files..."));
1240 splash_screen.hide();
1241 open((*argv)[*argc]);
1243 splash_screen.show();
1246 // if no file was specified to be opened, create a new document to help new users get started more easily
1247 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1250 studio_init_cb.task(_("Done."));
1251 studio_init_cb.amount_complete(10000,10000);
1257 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1261 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1265 StateManager* App::get_state_manager() { return state_manager; }
1269 shutdown_in_progress=true;
1273 synfigapp::Main::settings().remove_domain("pref");
1275 selected_instance=0;
1277 // Unload all of the modules
1278 for(;!module_list_.empty();module_list_.pop_back())
1281 delete state_manager;
1285 delete auto_recover;
1291 // studio::App::iteration(false);
1295 // studio::App::iteration(false);
1297 // studio::App::iteration(false);
1299 delete dialog_setup;
1301 delete dialog_gradient;
1303 delete dialog_color;
1305 delete dialog_input;
1307 delete dock_manager;
1309 instance_list.clear();
1311 // studio::App::iteration(false);
1315 App::get_user_app_directory()
1317 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1321 App::get_config_file(const synfig::String& file)
1323 return Glib::build_filename(get_user_app_directory(),file);
1327 App::add_recent_file(const std::string &file_name)
1329 std::string filename(file_name);
1331 assert(!filename.empty());
1333 if(filename.empty())
1336 // Toss out any "hidden" files
1337 if(basename(filename)[0]=='.')
1340 // If we aren't an absolute path, turn ourselves into one
1341 if(!is_absolute_path(filename))
1342 filename=absolute_path(filename);
1344 list<string>::iterator iter;
1345 // Check to see if the file is already on the list.
1346 // If it is, then remove it from the list
1347 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1350 recent_files.erase(iter);
1355 // Push the filename to the front of the list
1356 recent_files.push_front(filename);
1358 // Clean out the files at the end of the list.
1359 while(recent_files.size()>(unsigned)get_max_recent_files())
1360 recent_files.pop_back();
1362 signal_recent_files_changed_();
1367 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1370 App::get_time_format()
1372 return _App_time_format;
1376 App::set_time_format(synfig::Time::Format x)
1383 App::save_settings()
1388 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1389 setlocale(LC_NUMERIC, "C");
1391 std::string filename=get_config_file("accelrc");
1392 Gtk::AccelMap::save(filename);
1395 std::string filename=get_config_file("recentfiles");
1397 std::ofstream file(filename.c_str());
1401 synfig::warning("Unable to save %s",filename.c_str());
1405 list<string>::reverse_iterator iter;
1407 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1411 std::string filename=get_config_file("settings");
1412 synfigapp::Main::settings().save_to_file(filename);
1413 setlocale(LC_NUMERIC,old_locale);
1417 synfig::warning("Caught exception when attempting to save settings.");
1422 App::load_settings()
1427 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1428 setlocale(LC_NUMERIC, "C");
1430 std::string filename=get_config_file("accelrc");
1431 Gtk::AccelMap::load(filename);
1434 std::string filename=get_config_file("recentfiles");
1436 std::ifstream file(filename.c_str());
1440 std::string recent_file;
1441 getline(file,recent_file);
1442 if(!recent_file.empty())
1443 add_recent_file(recent_file);
1446 std::string filename=get_config_file("settings");
1447 if(!synfigapp::Main::settings().load_from_file(filename))
1449 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1450 //if(!synfigapp::Main::settings().load_from_file(filename))
1452 gamma.set_gamma(1.0/2.2);
1453 reset_initial_window_configuration();
1456 setlocale(LC_NUMERIC,old_locale);
1460 synfig::warning("Caught exception when attempting to load settings.");
1465 App::reset_initial_window_configuration()
1467 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1468 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1469 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1470 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1471 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1472 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1473 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1474 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1475 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1476 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1477 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1478 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1479 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1480 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1481 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1485 App::shutdown_request(GdkEventAny*)
1489 //return !shutdown_in_progress;
1495 if(shutdown_in_progress)return;
1498 get_ui_interface()->task(_("Quit Request"));
1501 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1505 std::list<etl::handle<Instance> >::iterator iter;
1506 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1508 if(!(*iter)->safe_close())
1512 if((*iter)->synfigapp::Instance::get_action_count())
1514 handle<synfigapp::UIInterface> uim;
1515 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1517 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1518 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1520 case synfigapp::UIInterface::RESPONSE_NO:
1522 case synfigapp::UIInterface::RESPONSE_YES:
1525 case synfigapp::UIInterface::RESPONSE_CANCEL:
1534 if((*iter)->synfigapp::Instance::is_modified())
1536 handle<synfigapp::UIInterface> uim;
1537 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1539 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() );
1540 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1542 case synfigapp::UIInterface::RESPONSE_NO:
1544 case synfigapp::UIInterface::RESPONSE_YES:
1545 (*iter)->dialog_cvs_commit();
1547 case synfigapp::UIInterface::RESPONSE_CANCEL:
1556 // This next line causes things to crash for some reason
1560 shutdown_in_progress=true;
1562 instance_list.clear();
1564 while(studio::App::events_pending())studio::App::iteration(false);
1567 auto_recover->normal_shutdown();
1569 get_ui_interface()->task(_("Quit Request sent"));
1575 dialog_setup->refresh();
1576 dialog_setup->show();
1579 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1580 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1583 //#define USE_WIN32_FILE_DIALOGS 1
1586 #ifdef USE_WIN32_FILE_DIALOGS
1587 static OPENFILENAME ofn={};
1591 #include <gdk/gdkwin32.h>
1595 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1597 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1599 #ifdef USE_WIN32_FILE_DIALOGS
1600 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1602 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1603 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1604 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1606 ofn.lStructSize=sizeof(OPENFILENAME);
1607 ofn.hwndOwner = hWnd;
1608 ofn.hInstance = hInstance;
1609 ofn.lpstrFilter = szFilter;
1610 // ofn.lpstrCustomFilter=NULL;
1611 // ofn.nMaxCustFilter=0;
1612 // ofn.nFilterIndex=0;
1613 // ofn.lpstrFile=NULL;
1614 ofn.nMaxFile=MAX_PATH;
1615 // ofn.lpstrFileTitle=NULL;
1616 // ofn.lpstrInitialDir=NULL;
1617 // ofn.lpstrTitle=NULL;
1618 ofn.Flags=OFN_HIDEREADONLY;
1619 // ofn.nFileOffset=0;
1620 // ofn.nFileExtension=0;
1621 ofn.lpstrDefExt=TEXT("sif");
1622 // ofn.lCustData = 0l;
1624 // ofn.lpTemplateName=NULL;
1626 CHAR szFilename[MAX_PATH];
1628 strcpy(szFilename,filename.c_str());
1629 strcpy(szTitle,title.c_str());
1631 ofn.lpstrFile=szFilename;
1632 ofn.lpstrFileTitle=szTitle;
1634 if(GetOpenFileName(&ofn))
1636 filename=szFilename;
1642 synfig::String prev_path;
1644 if(!_preferences.get_value(preference, prev_path))
1647 prev_path = absolute_path(prev_path);
1649 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1651 dialog->set_current_folder(prev_path);
1652 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1653 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1655 if (filename.empty())
1656 dialog->set_filename(prev_path);
1657 else if (is_absolute_path(filename))
1658 dialog->set_filename(filename);
1660 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1662 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1663 filename = dialog->get_filename();
1664 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1665 _preferences.set_value(preference, dirname(filename));
1679 GtkWidget *fileselection;
1680 fileselection = gtk_file_selection_new(title.c_str());
1683 if(basename(filename)==filename)
1685 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1688 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1690 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1692 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1693 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1695 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1696 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1698 gtk_widget_show(fileselection);
1706 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1707 _preferences.set_value(preference,dirname(filename));
1711 gtk_widget_destroy(fileselection);
1714 gtk_widget_destroy(fileselection);
1721 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1723 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1725 #if USE_WIN32_FILE_DIALOGS
1726 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1728 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1729 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1730 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1732 ofn.lStructSize=sizeof(OPENFILENAME);
1733 ofn.hwndOwner = hWnd;
1734 ofn.hInstance = hInstance;
1735 ofn.lpstrFilter = szFilter;
1736 // ofn.lpstrCustomFilter=NULL;
1737 // ofn.nMaxCustFilter=0;
1738 // ofn.nFilterIndex=0;
1739 // ofn.lpstrFile=NULL;
1740 ofn.nMaxFile=MAX_PATH;
1741 // ofn.lpstrFileTitle=NULL;
1742 // ofn.lpstrInitialDir=NULL;
1743 // ofn.lpstrTitle=NULL;
1744 ofn.Flags=OFN_OVERWRITEPROMPT;
1745 // ofn.nFileOffset=0;
1746 // ofn.nFileExtension=0;
1747 ofn.lpstrDefExt=TEXT("sif");
1748 // ofn.lCustData = 0l;
1750 // ofn.lpTemplateName=NULL;
1752 CHAR szFilename[MAX_PATH];
1754 strcpy(szFilename,filename.c_str());
1755 strcpy(szTitle,title.c_str());
1757 ofn.lpstrFile=szFilename;
1758 ofn.lpstrFileTitle=szTitle;
1760 if(GetSaveFileName(&ofn))
1762 filename=szFilename;
1763 _preferences.set_value(preference,dirname(filename));
1768 synfig::String prev_path;
1770 if(!_preferences.get_value(preference, prev_path))
1773 prev_path = absolute_path(prev_path);
1775 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1777 dialog->set_current_folder(prev_path);
1778 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1779 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1781 Widget_Enum *file_type_enum = 0;
1782 if (preference == ANIMATION_DIR_PREFERENCE)
1784 file_type_enum = manage(new Widget_Enum());
1785 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1786 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", strprintf("0.61.08 (%s)", _("current")))
1787 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1788 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1789 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1791 Gtk::HBox *hbox = manage(new Gtk::HBox);
1792 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1793 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1796 dialog->set_extra_widget(*hbox);
1799 if (filename.empty())
1800 dialog->set_filename(prev_path);
1803 std::string full_path;
1804 if (is_absolute_path(filename))
1805 full_path = filename;
1807 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1809 // select the file if it exists
1810 dialog->set_filename(full_path);
1812 // if the file doesn't exist, put its name into the filename box
1814 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1815 dialog->set_current_name(basename(filename));
1818 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1819 if (preference == ANIMATION_DIR_PREFERENCE)
1820 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
1821 filename = dialog->get_filename();
1822 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1823 _preferences.set_value(preference, dirname(filename));
1834 App::dialog_error_blocking(const std::string &title, const std::string &message)
1836 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1837 dialog.set_title(title);
1843 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1845 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1846 dialog.set_title(title);
1852 App::dialog_yes_no(const std::string &title, const std::string &message)
1857 true // use_separator
1859 Gtk::Label label(message);
1862 dialog.get_vbox()->pack_start(label);
1863 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1864 dialog.add_button(Gtk::StockID("gtk-no"),0);
1866 return dialog.run();
1870 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1875 true // use_separator
1877 Gtk::Label label(message);
1880 dialog.get_vbox()->pack_start(label);
1881 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1882 dialog.add_button(Gtk::StockID("gtk-no"),0);
1883 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1885 return dialog.run();
1889 App::dialog_not_implemented()
1891 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1892 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1897 try_open_url(const std::string &url)
1900 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
1902 gchar* argv[3] = {strdup(App::browser_command.c_str()), strdup(url.c_str()), NULL};
1904 GError* gerror = NULL;
1906 retval = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &gerror);
1912 error(_("Could not execute specified web browser: %s"), gerror->message);
1913 g_error_free(gerror);
1924 if (!try_open_url("http://synfig.org/Documentation"))
1926 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
1927 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
1928 dialog.set_title(_("Help"));
1934 App::open_url(const std::string &url)
1940 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1945 true // use_separator
1947 Gtk::Label label(message);
1949 dialog.get_vbox()->pack_start(label);
1952 entry.set_text(text);
1954 entry.set_activates_default(true);
1955 dialog.get_vbox()->pack_start(entry);
1957 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1958 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1959 dialog.set_default_response(Gtk::RESPONSE_OK);
1960 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1963 if(dialog.run()!=Gtk::RESPONSE_OK)
1966 text=entry.get_text();
1975 App::open(std::string filename)
1977 return open_as(filename,filename);
1980 // this is called from autorecover.cpp:
1981 // App::open_as(get_shadow_file_name(filename),filename)
1982 // other than that, 'filename' and 'as' are the same
1984 App::open_as(std::string filename,std::string as)
1987 char long_name[1024];
1988 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1994 OneMoment one_moment;
1996 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1997 if(canvas && get_instance(canvas))
1999 get_instance(canvas)->find_canvas_view(canvas)->present();
2000 info("%s is already open", filename.c_str());
2001 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2006 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2008 add_recent_file(as);
2010 handle<Instance> instance(Instance::create(canvas));
2013 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2017 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)")))
2018 instance->dialog_cvs_update();
2023 dialog_error_blocking(_("Error"), x);
2028 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2039 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2040 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2042 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2044 canvas->rend_desc().set_frame_rate(24.0);
2045 canvas->rend_desc().set_time_start(0.0);
2046 canvas->rend_desc().set_time_end(5.0);
2047 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2048 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2049 canvas->rend_desc().set_tl(Vector(-4,2.25));
2050 canvas->rend_desc().set_br(Vector(4,-2.25));
2051 canvas->rend_desc().set_w(480);
2052 canvas->rend_desc().set_h(270);
2053 canvas->rend_desc().set_antialias(1);
2054 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2055 canvas->set_file_name(file_name);
2057 handle<Instance> instance = Instance::create(canvas);
2059 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2060 instance->find_canvas_view(canvas)->canvas_properties.present();
2064 App::dialog_open(string filename)
2066 if (filename.empty())
2069 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2071 // If the filename still has wildcards, then we should
2072 // continue looking for the file we want
2073 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2079 get_ui_interface()->error(_("Unable to open file"));
2084 App::set_selected_instance(etl::loose_handle<Instance> instance)
2086 /* if(get_selected_instance()==instance)
2088 selected_instance=instance;
2089 signal_instance_selected()(instance);
2095 selected_instance=instance;
2096 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2100 instance->focus(instance->get_canvas());
2103 set_selected_canvas_view(0);
2105 signal_instance_selected()(instance);
2109 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2111 selected_canvas_view=canvas_view;
2112 signal_canvas_view_focus()(selected_canvas_view);
2115 selected_instance=canvas_view->get_instance();
2116 signal_instance_selected()(canvas_view->get_instance());
2119 if(get_selected_canvas_view()==canvas_view)
2121 signal_canvas_view_focus()(selected_canvas_view);
2122 signal_instance_selected()(canvas_view->get_instance());
2125 selected_canvas_view=canvas_view;
2126 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2127 set_selected_instance(canvas_view->get_instance());
2128 signal_canvas_view_focus()(selected_canvas_view);
2132 etl::loose_handle<Instance>
2133 App::get_instance(etl::handle<synfig::Canvas> canvas)
2135 if(!canvas) return 0;
2136 canvas=canvas->get_root();
2138 std::list<etl::handle<Instance> >::iterator iter;
2139 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2141 if((*iter)->get_canvas()==canvas)
2157 if(selected_instance)
2158 selected_instance->undo();
2164 if(selected_instance)
2165 selected_instance->redo();
2169 studio::App::get_base_path()
2171 return app_base_path_;