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..."));
1131 state_manager->add_state(&state_normal);
1132 state_manager->add_state(&state_smooth_move);
1133 state_manager->add_state(&state_scale);
1134 state_manager->add_state(&state_rotate);
1136 state_manager->add_state(&state_bline);
1139 state_manager->add_state(&state_circle);
1140 state_manager->add_state(&state_rectangle);
1142 state_manager->add_state(&state_gradient);
1143 state_manager->add_state(&state_eyedrop);
1144 state_manager->add_state(&state_fill);
1146 state_manager->add_state(&state_zoom);
1148 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1149 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1150 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1152 // Enabled for now. Let's see whether they're good enough yet.
1153 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1154 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1156 // Disabled by default - it doesn't work properly?
1157 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1159 studio_init_cb.task(_("Init ModPalette..."));
1160 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1162 studio_init_cb.task(_("Init ModMirror..."));
1163 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1166 studio_init_cb.task(_("Init Setup Dialog..."));
1167 dialog_setup=new studio::Dialog_Setup();
1169 studio_init_cb.task(_("Init Input Dialog..."));
1170 dialog_input=new Gtk::InputDialog();
1171 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1172 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1174 studio_init_cb.task(_("Init auto recovery..."));
1175 auto_recover=new AutoRecover();
1177 studio_init_cb.amount_complete(9250,10000);
1178 studio_init_cb.task(_("Loading Settings..."));
1180 studio_init_cb.task(_("Checking auto-recover..."));
1182 studio_init_cb.amount_complete(9900,10000);
1184 if(auto_recover->recovery_needed())
1186 splash_screen.hide();
1188 get_ui_interface()->yes_no(
1190 _("Synfig Studio seems to have crashed\n"
1191 "before you could save all your files.\n"
1192 "Would you like to re-open those files\n"
1193 "and recover your unsaved changes?")
1194 )==synfigapp::UIInterface::RESPONSE_YES
1197 if(!auto_recover->recover())
1199 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1202 get_ui_interface()->error(
1203 _("Synfig Studio has attempted to recover\n"
1204 "from a previous crash. The files that it has\n"
1205 "recovered are NOT YET SAVED. It would be a good\n"
1206 "idea to review them and save them now.")
1209 splash_screen.show();
1212 // Look for any files given on the command line,
1213 // and load them if found.
1214 bool opened_any = false;
1215 for(;*argc>=1;(*argc)--)
1216 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1218 studio_init_cb.task(_("Loading files..."));
1219 splash_screen.hide();
1220 open((*argv)[*argc]);
1222 splash_screen.show();
1225 // if no file was specified to be opened, create a new document to help new users get started more easily
1226 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1229 studio_init_cb.task(_("Done."));
1230 studio_init_cb.amount_complete(10000,10000);
1236 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1240 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1244 StateManager* App::get_state_manager() { return state_manager; }
1248 shutdown_in_progress=true;
1252 synfigapp::Main::settings().remove_domain("pref");
1254 selected_instance=0;
1256 // Unload all of the modules
1257 for(;!module_list_.empty();module_list_.pop_back())
1260 delete state_manager;
1264 delete auto_recover;
1270 // studio::App::iteration(false);
1274 // studio::App::iteration(false);
1276 // studio::App::iteration(false);
1278 delete dialog_setup;
1280 delete dialog_gradient;
1282 delete dialog_color;
1284 delete dialog_input;
1286 delete dock_manager;
1288 instance_list.clear();
1290 // studio::App::iteration(false);
1294 App::get_user_app_directory()
1296 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1300 App::get_config_file(const synfig::String& file)
1302 return Glib::build_filename(get_user_app_directory(),file);
1306 App::add_recent_file(const std::string &file_name)
1308 std::string filename(file_name);
1310 assert(!filename.empty());
1312 if(filename.empty())
1315 // Toss out any "hidden" files
1316 if(basename(filename)[0]=='.')
1319 // If we aren't an absolute path, turn ourselves into one
1320 if(!is_absolute_path(filename))
1321 filename=absolute_path(filename);
1323 list<string>::iterator iter;
1324 // Check to see if the file is already on the list.
1325 // If it is, then remove it from the list
1326 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1329 recent_files.erase(iter);
1334 // Push the filename to the front of the list
1335 recent_files.push_front(filename);
1337 // Clean out the files at the end of the list.
1338 while(recent_files.size()>(unsigned)get_max_recent_files())
1339 recent_files.pop_back();
1341 signal_recent_files_changed_();
1346 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1349 App::get_time_format()
1351 return _App_time_format;
1355 App::set_time_format(synfig::Time::Format x)
1362 App::save_settings()
1367 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1368 setlocale(LC_NUMERIC, "C");
1370 std::string filename=get_config_file("accelrc");
1371 Gtk::AccelMap::save(filename);
1374 std::string filename=get_config_file("recentfiles");
1376 std::ofstream file(filename.c_str());
1380 synfig::warning("Unable to save %s",filename.c_str());
1384 list<string>::reverse_iterator iter;
1386 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1390 std::string filename=get_config_file("settings");
1391 synfigapp::Main::settings().save_to_file(filename);
1392 setlocale(LC_NUMERIC,old_locale);
1396 synfig::warning("Caught exception when attempting to save settings.");
1401 App::load_settings()
1406 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1407 setlocale(LC_NUMERIC, "C");
1409 std::string filename=get_config_file("accelrc");
1410 Gtk::AccelMap::load(filename);
1413 std::string filename=get_config_file("recentfiles");
1415 std::ifstream file(filename.c_str());
1419 std::string recent_file;
1420 getline(file,recent_file);
1421 if(!recent_file.empty())
1422 add_recent_file(recent_file);
1425 std::string filename=get_config_file("settings");
1426 if(!synfigapp::Main::settings().load_from_file(filename))
1428 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1429 //if(!synfigapp::Main::settings().load_from_file(filename))
1431 gamma.set_gamma(1.0/2.2);
1432 reset_initial_window_configuration();
1435 setlocale(LC_NUMERIC,old_locale);
1439 synfig::warning("Caught exception when attempting to load settings.");
1444 App::reset_initial_window_configuration()
1446 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1447 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1448 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1449 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1450 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1451 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1452 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1453 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1454 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1455 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1456 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1457 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1458 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1459 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1463 App::shutdown_request(GdkEventAny*)
1467 //return !shutdown_in_progress;
1473 if(shutdown_in_progress)return;
1476 get_ui_interface()->task(_("Quit Request"));
1479 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1483 std::list<etl::handle<Instance> >::iterator iter;
1484 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1486 if(!(*iter)->safe_close())
1490 if((*iter)->synfigapp::Instance::get_action_count())
1492 handle<synfigapp::UIInterface> uim;
1493 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1495 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1496 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1498 case synfigapp::UIInterface::RESPONSE_NO:
1500 case synfigapp::UIInterface::RESPONSE_YES:
1503 case synfigapp::UIInterface::RESPONSE_CANCEL:
1512 if((*iter)->synfigapp::Instance::is_modified())
1514 handle<synfigapp::UIInterface> uim;
1515 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1517 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() );
1518 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1520 case synfigapp::UIInterface::RESPONSE_NO:
1522 case synfigapp::UIInterface::RESPONSE_YES:
1523 (*iter)->dialog_cvs_commit();
1525 case synfigapp::UIInterface::RESPONSE_CANCEL:
1534 // This next line causes things to crash for some reason
1538 shutdown_in_progress=true;
1540 instance_list.clear();
1542 while(studio::App::events_pending())studio::App::iteration(false);
1545 auto_recover->normal_shutdown();
1547 get_ui_interface()->task(_("Quit Request sent"));
1553 dialog_setup->refresh();
1554 dialog_setup->show();
1557 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1558 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1561 //#define USE_WIN32_FILE_DIALOGS 1
1564 #ifdef USE_WIN32_FILE_DIALOGS
1565 static OPENFILENAME ofn={};
1569 #include <gdk/gdkwin32.h>
1573 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1575 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1577 #ifdef USE_WIN32_FILE_DIALOGS
1578 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1580 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1581 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1582 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1584 ofn.lStructSize=sizeof(OPENFILENAME);
1585 ofn.hwndOwner = hWnd;
1586 ofn.hInstance = hInstance;
1587 ofn.lpstrFilter = szFilter;
1588 // ofn.lpstrCustomFilter=NULL;
1589 // ofn.nMaxCustFilter=0;
1590 // ofn.nFilterIndex=0;
1591 // ofn.lpstrFile=NULL;
1592 ofn.nMaxFile=MAX_PATH;
1593 // ofn.lpstrFileTitle=NULL;
1594 // ofn.lpstrInitialDir=NULL;
1595 // ofn.lpstrTitle=NULL;
1596 ofn.Flags=OFN_HIDEREADONLY;
1597 // ofn.nFileOffset=0;
1598 // ofn.nFileExtension=0;
1599 ofn.lpstrDefExt=TEXT("sif");
1600 // ofn.lCustData = 0l;
1602 // ofn.lpTemplateName=NULL;
1604 CHAR szFilename[MAX_PATH];
1606 strcpy(szFilename,filename.c_str());
1607 strcpy(szTitle,title.c_str());
1609 ofn.lpstrFile=szFilename;
1610 ofn.lpstrFileTitle=szTitle;
1612 if(GetOpenFileName(&ofn))
1614 filename=szFilename;
1620 synfig::String prev_path;
1622 if(!_preferences.get_value(preference, prev_path))
1625 prev_path = absolute_path(prev_path);
1627 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1629 dialog->set_current_folder(prev_path);
1630 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1631 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1633 if (filename.empty())
1634 dialog->set_filename(prev_path);
1635 else if (is_absolute_path(filename))
1636 dialog->set_filename(filename);
1638 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1640 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1641 filename = dialog->get_filename();
1642 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1643 _preferences.set_value(preference, dirname(filename));
1657 GtkWidget *fileselection;
1658 fileselection = gtk_file_selection_new(title.c_str());
1661 if(basename(filename)==filename)
1663 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1666 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1668 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1670 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1671 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1673 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1674 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1676 gtk_widget_show(fileselection);
1684 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1685 _preferences.set_value(preference,dirname(filename));
1689 gtk_widget_destroy(fileselection);
1692 gtk_widget_destroy(fileselection);
1699 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1701 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1703 #if USE_WIN32_FILE_DIALOGS
1704 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1706 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1707 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1708 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1710 ofn.lStructSize=sizeof(OPENFILENAME);
1711 ofn.hwndOwner = hWnd;
1712 ofn.hInstance = hInstance;
1713 ofn.lpstrFilter = szFilter;
1714 // ofn.lpstrCustomFilter=NULL;
1715 // ofn.nMaxCustFilter=0;
1716 // ofn.nFilterIndex=0;
1717 // ofn.lpstrFile=NULL;
1718 ofn.nMaxFile=MAX_PATH;
1719 // ofn.lpstrFileTitle=NULL;
1720 // ofn.lpstrInitialDir=NULL;
1721 // ofn.lpstrTitle=NULL;
1722 ofn.Flags=OFN_OVERWRITEPROMPT;
1723 // ofn.nFileOffset=0;
1724 // ofn.nFileExtension=0;
1725 ofn.lpstrDefExt=TEXT("sif");
1726 // ofn.lCustData = 0l;
1728 // ofn.lpTemplateName=NULL;
1730 CHAR szFilename[MAX_PATH];
1732 strcpy(szFilename,filename.c_str());
1733 strcpy(szTitle,title.c_str());
1735 ofn.lpstrFile=szFilename;
1736 ofn.lpstrFileTitle=szTitle;
1738 if(GetSaveFileName(&ofn))
1740 filename=szFilename;
1741 _preferences.set_value(preference,dirname(filename));
1746 synfig::String prev_path;
1748 if(!_preferences.get_value(preference, prev_path))
1751 prev_path = absolute_path(prev_path);
1753 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1755 dialog->set_current_folder(prev_path);
1756 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1757 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1759 if (filename.empty())
1760 dialog->set_filename(prev_path);
1763 std::string full_path;
1764 if (is_absolute_path(filename))
1765 full_path = filename;
1767 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1769 // select the file if it exists
1770 dialog->set_filename(full_path);
1772 // if the file doesn't exist, put its name into the filename box
1774 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1775 dialog->set_current_name(basename(filename));
1778 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1779 filename = dialog->get_filename();
1780 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1781 _preferences.set_value(preference, dirname(filename));
1792 App::dialog_error_blocking(const std::string &title, const std::string &message)
1794 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1795 dialog.set_title(title);
1801 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1803 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1804 dialog.set_title(title);
1810 App::dialog_yes_no(const std::string &title, const std::string &message)
1815 true // use_separator
1817 Gtk::Label label(message);
1820 dialog.get_vbox()->pack_start(label);
1821 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1822 dialog.add_button(Gtk::StockID("gtk-no"),0);
1824 return dialog.run();
1828 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1833 true // use_separator
1835 Gtk::Label label(message);
1838 dialog.get_vbox()->pack_start(label);
1839 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1840 dialog.add_button(Gtk::StockID("gtk-no"),0);
1841 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1843 return dialog.run();
1847 App::dialog_not_implemented()
1849 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1850 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1855 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1860 true // use_separator
1862 Gtk::Label label(message);
1864 dialog.get_vbox()->pack_start(label);
1867 entry.set_text(text);
1869 entry.set_activates_default(true);
1870 dialog.get_vbox()->pack_start(entry);
1872 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1873 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1874 dialog.set_default_response(Gtk::RESPONSE_OK);
1875 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1878 if(dialog.run()!=Gtk::RESPONSE_OK)
1881 text=entry.get_text();
1890 App::open(std::string filename)
1892 return open_as(filename,filename);
1895 // this is called from autorecover.cpp:
1896 // App::open_as(get_shadow_file_name(filename),filename)
1897 // other than that, 'filename' and 'as' are the same
1899 App::open_as(std::string filename,std::string as)
1902 char long_name[1024];
1903 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1909 OneMoment one_moment;
1911 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1912 if(canvas && get_instance(canvas))
1914 get_instance(canvas)->find_canvas_view(canvas)->present();
1915 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1918 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1920 add_recent_file(as);
1922 handle<Instance> instance(Instance::create(canvas));
1925 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1929 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)")))
1930 instance->dialog_cvs_update();
1934 dialog_error_blocking(_("Error"), x);
1939 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1950 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1951 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1953 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1955 canvas->rend_desc().set_frame_rate(24.0);
1956 canvas->rend_desc().set_time_start(0.0);
1957 canvas->rend_desc().set_time_end(5.0);
1958 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1959 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1960 canvas->rend_desc().set_tl(Vector(-4,2.25));
1961 canvas->rend_desc().set_br(Vector(4,-2.25));
1962 canvas->rend_desc().set_w(480);
1963 canvas->rend_desc().set_h(270);
1964 canvas->rend_desc().set_antialias(1);
1965 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1966 canvas->set_file_name(file_name);
1968 handle<Instance> instance = Instance::create(canvas);
1970 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1971 instance->find_canvas_view(canvas)->canvas_properties.present();
1977 string filename="*.sif";
1979 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
1981 // If the filename still has wildcards, then we should
1982 // continue looking for the file we want
1983 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1989 get_ui_interface()->error(_("Unable to open file"));
1994 App::set_selected_instance(etl::loose_handle<Instance> instance)
1996 /* if(get_selected_instance()==instance)
1998 selected_instance=instance;
1999 signal_instance_selected()(instance);
2005 selected_instance=instance;
2006 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2010 instance->focus(instance->get_canvas());
2013 set_selected_canvas_view(0);
2015 signal_instance_selected()(instance);
2019 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2021 selected_canvas_view=canvas_view;
2022 signal_canvas_view_focus()(selected_canvas_view);
2025 selected_instance=canvas_view->get_instance();
2026 signal_instance_selected()(canvas_view->get_instance());
2029 if(get_selected_canvas_view()==canvas_view)
2031 signal_canvas_view_focus()(selected_canvas_view);
2032 signal_instance_selected()(canvas_view->get_instance());
2035 selected_canvas_view=canvas_view;
2036 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2037 set_selected_instance(canvas_view->get_instance());
2038 signal_canvas_view_focus()(selected_canvas_view);
2042 etl::loose_handle<Instance>
2043 App::get_instance(etl::handle<synfig::Canvas> canvas)
2045 if(!canvas) return 0;
2046 canvas=canvas->get_root();
2048 std::list<etl::handle<Instance> >::iterator iter;
2049 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2051 if((*iter)->get_canvas()==canvas)
2067 if(selected_instance)
2068 selected_instance->undo();
2074 if(selected_instance)
2075 selected_instance->redo();
2079 studio::App::get_base_path()
2081 return app_base_path_;