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 if(auto_recover->recovery_needed())
1179 splash_screen.hide();
1181 get_ui_interface()->yes_no(
1183 _("Synfig Studio seems to have crashed\n"
1184 "before you could save all your files.\n"
1185 "Would you like to re-open those files\n"
1186 "and recover your unsaved changes?")
1187 )==synfigapp::UIInterface::RESPONSE_YES
1190 if(!auto_recover->recover())
1192 get_ui_interface()->error(_("Unable to fully 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.")
1202 splash_screen.show();
1205 // Look for any files given on the command line,
1206 // and load them if found.
1207 bool opened_any = false;
1208 for(;*argc>=1;(*argc)--)
1209 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1211 studio_init_cb.task(_("Loading files..."));
1212 splash_screen.hide();
1213 open((*argv)[*argc]);
1215 splash_screen.show();
1218 // if no file was specified to be opened, create a new document to help new users get started more easily
1219 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1222 studio_init_cb.task(_("Done."));
1223 studio_init_cb.amount_complete(10000,10000);
1229 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1233 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1237 StateManager* App::get_state_manager() { return state_manager; }
1241 shutdown_in_progress=true;
1245 synfigapp::Main::settings().remove_domain("pref");
1247 selected_instance=0;
1249 // Unload all of the modules
1250 for(;!module_list_.empty();module_list_.pop_back())
1253 delete state_manager;
1257 delete auto_recover;
1263 // studio::App::iteration(false);
1267 // studio::App::iteration(false);
1269 // studio::App::iteration(false);
1271 delete dialog_setup;
1273 delete dialog_gradient;
1275 delete dialog_color;
1277 delete dialog_input;
1279 delete dock_manager;
1281 instance_list.clear();
1283 // studio::App::iteration(false);
1287 App::get_user_app_directory()
1289 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1293 App::get_config_file(const synfig::String& file)
1295 return Glib::build_filename(get_user_app_directory(),file);
1299 App::add_recent_file(const std::string &file_name)
1301 std::string filename(file_name);
1303 assert(!filename.empty());
1305 if(filename.empty())
1308 // Toss out any "hidden" files
1309 if(basename(filename)[0]=='.')
1312 // If we aren't an absolute path, turn ourselves into one
1313 if(!is_absolute_path(filename))
1314 filename=absolute_path(filename);
1316 list<string>::iterator iter;
1317 // Check to see if the file is already on the list.
1318 // If it is, then remove it from the list
1319 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1322 recent_files.erase(iter);
1327 // Push the filename to the front of the list
1328 recent_files.push_front(filename);
1330 // Clean out the files at the end of the list.
1331 while(recent_files.size()>(unsigned)get_max_recent_files())
1332 recent_files.pop_back();
1334 signal_recent_files_changed_();
1339 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1342 App::get_time_format()
1344 return _App_time_format;
1348 App::set_time_format(synfig::Time::Format x)
1355 App::save_settings()
1360 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1361 setlocale(LC_NUMERIC, "C");
1363 std::string filename=get_config_file("accelrc");
1364 Gtk::AccelMap::save(filename);
1367 std::string filename=get_config_file("recentfiles");
1369 std::ofstream file(filename.c_str());
1373 synfig::warning("Unable to save %s",filename.c_str());
1377 list<string>::reverse_iterator iter;
1379 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1383 std::string filename=get_config_file("settings");
1384 synfigapp::Main::settings().save_to_file(filename);
1385 setlocale(LC_NUMERIC,old_locale);
1389 synfig::warning("Caught exception when attempting to save settings.");
1394 App::load_settings()
1399 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1400 setlocale(LC_NUMERIC, "C");
1402 std::string filename=get_config_file("accelrc");
1403 Gtk::AccelMap::load(filename);
1406 std::string filename=get_config_file("recentfiles");
1408 std::ifstream file(filename.c_str());
1412 std::string recent_file;
1413 getline(file,recent_file);
1414 if(!recent_file.empty())
1415 add_recent_file(recent_file);
1418 std::string filename=get_config_file("settings");
1419 if(!synfigapp::Main::settings().load_from_file(filename))
1421 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1422 //if(!synfigapp::Main::settings().load_from_file(filename))
1424 gamma.set_gamma(1.0/2.2);
1425 reset_initial_window_configuration();
1428 setlocale(LC_NUMERIC,old_locale);
1432 synfig::warning("Caught exception when attempting to load settings.");
1437 App::reset_initial_window_configuration()
1439 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1440 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1441 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1442 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1443 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1444 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1445 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1446 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1447 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1448 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1449 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1450 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1451 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1452 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1456 App::shutdown_request(GdkEventAny*)
1460 //return !shutdown_in_progress;
1466 if(shutdown_in_progress)return;
1469 get_ui_interface()->task(_("Quit Request"));
1472 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1476 std::list<etl::handle<Instance> >::iterator iter;
1477 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1479 if(!(*iter)->safe_close())
1483 if((*iter)->synfigapp::Instance::get_action_count())
1485 handle<synfigapp::UIInterface> uim;
1486 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1488 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1489 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1491 case synfigapp::UIInterface::RESPONSE_NO:
1493 case synfigapp::UIInterface::RESPONSE_YES:
1496 case synfigapp::UIInterface::RESPONSE_CANCEL:
1505 if((*iter)->synfigapp::Instance::is_modified())
1507 handle<synfigapp::UIInterface> uim;
1508 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1510 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() );
1511 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1513 case synfigapp::UIInterface::RESPONSE_NO:
1515 case synfigapp::UIInterface::RESPONSE_YES:
1516 (*iter)->dialog_cvs_commit();
1518 case synfigapp::UIInterface::RESPONSE_CANCEL:
1527 // This next line causes things to crash for some reason
1531 shutdown_in_progress=true;
1533 instance_list.clear();
1535 while(studio::App::events_pending())studio::App::iteration(false);
1538 auto_recover->normal_shutdown();
1540 get_ui_interface()->task(_("Quit Request sent"));
1546 dialog_setup->refresh();
1547 dialog_setup->show();
1550 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1551 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1554 //#define USE_WIN32_FILE_DIALOGS 1
1557 #ifdef USE_WIN32_FILE_DIALOGS
1558 static OPENFILENAME ofn={};
1562 #include <gdk/gdkwin32.h>
1566 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1568 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1570 #ifdef USE_WIN32_FILE_DIALOGS
1571 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1573 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1574 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1575 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1577 ofn.lStructSize=sizeof(OPENFILENAME);
1578 ofn.hwndOwner = hWnd;
1579 ofn.hInstance = hInstance;
1580 ofn.lpstrFilter = szFilter;
1581 // ofn.lpstrCustomFilter=NULL;
1582 // ofn.nMaxCustFilter=0;
1583 // ofn.nFilterIndex=0;
1584 // ofn.lpstrFile=NULL;
1585 ofn.nMaxFile=MAX_PATH;
1586 // ofn.lpstrFileTitle=NULL;
1587 // ofn.lpstrInitialDir=NULL;
1588 // ofn.lpstrTitle=NULL;
1589 ofn.Flags=OFN_HIDEREADONLY;
1590 // ofn.nFileOffset=0;
1591 // ofn.nFileExtension=0;
1592 ofn.lpstrDefExt=TEXT("sif");
1593 // ofn.lCustData = 0l;
1595 // ofn.lpTemplateName=NULL;
1597 CHAR szFilename[MAX_PATH];
1599 strcpy(szFilename,filename.c_str());
1600 strcpy(szTitle,title.c_str());
1602 ofn.lpstrFile=szFilename;
1603 ofn.lpstrFileTitle=szTitle;
1605 if(GetOpenFileName(&ofn))
1607 filename=szFilename;
1613 synfig::String prev_path;
1615 if(!_preferences.get_value(preference, prev_path))
1618 prev_path = absolute_path(prev_path);
1620 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1622 dialog->set_current_folder(prev_path);
1623 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1624 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1626 if (filename.empty())
1627 dialog->set_filename(prev_path);
1628 else if (is_absolute_path(filename))
1629 dialog->set_filename(filename);
1631 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1633 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1634 filename = dialog->get_filename();
1635 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1636 _preferences.set_value(preference, dirname(filename));
1650 GtkWidget *fileselection;
1651 fileselection = gtk_file_selection_new(title.c_str());
1654 if(basename(filename)==filename)
1656 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1659 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1661 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1663 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1664 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1666 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1667 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1669 gtk_widget_show(fileselection);
1677 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1678 _preferences.set_value(preference,dirname(filename));
1682 gtk_widget_destroy(fileselection);
1685 gtk_widget_destroy(fileselection);
1692 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1694 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1696 #if USE_WIN32_FILE_DIALOGS
1697 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1699 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1700 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1701 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1703 ofn.lStructSize=sizeof(OPENFILENAME);
1704 ofn.hwndOwner = hWnd;
1705 ofn.hInstance = hInstance;
1706 ofn.lpstrFilter = szFilter;
1707 // ofn.lpstrCustomFilter=NULL;
1708 // ofn.nMaxCustFilter=0;
1709 // ofn.nFilterIndex=0;
1710 // ofn.lpstrFile=NULL;
1711 ofn.nMaxFile=MAX_PATH;
1712 // ofn.lpstrFileTitle=NULL;
1713 // ofn.lpstrInitialDir=NULL;
1714 // ofn.lpstrTitle=NULL;
1715 ofn.Flags=OFN_OVERWRITEPROMPT;
1716 // ofn.nFileOffset=0;
1717 // ofn.nFileExtension=0;
1718 ofn.lpstrDefExt=TEXT("sif");
1719 // ofn.lCustData = 0l;
1721 // ofn.lpTemplateName=NULL;
1723 CHAR szFilename[MAX_PATH];
1725 strcpy(szFilename,filename.c_str());
1726 strcpy(szTitle,title.c_str());
1728 ofn.lpstrFile=szFilename;
1729 ofn.lpstrFileTitle=szTitle;
1731 if(GetSaveFileName(&ofn))
1733 filename=szFilename;
1734 _preferences.set_value(preference,dirname(filename));
1739 synfig::String prev_path;
1741 if(!_preferences.get_value(preference, prev_path))
1744 prev_path = absolute_path(prev_path);
1746 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1748 dialog->set_current_folder(prev_path);
1749 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1750 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1752 if (filename.empty())
1753 dialog->set_filename(prev_path);
1756 std::string full_path;
1757 if (is_absolute_path(filename))
1758 full_path = filename;
1760 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1762 // select the file if it exists
1763 dialog->set_filename(full_path);
1765 // if the file doesn't exist, put its name into the filename box
1767 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1768 dialog->set_current_name(basename(filename));
1771 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1772 filename = dialog->get_filename();
1773 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1774 _preferences.set_value(preference, dirname(filename));
1785 App::dialog_error_blocking(const std::string &title, const std::string &message)
1787 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1788 dialog.set_title(title);
1794 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1796 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1797 dialog.set_title(title);
1803 App::dialog_yes_no(const std::string &title, const std::string &message)
1808 true // use_separator
1810 Gtk::Label label(message);
1813 dialog.get_vbox()->pack_start(label);
1814 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1815 dialog.add_button(Gtk::StockID("gtk-no"),0);
1817 return dialog.run();
1821 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1826 true // use_separator
1828 Gtk::Label label(message);
1831 dialog.get_vbox()->pack_start(label);
1832 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1833 dialog.add_button(Gtk::StockID("gtk-no"),0);
1834 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1836 return dialog.run();
1840 App::dialog_not_implemented()
1842 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1843 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1848 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1853 true // use_separator
1855 Gtk::Label label(message);
1857 dialog.get_vbox()->pack_start(label);
1860 entry.set_text(text);
1862 entry.set_activates_default(true);
1863 dialog.get_vbox()->pack_start(entry);
1865 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1866 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1867 dialog.set_default_response(Gtk::RESPONSE_OK);
1868 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1871 if(dialog.run()!=Gtk::RESPONSE_OK)
1874 text=entry.get_text();
1883 App::open(std::string filename)
1885 return open_as(filename,filename);
1888 // this is called from autorecover.cpp:
1889 // App::open_as(get_shadow_file_name(filename),filename)
1890 // other than that, 'filename' and 'as' are the same
1892 App::open_as(std::string filename,std::string as)
1895 char long_name[1024];
1896 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1902 OneMoment one_moment;
1904 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1905 if(canvas && get_instance(canvas))
1907 get_instance(canvas)->find_canvas_view(canvas)->present();
1908 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1911 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1913 add_recent_file(as);
1915 handle<Instance> instance(Instance::create(canvas));
1918 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1922 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)")))
1923 instance->dialog_cvs_update();
1927 dialog_error_blocking(_("Error"), x);
1932 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1943 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1944 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1946 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1948 canvas->rend_desc().set_frame_rate(24.0);
1949 canvas->rend_desc().set_time_start(0.0);
1950 canvas->rend_desc().set_time_end(5.0);
1951 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1952 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1953 canvas->rend_desc().set_tl(Vector(-4,2.25));
1954 canvas->rend_desc().set_br(Vector(4,-2.25));
1955 canvas->rend_desc().set_w(480);
1956 canvas->rend_desc().set_h(270);
1957 canvas->rend_desc().set_antialias(1);
1958 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1959 canvas->set_file_name(file_name);
1961 handle<Instance> instance = Instance::create(canvas);
1963 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1964 instance->find_canvas_view(canvas)->canvas_properties.present();
1970 string filename="*.sif";
1972 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
1974 // If the filename still has wildcards, then we should
1975 // continue looking for the file we want
1976 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1982 get_ui_interface()->error(_("Unable to open file"));
1987 App::set_selected_instance(etl::loose_handle<Instance> instance)
1989 /* if(get_selected_instance()==instance)
1991 selected_instance=instance;
1992 signal_instance_selected()(instance);
1998 selected_instance=instance;
1999 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2003 instance->focus(instance->get_canvas());
2006 set_selected_canvas_view(0);
2008 signal_instance_selected()(instance);
2012 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2014 selected_canvas_view=canvas_view;
2015 signal_canvas_view_focus()(selected_canvas_view);
2018 selected_instance=canvas_view->get_instance();
2019 signal_instance_selected()(canvas_view->get_instance());
2022 if(get_selected_canvas_view()==canvas_view)
2024 signal_canvas_view_focus()(selected_canvas_view);
2025 signal_instance_selected()(canvas_view->get_instance());
2028 selected_canvas_view=canvas_view;
2029 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2030 set_selected_instance(canvas_view->get_instance());
2031 signal_canvas_view_focus()(selected_canvas_view);
2035 etl::loose_handle<Instance>
2036 App::get_instance(etl::handle<synfig::Canvas> canvas)
2038 if(!canvas) return 0;
2039 canvas=canvas->get_root();
2041 std::list<etl::handle<Instance> >::iterator iter;
2042 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2044 if((*iter)->get_canvas()==canvas)
2060 if(selected_instance)
2061 selected_instance->undo();
2067 if(selected_instance)
2068 selected_instance->redo();
2072 studio::App::get_base_path()
2074 return app_base_path_;