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;
267 static int max_recent_files_=25;
268 int studio::App::get_max_recent_files() { return max_recent_files_; }
269 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
271 static synfig::String app_base_path_;
276 really_delete_widget(Gtk::Widget *widget)
278 // synfig::info("really delete %p", (void*)widget);
283 // nasty workaround - when we've finished with a popup menu, we want to delete it
284 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
285 // so schedule the real delete to happen in 50ms, giving the action a chance to run
287 delete_widget(Gtk::Widget *widget)
289 // synfig::info("delete %p", (void*)widget);
290 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
293 }; // END of namespace studio
294 studio::StateManager* state_manager;
299 class GlobalUIInterface : public synfigapp::UIInterface
303 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
308 true // use_separator
310 Gtk::Label label(message);
313 dialog.get_vbox()->pack_start(label);
314 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
315 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
317 dialog.set_default_response(dflt);
319 return (Response)dialog.run();
321 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
326 true // use_separator
328 Gtk::Label label(message);
331 dialog.get_vbox()->pack_start(label);
332 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
333 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
334 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
336 dialog.set_default_response(dflt);
338 return (Response)dialog.run();
340 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
345 true // use_separator
347 Gtk::Label label(message);
350 dialog.get_vbox()->pack_start(label);
351 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
352 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
354 dialog.set_default_response(dflt);
356 return (Response)dialog.run();
360 task(const std::string &task)
362 std::cerr<<task<<std::endl;
363 while(studio::App::events_pending())studio::App::iteration(false);
368 error(const std::string &err)
370 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
377 warning(const std::string &err)
379 std::cerr<<"warning: "<<err<<std::endl;
380 while(studio::App::events_pending())studio::App::iteration(false);
385 amount_complete(int /*current*/, int /*total*/)
387 while(studio::App::events_pending())studio::App::iteration(false);
392 /* === P R O C E D U R E S ================================================= */
396 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
398 action_group_list.push_back(action_group);
399 Gtk::UIManager::insert_action_group(action_group, pos);
403 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
405 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
406 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
407 if(*iter==action_group)
409 action_group_list.erase(iter);
410 Gtk::UIManager::remove_action_group(action_group);
413 synfig::error("Unable to find action group");
417 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
419 ui_manager->insert_action_group(group,0);
421 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
422 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
424 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
426 if(*iter && (*iter)->get_name()!="menus")
428 synfig::info("Removing action group "+(*iter)->get_name());
429 ui_manager->remove_action_group(*iter);
432 ui_manager->insert_action_group(group,0);
434 for(;!prev_groups.empty();prev_groups.pop_front())
436 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
437 ui_manager->insert_action_group(prev_groups.front(),1);
441 class Preferences : public synfigapp::Settings
444 virtual bool get_value(const synfig::String& key, synfig::String& value)const
448 value=strprintf("%f %f %f %f",
449 App::gamma.get_gamma_r(),
450 App::gamma.get_gamma_g(),
451 App::gamma.get_gamma_b(),
452 App::gamma.get_black_level()
456 if(key=="time_format")
458 value=strprintf("%i",App::get_time_format());
461 if(key=="file_history.size")
463 value=strprintf("%i",App::get_max_recent_files());
466 if(key=="use_colorspace_gamma")
468 value=strprintf("%i",(int)App::use_colorspace_gamma);
471 if(key=="distance_system")
473 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
476 if(key=="single_threaded")
478 value=strprintf("%i",(int)App::single_threaded);
481 if(key=="auto_recover_backup_interval")
483 value=strprintf("%i",App::auto_recover->get_timeout());
486 if(key=="restrict_radius_ducks")
488 value=strprintf("%i",(int)App::restrict_radius_ducks);
492 return synfigapp::Settings::get_value(key,value);
495 virtual bool set_value(const synfig::String& key,const synfig::String& value)
501 strscanf(value,"%f %f %f %f",
508 App::gamma.set_all(r,g,b,blk);
512 if(key=="time_format")
514 int i(atoi(value.c_str()));
515 App::set_time_format(static_cast<synfig::Time::Format>(i));
518 if(key=="auto_recover_backup_interval")
520 int i(atoi(value.c_str()));
521 App::auto_recover->set_timeout(i);
524 if(key=="file_history.size")
526 int i(atoi(value.c_str()));
527 App::set_max_recent_files(i);
530 if(key=="use_colorspace_gamma")
532 int i(atoi(value.c_str()));
533 App::use_colorspace_gamma=i;
536 if(key=="distance_system")
538 App::distance_system=Distance::ident_system(value);;
541 if(key=="single_threaded")
543 int i(atoi(value.c_str()));
544 App::single_threaded=i;
547 if(key=="restrict_radius_ducks")
549 int i(atoi(value.c_str()));
550 App::restrict_radius_ducks=i;
554 return synfigapp::Settings::set_value(key,value);
557 virtual KeyList get_key_list()const
559 KeyList ret(synfigapp::Settings::get_key_list());
560 ret.push_back("gamma");
561 ret.push_back("time_format");
562 ret.push_back("distance_system");
563 ret.push_back("file_history.size");
564 ret.push_back("use_colorspace_gamma");
565 ret.push_back("single_threaded");
566 ret.push_back("auto_recover_backup_interval");
567 ret.push_back("restrict_radius_ducks");
572 static ::Preferences _preferences;
577 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
579 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
581 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
583 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
584 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
585 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
586 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
587 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
588 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
589 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
590 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
591 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
592 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
593 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
594 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
595 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
597 // Add the synfigapp actions...
598 synfigapp::Action::Book::iterator iter;
599 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
601 actions_action_group->add(Gtk::Action::create(
602 "action-"+iter->second.name,
603 get_action_stock_id(iter->second),
604 iter->second.local_name,iter->second.local_name
608 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
609 #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); }
610 #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); }
612 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
613 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
614 DEFINE_ACTION("new", Gtk::Stock::NEW);
615 DEFINE_ACTION("open", Gtk::Stock::OPEN);
616 DEFINE_ACTION("save", Gtk::Stock::SAVE);
617 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
618 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
619 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
620 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
621 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
622 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
623 DEFINE_ACTION("import", _("Import"));
624 DEFINE_ACTION("render", _("Render"));
625 DEFINE_ACTION("preview", _("Preview"));
626 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
627 DEFINE_ACTION("sound", _("Sound File"));
628 DEFINE_ACTION("options", _("Options"));
629 DEFINE_ACTION("close", _("Close View"));
630 DEFINE_ACTION("close-document", _("Close Document"));
631 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
634 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
635 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
636 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
637 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
638 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
639 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
640 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
641 DEFINE_ACTION("properties", _("Properties"));
643 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
644 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
645 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
646 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
647 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
648 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
649 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
650 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
651 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
652 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
653 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
654 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
655 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
656 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
657 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
658 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
659 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
660 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
661 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
662 DEFINE_ACTION("play", _("Play"));
663 // DEFINE_ACTION("pause", _("Pause"));
664 DEFINE_ACTION("stop", _("Stop"));
665 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
666 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
667 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
668 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
669 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
670 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
671 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
672 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
673 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
674 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
675 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
676 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
677 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
678 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
679 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
680 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
681 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
682 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
683 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
684 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
685 DEFINE_ACTION("seek-end", _("Seek to End"));
687 DEFINE_ACTION("action-group_add", _("Add group"));
689 DEFINE_ACTION("canvas-new", _("New Canvas"));
691 DEFINE_ACTION("amount-inc", _("Increase Amount"));
692 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
697 // Set up synfigapp actions
699 synfigapp::Action::Book::iterator iter;
701 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
703 Gtk::StockID stock_id;
705 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
707 //Gtk::Image* image(manage(new Gtk::Image()));
708 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
709 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
710 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
711 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
712 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
713 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
714 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
715 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
716 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
717 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
719 actions_action_group->add(Gtk::Action::create(
720 "action-"+iter->second.name,
722 iter->second.local_name,iter->second.local_name
730 Glib::ustring ui_info =
732 " <popup name='menu-toolbox' action='menu-toolbox'>"
733 " <menu action='menu-file'>"
736 " <popup name='menu-main' action='menu-main'>"
737 " <menu action='menu-file'>"
738 " <menuitem action='new' />"
739 " <menuitem action='open' />"
740 " <menuitem action='save' />"
741 " <menuitem action='save-as' />"
742 " <menuitem action='revert' />"
743 " <separator name='bleh01'/>"
744 " <menuitem action='cvs-add' />"
745 " <menuitem action='cvs-update' />"
746 " <menuitem action='cvs-commit' />"
747 " <menuitem action='cvs-revert' />"
748 " <separator name='bleh02'/>"
749 " <menuitem action='import' />"
750 " <separator name='bleh03'/>"
751 " <menuitem action='render' />"
752 " <menuitem action='preview' />"
753 " <menuitem action='sound' />"
754 " <separator name='bleh04'/>"
755 " <menuitem action='options' />"
756 " <menuitem action='close' />"
757 " <menuitem action='close-document' />"
758 " <menuitem action='quit' />"
760 " <menu action='menu-edit'>"
761 " <menuitem action='undo'/>"
762 " <menuitem action='redo'/>"
763 " <separator name='bleh05'/>"
764 " <menuitem action='cut'/>"
765 " <menuitem action='copy'/>"
766 " <menuitem action='paste'/>"
767 " <separator name='bleh06'/>"
768 " <menuitem action='select-all-ducks'/>"
769 " <menuitem action='unselect-all-layers'/>"
770 " <separator name='bleh07'/>"
771 " <menuitem action='properties'/>"
773 " <menu action='menu-view'>"
774 " <menu action='menu-duck-mask'>"
775 " <menuitem action='mask-position-ducks' />"
776 " <menuitem action='mask-vertex-ducks' />"
777 " <menuitem action='mask-tangent-ducks' />"
778 " <menuitem action='mask-radius-ducks' />"
779 " <menuitem action='mask-width-ducks' />"
780 " <menuitem action='mask-angle-ducks' />"
782 " <menu action='menu-preview-quality'>"
783 " <menuitem action='quality-00' />"
784 " <menuitem action='quality-01' />"
785 " <menuitem action='quality-02' />"
786 " <menuitem action='quality-03' />"
787 " <menuitem action='quality-04' />"
788 " <menuitem action='quality-05' />"
789 " <menuitem action='quality-06' />"
790 " <menuitem action='quality-07' />"
791 " <menuitem action='quality-08' />"
792 " <menuitem action='quality-09' />"
793 " <menuitem action='quality-10' />"
795 " <menu action='menu-lowres-pixel'>"
796 " <menuitem action='decrease-low-res-pixel-size'/>"
797 " <menuitem action='increase-low-res-pixel-size'/>"
798 " <separator name='pixel-size-separator'/>"
801 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
802 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
806 " <separator name='bleh08'/>"
807 " <menuitem action='play'/>"
808 //" <menuitem action='pause'/>"
809 " <menuitem action='stop'/>"
810 " <menuitem action='dialog-flipbook'/>"
811 " <separator name='bleh09'/>"
812 " <menuitem action='toggle-grid-show'/>"
813 " <menuitem action='toggle-grid-snap'/>"
814 " <menuitem action='toggle-guide-show'/>"
815 " <menuitem action='toggle-low-res'/>"
816 " <menuitem action='toggle-onion-skin'/>"
817 " <separator name='bleh10'/>"
818 " <menuitem action='canvas-zoom-in'/>"
819 " <menuitem action='canvas-zoom-out'/>"
820 " <menuitem action='canvas-zoom-fit'/>"
821 " <menuitem action='canvas-zoom-100'/>"
822 " <separator name='bleh11'/>"
823 " <menuitem action='time-zoom-in'/>"
824 " <menuitem action='time-zoom-out'/>"
825 " <separator name='bleh12'/>"
826 " <menuitem action='jump-next-keyframe'/>"
827 " <menuitem action='jump-prev-keyframe'/>"
828 " <menuitem action='seek-next-frame'/>"
829 " <menuitem action='seek-prev-frame'/>"
830 " <menuitem action='seek-next-second'/>"
831 " <menuitem action='seek-prev-second'/>"
832 " <menuitem action='seek-begin'/>"
833 " <menuitem action='seek-end'/>"
835 " <menu action='menu-canvas'>"
836 " <menuitem action='canvas-new'/>"
838 " <menu name='menu-state' action='menu-state'>"
840 " <menu action='menu-group'>"
841 " <menuitem action='action-group_add'/>"
843 " <menu action='menu-layer'>"
844 //" <menuitem action='cut'/>"
845 //" <menuitem action='copy'/>"
846 //" <menuitem action='paste'/>"
847 //" <separator name='bleh06'/>"
848 " <menu action='menu-layer-new'></menu>"
849 " <menuitem action='amount-inc'/>"
850 " <menuitem action='amount-dec'/>"
852 " <menu action='menu-keyframe'>"
853 " <menuitem action='keyframe-properties'/>"
860 " <menubar name='MenuBar'>"
861 " <menu action='MenuFile'>"
862 " <menuitem action='New'/>"
863 " <menuitem action='Open'/>"
865 " <menuitem action='Quit'/>"
867 " <menu action='MenuEdit'>"
868 " <menuitem action='Cut'/>"
869 " <menuitem action='Copy'/>"
870 " <menuitem action='Paste'/>"
873 " <toolbar name='ToolBar'>"
874 " <toolitem action='Open'/>"
875 " <toolitem action='Quit'/>"
881 actions_action_group->set_sensitive(false);
882 App::ui_manager()->set_add_tearoffs(true);
883 App::ui_manager()->insert_action_group(menus_action_group,1);
884 App::ui_manager()->insert_action_group(actions_action_group,1);
885 App::ui_manager()->add_ui_from_string(ui_info);
887 //App::ui_manager()->get_accel_group()->unlock();
889 catch(const Glib::Error& ex)
891 synfig::error("building menus and toolbars failed: " + ex.what());
894 // Add default keyboard accelerators
895 #define ACCEL(path,accel) \
897 Gtk::AccelKey accel_key(accel,path); \
898 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
901 #define ACCEL2(accel) \
903 Gtk::AccelKey accel_key(accel); \
904 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
907 ACCEL("<Actions>//select-all-ducks","<Control>a");
908 ACCEL("<Actions>//unselect-all-layers","<Control>d");
909 ACCEL("<Actions>//render","F9");
910 ACCEL("<Actions>//preview","F11");
911 ACCEL("<Actions>//properties","F8");
912 ACCEL("<Actions>//options","F12");
913 ACCEL("<Actions>//import","<control>i");
914 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
915 ACCEL("<Actions>//toggle-grid-show","<Control>g");
916 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
917 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
918 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
919 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
920 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
921 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
922 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
923 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
925 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
926 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
928 ACCEL("<Actions>//quality-01","<Control>1");
929 ACCEL("<Actions>//quality-02","<Control>2");
930 ACCEL("<Actions>//quality-03","<Control>3");
931 ACCEL("<Actions>//quality-04","<Control>4");
932 ACCEL("<Actions>//quality-05","<Control>5");
933 ACCEL("<Actions>//quality-06","<Control>6");
934 ACCEL("<Actions>//quality-07","<Control>7");
935 ACCEL("<Actions>//quality-08","<Control>8");
936 ACCEL("<Actions>//quality-09","<Control>9");
937 ACCEL("<Actions>//quality-10","<Control>0");
938 ACCEL("<Actions>//undo","<Control>z");
939 ACCEL("<Actions>//redo","<Control>r");
940 ACCEL("<Actions>//action-layer_remove","Delete");
942 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
943 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
944 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
945 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
946 ACCEL("<Actions>//time-zoom-in","+");
947 ACCEL("<Actions>//time-zoom-out","_");
949 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
950 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
952 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
953 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
955 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
956 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
957 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
958 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
959 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
960 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
961 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
962 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
963 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
964 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
965 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
966 ACCEL("<Actions>//play", "<Control>p");
967 ACCEL("<Actions>//seek-begin","Home");
968 ACCEL("<Actions>//seek-end","End");
970 ACCEL("<Actions>//state-normal", "<Mod1>a");
971 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
972 ACCEL("<Actions>//state-scale", "<Mod1>d");
973 ACCEL("<Actions>//state-rotate", "<Mod1>s");
975 ACCEL("<Actions>//state-bline", "<Mod1>b");
976 ACCEL("<Actions>//state-circle", "<Mod1>c");
977 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
978 ACCEL("<Actions>//state-gradient", "<Mod1>g");
980 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
981 ACCEL("<Actions>//state-fill", "<Mod1>f");
982 ACCEL("<Actions>//state-zoom", "<Mod1>z");
983 ACCEL("<Actions>//state-polygon", "<Mod1>p");
985 ACCEL("<Actions>//state-draw", "<Mod1>w");
986 ACCEL("<Actions>//state-sketch", "<Mod1>k");
987 ACCEL("<Actions>//state-width", "<Mod1>t");
988 ACCEL("<Actions>//state-mirror", "<Mod1>m");
990 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
996 #define mkdir(x,y) mkdir(x)
999 /* === M E T H O D S ======================================================= */
1001 App::App(int *argc, char ***argv):
1002 Gtk::Main(argc,argv),
1003 IconController(etl::dirname((*argv)[0]))
1005 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1008 ui_interface_=new GlobalUIInterface();
1012 // don't call thread_init() if threads are already initialized
1013 // on some machines bonobo_init() initialized threads before we get here
1014 if (!g_thread_supported())
1015 Glib::thread_init();
1017 distance_system=Distance::SYSTEM_UNITS;
1019 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1022 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1026 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1032 if(!SYNFIG_CHECK_VERSION())
1034 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1035 dialog_error_blocking("Synfig Studio",
1036 "This copy of Synfig Studio was compiled against a\n"
1037 "different version of libsynfig than what is currently\n"
1038 "installed. Synfig Studio will now abort. Try downloading\n"
1039 "the latest version from the Synfig website at\n"
1040 "http://synfig.org/Download"
1044 Glib::set_application_name(_("Synfig Studio"));
1046 Splash splash_screen;
1047 splash_screen.set_can_self_destruct(false);
1048 splash_screen.show();
1050 shutdown_in_progress=false;
1051 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1052 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1054 // Initialize the Synfig library
1055 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1058 get_ui_interface()->error(_("Failed to initialize synfig!"));
1062 // add the preferences to the settings
1063 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1067 studio_init_cb.task(_("Init UI Manager..."));
1068 App::ui_manager_=studio::UIManager::create();
1071 studio_init_cb.task(_("Init Dock Manager..."));
1072 dock_manager=new studio::DockManager();
1074 studio_init_cb.task(_("Init State Manager..."));
1075 state_manager=new StateManager();
1077 studio_init_cb.task(_("Init Toolbox..."));
1078 toolbox=new studio::Toolbox();
1080 studio_init_cb.task(_("Init About Dialog..."));
1081 about=new studio::About();
1083 studio_init_cb.task(_("Init Tool Options..."));
1084 dialog_tool_options=new studio::Dialog_ToolOptions();
1085 dock_manager->register_dockable(*dialog_tool_options);
1087 studio_init_cb.task(_("Init History..."));
1088 dock_history=new studio::Dock_History();
1089 dock_manager->register_dockable(*dock_history);
1091 studio_init_cb.task(_("Init Canvases..."));
1092 dock_canvases=new studio::Dock_Canvases();
1093 dock_manager->register_dockable(*dock_canvases);
1095 studio_init_cb.task(_("Init Keyframes..."));
1096 dock_keyframes=new studio::Dock_Keyframes();
1097 dock_manager->register_dockable(*dock_keyframes);
1099 studio_init_cb.task(_("Init Layers..."));
1100 dock_layers=new studio::Dock_Layers();
1101 dock_manager->register_dockable(*dock_layers);
1103 studio_init_cb.task(_("Init Params..."));
1104 dock_params=new studio::Dock_Params();
1105 dock_manager->register_dockable(*dock_params);
1107 studio_init_cb.task(_("Init MetaData..."));
1108 dock_meta_data=new studio::Dock_MetaData();
1109 dock_manager->register_dockable(*dock_meta_data);
1111 studio_init_cb.task(_("Init Children..."));
1112 dock_children=new studio::Dock_Children();
1113 dock_manager->register_dockable(*dock_children);
1115 studio_init_cb.task(_("Init Info..."));
1116 dock_info = new studio::Dock_Info();
1117 dock_manager->register_dockable(*dock_info);
1119 studio_init_cb.task(_("Init Navigator..."));
1120 dock_navigator = new studio::Dock_Navigator();
1121 dock_manager->register_dockable(*dock_navigator);
1123 studio_init_cb.task(_("Init Timetrack..."));
1124 dock_timetrack = new studio::Dock_Timetrack();
1125 dock_manager->register_dockable(*dock_timetrack);
1127 studio_init_cb.task(_("Init Curve Editor..."));
1128 dock_curves = new studio::Dock_Curves();
1129 dock_manager->register_dockable(*dock_curves);
1131 studio_init_cb.task(_("Init Layer Groups..."));
1132 dock_layer_groups = new studio::Dock_LayerGroups();
1133 dock_manager->register_dockable(*dock_layer_groups);
1136 studio_init_cb.task(_("Init Color Dialog..."));
1137 dialog_color=new studio::Dialog_Color();
1139 studio_init_cb.task(_("Init Gradient Dialog..."));
1140 dialog_gradient=new studio::Dialog_Gradient();
1142 studio_init_cb.task(_("Init DeviceTracker..."));
1143 device_tracker=new studio::DeviceTracker();
1145 studio_init_cb.task(_("Init Tools..."));
1148 state_manager->add_state(&state_normal);
1149 state_manager->add_state(&state_smooth_move);
1150 state_manager->add_state(&state_scale);
1151 state_manager->add_state(&state_rotate);
1152 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1155 state_manager->add_state(&state_bline);
1156 state_manager->add_state(&state_circle);
1157 state_manager->add_state(&state_rectangle);
1158 state_manager->add_state(&state_gradient);
1159 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1162 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1163 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1164 state_manager->add_state(&state_fill);
1165 state_manager->add_state(&state_eyedrop);
1166 state_manager->add_state(&state_zoom);
1168 // Disabled by default - it doesn't work properly?
1169 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1171 studio_init_cb.task(_("Init ModPalette..."));
1172 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1174 studio_init_cb.task(_("Init Setup Dialog..."));
1175 dialog_setup=new studio::Dialog_Setup();
1177 studio_init_cb.task(_("Init Input Dialog..."));
1178 dialog_input=new Gtk::InputDialog();
1179 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1180 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1182 studio_init_cb.task(_("Init auto recovery..."));
1183 auto_recover=new AutoRecover();
1185 studio_init_cb.amount_complete(9250,10000);
1186 studio_init_cb.task(_("Loading Settings..."));
1188 studio_init_cb.task(_("Checking auto-recover..."));
1190 studio_init_cb.amount_complete(9900,10000);
1192 bool opened_any = false;
1193 if(auto_recover->recovery_needed())
1195 splash_screen.hide();
1196 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1197 _("Synfig Studio seems to have crashed\n"
1198 "before you could save all your files.\n"
1199 "Would you like to re-open those files\n"
1200 "and recover your unsaved changes?")) ==
1201 synfigapp::UIInterface::RESPONSE_YES)
1203 int number_recovered;
1204 if(!auto_recover->recover(number_recovered))
1205 if (number_recovered)
1206 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1208 get_ui_interface()->error(_("Unable to recover from previous crash"));
1210 get_ui_interface()->error(
1211 _("Synfig Studio has attempted to recover\n"
1212 "from a previous crash. The files that it has\n"
1213 "recovered are NOT YET SAVED. It would be a good\n"
1214 "idea to review them and save them now."));
1216 if (number_recovered)
1219 splash_screen.show();
1222 // Look for any files given on the command line,
1223 // and load them if found.
1224 for(;*argc>=1;(*argc)--)
1225 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1227 studio_init_cb.task(_("Loading files..."));
1228 splash_screen.hide();
1229 open((*argv)[*argc]);
1231 splash_screen.show();
1234 // if no file was specified to be opened, create a new document to help new users get started more easily
1235 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1238 studio_init_cb.task(_("Done."));
1239 studio_init_cb.amount_complete(10000,10000);
1245 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1249 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1253 StateManager* App::get_state_manager() { return state_manager; }
1257 shutdown_in_progress=true;
1261 synfigapp::Main::settings().remove_domain("pref");
1263 selected_instance=0;
1265 // Unload all of the modules
1266 for(;!module_list_.empty();module_list_.pop_back())
1269 delete state_manager;
1273 delete auto_recover;
1279 // studio::App::iteration(false);
1283 // studio::App::iteration(false);
1285 // studio::App::iteration(false);
1287 delete dialog_setup;
1289 delete dialog_gradient;
1291 delete dialog_color;
1293 delete dialog_input;
1295 delete dock_manager;
1297 instance_list.clear();
1299 // studio::App::iteration(false);
1303 App::get_user_app_directory()
1305 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1309 App::get_config_file(const synfig::String& file)
1311 return Glib::build_filename(get_user_app_directory(),file);
1315 App::add_recent_file(const std::string &file_name)
1317 std::string filename(file_name);
1319 assert(!filename.empty());
1321 if(filename.empty())
1324 // Toss out any "hidden" files
1325 if(basename(filename)[0]=='.')
1328 // If we aren't an absolute path, turn ourselves into one
1329 if(!is_absolute_path(filename))
1330 filename=absolute_path(filename);
1332 list<string>::iterator iter;
1333 // Check to see if the file is already on the list.
1334 // If it is, then remove it from the list
1335 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1338 recent_files.erase(iter);
1343 // Push the filename to the front of the list
1344 recent_files.push_front(filename);
1346 // Clean out the files at the end of the list.
1347 while(recent_files.size()>(unsigned)get_max_recent_files())
1348 recent_files.pop_back();
1350 signal_recent_files_changed_();
1355 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1358 App::get_time_format()
1360 return _App_time_format;
1364 App::set_time_format(synfig::Time::Format x)
1371 App::save_settings()
1376 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1377 setlocale(LC_NUMERIC, "C");
1379 std::string filename=get_config_file("accelrc");
1380 Gtk::AccelMap::save(filename);
1383 std::string filename=get_config_file("recentfiles");
1385 std::ofstream file(filename.c_str());
1389 synfig::warning("Unable to save %s",filename.c_str());
1393 list<string>::reverse_iterator iter;
1395 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1399 std::string filename=get_config_file("settings");
1400 synfigapp::Main::settings().save_to_file(filename);
1401 setlocale(LC_NUMERIC,old_locale);
1405 synfig::warning("Caught exception when attempting to save settings.");
1410 App::load_settings()
1415 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1416 setlocale(LC_NUMERIC, "C");
1418 std::string filename=get_config_file("accelrc");
1419 Gtk::AccelMap::load(filename);
1422 std::string filename=get_config_file("recentfiles");
1424 std::ifstream file(filename.c_str());
1428 std::string recent_file;
1429 getline(file,recent_file);
1430 if(!recent_file.empty())
1431 add_recent_file(recent_file);
1434 std::string filename=get_config_file("settings");
1435 if(!synfigapp::Main::settings().load_from_file(filename))
1437 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1438 //if(!synfigapp::Main::settings().load_from_file(filename))
1440 gamma.set_gamma(1.0/2.2);
1441 reset_initial_window_configuration();
1444 setlocale(LC_NUMERIC,old_locale);
1448 synfig::warning("Caught exception when attempting to load settings.");
1453 App::reset_initial_window_configuration()
1455 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1456 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1457 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1458 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1459 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1460 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1461 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1462 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1463 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1464 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1465 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1466 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1467 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1468 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1469 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1473 App::shutdown_request(GdkEventAny*)
1477 //return !shutdown_in_progress;
1483 if(shutdown_in_progress)return;
1486 get_ui_interface()->task(_("Quit Request"));
1489 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1493 std::list<etl::handle<Instance> >::iterator iter;
1494 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1496 if(!(*iter)->safe_close())
1500 if((*iter)->synfigapp::Instance::get_action_count())
1502 handle<synfigapp::UIInterface> uim;
1503 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1505 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1506 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1508 case synfigapp::UIInterface::RESPONSE_NO:
1510 case synfigapp::UIInterface::RESPONSE_YES:
1513 case synfigapp::UIInterface::RESPONSE_CANCEL:
1522 if((*iter)->synfigapp::Instance::is_modified())
1524 handle<synfigapp::UIInterface> uim;
1525 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1527 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() );
1528 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1530 case synfigapp::UIInterface::RESPONSE_NO:
1532 case synfigapp::UIInterface::RESPONSE_YES:
1533 (*iter)->dialog_cvs_commit();
1535 case synfigapp::UIInterface::RESPONSE_CANCEL:
1544 // This next line causes things to crash for some reason
1548 shutdown_in_progress=true;
1550 instance_list.clear();
1552 while(studio::App::events_pending())studio::App::iteration(false);
1555 auto_recover->normal_shutdown();
1557 get_ui_interface()->task(_("Quit Request sent"));
1563 dialog_setup->refresh();
1564 dialog_setup->show();
1567 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1568 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1571 //#define USE_WIN32_FILE_DIALOGS 1
1574 #ifdef USE_WIN32_FILE_DIALOGS
1575 static OPENFILENAME ofn={};
1579 #include <gdk/gdkwin32.h>
1583 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1585 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1587 #ifdef USE_WIN32_FILE_DIALOGS
1588 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1590 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1591 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1592 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1594 ofn.lStructSize=sizeof(OPENFILENAME);
1595 ofn.hwndOwner = hWnd;
1596 ofn.hInstance = hInstance;
1597 ofn.lpstrFilter = szFilter;
1598 // ofn.lpstrCustomFilter=NULL;
1599 // ofn.nMaxCustFilter=0;
1600 // ofn.nFilterIndex=0;
1601 // ofn.lpstrFile=NULL;
1602 ofn.nMaxFile=MAX_PATH;
1603 // ofn.lpstrFileTitle=NULL;
1604 // ofn.lpstrInitialDir=NULL;
1605 // ofn.lpstrTitle=NULL;
1606 ofn.Flags=OFN_HIDEREADONLY;
1607 // ofn.nFileOffset=0;
1608 // ofn.nFileExtension=0;
1609 ofn.lpstrDefExt=TEXT("sif");
1610 // ofn.lCustData = 0l;
1612 // ofn.lpTemplateName=NULL;
1614 CHAR szFilename[MAX_PATH];
1616 strcpy(szFilename,filename.c_str());
1617 strcpy(szTitle,title.c_str());
1619 ofn.lpstrFile=szFilename;
1620 ofn.lpstrFileTitle=szTitle;
1622 if(GetOpenFileName(&ofn))
1624 filename=szFilename;
1630 synfig::String prev_path;
1632 if(!_preferences.get_value(preference, prev_path))
1635 prev_path = absolute_path(prev_path);
1637 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1639 dialog->set_current_folder(prev_path);
1640 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1641 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1643 if (filename.empty())
1644 dialog->set_filename(prev_path);
1645 else if (is_absolute_path(filename))
1646 dialog->set_filename(filename);
1648 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1650 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1651 filename = dialog->get_filename();
1652 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1653 _preferences.set_value(preference, dirname(filename));
1667 GtkWidget *fileselection;
1668 fileselection = gtk_file_selection_new(title.c_str());
1671 if(basename(filename)==filename)
1673 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1676 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1678 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1680 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1681 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1683 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1684 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1686 gtk_widget_show(fileselection);
1694 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1695 _preferences.set_value(preference,dirname(filename));
1699 gtk_widget_destroy(fileselection);
1702 gtk_widget_destroy(fileselection);
1709 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1711 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1713 #if USE_WIN32_FILE_DIALOGS
1714 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1716 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1717 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1718 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1720 ofn.lStructSize=sizeof(OPENFILENAME);
1721 ofn.hwndOwner = hWnd;
1722 ofn.hInstance = hInstance;
1723 ofn.lpstrFilter = szFilter;
1724 // ofn.lpstrCustomFilter=NULL;
1725 // ofn.nMaxCustFilter=0;
1726 // ofn.nFilterIndex=0;
1727 // ofn.lpstrFile=NULL;
1728 ofn.nMaxFile=MAX_PATH;
1729 // ofn.lpstrFileTitle=NULL;
1730 // ofn.lpstrInitialDir=NULL;
1731 // ofn.lpstrTitle=NULL;
1732 ofn.Flags=OFN_OVERWRITEPROMPT;
1733 // ofn.nFileOffset=0;
1734 // ofn.nFileExtension=0;
1735 ofn.lpstrDefExt=TEXT("sif");
1736 // ofn.lCustData = 0l;
1738 // ofn.lpTemplateName=NULL;
1740 CHAR szFilename[MAX_PATH];
1742 strcpy(szFilename,filename.c_str());
1743 strcpy(szTitle,title.c_str());
1745 ofn.lpstrFile=szFilename;
1746 ofn.lpstrFileTitle=szTitle;
1748 if(GetSaveFileName(&ofn))
1750 filename=szFilename;
1751 _preferences.set_value(preference,dirname(filename));
1756 synfig::String prev_path;
1758 if(!_preferences.get_value(preference, prev_path))
1761 prev_path = absolute_path(prev_path);
1763 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1765 dialog->set_current_folder(prev_path);
1766 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1767 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1769 Widget_Enum *file_type_enum = 0;
1770 if (preference == ANIMATION_DIR_PREFERENCE)
1772 file_type_enum = manage(new Widget_Enum());
1773 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1774 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", strprintf("0.61.08 (%s)", _("current")))
1775 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1776 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1777 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1779 Gtk::HBox *hbox = manage(new Gtk::HBox);
1780 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1781 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1784 dialog->set_extra_widget(*hbox);
1787 if (filename.empty())
1788 dialog->set_filename(prev_path);
1791 std::string full_path;
1792 if (is_absolute_path(filename))
1793 full_path = filename;
1795 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1797 // select the file if it exists
1798 dialog->set_filename(full_path);
1800 // if the file doesn't exist, put its name into the filename box
1802 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1803 dialog->set_current_name(basename(filename));
1806 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1807 if (preference == ANIMATION_DIR_PREFERENCE)
1808 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
1809 filename = dialog->get_filename();
1810 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1811 _preferences.set_value(preference, dirname(filename));
1822 App::dialog_error_blocking(const std::string &title, const std::string &message)
1824 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1825 dialog.set_title(title);
1831 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1833 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1834 dialog.set_title(title);
1840 App::dialog_yes_no(const std::string &title, const std::string &message)
1845 true // use_separator
1847 Gtk::Label label(message);
1850 dialog.get_vbox()->pack_start(label);
1851 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1852 dialog.add_button(Gtk::StockID("gtk-no"),0);
1854 return dialog.run();
1858 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1863 true // use_separator
1865 Gtk::Label label(message);
1868 dialog.get_vbox()->pack_start(label);
1869 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1870 dialog.add_button(Gtk::StockID("gtk-no"),0);
1871 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1873 return dialog.run();
1877 App::dialog_not_implemented()
1879 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1880 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1885 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1890 true // use_separator
1892 Gtk::Label label(message);
1894 dialog.get_vbox()->pack_start(label);
1897 entry.set_text(text);
1899 entry.set_activates_default(true);
1900 dialog.get_vbox()->pack_start(entry);
1902 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1903 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1904 dialog.set_default_response(Gtk::RESPONSE_OK);
1905 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1908 if(dialog.run()!=Gtk::RESPONSE_OK)
1911 text=entry.get_text();
1920 App::open(std::string filename)
1922 return open_as(filename,filename);
1925 // this is called from autorecover.cpp:
1926 // App::open_as(get_shadow_file_name(filename),filename)
1927 // other than that, 'filename' and 'as' are the same
1929 App::open_as(std::string filename,std::string as)
1932 char long_name[1024];
1933 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1939 OneMoment one_moment;
1941 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1942 if(canvas && get_instance(canvas))
1944 get_instance(canvas)->find_canvas_view(canvas)->present();
1945 info("%s is already open", filename.c_str());
1946 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1951 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1953 add_recent_file(as);
1955 handle<Instance> instance(Instance::create(canvas));
1958 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1962 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)")))
1963 instance->dialog_cvs_update();
1968 dialog_error_blocking(_("Error"), x);
1973 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1984 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1985 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1987 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1989 canvas->rend_desc().set_frame_rate(24.0);
1990 canvas->rend_desc().set_time_start(0.0);
1991 canvas->rend_desc().set_time_end(5.0);
1992 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1993 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1994 canvas->rend_desc().set_tl(Vector(-4,2.25));
1995 canvas->rend_desc().set_br(Vector(4,-2.25));
1996 canvas->rend_desc().set_w(480);
1997 canvas->rend_desc().set_h(270);
1998 canvas->rend_desc().set_antialias(1);
1999 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2000 canvas->set_file_name(file_name);
2002 handle<Instance> instance = Instance::create(canvas);
2004 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2005 instance->find_canvas_view(canvas)->canvas_properties.present();
2011 string filename="*.sif";
2013 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2015 // If the filename still has wildcards, then we should
2016 // continue looking for the file we want
2017 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2023 get_ui_interface()->error(_("Unable to open file"));
2028 App::set_selected_instance(etl::loose_handle<Instance> instance)
2030 /* if(get_selected_instance()==instance)
2032 selected_instance=instance;
2033 signal_instance_selected()(instance);
2039 selected_instance=instance;
2040 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2044 instance->focus(instance->get_canvas());
2047 set_selected_canvas_view(0);
2049 signal_instance_selected()(instance);
2053 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2055 selected_canvas_view=canvas_view;
2056 signal_canvas_view_focus()(selected_canvas_view);
2059 selected_instance=canvas_view->get_instance();
2060 signal_instance_selected()(canvas_view->get_instance());
2063 if(get_selected_canvas_view()==canvas_view)
2065 signal_canvas_view_focus()(selected_canvas_view);
2066 signal_instance_selected()(canvas_view->get_instance());
2069 selected_canvas_view=canvas_view;
2070 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2071 set_selected_instance(canvas_view->get_instance());
2072 signal_canvas_view_focus()(selected_canvas_view);
2076 etl::loose_handle<Instance>
2077 App::get_instance(etl::handle<synfig::Canvas> canvas)
2079 if(!canvas) return 0;
2080 canvas=canvas->get_root();
2082 std::list<etl::handle<Instance> >::iterator iter;
2083 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2085 if((*iter)->get_canvas()==canvas)
2101 if(selected_instance)
2102 selected_instance->undo();
2108 if(selected_instance)
2109 selected_instance->redo();
2113 studio::App::get_base_path()
2115 return app_base_path_;