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 #ifdef SINGLE_THREADED
265 bool studio::App::single_threaded=false;
267 bool studio::App::restrict_radius_ducks=false;
268 String studio::App::browser_command("firefox");
270 static int max_recent_files_=25;
271 int studio::App::get_max_recent_files() { return max_recent_files_; }
272 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
274 static synfig::String app_base_path_;
279 really_delete_widget(Gtk::Widget *widget)
281 // synfig::info("really delete %p", (void*)widget);
286 // nasty workaround - when we've finished with a popup menu, we want to delete it
287 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
288 // so schedule the real delete to happen in 50ms, giving the action a chance to run
290 delete_widget(Gtk::Widget *widget)
292 // synfig::info("delete %p", (void*)widget);
293 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
296 }; // END of namespace studio
297 studio::StateManager* state_manager;
302 class GlobalUIInterface : public synfigapp::UIInterface
306 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
311 true // use_separator
313 Gtk::Label label(message);
316 dialog.get_vbox()->pack_start(label);
317 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
318 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
320 dialog.set_default_response(dflt);
322 return (Response)dialog.run();
324 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
329 true // use_separator
331 Gtk::Label label(message);
334 dialog.get_vbox()->pack_start(label);
335 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
336 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
337 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
339 dialog.set_default_response(dflt);
341 return (Response)dialog.run();
343 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
348 true // use_separator
350 Gtk::Label label(message);
353 dialog.get_vbox()->pack_start(label);
354 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
355 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
357 dialog.set_default_response(dflt);
359 return (Response)dialog.run();
363 task(const std::string &task)
365 std::cerr<<task<<std::endl;
366 while(studio::App::events_pending())studio::App::iteration(false);
371 error(const std::string &err)
373 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
380 warning(const std::string &err)
382 std::cerr<<"warning: "<<err<<std::endl;
383 while(studio::App::events_pending())studio::App::iteration(false);
388 amount_complete(int /*current*/, int /*total*/)
390 while(studio::App::events_pending())studio::App::iteration(false);
395 /* === P R O C E D U R E S ================================================= */
399 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
401 action_group_list.push_back(action_group);
402 Gtk::UIManager::insert_action_group(action_group, pos);
406 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
408 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
409 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
410 if(*iter==action_group)
412 action_group_list.erase(iter);
413 Gtk::UIManager::remove_action_group(action_group);
416 synfig::error("Unable to find action group");
420 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
422 ui_manager->insert_action_group(group,0);
424 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
425 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
427 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
429 if(*iter && (*iter)->get_name()!="menus")
431 synfig::info("Removing action group "+(*iter)->get_name());
432 ui_manager->remove_action_group(*iter);
435 ui_manager->insert_action_group(group,0);
437 for(;!prev_groups.empty();prev_groups.pop_front())
439 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
440 ui_manager->insert_action_group(prev_groups.front(),1);
444 class Preferences : public synfigapp::Settings
447 virtual bool get_value(const synfig::String& key, synfig::String& value)const
451 value=strprintf("%f %f %f %f",
452 App::gamma.get_gamma_r(),
453 App::gamma.get_gamma_g(),
454 App::gamma.get_gamma_b(),
455 App::gamma.get_black_level()
459 if(key=="time_format")
461 value=strprintf("%i",App::get_time_format());
464 if(key=="file_history.size")
466 value=strprintf("%i",App::get_max_recent_files());
469 if(key=="use_colorspace_gamma")
471 value=strprintf("%i",(int)App::use_colorspace_gamma);
474 if(key=="distance_system")
476 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
479 #ifdef SINGLE_THREADED
480 if(key=="single_threaded")
482 value=strprintf("%i",(int)App::single_threaded);
486 if(key=="auto_recover_backup_interval")
488 value=strprintf("%i",App::auto_recover->get_timeout());
491 if(key=="restrict_radius_ducks")
493 value=strprintf("%i",(int)App::restrict_radius_ducks);
496 if(key=="browser_command")
498 value=App::browser_command;
502 return synfigapp::Settings::get_value(key,value);
505 virtual bool set_value(const synfig::String& key,const synfig::String& value)
511 strscanf(value,"%f %f %f %f",
518 App::gamma.set_all(r,g,b,blk);
522 if(key=="time_format")
524 int i(atoi(value.c_str()));
525 App::set_time_format(static_cast<synfig::Time::Format>(i));
528 if(key=="auto_recover_backup_interval")
530 int i(atoi(value.c_str()));
531 App::auto_recover->set_timeout(i);
534 if(key=="file_history.size")
536 int i(atoi(value.c_str()));
537 App::set_max_recent_files(i);
540 if(key=="use_colorspace_gamma")
542 int i(atoi(value.c_str()));
543 App::use_colorspace_gamma=i;
546 if(key=="distance_system")
548 App::distance_system=Distance::ident_system(value);;
551 #ifdef SINGLE_THREADED
552 if(key=="single_threaded")
554 int i(atoi(value.c_str()));
555 App::single_threaded=i;
559 if(key=="restrict_radius_ducks")
561 int i(atoi(value.c_str()));
562 App::restrict_radius_ducks=i;
565 if(key=="browser_command")
567 App::browser_command=value;
571 return synfigapp::Settings::set_value(key,value);
574 virtual KeyList get_key_list()const
576 KeyList ret(synfigapp::Settings::get_key_list());
577 ret.push_back("gamma");
578 ret.push_back("time_format");
579 ret.push_back("distance_system");
580 ret.push_back("file_history.size");
581 ret.push_back("use_colorspace_gamma");
582 #ifdef SINGLE_THREADED
583 ret.push_back("single_threaded");
585 ret.push_back("auto_recover_backup_interval");
586 ret.push_back("restrict_radius_ducks");
587 ret.push_back("browser_command");
592 static ::Preferences _preferences;
597 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
599 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
601 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
603 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
604 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
605 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
606 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
607 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
608 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
609 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
610 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
611 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
612 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
613 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
614 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
615 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
617 // Add the synfigapp actions...
618 synfigapp::Action::Book::iterator iter;
619 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
621 actions_action_group->add(Gtk::Action::create(
622 "action-"+iter->second.name,
623 get_action_stock_id(iter->second),
624 iter->second.local_name,iter->second.local_name
628 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
629 #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); }
630 #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); }
632 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
633 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
634 DEFINE_ACTION("new", Gtk::Stock::NEW);
635 DEFINE_ACTION("open", Gtk::Stock::OPEN);
636 DEFINE_ACTION("save", Gtk::Stock::SAVE);
637 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
638 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
639 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
640 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
641 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
642 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
643 DEFINE_ACTION("import", _("Import"));
644 DEFINE_ACTION("render", _("Render"));
645 DEFINE_ACTION("preview", _("Preview"));
646 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
647 DEFINE_ACTION("sound", _("Sound File"));
648 DEFINE_ACTION("options", _("Options"));
649 DEFINE_ACTION("close", _("Close View"));
650 DEFINE_ACTION("close-document", _("Close Document"));
651 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
654 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
655 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
656 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
657 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
658 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
659 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
660 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
661 DEFINE_ACTION("properties", _("Properties"));
663 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
664 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
665 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
666 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
667 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
668 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
669 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
670 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
671 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
672 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
673 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
674 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
675 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
676 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
677 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
678 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
679 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
680 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
681 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
682 DEFINE_ACTION("play", _("Play"));
683 // DEFINE_ACTION("pause", _("Pause"));
684 DEFINE_ACTION("stop", _("Stop"));
685 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
686 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
687 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
688 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
689 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
690 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
691 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
692 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
693 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
694 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
695 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
696 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
697 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
698 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
699 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
700 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
701 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
702 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
703 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
704 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
705 DEFINE_ACTION("seek-end", _("Seek to End"));
707 DEFINE_ACTION("action-group_add", _("Add group"));
709 DEFINE_ACTION("canvas-new", _("New Canvas"));
711 DEFINE_ACTION("amount-inc", _("Increase Amount"));
712 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
717 // Set up synfigapp actions
719 synfigapp::Action::Book::iterator iter;
721 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
723 Gtk::StockID stock_id;
725 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
727 //Gtk::Image* image(manage(new Gtk::Image()));
728 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
729 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
730 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
731 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
732 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
733 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
734 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
735 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
736 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
737 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
739 actions_action_group->add(Gtk::Action::create(
740 "action-"+iter->second.name,
742 iter->second.local_name,iter->second.local_name
750 Glib::ustring ui_info =
752 " <popup name='menu-toolbox' action='menu-toolbox'>"
753 " <menu action='menu-file'>"
756 " <popup name='menu-main' action='menu-main'>"
757 " <menu action='menu-file'>"
758 " <menuitem action='new' />"
759 " <menuitem action='open' />"
760 " <menuitem action='save' />"
761 " <menuitem action='save-as' />"
762 " <menuitem action='revert' />"
763 " <separator name='bleh01'/>"
764 " <menuitem action='cvs-add' />"
765 " <menuitem action='cvs-update' />"
766 " <menuitem action='cvs-commit' />"
767 " <menuitem action='cvs-revert' />"
768 " <separator name='bleh02'/>"
769 " <menuitem action='import' />"
770 " <separator name='bleh03'/>"
771 " <menuitem action='render' />"
772 " <menuitem action='preview' />"
773 " <menuitem action='sound' />"
774 " <separator name='bleh04'/>"
775 " <menuitem action='options' />"
776 " <menuitem action='close' />"
777 " <menuitem action='close-document' />"
778 " <menuitem action='quit' />"
780 " <menu action='menu-edit'>"
781 " <menuitem action='undo'/>"
782 " <menuitem action='redo'/>"
783 " <separator name='bleh05'/>"
784 " <menuitem action='cut'/>"
785 " <menuitem action='copy'/>"
786 " <menuitem action='paste'/>"
787 " <separator name='bleh06'/>"
788 " <menuitem action='select-all-ducks'/>"
789 " <menuitem action='unselect-all-layers'/>"
790 " <separator name='bleh07'/>"
791 " <menuitem action='properties'/>"
793 " <menu action='menu-view'>"
794 " <menu action='menu-duck-mask'>"
795 " <menuitem action='mask-position-ducks' />"
796 " <menuitem action='mask-vertex-ducks' />"
797 " <menuitem action='mask-tangent-ducks' />"
798 " <menuitem action='mask-radius-ducks' />"
799 " <menuitem action='mask-width-ducks' />"
800 " <menuitem action='mask-angle-ducks' />"
802 " <menu action='menu-preview-quality'>"
803 " <menuitem action='quality-00' />"
804 " <menuitem action='quality-01' />"
805 " <menuitem action='quality-02' />"
806 " <menuitem action='quality-03' />"
807 " <menuitem action='quality-04' />"
808 " <menuitem action='quality-05' />"
809 " <menuitem action='quality-06' />"
810 " <menuitem action='quality-07' />"
811 " <menuitem action='quality-08' />"
812 " <menuitem action='quality-09' />"
813 " <menuitem action='quality-10' />"
815 " <menu action='menu-lowres-pixel'>"
816 " <menuitem action='decrease-low-res-pixel-size'/>"
817 " <menuitem action='increase-low-res-pixel-size'/>"
818 " <separator name='pixel-size-separator'/>"
821 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
822 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
826 " <separator name='bleh08'/>"
827 " <menuitem action='play'/>"
828 //" <menuitem action='pause'/>"
829 " <menuitem action='stop'/>"
830 " <menuitem action='dialog-flipbook'/>"
831 " <separator name='bleh09'/>"
832 " <menuitem action='toggle-grid-show'/>"
833 " <menuitem action='toggle-grid-snap'/>"
834 " <menuitem action='toggle-guide-show'/>"
835 " <menuitem action='toggle-low-res'/>"
836 " <menuitem action='toggle-onion-skin'/>"
837 " <separator name='bleh10'/>"
838 " <menuitem action='canvas-zoom-in'/>"
839 " <menuitem action='canvas-zoom-out'/>"
840 " <menuitem action='canvas-zoom-fit'/>"
841 " <menuitem action='canvas-zoom-100'/>"
842 " <separator name='bleh11'/>"
843 " <menuitem action='time-zoom-in'/>"
844 " <menuitem action='time-zoom-out'/>"
845 " <separator name='bleh12'/>"
846 " <menuitem action='jump-next-keyframe'/>"
847 " <menuitem action='jump-prev-keyframe'/>"
848 " <menuitem action='seek-next-frame'/>"
849 " <menuitem action='seek-prev-frame'/>"
850 " <menuitem action='seek-next-second'/>"
851 " <menuitem action='seek-prev-second'/>"
852 " <menuitem action='seek-begin'/>"
853 " <menuitem action='seek-end'/>"
855 " <menu action='menu-canvas'>"
856 " <menuitem action='canvas-new'/>"
858 " <menu name='menu-state' action='menu-state'>"
860 " <menu action='menu-group'>"
861 " <menuitem action='action-group_add'/>"
863 " <menu action='menu-layer'>"
864 //" <menuitem action='cut'/>"
865 //" <menuitem action='copy'/>"
866 //" <menuitem action='paste'/>"
867 //" <separator name='bleh06'/>"
868 " <menu action='menu-layer-new'></menu>"
869 " <menuitem action='amount-inc'/>"
870 " <menuitem action='amount-dec'/>"
872 " <menu action='menu-keyframe'>"
873 " <menuitem action='keyframe-properties'/>"
880 " <menubar name='MenuBar'>"
881 " <menu action='MenuFile'>"
882 " <menuitem action='New'/>"
883 " <menuitem action='Open'/>"
885 " <menuitem action='Quit'/>"
887 " <menu action='MenuEdit'>"
888 " <menuitem action='Cut'/>"
889 " <menuitem action='Copy'/>"
890 " <menuitem action='Paste'/>"
893 " <toolbar name='ToolBar'>"
894 " <toolitem action='Open'/>"
895 " <toolitem action='Quit'/>"
901 actions_action_group->set_sensitive(false);
902 App::ui_manager()->set_add_tearoffs(true);
903 App::ui_manager()->insert_action_group(menus_action_group,1);
904 App::ui_manager()->insert_action_group(actions_action_group,1);
905 App::ui_manager()->add_ui_from_string(ui_info);
907 //App::ui_manager()->get_accel_group()->unlock();
909 catch(const Glib::Error& ex)
911 synfig::error("building menus and toolbars failed: " + ex.what());
914 // Add default keyboard accelerators
915 #define ACCEL(path,accel) \
917 Gtk::AccelKey accel_key(accel,path); \
918 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
921 #define ACCEL2(accel) \
923 Gtk::AccelKey accel_key(accel); \
924 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
927 ACCEL("<Actions>//select-all-ducks","<Control>a");
928 ACCEL("<Actions>//unselect-all-layers","<Control>d");
929 ACCEL("<Actions>//render","F9");
930 ACCEL("<Actions>//preview","F11");
931 ACCEL("<Actions>//properties","F8");
932 ACCEL("<Actions>//options","F12");
933 ACCEL("<Actions>//import","<control>i");
934 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
935 ACCEL("<Actions>//toggle-grid-show","<Control>g");
936 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
937 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
938 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
939 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
940 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
941 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
942 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
943 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
945 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
946 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
948 ACCEL("<Actions>//quality-01","<Control>1");
949 ACCEL("<Actions>//quality-02","<Control>2");
950 ACCEL("<Actions>//quality-03","<Control>3");
951 ACCEL("<Actions>//quality-04","<Control>4");
952 ACCEL("<Actions>//quality-05","<Control>5");
953 ACCEL("<Actions>//quality-06","<Control>6");
954 ACCEL("<Actions>//quality-07","<Control>7");
955 ACCEL("<Actions>//quality-08","<Control>8");
956 ACCEL("<Actions>//quality-09","<Control>9");
957 ACCEL("<Actions>//quality-10","<Control>0");
958 ACCEL("<Actions>//undo","<Control>z");
959 ACCEL("<Actions>//redo","<Control>r");
960 ACCEL("<Actions>//action-layer_remove","Delete");
962 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
963 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
964 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
965 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
966 ACCEL("<Actions>//time-zoom-in","+");
967 ACCEL("<Actions>//time-zoom-out","_");
969 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
970 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
972 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
973 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
975 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
976 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
977 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
978 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
979 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
980 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
981 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
982 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
983 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
984 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
985 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
986 ACCEL("<Actions>//play", "<Control>p");
987 ACCEL("<Actions>//seek-begin","Home");
988 ACCEL("<Actions>//seek-end","End");
990 ACCEL("<Actions>//state-normal", "<Mod1>a");
991 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
992 ACCEL("<Actions>//state-scale", "<Mod1>d");
993 ACCEL("<Actions>//state-rotate", "<Mod1>s");
995 ACCEL("<Actions>//state-bline", "<Mod1>b");
996 ACCEL("<Actions>//state-circle", "<Mod1>c");
997 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
998 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1000 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1001 ACCEL("<Actions>//state-fill", "<Mod1>f");
1002 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1003 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1005 ACCEL("<Actions>//state-draw", "<Mod1>w");
1006 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1007 ACCEL("<Actions>//state-width", "<Mod1>t");
1008 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1010 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1016 #define mkdir(x,y) mkdir(x)
1019 /* === M E T H O D S ======================================================= */
1021 App::App(int *argc, char ***argv):
1022 Gtk::Main(argc,argv),
1023 IconController(etl::dirname((*argv)[0]))
1025 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1028 ui_interface_=new GlobalUIInterface();
1032 // don't call thread_init() if threads are already initialized
1033 // on some machines bonobo_init() initialized threads before we get here
1034 if (!g_thread_supported())
1035 Glib::thread_init();
1037 distance_system=Distance::SYSTEM_UNITS;
1039 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1042 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1046 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1052 if(!SYNFIG_CHECK_VERSION())
1054 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1055 dialog_error_blocking("Synfig Studio",
1056 "This copy of Synfig Studio was compiled against a\n"
1057 "different version of libsynfig than what is currently\n"
1058 "installed. Synfig Studio will now abort. Try downloading\n"
1059 "the latest version from the Synfig website at\n"
1060 "http://synfig.org/Download"
1064 Glib::set_application_name(_("Synfig Studio"));
1066 Splash splash_screen;
1067 splash_screen.set_can_self_destruct(false);
1068 splash_screen.show();
1070 shutdown_in_progress=false;
1071 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1072 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1074 // Initialize the Synfig library
1075 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1078 get_ui_interface()->error(_("Failed to initialize synfig!"));
1082 // add the preferences to the settings
1083 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1087 studio_init_cb.task(_("Init UI Manager..."));
1088 App::ui_manager_=studio::UIManager::create();
1091 studio_init_cb.task(_("Init Dock Manager..."));
1092 dock_manager=new studio::DockManager();
1094 studio_init_cb.task(_("Init State Manager..."));
1095 state_manager=new StateManager();
1097 studio_init_cb.task(_("Init Toolbox..."));
1098 toolbox=new studio::Toolbox();
1100 studio_init_cb.task(_("Init About Dialog..."));
1101 about=new studio::About();
1103 studio_init_cb.task(_("Init Tool Options..."));
1104 dialog_tool_options=new studio::Dialog_ToolOptions();
1105 dock_manager->register_dockable(*dialog_tool_options);
1107 studio_init_cb.task(_("Init History..."));
1108 dock_history=new studio::Dock_History();
1109 dock_manager->register_dockable(*dock_history);
1111 studio_init_cb.task(_("Init Canvases..."));
1112 dock_canvases=new studio::Dock_Canvases();
1113 dock_manager->register_dockable(*dock_canvases);
1115 studio_init_cb.task(_("Init Keyframes..."));
1116 dock_keyframes=new studio::Dock_Keyframes();
1117 dock_manager->register_dockable(*dock_keyframes);
1119 studio_init_cb.task(_("Init Layers..."));
1120 dock_layers=new studio::Dock_Layers();
1121 dock_manager->register_dockable(*dock_layers);
1123 studio_init_cb.task(_("Init Params..."));
1124 dock_params=new studio::Dock_Params();
1125 dock_manager->register_dockable(*dock_params);
1127 studio_init_cb.task(_("Init MetaData..."));
1128 dock_meta_data=new studio::Dock_MetaData();
1129 dock_manager->register_dockable(*dock_meta_data);
1131 studio_init_cb.task(_("Init Children..."));
1132 dock_children=new studio::Dock_Children();
1133 dock_manager->register_dockable(*dock_children);
1135 studio_init_cb.task(_("Init Info..."));
1136 dock_info = new studio::Dock_Info();
1137 dock_manager->register_dockable(*dock_info);
1139 studio_init_cb.task(_("Init Navigator..."));
1140 dock_navigator = new studio::Dock_Navigator();
1141 dock_manager->register_dockable(*dock_navigator);
1143 studio_init_cb.task(_("Init Timetrack..."));
1144 dock_timetrack = new studio::Dock_Timetrack();
1145 dock_manager->register_dockable(*dock_timetrack);
1147 studio_init_cb.task(_("Init Curve Editor..."));
1148 dock_curves = new studio::Dock_Curves();
1149 dock_manager->register_dockable(*dock_curves);
1151 studio_init_cb.task(_("Init Layer Groups..."));
1152 dock_layer_groups = new studio::Dock_LayerGroups();
1153 dock_manager->register_dockable(*dock_layer_groups);
1156 studio_init_cb.task(_("Init Color Dialog..."));
1157 dialog_color=new studio::Dialog_Color();
1159 studio_init_cb.task(_("Init Gradient Dialog..."));
1160 dialog_gradient=new studio::Dialog_Gradient();
1162 studio_init_cb.task(_("Init DeviceTracker..."));
1163 device_tracker=new studio::DeviceTracker();
1165 studio_init_cb.task(_("Init Tools..."));
1168 state_manager->add_state(&state_normal);
1169 state_manager->add_state(&state_smooth_move);
1170 state_manager->add_state(&state_scale);
1171 state_manager->add_state(&state_rotate);
1172 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1175 state_manager->add_state(&state_bline);
1176 state_manager->add_state(&state_circle);
1177 state_manager->add_state(&state_rectangle);
1178 state_manager->add_state(&state_gradient);
1179 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1182 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1183 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1184 state_manager->add_state(&state_fill);
1185 state_manager->add_state(&state_eyedrop);
1186 state_manager->add_state(&state_zoom);
1188 // Disabled by default - it doesn't work properly?
1189 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1191 studio_init_cb.task(_("Init ModPalette..."));
1192 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1194 studio_init_cb.task(_("Init Setup Dialog..."));
1195 dialog_setup=new studio::Dialog_Setup();
1197 studio_init_cb.task(_("Init Input Dialog..."));
1198 dialog_input=new Gtk::InputDialog();
1199 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1200 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1202 studio_init_cb.task(_("Init auto recovery..."));
1203 auto_recover=new AutoRecover();
1205 studio_init_cb.amount_complete(9250,10000);
1206 studio_init_cb.task(_("Loading Settings..."));
1208 studio_init_cb.task(_("Checking auto-recover..."));
1210 studio_init_cb.amount_complete(9900,10000);
1212 bool opened_any = false;
1213 if(auto_recover->recovery_needed())
1215 splash_screen.hide();
1216 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1217 _("Synfig Studio seems to have crashed\n"
1218 "before you could save all your files.\n"
1219 "Would you like to re-open those files\n"
1220 "and recover your unsaved changes?")) ==
1221 synfigapp::UIInterface::RESPONSE_YES)
1223 int number_recovered;
1224 if(!auto_recover->recover(number_recovered))
1225 if (number_recovered)
1226 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1228 get_ui_interface()->error(_("Unable to recover from previous crash"));
1230 get_ui_interface()->error(
1231 _("Synfig Studio has attempted to recover\n"
1232 "from a previous crash. The files that it has\n"
1233 "recovered are NOT YET SAVED. It would be a good\n"
1234 "idea to review them and save them now."));
1236 if (number_recovered)
1239 splash_screen.show();
1242 // Look for any files given on the command line,
1243 // and load them if found.
1244 for(;*argc>=1;(*argc)--)
1245 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1247 studio_init_cb.task(_("Loading files..."));
1248 splash_screen.hide();
1249 open((*argv)[*argc]);
1251 splash_screen.show();
1254 // if no file was specified to be opened, create a new document to help new users get started more easily
1255 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1258 studio_init_cb.task(_("Done."));
1259 studio_init_cb.amount_complete(10000,10000);
1265 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1269 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1273 StateManager* App::get_state_manager() { return state_manager; }
1277 shutdown_in_progress=true;
1281 synfigapp::Main::settings().remove_domain("pref");
1283 selected_instance=0;
1285 // Unload all of the modules
1286 for(;!module_list_.empty();module_list_.pop_back())
1289 delete state_manager;
1293 delete auto_recover;
1299 // studio::App::iteration(false);
1303 // studio::App::iteration(false);
1305 // studio::App::iteration(false);
1307 delete dialog_setup;
1309 delete dialog_gradient;
1311 delete dialog_color;
1313 delete dialog_input;
1315 delete dock_manager;
1317 instance_list.clear();
1319 // studio::App::iteration(false);
1323 App::get_user_app_directory()
1325 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1329 App::get_config_file(const synfig::String& file)
1331 return Glib::build_filename(get_user_app_directory(),file);
1335 App::add_recent_file(const std::string &file_name)
1337 std::string filename(file_name);
1339 assert(!filename.empty());
1341 if(filename.empty())
1344 // Toss out any "hidden" files
1345 if(basename(filename)[0]=='.')
1348 // If we aren't an absolute path, turn ourselves into one
1349 if(!is_absolute_path(filename))
1350 filename=absolute_path(filename);
1352 list<string>::iterator iter;
1353 // Check to see if the file is already on the list.
1354 // If it is, then remove it from the list
1355 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1358 recent_files.erase(iter);
1363 // Push the filename to the front of the list
1364 recent_files.push_front(filename);
1366 // Clean out the files at the end of the list.
1367 while(recent_files.size()>(unsigned)get_max_recent_files())
1368 recent_files.pop_back();
1370 signal_recent_files_changed_();
1375 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1378 App::get_time_format()
1380 return _App_time_format;
1384 App::set_time_format(synfig::Time::Format x)
1391 App::save_settings()
1396 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1397 setlocale(LC_NUMERIC, "C");
1399 std::string filename=get_config_file("accelrc");
1400 Gtk::AccelMap::save(filename);
1403 std::string filename=get_config_file("recentfiles");
1405 std::ofstream file(filename.c_str());
1409 synfig::warning("Unable to save %s",filename.c_str());
1413 list<string>::reverse_iterator iter;
1415 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1419 std::string filename=get_config_file("settings");
1420 synfigapp::Main::settings().save_to_file(filename);
1421 setlocale(LC_NUMERIC,old_locale);
1425 synfig::warning("Caught exception when attempting to save settings.");
1430 App::load_settings()
1435 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1436 setlocale(LC_NUMERIC, "C");
1438 std::string filename=get_config_file("accelrc");
1439 Gtk::AccelMap::load(filename);
1442 std::string filename=get_config_file("recentfiles");
1444 std::ifstream file(filename.c_str());
1448 std::string recent_file;
1449 getline(file,recent_file);
1450 if(!recent_file.empty())
1451 add_recent_file(recent_file);
1454 std::string filename=get_config_file("settings");
1455 if(!synfigapp::Main::settings().load_from_file(filename))
1457 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1458 //if(!synfigapp::Main::settings().load_from_file(filename))
1460 gamma.set_gamma(1.0/2.2);
1461 reset_initial_window_configuration();
1464 setlocale(LC_NUMERIC,old_locale);
1468 synfig::warning("Caught exception when attempting to load settings.");
1473 App::reset_initial_window_configuration()
1475 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1476 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1477 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1478 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1479 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1480 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1481 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1482 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1483 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1484 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1485 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1486 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1487 #ifdef SINGLE_THREADED
1488 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1490 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1491 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1495 App::shutdown_request(GdkEventAny*)
1499 //return !shutdown_in_progress;
1505 if(shutdown_in_progress)return;
1508 get_ui_interface()->task(_("Quit Request"));
1511 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1515 std::list<etl::handle<Instance> >::iterator iter;
1516 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1518 if(!(*iter)->safe_close())
1522 if((*iter)->synfigapp::Instance::get_action_count())
1524 handle<synfigapp::UIInterface> uim;
1525 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1527 string str=strprintf(_("Would you like to save your changes to %s?"),(*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:
1535 case synfigapp::UIInterface::RESPONSE_CANCEL:
1544 if((*iter)->synfigapp::Instance::is_modified())
1546 handle<synfigapp::UIInterface> uim;
1547 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1549 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() );
1550 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1552 case synfigapp::UIInterface::RESPONSE_NO:
1554 case synfigapp::UIInterface::RESPONSE_YES:
1555 (*iter)->dialog_cvs_commit();
1557 case synfigapp::UIInterface::RESPONSE_CANCEL:
1566 // This next line causes things to crash for some reason
1570 shutdown_in_progress=true;
1572 instance_list.clear();
1574 while(studio::App::events_pending())studio::App::iteration(false);
1577 auto_recover->normal_shutdown();
1579 get_ui_interface()->task(_("Quit Request sent"));
1585 dialog_setup->refresh();
1586 dialog_setup->show();
1589 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1590 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1593 //#define USE_WIN32_FILE_DIALOGS 1
1596 #ifdef USE_WIN32_FILE_DIALOGS
1597 static OPENFILENAME ofn={};
1601 #include <gdk/gdkwin32.h>
1605 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1607 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1609 #ifdef USE_WIN32_FILE_DIALOGS
1610 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1612 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1613 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1614 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1616 ofn.lStructSize=sizeof(OPENFILENAME);
1617 ofn.hwndOwner = hWnd;
1618 ofn.hInstance = hInstance;
1619 ofn.lpstrFilter = szFilter;
1620 // ofn.lpstrCustomFilter=NULL;
1621 // ofn.nMaxCustFilter=0;
1622 // ofn.nFilterIndex=0;
1623 // ofn.lpstrFile=NULL;
1624 ofn.nMaxFile=MAX_PATH;
1625 // ofn.lpstrFileTitle=NULL;
1626 // ofn.lpstrInitialDir=NULL;
1627 // ofn.lpstrTitle=NULL;
1628 ofn.Flags=OFN_HIDEREADONLY;
1629 // ofn.nFileOffset=0;
1630 // ofn.nFileExtension=0;
1631 ofn.lpstrDefExt=TEXT("sif");
1632 // ofn.lCustData = 0l;
1634 // ofn.lpTemplateName=NULL;
1636 CHAR szFilename[MAX_PATH];
1638 strcpy(szFilename,filename.c_str());
1639 strcpy(szTitle,title.c_str());
1641 ofn.lpstrFile=szFilename;
1642 ofn.lpstrFileTitle=szTitle;
1644 if(GetOpenFileName(&ofn))
1646 filename=szFilename;
1652 synfig::String prev_path;
1654 if(!_preferences.get_value(preference, prev_path))
1657 prev_path = absolute_path(prev_path);
1659 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1661 dialog->set_current_folder(prev_path);
1662 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1663 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1665 if (filename.empty())
1666 dialog->set_filename(prev_path);
1667 else if (is_absolute_path(filename))
1668 dialog->set_filename(filename);
1670 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1672 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1673 filename = dialog->get_filename();
1674 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1675 _preferences.set_value(preference, dirname(filename));
1689 GtkWidget *fileselection;
1690 fileselection = gtk_file_selection_new(title.c_str());
1693 if(basename(filename)==filename)
1695 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1698 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1700 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1702 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1703 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1705 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1706 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1708 gtk_widget_show(fileselection);
1716 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1717 _preferences.set_value(preference,dirname(filename));
1721 gtk_widget_destroy(fileselection);
1724 gtk_widget_destroy(fileselection);
1731 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1733 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1735 #if USE_WIN32_FILE_DIALOGS
1736 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1738 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1739 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1740 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1742 ofn.lStructSize=sizeof(OPENFILENAME);
1743 ofn.hwndOwner = hWnd;
1744 ofn.hInstance = hInstance;
1745 ofn.lpstrFilter = szFilter;
1746 // ofn.lpstrCustomFilter=NULL;
1747 // ofn.nMaxCustFilter=0;
1748 // ofn.nFilterIndex=0;
1749 // ofn.lpstrFile=NULL;
1750 ofn.nMaxFile=MAX_PATH;
1751 // ofn.lpstrFileTitle=NULL;
1752 // ofn.lpstrInitialDir=NULL;
1753 // ofn.lpstrTitle=NULL;
1754 ofn.Flags=OFN_OVERWRITEPROMPT;
1755 // ofn.nFileOffset=0;
1756 // ofn.nFileExtension=0;
1757 ofn.lpstrDefExt=TEXT("sif");
1758 // ofn.lCustData = 0l;
1760 // ofn.lpTemplateName=NULL;
1762 CHAR szFilename[MAX_PATH];
1764 strcpy(szFilename,filename.c_str());
1765 strcpy(szTitle,title.c_str());
1767 ofn.lpstrFile=szFilename;
1768 ofn.lpstrFileTitle=szTitle;
1770 if(GetSaveFileName(&ofn))
1772 filename=szFilename;
1773 _preferences.set_value(preference,dirname(filename));
1778 synfig::String prev_path;
1780 if(!_preferences.get_value(preference, prev_path))
1783 prev_path = absolute_path(prev_path);
1785 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1787 dialog->set_current_folder(prev_path);
1788 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1789 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1791 Widget_Enum *file_type_enum = 0;
1792 if (preference == ANIMATION_DIR_PREFERENCE)
1794 file_type_enum = manage(new Widget_Enum());
1795 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1796 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", strprintf("0.61.08 (%s)", _("current")))
1797 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1798 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1799 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1801 Gtk::HBox *hbox = manage(new Gtk::HBox);
1802 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1803 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1806 dialog->set_extra_widget(*hbox);
1809 if (filename.empty())
1810 dialog->set_filename(prev_path);
1813 std::string full_path;
1814 if (is_absolute_path(filename))
1815 full_path = filename;
1817 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1819 // select the file if it exists
1820 dialog->set_filename(full_path);
1822 // if the file doesn't exist, put its name into the filename box
1824 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1825 dialog->set_current_name(basename(filename));
1828 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1829 if (preference == ANIMATION_DIR_PREFERENCE)
1830 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
1831 filename = dialog->get_filename();
1832 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1833 _preferences.set_value(preference, dirname(filename));
1844 App::dialog_error_blocking(const std::string &title, const std::string &message)
1846 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1847 dialog.set_title(title);
1853 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1855 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1856 dialog.set_title(title);
1862 App::dialog_yes_no(const std::string &title, const std::string &message)
1867 true // use_separator
1869 Gtk::Label label(message);
1872 dialog.get_vbox()->pack_start(label);
1873 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1874 dialog.add_button(Gtk::StockID("gtk-no"),0);
1876 return dialog.run();
1880 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1885 true // use_separator
1887 Gtk::Label label(message);
1890 dialog.get_vbox()->pack_start(label);
1891 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1892 dialog.add_button(Gtk::StockID("gtk-no"),0);
1893 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1895 return dialog.run();
1899 App::dialog_not_implemented()
1901 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1902 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1907 try_open_url(const std::string &url)
1910 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
1912 gchar* argv[3] = {strdup(App::browser_command.c_str()), strdup(url.c_str()), NULL};
1914 GError* gerror = NULL;
1916 retval = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &gerror);
1922 error(_("Could not execute specified web browser: %s"), gerror->message);
1923 g_error_free(gerror);
1934 if (!try_open_url("http://synfig.org/Documentation"))
1936 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
1937 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
1938 dialog.set_title(_("Help"));
1944 App::open_url(const std::string &url)
1950 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1955 true // use_separator
1957 Gtk::Label label(message);
1959 dialog.get_vbox()->pack_start(label);
1962 entry.set_text(text);
1964 entry.set_activates_default(true);
1965 dialog.get_vbox()->pack_start(entry);
1967 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1968 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1969 dialog.set_default_response(Gtk::RESPONSE_OK);
1970 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1973 if(dialog.run()!=Gtk::RESPONSE_OK)
1976 text=entry.get_text();
1985 App::open(std::string filename)
1987 return open_as(filename,filename);
1990 // this is called from autorecover.cpp:
1991 // App::open_as(get_shadow_file_name(filename),filename)
1992 // other than that, 'filename' and 'as' are the same
1994 App::open_as(std::string filename,std::string as)
1997 char long_name[1024];
1998 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2004 OneMoment one_moment;
2006 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2007 if(canvas && get_instance(canvas))
2009 get_instance(canvas)->find_canvas_view(canvas)->present();
2010 info("%s is already open", filename.c_str());
2011 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2016 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2018 add_recent_file(as);
2020 handle<Instance> instance(Instance::create(canvas));
2023 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2027 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)")))
2028 instance->dialog_cvs_update();
2033 dialog_error_blocking(_("Error"), x);
2038 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2049 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2051 String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2052 canvas->set_name(file_name);
2053 file_name += ".sifz";
2055 canvas->rend_desc().set_frame_rate(24.0);
2056 canvas->rend_desc().set_time_start(0.0);
2057 canvas->rend_desc().set_time_end(5.0);
2058 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2059 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2060 canvas->rend_desc().set_tl(Vector(-4,2.25));
2061 canvas->rend_desc().set_br(Vector(4,-2.25));
2062 canvas->rend_desc().set_w(480);
2063 canvas->rend_desc().set_h(270);
2064 canvas->rend_desc().set_antialias(1);
2065 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2066 canvas->set_file_name(file_name);
2068 handle<Instance> instance = Instance::create(canvas);
2070 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2071 instance->find_canvas_view(canvas)->canvas_properties.present();
2075 App::dialog_open(string filename)
2077 if (filename.empty())
2080 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2082 // If the filename still has wildcards, then we should
2083 // continue looking for the file we want
2084 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2090 get_ui_interface()->error(_("Unable to open file"));
2095 App::set_selected_instance(etl::loose_handle<Instance> instance)
2097 /* if(get_selected_instance()==instance)
2099 selected_instance=instance;
2100 signal_instance_selected()(instance);
2106 selected_instance=instance;
2107 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2111 instance->focus(instance->get_canvas());
2114 set_selected_canvas_view(0);
2116 signal_instance_selected()(instance);
2120 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2122 selected_canvas_view=canvas_view;
2123 signal_canvas_view_focus()(selected_canvas_view);
2126 selected_instance=canvas_view->get_instance();
2127 signal_instance_selected()(canvas_view->get_instance());
2130 if(get_selected_canvas_view()==canvas_view)
2132 signal_canvas_view_focus()(selected_canvas_view);
2133 signal_instance_selected()(canvas_view->get_instance());
2136 selected_canvas_view=canvas_view;
2137 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2138 set_selected_instance(canvas_view->get_instance());
2139 signal_canvas_view_focus()(selected_canvas_view);
2143 etl::loose_handle<Instance>
2144 App::get_instance(etl::handle<synfig::Canvas> canvas)
2146 if(!canvas) return 0;
2147 canvas=canvas->get_root();
2149 std::list<etl::handle<Instance> >::iterator iter;
2150 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2152 if((*iter)->get_canvas()==canvas)
2168 if(selected_instance)
2169 selected_instance->undo();
2175 if(selected_instance)
2176 selected_instance->redo();
2180 studio::App::get_base_path()
2182 return app_base_path_;