1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 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>
60 #include "canvasview.h"
61 #include "dialog_setup.h"
62 #include "dialog_gradient.h"
63 #include "dialog_color.h"
66 #include "onemoment.h"
68 #include "dockmanager.h"
70 #include "state_eyedrop.h"
71 #include "state_normal.h"
72 #include "state_draw.h"
73 #include "state_fill.h"
74 #include "state_bline.h"
75 #include "state_polygon.h"
76 #include "state_sketch.h"
77 #include "state_gradient.h"
78 #include "state_circle.h"
79 #include "state_rectangle.h"
80 #include "state_smoothmove.h"
81 #include "state_scale.h"
82 #include "state_width.h"
83 #include "state_rotate.h"
84 #include "state_zoom.h"
86 #include "devicetracker.h"
87 #include "dialog_tooloptions.h"
89 #include "autorecover.h"
91 #include <synfigapp/settings.h>
92 #include "dock_history.h"
93 #include "dock_canvases.h"
94 #include "dock_keyframes.h"
95 #include "dock_layers.h"
96 #include "dock_params.h"
97 #include "dock_metadata.h"
98 #include "dock_children.h"
99 #include "dock_info.h"
100 #include "dock_navigator.h"
101 #include "dock_layergroups.h"
102 #include "dock_timetrack.h"
103 #include "dock_curves.h"
105 #include "mod_palette/mod_palette.h"
106 #include "mod_mirror/mod_mirror.h"
108 #include <sys/stat.h>
114 #include "statemanager.h"
121 #define _WIN32_WINNT 0x0500
124 #include <gtkmm/accelmap.h>
125 #include <gtkmm/filechooser.h>
126 #include <gtkmm/filechooserdialog.h>
132 /* === U S I N G =========================================================== */
136 using namespace synfig;
137 using namespace studio;
139 /* === M A C R O S ========================================================= */
141 #ifndef SYNFIG_USER_APP_DIR
143 #define SYNFIG_USER_APP_DIR "Library/Synfig"
144 #elif defined(_WIN32)
145 #define SYNFIG_USER_APP_DIR "Synfig"
147 #define SYNFIG_USER_APP_DIR ".synfig"
152 #define DPM2DPI(x) (float(x)/39.3700787402f)
153 #define DPI2DPM(x) (float(x)*39.3700787402f)
159 # define IMAGE_DIR "share\\pixmaps"
164 # define IMAGE_DIR "/usr/local/share/pixmaps"
168 # define IMAGE_EXT "tif"
171 #include <synfigapp/main.h>
173 /* === S I G N A L S ======================================================= */
175 static sigc::signal<void> signal_present_all_;
177 App::signal_present_all() { return signal_present_all_; }
179 static sigc::signal<void> signal_recent_files_changed_;
181 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
183 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
184 sigc::signal<void,etl::loose_handle<CanvasView> >&
185 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
187 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
188 sigc::signal<void,etl::handle<Instance> >&
189 App::signal_instance_selected() { return signal_instance_selected_; }
191 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
192 sigc::signal<void,etl::handle<Instance> >&
193 App::signal_instance_created() { return signal_instance_created_; }
195 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
196 sigc::signal<void,etl::handle<Instance> >&
197 App::signal_instance_deleted() { return signal_instance_deleted_; }
199 /* === G L O B A L S ======================================================= */
201 static std::list<std::string> recent_files;
202 const std::list<std::string>& App::get_recent_files() { return recent_files; }
204 int App::Busy::count;
205 bool App::shutdown_in_progress;
207 synfig::Gamma App::gamma;
209 Glib::RefPtr<studio::UIManager> App::ui_manager_;
211 synfig::Distance::System App::distance_system;
213 studio::Dialog_Setup* App::dialog_setup;
215 etl::handle< studio::ModPalette > mod_palette_;
216 //studio::Dialog_Palette* App::dialog_palette;
218 std::list<etl::handle<Instance> > App::instance_list;
220 static etl::handle<synfigapp::UIInterface> ui_interface_;
221 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
223 etl::handle<Instance> App::selected_instance;
224 etl::handle<CanvasView> App::selected_canvas_view;
226 studio::About *studio::App::about=NULL;
228 studio::Toolbox *studio::App::toolbox=NULL;
230 studio::AutoRecover *studio::App::auto_recover=NULL;
232 studio::IPC *ipc=NULL;
234 studio::DockManager* studio::App::dock_manager=0;
236 studio::DeviceTracker* studio::App::device_tracker=0;
238 studio::Dialog_Gradient* studio::App::dialog_gradient;
240 studio::Dialog_Color* studio::App::dialog_color;
242 Gtk::InputDialog* studio::App::dialog_input;
244 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
246 studio::Dock_History* dock_history;
247 studio::Dock_Canvases* dock_canvases;
248 studio::Dock_Keyframes* dock_keyframes;
249 studio::Dock_Layers* dock_layers;
250 studio::Dock_Params* dock_params;
251 studio::Dock_MetaData* dock_meta_data;
252 studio::Dock_Children* dock_children;
253 studio::Dock_Info* dock_info;
254 studio::Dock_LayerGroups* dock_layer_groups;
255 studio::Dock_Navigator* dock_navigator;
256 studio::Dock_Timetrack* dock_timetrack;
257 studio::Dock_Curves* dock_curves;
259 std::list< etl::handle< studio::Module > > module_list_;
261 bool studio::App::use_colorspace_gamma=true;
262 bool studio::App::single_threaded=false;
264 static int max_recent_files_=25;
265 int studio::App::get_max_recent_files() { return max_recent_files_; }
266 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
268 static synfig::String app_base_path_;
273 really_delete_widget(Gtk::Widget *widget)
275 // synfig::info("really delete %p", (void*)widget);
280 // nasty workaround - when we've finished with a popup menu, we want to delete it
281 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
282 // so schedule the real delete to happen in 50ms, giving the action a chance to run
284 delete_widget(Gtk::Widget *widget)
286 // synfig::info("delete %p", (void*)widget);
287 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
290 }; // END of namespace studio
291 studio::StateManager* state_manager;
296 class GlobalUIInterface : public synfigapp::UIInterface
300 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
305 true // use_separator
307 Gtk::Label label(message);
310 dialog.get_vbox()->pack_start(label);
311 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
312 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
314 dialog.set_default_response(dflt);
316 return (Response)dialog.run();
318 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
323 true // use_separator
325 Gtk::Label label(message);
328 dialog.get_vbox()->pack_start(label);
329 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
330 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
331 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
333 dialog.set_default_response(dflt);
335 return (Response)dialog.run();
337 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
342 true // use_separator
344 Gtk::Label label(message);
347 dialog.get_vbox()->pack_start(label);
348 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
349 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
351 dialog.set_default_response(dflt);
353 return (Response)dialog.run();
357 task(const std::string &task)
359 std::cerr<<task<<std::endl;
360 while(studio::App::events_pending())studio::App::iteration(false);
365 error(const std::string &err)
367 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
374 warning(const std::string &err)
376 std::cerr<<"warning: "<<err<<std::endl;
377 while(studio::App::events_pending())studio::App::iteration(false);
382 amount_complete(int /*current*/, int /*total*/)
384 while(studio::App::events_pending())studio::App::iteration(false);
389 /* === P R O C E D U R E S ================================================= */
393 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
395 action_group_list.push_back(action_group);
396 Gtk::UIManager::insert_action_group(action_group, pos);
400 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
402 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
403 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
404 if(*iter==action_group)
406 action_group_list.erase(iter);
407 Gtk::UIManager::remove_action_group(action_group);
410 synfig::error("Unable to find action group");
414 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
416 ui_manager->insert_action_group(group,0);
418 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
419 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
421 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
423 if(*iter && (*iter)->get_name()!="menus")
425 synfig::info("Removing action group "+(*iter)->get_name());
426 ui_manager->remove_action_group(*iter);
429 ui_manager->insert_action_group(group,0);
431 for(;!prev_groups.empty();prev_groups.pop_front())
433 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
434 ui_manager->insert_action_group(prev_groups.front(),1);
438 class Preferences : public synfigapp::Settings
441 virtual bool get_value(const synfig::String& key, synfig::String& value)const
445 value=strprintf("%f %f %f %f",
446 App::gamma.get_gamma_r(),
447 App::gamma.get_gamma_g(),
448 App::gamma.get_gamma_b(),
449 App::gamma.get_black_level()
453 if(key=="time_format")
455 value=strprintf("%i",App::get_time_format());
458 if(key=="file_history.size")
460 value=strprintf("%i",App::get_max_recent_files());
463 if(key=="use_colorspace_gamma")
465 value=strprintf("%i",(int)App::use_colorspace_gamma);
468 if(key=="distance_system")
470 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
473 if(key=="single_threaded")
475 value=strprintf("%i",(int)App::single_threaded);
478 if(key=="auto_recover_backup_interval")
480 value=strprintf("%i",App::auto_recover->get_timeout());
484 return synfigapp::Settings::get_value(key,value);
487 virtual bool set_value(const synfig::String& key,const synfig::String& value)
493 strscanf(value,"%f %f %f %f",
500 App::gamma.set_all(r,g,b,blk);
504 if(key=="time_format")
506 int i(atoi(value.c_str()));
507 App::set_time_format(static_cast<synfig::Time::Format>(i));
510 if(key=="auto_recover_backup_interval")
512 int i(atoi(value.c_str()));
513 App::auto_recover->set_timeout(i);
516 if(key=="file_history.size")
518 int i(atoi(value.c_str()));
519 App::set_max_recent_files(i);
522 if(key=="use_colorspace_gamma")
524 int i(atoi(value.c_str()));
525 App::use_colorspace_gamma=i;
528 if(key=="distance_system")
530 App::distance_system=Distance::ident_system(value);;
533 if(key=="single_threaded")
535 int i(atoi(value.c_str()));
536 App::single_threaded=i;
540 return synfigapp::Settings::set_value(key,value);
543 virtual KeyList get_key_list()const
545 KeyList ret(synfigapp::Settings::get_key_list());
546 ret.push_back("gamma");
547 ret.push_back("time_format");
548 ret.push_back("distance_system");
549 ret.push_back("file_history.size");
550 ret.push_back("use_colorspace_gamma");
551 ret.push_back("single_threaded");
552 ret.push_back("auto_recover_backup_interval");
557 static ::Preferences _preferences;
562 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
564 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
566 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
568 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
569 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
570 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
571 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
572 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
573 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
574 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
575 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
576 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
577 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
578 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
579 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
580 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
582 // Add the synfigapp actions...
583 synfigapp::Action::Book::iterator iter;
584 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
586 actions_action_group->add(Gtk::Action::create(
587 "action-"+iter->second.name,
588 get_action_stock_id(iter->second),
589 iter->second.local_name,iter->second.local_name
593 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
594 #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); }
595 #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); }
597 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
598 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
599 DEFINE_ACTION("new", Gtk::Stock::NEW);
600 DEFINE_ACTION("open", Gtk::Stock::OPEN);
601 DEFINE_ACTION("save", Gtk::Stock::SAVE);
602 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
603 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
604 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
605 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
606 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
607 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
608 DEFINE_ACTION("import", _("Import"));
609 DEFINE_ACTION("render", _("Render"));
610 DEFINE_ACTION("preview", _("Preview"));
611 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
612 DEFINE_ACTION("sound", _("Sound File"));
613 DEFINE_ACTION("options", _("Options"));
614 DEFINE_ACTION("close", _("Close View"));
615 DEFINE_ACTION("close-document", _("Close Document"));
616 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
619 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
620 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
621 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
622 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
623 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
624 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
625 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
626 DEFINE_ACTION("properties", _("Properties"));
628 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
629 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
630 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
631 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
632 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
633 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
634 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
635 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
636 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
637 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
638 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
639 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
640 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
641 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
642 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
643 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
644 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
645 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
646 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
647 DEFINE_ACTION("play", _("Play"));
648 // DEFINE_ACTION("pause", _("Pause"));
649 DEFINE_ACTION("stop", _("Stop"));
650 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
651 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
652 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
653 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
654 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
655 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
656 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
657 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
658 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
659 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
660 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
661 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
662 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
663 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
664 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
665 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
666 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
667 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
668 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
669 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
670 DEFINE_ACTION("seek-end", _("Seek to End"));
672 DEFINE_ACTION("action-group_add", _("Add group"));
674 DEFINE_ACTION("canvas-new", _("New Canvas"));
676 DEFINE_ACTION("amount-inc", _("Increase Amount"));
677 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
682 // Set up synfigapp actions
684 synfigapp::Action::Book::iterator iter;
686 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
688 Gtk::StockID stock_id;
690 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
692 //Gtk::Image* image(manage(new Gtk::Image()));
693 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
694 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
695 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
696 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
697 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
698 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
699 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
700 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
701 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
702 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
704 actions_action_group->add(Gtk::Action::create(
705 "action-"+iter->second.name,
707 iter->second.local_name,iter->second.local_name
715 Glib::ustring ui_info =
717 " <popup name='menu-toolbox' action='menu-toolbox'>"
718 " <menu action='menu-file'>"
721 " <popup name='menu-main' action='menu-main'>"
722 " <menu action='menu-file'>"
723 " <menuitem action='new' />"
724 " <menuitem action='open' />"
725 " <menuitem action='save' />"
726 " <menuitem action='save-as' />"
727 " <menuitem action='revert' />"
728 " <separator name='bleh01'/>"
729 " <menuitem action='cvs-add' />"
730 " <menuitem action='cvs-update' />"
731 " <menuitem action='cvs-commit' />"
732 " <menuitem action='cvs-revert' />"
733 " <separator name='bleh02'/>"
734 " <menuitem action='import' />"
735 " <separator name='bleh03'/>"
736 " <menuitem action='render' />"
737 " <menuitem action='preview' />"
738 " <menuitem action='sound' />"
739 " <separator name='bleh04'/>"
740 " <menuitem action='options' />"
741 " <menuitem action='close' />"
742 " <menuitem action='close-document' />"
743 " <menuitem action='quit' />"
745 " <menu action='menu-edit'>"
746 " <menuitem action='undo'/>"
747 " <menuitem action='redo'/>"
748 " <separator name='bleh05'/>"
749 " <menuitem action='cut'/>"
750 " <menuitem action='copy'/>"
751 " <menuitem action='paste'/>"
752 " <separator name='bleh06'/>"
753 " <menuitem action='select-all-ducks'/>"
754 " <menuitem action='unselect-all-layers'/>"
755 " <separator name='bleh07'/>"
756 " <menuitem action='properties'/>"
758 " <menu action='menu-view'>"
759 " <menu action='menu-duck-mask'>"
760 " <menuitem action='mask-position-ducks' />"
761 " <menuitem action='mask-vertex-ducks' />"
762 " <menuitem action='mask-tangent-ducks' />"
763 " <menuitem action='mask-radius-ducks' />"
764 " <menuitem action='mask-width-ducks' />"
765 " <menuitem action='mask-angle-ducks' />"
767 " <menu action='menu-preview-quality'>"
768 " <menuitem action='quality-00' />"
769 " <menuitem action='quality-01' />"
770 " <menuitem action='quality-02' />"
771 " <menuitem action='quality-03' />"
772 " <menuitem action='quality-04' />"
773 " <menuitem action='quality-05' />"
774 " <menuitem action='quality-06' />"
775 " <menuitem action='quality-07' />"
776 " <menuitem action='quality-08' />"
777 " <menuitem action='quality-09' />"
778 " <menuitem action='quality-10' />"
780 " <menu action='menu-lowres-pixel'>"
781 " <menuitem action='decrease-low-res-pixel-size'/>"
782 " <menuitem action='increase-low-res-pixel-size'/>"
783 " <separator name='pixel-size-separator'/>"
786 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
787 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
791 " <separator name='bleh08'/>"
792 " <menuitem action='play'/>"
793 //" <menuitem action='pause'/>"
794 " <menuitem action='stop'/>"
795 " <menuitem action='dialog-flipbook'/>"
796 " <separator name='bleh09'/>"
797 " <menuitem action='toggle-grid-show'/>"
798 " <menuitem action='toggle-grid-snap'/>"
799 " <menuitem action='toggle-guide-show'/>"
800 " <menuitem action='toggle-low-res'/>"
801 " <menuitem action='toggle-onion-skin'/>"
802 " <separator name='bleh10'/>"
803 " <menuitem action='canvas-zoom-in'/>"
804 " <menuitem action='canvas-zoom-out'/>"
805 " <menuitem action='canvas-zoom-fit'/>"
806 " <menuitem action='canvas-zoom-100'/>"
807 " <separator name='bleh11'/>"
808 " <menuitem action='time-zoom-in'/>"
809 " <menuitem action='time-zoom-out'/>"
810 " <separator name='bleh12'/>"
811 " <menuitem action='jump-next-keyframe'/>"
812 " <menuitem action='jump-prev-keyframe'/>"
813 " <menuitem action='seek-next-frame'/>"
814 " <menuitem action='seek-prev-frame'/>"
815 " <menuitem action='seek-next-second'/>"
816 " <menuitem action='seek-prev-second'/>"
817 " <menuitem action='seek-begin'/>"
818 " <menuitem action='seek-end'/>"
820 " <menu action='menu-canvas'>"
821 " <menuitem action='canvas-new'/>"
823 " <menu name='menu-state' action='menu-state'>"
825 " <menu action='menu-group'>"
826 " <menuitem action='action-group_add'/>"
828 " <menu action='menu-layer'>"
829 //" <menuitem action='cut'/>"
830 //" <menuitem action='copy'/>"
831 //" <menuitem action='paste'/>"
832 //" <separator name='bleh06'/>"
833 " <menu action='menu-layer-new'></menu>"
834 " <menuitem action='amount-inc'/>"
835 " <menuitem action='amount-dec'/>"
837 " <menu action='menu-keyframe'>"
838 " <menuitem action='keyframe-properties'/>"
845 " <menubar name='MenuBar'>"
846 " <menu action='MenuFile'>"
847 " <menuitem action='New'/>"
848 " <menuitem action='Open'/>"
850 " <menuitem action='Quit'/>"
852 " <menu action='MenuEdit'>"
853 " <menuitem action='Cut'/>"
854 " <menuitem action='Copy'/>"
855 " <menuitem action='Paste'/>"
858 " <toolbar name='ToolBar'>"
859 " <toolitem action='Open'/>"
860 " <toolitem action='Quit'/>"
866 actions_action_group->set_sensitive(false);
867 App::ui_manager()->set_add_tearoffs(true);
868 App::ui_manager()->insert_action_group(menus_action_group,1);
869 App::ui_manager()->insert_action_group(actions_action_group,1);
870 App::ui_manager()->add_ui_from_string(ui_info);
872 //App::ui_manager()->get_accel_group()->unlock();
874 catch(const Glib::Error& ex)
876 synfig::error("building menus and toolbars failed: " + ex.what());
879 // Add default keyboard accelerators
880 #define ACCEL(path,accel) \
882 Gtk::AccelKey accel_key(accel,path); \
883 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
886 #define ACCEL2(accel) \
888 Gtk::AccelKey accel_key(accel); \
889 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
892 ACCEL("<Actions>//select-all-ducks","<Control>a");
893 ACCEL("<Actions>//unselect-all-layers","<Control>d");
894 ACCEL("<Actions>//render","F9");
895 ACCEL("<Actions>//preview","F11");
896 ACCEL("<Actions>//properties","F8");
897 ACCEL("<Actions>//options","F12");
898 ACCEL("<Actions>//import","<control>i");
899 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
900 ACCEL("<Actions>//toggle-grid-show","<Control>g");
901 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
902 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
903 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
904 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
905 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
906 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
907 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
908 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
910 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
911 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
913 ACCEL("<Actions>//quality-01","<Control>1");
914 ACCEL("<Actions>//quality-02","<Control>2");
915 ACCEL("<Actions>//quality-03","<Control>3");
916 ACCEL("<Actions>//quality-04","<Control>4");
917 ACCEL("<Actions>//quality-05","<Control>5");
918 ACCEL("<Actions>//quality-06","<Control>6");
919 ACCEL("<Actions>//quality-07","<Control>7");
920 ACCEL("<Actions>//quality-08","<Control>8");
921 ACCEL("<Actions>//quality-09","<Control>9");
922 ACCEL("<Actions>//quality-10","<Control>0");
923 ACCEL("<Actions>//undo","<Control>z");
924 ACCEL("<Actions>//redo","<Control>r");
925 ACCEL("<Actions>//action-layer_remove","Delete");
927 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
928 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
929 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
930 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
931 ACCEL("<Actions>//time-zoom-in","+");
932 ACCEL("<Actions>//time-zoom-out","_");
934 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
935 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
937 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
938 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
940 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
941 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
942 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
943 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
944 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
945 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
946 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
947 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
948 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
949 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
950 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
951 ACCEL("<Actions>//play", "<Control>p");
952 ACCEL("<Actions>//seek-begin","Home");
953 ACCEL("<Actions>//seek-end","End");
955 ACCEL("<Actions>//state-normal", "<Mod1>a");
956 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
957 ACCEL("<Actions>//state-scale", "<Mod1>d");
958 ACCEL("<Actions>//state-rotate", "<Mod1>s");
960 ACCEL("<Actions>//state-bline", "<Mod1>b");
961 ACCEL("<Actions>//state-circle", "<Mod1>c");
962 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
963 ACCEL("<Actions>//state-gradient", "<Mod1>g");
965 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
966 ACCEL("<Actions>//state-fill", "<Mod1>f");
967 ACCEL("<Actions>//state-zoom", "<Mod1>z");
968 ACCEL("<Actions>//state-polygon", "<Mod1>p");
970 ACCEL("<Actions>//state-draw", "<Mod1>w");
971 ACCEL("<Actions>//state-sketch", "<Mod1>k");
972 ACCEL("<Actions>//state-width", "<Mod1>t");
973 ACCEL("<Actions>//state-mirror", "<Mod1>m");
975 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
981 #define mkdir(x,y) mkdir(x)
984 /* === M E T H O D S ======================================================= */
986 App::App(int *argc, char ***argv):
987 Gtk::Main(argc,argv),
988 IconController(etl::dirname((*argv)[0]))
990 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
993 ui_interface_=new GlobalUIInterface();
997 // don't call thread_init() if threads are already initialized
998 // on some machines bonobo_init() initialized threads before we get here
999 if (!g_thread_supported())
1000 Glib::thread_init();
1002 distance_system=Distance::SYSTEM_UNITS;
1004 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1007 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1011 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1017 if(!SYNFIG_CHECK_VERSION())
1019 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1020 dialog_error_blocking("Synfig Studio",
1021 "This copy of Synfig Studio was compiled against a\n"
1022 "different version of libsynfig than what is currently\n"
1023 "installed. Synfig Studio will now abort. Try downloading\n"
1024 "the latest version from the Synfig website at\n"
1025 "http://synfig.org/Download"
1029 Glib::set_application_name(_("Synfig Studio"));
1031 Splash splash_screen;
1032 splash_screen.set_can_self_destruct(false);
1033 splash_screen.show();
1035 shutdown_in_progress=false;
1036 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1037 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1039 // Initialize the Synfig library
1040 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1043 get_ui_interface()->error(_("Failed to initialize synfig!"));
1047 // add the preferences to the settings
1048 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1052 studio_init_cb.task(_("Init UI Manager..."));
1053 App::ui_manager_=studio::UIManager::create();
1056 studio_init_cb.task(_("Init Dock Manager..."));
1057 dock_manager=new studio::DockManager();
1059 studio_init_cb.task(_("Init State Manager..."));
1060 state_manager=new StateManager();
1062 studio_init_cb.task(_("Init Toolbox..."));
1063 toolbox=new studio::Toolbox();
1065 studio_init_cb.task(_("Init About Dialog..."));
1066 about=new studio::About();
1068 studio_init_cb.task(_("Init Tool Options..."));
1069 dialog_tool_options=new studio::Dialog_ToolOptions();
1070 dock_manager->register_dockable(*dialog_tool_options);
1072 studio_init_cb.task(_("Init History..."));
1073 dock_history=new studio::Dock_History();
1074 dock_manager->register_dockable(*dock_history);
1076 studio_init_cb.task(_("Init Canvases..."));
1077 dock_canvases=new studio::Dock_Canvases();
1078 dock_manager->register_dockable(*dock_canvases);
1080 studio_init_cb.task(_("Init Keyframes..."));
1081 dock_keyframes=new studio::Dock_Keyframes();
1082 dock_manager->register_dockable(*dock_keyframes);
1084 studio_init_cb.task(_("Init Layers..."));
1085 dock_layers=new studio::Dock_Layers();
1086 dock_manager->register_dockable(*dock_layers);
1088 studio_init_cb.task(_("Init Params..."));
1089 dock_params=new studio::Dock_Params();
1090 dock_manager->register_dockable(*dock_params);
1092 studio_init_cb.task(_("Init MetaData..."));
1093 dock_meta_data=new studio::Dock_MetaData();
1094 dock_manager->register_dockable(*dock_meta_data);
1096 studio_init_cb.task(_("Init Children..."));
1097 dock_children=new studio::Dock_Children();
1098 dock_manager->register_dockable(*dock_children);
1100 studio_init_cb.task(_("Init Info..."));
1101 dock_info = new studio::Dock_Info();
1102 dock_manager->register_dockable(*dock_info);
1104 studio_init_cb.task(_("Init Navigator..."));
1105 dock_navigator = new studio::Dock_Navigator();
1106 dock_manager->register_dockable(*dock_navigator);
1108 studio_init_cb.task(_("Init Timetrack..."));
1109 dock_timetrack = new studio::Dock_Timetrack();
1110 dock_manager->register_dockable(*dock_timetrack);
1112 studio_init_cb.task(_("Init Curve Editor..."));
1113 dock_curves = new studio::Dock_Curves();
1114 dock_manager->register_dockable(*dock_curves);
1116 studio_init_cb.task(_("Init Layer Groups..."));
1117 dock_layer_groups = new studio::Dock_LayerGroups();
1118 dock_manager->register_dockable(*dock_layer_groups);
1121 studio_init_cb.task(_("Init Color Dialog..."));
1122 dialog_color=new studio::Dialog_Color();
1124 studio_init_cb.task(_("Init Gradient Dialog..."));
1125 dialog_gradient=new studio::Dialog_Gradient();
1127 studio_init_cb.task(_("Init DeviceTracker..."));
1128 device_tracker=new studio::DeviceTracker();
1130 studio_init_cb.task(_("Init Tools..."));
1133 state_manager->add_state(&state_normal);
1134 state_manager->add_state(&state_smooth_move);
1135 state_manager->add_state(&state_scale);
1136 state_manager->add_state(&state_rotate);
1137 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1140 state_manager->add_state(&state_bline);
1141 state_manager->add_state(&state_circle);
1142 state_manager->add_state(&state_rectangle);
1143 state_manager->add_state(&state_gradient);
1144 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1147 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1148 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1149 state_manager->add_state(&state_fill);
1150 state_manager->add_state(&state_eyedrop);
1151 state_manager->add_state(&state_zoom);
1153 // Disabled by default - it doesn't work properly?
1154 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1156 studio_init_cb.task(_("Init ModPalette..."));
1157 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1159 studio_init_cb.task(_("Init Setup Dialog..."));
1160 dialog_setup=new studio::Dialog_Setup();
1162 studio_init_cb.task(_("Init Input Dialog..."));
1163 dialog_input=new Gtk::InputDialog();
1164 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1165 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1167 studio_init_cb.task(_("Init auto recovery..."));
1168 auto_recover=new AutoRecover();
1170 studio_init_cb.amount_complete(9250,10000);
1171 studio_init_cb.task(_("Loading Settings..."));
1173 studio_init_cb.task(_("Checking auto-recover..."));
1175 studio_init_cb.amount_complete(9900,10000);
1177 bool opened_any = false;
1178 if(auto_recover->recovery_needed())
1180 splash_screen.hide();
1181 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1182 _("Synfig Studio seems to have crashed\n"
1183 "before you could save all your files.\n"
1184 "Would you like to re-open those files\n"
1185 "and recover your unsaved changes?")) ==
1186 synfigapp::UIInterface::RESPONSE_YES)
1188 int number_recovered;
1189 if(!auto_recover->recover(number_recovered))
1190 if (number_recovered)
1191 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1193 get_ui_interface()->error(_("Unable to recover from previous crash"));
1195 get_ui_interface()->error(
1196 _("Synfig Studio has attempted to recover\n"
1197 "from a previous crash. The files that it has\n"
1198 "recovered are NOT YET SAVED. It would be a good\n"
1199 "idea to review them and save them now."));
1201 if (number_recovered)
1204 splash_screen.show();
1207 // Look for any files given on the command line,
1208 // and load them if found.
1209 for(;*argc>=1;(*argc)--)
1210 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1212 studio_init_cb.task(_("Loading files..."));
1213 splash_screen.hide();
1214 open((*argv)[*argc]);
1216 splash_screen.show();
1219 // if no file was specified to be opened, create a new document to help new users get started more easily
1220 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1223 studio_init_cb.task(_("Done."));
1224 studio_init_cb.amount_complete(10000,10000);
1230 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1234 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1238 StateManager* App::get_state_manager() { return state_manager; }
1242 shutdown_in_progress=true;
1246 synfigapp::Main::settings().remove_domain("pref");
1248 selected_instance=0;
1250 // Unload all of the modules
1251 for(;!module_list_.empty();module_list_.pop_back())
1254 delete state_manager;
1258 delete auto_recover;
1264 // studio::App::iteration(false);
1268 // studio::App::iteration(false);
1270 // studio::App::iteration(false);
1272 delete dialog_setup;
1274 delete dialog_gradient;
1276 delete dialog_color;
1278 delete dialog_input;
1280 delete dock_manager;
1282 instance_list.clear();
1284 // studio::App::iteration(false);
1288 App::get_user_app_directory()
1290 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1294 App::get_config_file(const synfig::String& file)
1296 return Glib::build_filename(get_user_app_directory(),file);
1300 App::add_recent_file(const std::string &file_name)
1302 std::string filename(file_name);
1304 assert(!filename.empty());
1306 if(filename.empty())
1309 // Toss out any "hidden" files
1310 if(basename(filename)[0]=='.')
1313 // If we aren't an absolute path, turn ourselves into one
1314 if(!is_absolute_path(filename))
1315 filename=absolute_path(filename);
1317 list<string>::iterator iter;
1318 // Check to see if the file is already on the list.
1319 // If it is, then remove it from the list
1320 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1323 recent_files.erase(iter);
1328 // Push the filename to the front of the list
1329 recent_files.push_front(filename);
1331 // Clean out the files at the end of the list.
1332 while(recent_files.size()>(unsigned)get_max_recent_files())
1333 recent_files.pop_back();
1335 signal_recent_files_changed_();
1340 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1343 App::get_time_format()
1345 return _App_time_format;
1349 App::set_time_format(synfig::Time::Format x)
1356 App::save_settings()
1361 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1362 setlocale(LC_NUMERIC, "C");
1364 std::string filename=get_config_file("accelrc");
1365 Gtk::AccelMap::save(filename);
1368 std::string filename=get_config_file("recentfiles");
1370 std::ofstream file(filename.c_str());
1374 synfig::warning("Unable to save %s",filename.c_str());
1378 list<string>::reverse_iterator iter;
1380 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1384 std::string filename=get_config_file("settings");
1385 synfigapp::Main::settings().save_to_file(filename);
1386 setlocale(LC_NUMERIC,old_locale);
1390 synfig::warning("Caught exception when attempting to save settings.");
1395 App::load_settings()
1400 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1401 setlocale(LC_NUMERIC, "C");
1403 std::string filename=get_config_file("accelrc");
1404 Gtk::AccelMap::load(filename);
1407 std::string filename=get_config_file("recentfiles");
1409 std::ifstream file(filename.c_str());
1413 std::string recent_file;
1414 getline(file,recent_file);
1415 if(!recent_file.empty())
1416 add_recent_file(recent_file);
1419 std::string filename=get_config_file("settings");
1420 if(!synfigapp::Main::settings().load_from_file(filename))
1422 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1423 //if(!synfigapp::Main::settings().load_from_file(filename))
1425 gamma.set_gamma(1.0/2.2);
1426 reset_initial_window_configuration();
1429 setlocale(LC_NUMERIC,old_locale);
1433 synfig::warning("Caught exception when attempting to load settings.");
1438 App::reset_initial_window_configuration()
1440 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1441 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1442 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1443 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1444 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1445 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1446 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1447 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1448 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1449 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1450 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1451 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1452 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1453 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1457 App::shutdown_request(GdkEventAny*)
1461 //return !shutdown_in_progress;
1467 if(shutdown_in_progress)return;
1470 get_ui_interface()->task(_("Quit Request"));
1473 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1477 std::list<etl::handle<Instance> >::iterator iter;
1478 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1480 if(!(*iter)->safe_close())
1484 if((*iter)->synfigapp::Instance::get_action_count())
1486 handle<synfigapp::UIInterface> uim;
1487 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1489 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1490 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1492 case synfigapp::UIInterface::RESPONSE_NO:
1494 case synfigapp::UIInterface::RESPONSE_YES:
1497 case synfigapp::UIInterface::RESPONSE_CANCEL:
1506 if((*iter)->synfigapp::Instance::is_modified())
1508 handle<synfigapp::UIInterface> uim;
1509 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1511 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() );
1512 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1514 case synfigapp::UIInterface::RESPONSE_NO:
1516 case synfigapp::UIInterface::RESPONSE_YES:
1517 (*iter)->dialog_cvs_commit();
1519 case synfigapp::UIInterface::RESPONSE_CANCEL:
1528 // This next line causes things to crash for some reason
1532 shutdown_in_progress=true;
1534 instance_list.clear();
1536 while(studio::App::events_pending())studio::App::iteration(false);
1539 auto_recover->normal_shutdown();
1541 get_ui_interface()->task(_("Quit Request sent"));
1547 dialog_setup->refresh();
1548 dialog_setup->show();
1551 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1552 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1555 //#define USE_WIN32_FILE_DIALOGS 1
1558 #ifdef USE_WIN32_FILE_DIALOGS
1559 static OPENFILENAME ofn={};
1563 #include <gdk/gdkwin32.h>
1567 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1569 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1571 #ifdef USE_WIN32_FILE_DIALOGS
1572 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1574 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1575 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1576 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1578 ofn.lStructSize=sizeof(OPENFILENAME);
1579 ofn.hwndOwner = hWnd;
1580 ofn.hInstance = hInstance;
1581 ofn.lpstrFilter = szFilter;
1582 // ofn.lpstrCustomFilter=NULL;
1583 // ofn.nMaxCustFilter=0;
1584 // ofn.nFilterIndex=0;
1585 // ofn.lpstrFile=NULL;
1586 ofn.nMaxFile=MAX_PATH;
1587 // ofn.lpstrFileTitle=NULL;
1588 // ofn.lpstrInitialDir=NULL;
1589 // ofn.lpstrTitle=NULL;
1590 ofn.Flags=OFN_HIDEREADONLY;
1591 // ofn.nFileOffset=0;
1592 // ofn.nFileExtension=0;
1593 ofn.lpstrDefExt=TEXT("sif");
1594 // ofn.lCustData = 0l;
1596 // ofn.lpTemplateName=NULL;
1598 CHAR szFilename[MAX_PATH];
1600 strcpy(szFilename,filename.c_str());
1601 strcpy(szTitle,title.c_str());
1603 ofn.lpstrFile=szFilename;
1604 ofn.lpstrFileTitle=szTitle;
1606 if(GetOpenFileName(&ofn))
1608 filename=szFilename;
1614 synfig::String prev_path;
1616 if(!_preferences.get_value(preference, prev_path))
1619 prev_path = absolute_path(prev_path);
1621 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1623 dialog->set_current_folder(prev_path);
1624 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1625 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1627 if (filename.empty())
1628 dialog->set_filename(prev_path);
1629 else if (is_absolute_path(filename))
1630 dialog->set_filename(filename);
1632 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1634 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1635 filename = dialog->get_filename();
1636 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1637 _preferences.set_value(preference, dirname(filename));
1651 GtkWidget *fileselection;
1652 fileselection = gtk_file_selection_new(title.c_str());
1655 if(basename(filename)==filename)
1657 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1660 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1662 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1664 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1665 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1667 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1668 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1670 gtk_widget_show(fileselection);
1678 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1679 _preferences.set_value(preference,dirname(filename));
1683 gtk_widget_destroy(fileselection);
1686 gtk_widget_destroy(fileselection);
1693 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1695 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1697 #if USE_WIN32_FILE_DIALOGS
1698 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1700 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1701 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1702 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1704 ofn.lStructSize=sizeof(OPENFILENAME);
1705 ofn.hwndOwner = hWnd;
1706 ofn.hInstance = hInstance;
1707 ofn.lpstrFilter = szFilter;
1708 // ofn.lpstrCustomFilter=NULL;
1709 // ofn.nMaxCustFilter=0;
1710 // ofn.nFilterIndex=0;
1711 // ofn.lpstrFile=NULL;
1712 ofn.nMaxFile=MAX_PATH;
1713 // ofn.lpstrFileTitle=NULL;
1714 // ofn.lpstrInitialDir=NULL;
1715 // ofn.lpstrTitle=NULL;
1716 ofn.Flags=OFN_OVERWRITEPROMPT;
1717 // ofn.nFileOffset=0;
1718 // ofn.nFileExtension=0;
1719 ofn.lpstrDefExt=TEXT("sif");
1720 // ofn.lCustData = 0l;
1722 // ofn.lpTemplateName=NULL;
1724 CHAR szFilename[MAX_PATH];
1726 strcpy(szFilename,filename.c_str());
1727 strcpy(szTitle,title.c_str());
1729 ofn.lpstrFile=szFilename;
1730 ofn.lpstrFileTitle=szTitle;
1732 if(GetSaveFileName(&ofn))
1734 filename=szFilename;
1735 _preferences.set_value(preference,dirname(filename));
1740 synfig::String prev_path;
1742 if(!_preferences.get_value(preference, prev_path))
1745 prev_path = absolute_path(prev_path);
1747 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1749 dialog->set_current_folder(prev_path);
1750 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1751 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1753 if (filename.empty())
1754 dialog->set_filename(prev_path);
1757 std::string full_path;
1758 if (is_absolute_path(filename))
1759 full_path = filename;
1761 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1763 // select the file if it exists
1764 dialog->set_filename(full_path);
1766 // if the file doesn't exist, put its name into the filename box
1768 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1769 dialog->set_current_name(basename(filename));
1772 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1773 filename = dialog->get_filename();
1774 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1775 _preferences.set_value(preference, dirname(filename));
1786 App::dialog_error_blocking(const std::string &title, const std::string &message)
1788 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1789 dialog.set_title(title);
1795 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1797 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1798 dialog.set_title(title);
1804 App::dialog_yes_no(const std::string &title, const std::string &message)
1809 true // use_separator
1811 Gtk::Label label(message);
1814 dialog.get_vbox()->pack_start(label);
1815 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1816 dialog.add_button(Gtk::StockID("gtk-no"),0);
1818 return dialog.run();
1822 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1827 true // use_separator
1829 Gtk::Label label(message);
1832 dialog.get_vbox()->pack_start(label);
1833 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1834 dialog.add_button(Gtk::StockID("gtk-no"),0);
1835 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1837 return dialog.run();
1841 App::dialog_not_implemented()
1843 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1844 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1849 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1854 true // use_separator
1856 Gtk::Label label(message);
1858 dialog.get_vbox()->pack_start(label);
1861 entry.set_text(text);
1863 entry.set_activates_default(true);
1864 dialog.get_vbox()->pack_start(entry);
1866 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1867 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1868 dialog.set_default_response(Gtk::RESPONSE_OK);
1869 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1872 if(dialog.run()!=Gtk::RESPONSE_OK)
1875 text=entry.get_text();
1884 App::open(std::string filename)
1886 return open_as(filename,filename);
1889 // this is called from autorecover.cpp:
1890 // App::open_as(get_shadow_file_name(filename),filename)
1891 // other than that, 'filename' and 'as' are the same
1893 App::open_as(std::string filename,std::string as)
1896 char long_name[1024];
1897 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1903 OneMoment one_moment;
1905 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1906 if(canvas && get_instance(canvas))
1908 get_instance(canvas)->find_canvas_view(canvas)->present();
1909 info("%s is already open", filename.c_str());
1910 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1915 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1917 add_recent_file(as);
1919 handle<Instance> instance(Instance::create(canvas));
1922 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1926 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)")))
1927 instance->dialog_cvs_update();
1932 dialog_error_blocking(_("Error"), x);
1937 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1948 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1949 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1951 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1953 canvas->rend_desc().set_frame_rate(24.0);
1954 canvas->rend_desc().set_time_start(0.0);
1955 canvas->rend_desc().set_time_end(5.0);
1956 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1957 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1958 canvas->rend_desc().set_tl(Vector(-4,2.25));
1959 canvas->rend_desc().set_br(Vector(4,-2.25));
1960 canvas->rend_desc().set_w(480);
1961 canvas->rend_desc().set_h(270);
1962 canvas->rend_desc().set_antialias(1);
1963 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1964 canvas->set_file_name(file_name);
1966 handle<Instance> instance = Instance::create(canvas);
1968 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1969 instance->find_canvas_view(canvas)->canvas_properties.present();
1975 string filename="*.sif";
1977 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
1979 // If the filename still has wildcards, then we should
1980 // continue looking for the file we want
1981 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1987 get_ui_interface()->error(_("Unable to open file"));
1992 App::set_selected_instance(etl::loose_handle<Instance> instance)
1994 /* if(get_selected_instance()==instance)
1996 selected_instance=instance;
1997 signal_instance_selected()(instance);
2003 selected_instance=instance;
2004 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2008 instance->focus(instance->get_canvas());
2011 set_selected_canvas_view(0);
2013 signal_instance_selected()(instance);
2017 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2019 selected_canvas_view=canvas_view;
2020 signal_canvas_view_focus()(selected_canvas_view);
2023 selected_instance=canvas_view->get_instance();
2024 signal_instance_selected()(canvas_view->get_instance());
2027 if(get_selected_canvas_view()==canvas_view)
2029 signal_canvas_view_focus()(selected_canvas_view);
2030 signal_instance_selected()(canvas_view->get_instance());
2033 selected_canvas_view=canvas_view;
2034 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2035 set_selected_instance(canvas_view->get_instance());
2036 signal_canvas_view_focus()(selected_canvas_view);
2040 etl::loose_handle<Instance>
2041 App::get_instance(etl::handle<synfig::Canvas> canvas)
2043 if(!canvas) return 0;
2044 canvas=canvas->get_root();
2046 std::list<etl::handle<Instance> >::iterator iter;
2047 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2049 if((*iter)->get_canvas()==canvas)
2065 if(selected_instance)
2066 selected_instance->undo();
2072 if(selected_instance)
2073 selected_instance->redo();
2077 studio::App::get_base_path()
2079 return app_base_path_;