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>
55 #include <synfig/savecanvas.h>
61 #include "canvasview.h"
62 #include "dialog_setup.h"
63 #include "dialog_gradient.h"
64 #include "dialog_color.h"
67 #include "onemoment.h"
69 #include "dockmanager.h"
71 #include "state_eyedrop.h"
72 #include "state_normal.h"
73 #include "state_draw.h"
74 #include "state_fill.h"
75 #include "state_bline.h"
76 #include "state_polygon.h"
77 #include "state_sketch.h"
78 #include "state_gradient.h"
79 #include "state_circle.h"
80 #include "state_rectangle.h"
81 #include "state_smoothmove.h"
82 #include "state_scale.h"
83 #include "state_width.h"
84 #include "state_rotate.h"
85 #include "state_zoom.h"
87 #include "devicetracker.h"
88 #include "dialog_tooloptions.h"
89 #include "widget_enum.h"
91 #include "autorecover.h"
93 #include <synfigapp/settings.h>
94 #include "dock_history.h"
95 #include "dock_canvases.h"
96 #include "dock_keyframes.h"
97 #include "dock_layers.h"
98 #include "dock_params.h"
99 #include "dock_metadata.h"
100 #include "dock_children.h"
101 #include "dock_info.h"
102 #include "dock_navigator.h"
103 #include "dock_layergroups.h"
104 #include "dock_timetrack.h"
105 #include "dock_curves.h"
107 #include "mod_palette/mod_palette.h"
108 #include "mod_mirror/mod_mirror.h"
110 #include <sys/stat.h>
116 #include "statemanager.h"
123 #define _WIN32_WINNT 0x0500
126 #include <gtkmm/accelmap.h>
127 #include <gtkmm/filechooser.h>
128 #include <gtkmm/filechooserdialog.h>
134 /* === U S I N G =========================================================== */
138 using namespace synfig;
139 using namespace studio;
141 /* === M A C R O S ========================================================= */
143 #ifndef SYNFIG_USER_APP_DIR
145 #define SYNFIG_USER_APP_DIR "Library/Synfig"
146 #elif defined(_WIN32)
147 #define SYNFIG_USER_APP_DIR "Synfig"
149 #define SYNFIG_USER_APP_DIR ".synfig"
154 #define DPM2DPI(x) (float(x)/39.3700787402f)
155 #define DPI2DPM(x) (float(x)*39.3700787402f)
161 # define IMAGE_DIR "share\\pixmaps"
166 # define IMAGE_DIR "/usr/local/share/pixmaps"
170 # define IMAGE_EXT "tif"
173 #include <synfigapp/main.h>
175 /* === S I G N A L S ======================================================= */
177 static sigc::signal<void> signal_present_all_;
179 App::signal_present_all() { return signal_present_all_; }
181 static sigc::signal<void> signal_recent_files_changed_;
183 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
185 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
186 sigc::signal<void,etl::loose_handle<CanvasView> >&
187 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
189 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
190 sigc::signal<void,etl::handle<Instance> >&
191 App::signal_instance_selected() { return signal_instance_selected_; }
193 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
194 sigc::signal<void,etl::handle<Instance> >&
195 App::signal_instance_created() { return signal_instance_created_; }
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_deleted() { return signal_instance_deleted_; }
201 /* === G L O B A L S ======================================================= */
203 static std::list<std::string> recent_files;
204 const std::list<std::string>& App::get_recent_files() { return recent_files; }
206 int App::Busy::count;
207 bool App::shutdown_in_progress;
209 synfig::Gamma App::gamma;
211 Glib::RefPtr<studio::UIManager> App::ui_manager_;
213 synfig::Distance::System App::distance_system;
215 studio::Dialog_Setup* App::dialog_setup;
217 etl::handle< studio::ModPalette > mod_palette_;
218 //studio::Dialog_Palette* App::dialog_palette;
220 std::list<etl::handle<Instance> > App::instance_list;
222 static etl::handle<synfigapp::UIInterface> ui_interface_;
223 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
225 etl::handle<Instance> App::selected_instance;
226 etl::handle<CanvasView> App::selected_canvas_view;
228 studio::About *studio::App::about=NULL;
230 studio::Toolbox *studio::App::toolbox=NULL;
232 studio::AutoRecover *studio::App::auto_recover=NULL;
234 studio::IPC *ipc=NULL;
236 studio::DockManager* studio::App::dock_manager=0;
238 studio::DeviceTracker* studio::App::device_tracker=0;
240 studio::Dialog_Gradient* studio::App::dialog_gradient;
242 studio::Dialog_Color* studio::App::dialog_color;
244 Gtk::InputDialog* studio::App::dialog_input;
246 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
248 studio::Dock_History* dock_history;
249 studio::Dock_Canvases* dock_canvases;
250 studio::Dock_Keyframes* dock_keyframes;
251 studio::Dock_Layers* dock_layers;
252 studio::Dock_Params* dock_params;
253 studio::Dock_MetaData* dock_meta_data;
254 studio::Dock_Children* dock_children;
255 studio::Dock_Info* dock_info;
256 studio::Dock_LayerGroups* dock_layer_groups;
257 studio::Dock_Navigator* dock_navigator;
258 studio::Dock_Timetrack* dock_timetrack;
259 studio::Dock_Curves* dock_curves;
261 std::list< etl::handle< studio::Module > > module_list_;
263 bool studio::App::use_colorspace_gamma=true;
264 bool studio::App::single_threaded=false;
266 static int max_recent_files_=25;
267 int studio::App::get_max_recent_files() { return max_recent_files_; }
268 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
270 static synfig::String app_base_path_;
275 really_delete_widget(Gtk::Widget *widget)
277 // synfig::info("really delete %p", (void*)widget);
282 // nasty workaround - when we've finished with a popup menu, we want to delete it
283 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
284 // so schedule the real delete to happen in 50ms, giving the action a chance to run
286 delete_widget(Gtk::Widget *widget)
288 // synfig::info("delete %p", (void*)widget);
289 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
292 }; // END of namespace studio
293 studio::StateManager* state_manager;
298 class GlobalUIInterface : public synfigapp::UIInterface
302 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
307 true // use_separator
309 Gtk::Label label(message);
312 dialog.get_vbox()->pack_start(label);
313 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
314 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
316 dialog.set_default_response(dflt);
318 return (Response)dialog.run();
320 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
325 true // use_separator
327 Gtk::Label label(message);
330 dialog.get_vbox()->pack_start(label);
331 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
332 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
333 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
335 dialog.set_default_response(dflt);
337 return (Response)dialog.run();
339 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
344 true // use_separator
346 Gtk::Label label(message);
349 dialog.get_vbox()->pack_start(label);
350 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
351 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
353 dialog.set_default_response(dflt);
355 return (Response)dialog.run();
359 task(const std::string &task)
361 std::cerr<<task<<std::endl;
362 while(studio::App::events_pending())studio::App::iteration(false);
367 error(const std::string &err)
369 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
376 warning(const std::string &err)
378 std::cerr<<"warning: "<<err<<std::endl;
379 while(studio::App::events_pending())studio::App::iteration(false);
384 amount_complete(int /*current*/, int /*total*/)
386 while(studio::App::events_pending())studio::App::iteration(false);
391 /* === P R O C E D U R E S ================================================= */
395 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
397 action_group_list.push_back(action_group);
398 Gtk::UIManager::insert_action_group(action_group, pos);
402 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
404 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
405 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
406 if(*iter==action_group)
408 action_group_list.erase(iter);
409 Gtk::UIManager::remove_action_group(action_group);
412 synfig::error("Unable to find action group");
416 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
418 ui_manager->insert_action_group(group,0);
420 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
421 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
423 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
425 if(*iter && (*iter)->get_name()!="menus")
427 synfig::info("Removing action group "+(*iter)->get_name());
428 ui_manager->remove_action_group(*iter);
431 ui_manager->insert_action_group(group,0);
433 for(;!prev_groups.empty();prev_groups.pop_front())
435 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
436 ui_manager->insert_action_group(prev_groups.front(),1);
440 class Preferences : public synfigapp::Settings
443 virtual bool get_value(const synfig::String& key, synfig::String& value)const
447 value=strprintf("%f %f %f %f",
448 App::gamma.get_gamma_r(),
449 App::gamma.get_gamma_g(),
450 App::gamma.get_gamma_b(),
451 App::gamma.get_black_level()
455 if(key=="time_format")
457 value=strprintf("%i",App::get_time_format());
460 if(key=="file_history.size")
462 value=strprintf("%i",App::get_max_recent_files());
465 if(key=="use_colorspace_gamma")
467 value=strprintf("%i",(int)App::use_colorspace_gamma);
470 if(key=="distance_system")
472 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
475 if(key=="single_threaded")
477 value=strprintf("%i",(int)App::single_threaded);
480 if(key=="auto_recover_backup_interval")
482 value=strprintf("%i",App::auto_recover->get_timeout());
486 return synfigapp::Settings::get_value(key,value);
489 virtual bool set_value(const synfig::String& key,const synfig::String& value)
495 strscanf(value,"%f %f %f %f",
502 App::gamma.set_all(r,g,b,blk);
506 if(key=="time_format")
508 int i(atoi(value.c_str()));
509 App::set_time_format(static_cast<synfig::Time::Format>(i));
512 if(key=="auto_recover_backup_interval")
514 int i(atoi(value.c_str()));
515 App::auto_recover->set_timeout(i);
518 if(key=="file_history.size")
520 int i(atoi(value.c_str()));
521 App::set_max_recent_files(i);
524 if(key=="use_colorspace_gamma")
526 int i(atoi(value.c_str()));
527 App::use_colorspace_gamma=i;
530 if(key=="distance_system")
532 App::distance_system=Distance::ident_system(value);;
535 if(key=="single_threaded")
537 int i(atoi(value.c_str()));
538 App::single_threaded=i;
542 return synfigapp::Settings::set_value(key,value);
545 virtual KeyList get_key_list()const
547 KeyList ret(synfigapp::Settings::get_key_list());
548 ret.push_back("gamma");
549 ret.push_back("time_format");
550 ret.push_back("distance_system");
551 ret.push_back("file_history.size");
552 ret.push_back("use_colorspace_gamma");
553 ret.push_back("single_threaded");
554 ret.push_back("auto_recover_backup_interval");
559 static ::Preferences _preferences;
564 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
566 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
568 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
570 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
571 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
572 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
573 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
574 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
575 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
576 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
577 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
578 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
579 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
580 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
581 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
582 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
584 // Add the synfigapp actions...
585 synfigapp::Action::Book::iterator iter;
586 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
588 actions_action_group->add(Gtk::Action::create(
589 "action-"+iter->second.name,
590 get_action_stock_id(iter->second),
591 iter->second.local_name,iter->second.local_name
595 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
596 #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); }
597 #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); }
599 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
600 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
601 DEFINE_ACTION("new", Gtk::Stock::NEW);
602 DEFINE_ACTION("open", Gtk::Stock::OPEN);
603 DEFINE_ACTION("save", Gtk::Stock::SAVE);
604 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
605 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
606 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
607 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
608 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
609 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
610 DEFINE_ACTION("import", _("Import"));
611 DEFINE_ACTION("render", _("Render"));
612 DEFINE_ACTION("preview", _("Preview"));
613 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
614 DEFINE_ACTION("sound", _("Sound File"));
615 DEFINE_ACTION("options", _("Options"));
616 DEFINE_ACTION("close", _("Close View"));
617 DEFINE_ACTION("close-document", _("Close Document"));
618 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
621 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
622 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
623 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
624 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
625 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
626 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
627 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
628 DEFINE_ACTION("properties", _("Properties"));
630 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
631 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
632 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
633 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
634 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
635 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
636 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
637 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
638 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
639 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
640 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
641 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
642 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
643 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
644 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
645 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
646 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
647 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
648 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
649 DEFINE_ACTION("play", _("Play"));
650 // DEFINE_ACTION("pause", _("Pause"));
651 DEFINE_ACTION("stop", _("Stop"));
652 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
653 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
654 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
655 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
656 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
657 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
658 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
659 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
660 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
661 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
662 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
663 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
664 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
665 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
666 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
667 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
668 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
669 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
670 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
671 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
672 DEFINE_ACTION("seek-end", _("Seek to End"));
674 DEFINE_ACTION("action-group_add", _("Add group"));
676 DEFINE_ACTION("canvas-new", _("New Canvas"));
678 DEFINE_ACTION("amount-inc", _("Increase Amount"));
679 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
684 // Set up synfigapp actions
686 synfigapp::Action::Book::iterator iter;
688 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
690 Gtk::StockID stock_id;
692 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
694 //Gtk::Image* image(manage(new Gtk::Image()));
695 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
696 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
697 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
698 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
699 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
700 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
701 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
702 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
703 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
704 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
706 actions_action_group->add(Gtk::Action::create(
707 "action-"+iter->second.name,
709 iter->second.local_name,iter->second.local_name
717 Glib::ustring ui_info =
719 " <popup name='menu-toolbox' action='menu-toolbox'>"
720 " <menu action='menu-file'>"
723 " <popup name='menu-main' action='menu-main'>"
724 " <menu action='menu-file'>"
725 " <menuitem action='new' />"
726 " <menuitem action='open' />"
727 " <menuitem action='save' />"
728 " <menuitem action='save-as' />"
729 " <menuitem action='revert' />"
730 " <separator name='bleh01'/>"
731 " <menuitem action='cvs-add' />"
732 " <menuitem action='cvs-update' />"
733 " <menuitem action='cvs-commit' />"
734 " <menuitem action='cvs-revert' />"
735 " <separator name='bleh02'/>"
736 " <menuitem action='import' />"
737 " <separator name='bleh03'/>"
738 " <menuitem action='render' />"
739 " <menuitem action='preview' />"
740 " <menuitem action='sound' />"
741 " <separator name='bleh04'/>"
742 " <menuitem action='options' />"
743 " <menuitem action='close' />"
744 " <menuitem action='close-document' />"
745 " <menuitem action='quit' />"
747 " <menu action='menu-edit'>"
748 " <menuitem action='undo'/>"
749 " <menuitem action='redo'/>"
750 " <separator name='bleh05'/>"
751 " <menuitem action='cut'/>"
752 " <menuitem action='copy'/>"
753 " <menuitem action='paste'/>"
754 " <separator name='bleh06'/>"
755 " <menuitem action='select-all-ducks'/>"
756 " <menuitem action='unselect-all-layers'/>"
757 " <separator name='bleh07'/>"
758 " <menuitem action='properties'/>"
760 " <menu action='menu-view'>"
761 " <menu action='menu-duck-mask'>"
762 " <menuitem action='mask-position-ducks' />"
763 " <menuitem action='mask-vertex-ducks' />"
764 " <menuitem action='mask-tangent-ducks' />"
765 " <menuitem action='mask-radius-ducks' />"
766 " <menuitem action='mask-width-ducks' />"
767 " <menuitem action='mask-angle-ducks' />"
769 " <menu action='menu-preview-quality'>"
770 " <menuitem action='quality-00' />"
771 " <menuitem action='quality-01' />"
772 " <menuitem action='quality-02' />"
773 " <menuitem action='quality-03' />"
774 " <menuitem action='quality-04' />"
775 " <menuitem action='quality-05' />"
776 " <menuitem action='quality-06' />"
777 " <menuitem action='quality-07' />"
778 " <menuitem action='quality-08' />"
779 " <menuitem action='quality-09' />"
780 " <menuitem action='quality-10' />"
782 " <menu action='menu-lowres-pixel'>"
783 " <menuitem action='decrease-low-res-pixel-size'/>"
784 " <menuitem action='increase-low-res-pixel-size'/>"
785 " <separator name='pixel-size-separator'/>"
788 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
789 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
793 " <separator name='bleh08'/>"
794 " <menuitem action='play'/>"
795 //" <menuitem action='pause'/>"
796 " <menuitem action='stop'/>"
797 " <menuitem action='dialog-flipbook'/>"
798 " <separator name='bleh09'/>"
799 " <menuitem action='toggle-grid-show'/>"
800 " <menuitem action='toggle-grid-snap'/>"
801 " <menuitem action='toggle-guide-show'/>"
802 " <menuitem action='toggle-low-res'/>"
803 " <menuitem action='toggle-onion-skin'/>"
804 " <separator name='bleh10'/>"
805 " <menuitem action='canvas-zoom-in'/>"
806 " <menuitem action='canvas-zoom-out'/>"
807 " <menuitem action='canvas-zoom-fit'/>"
808 " <menuitem action='canvas-zoom-100'/>"
809 " <separator name='bleh11'/>"
810 " <menuitem action='time-zoom-in'/>"
811 " <menuitem action='time-zoom-out'/>"
812 " <separator name='bleh12'/>"
813 " <menuitem action='jump-next-keyframe'/>"
814 " <menuitem action='jump-prev-keyframe'/>"
815 " <menuitem action='seek-next-frame'/>"
816 " <menuitem action='seek-prev-frame'/>"
817 " <menuitem action='seek-next-second'/>"
818 " <menuitem action='seek-prev-second'/>"
819 " <menuitem action='seek-begin'/>"
820 " <menuitem action='seek-end'/>"
822 " <menu action='menu-canvas'>"
823 " <menuitem action='canvas-new'/>"
825 " <menu name='menu-state' action='menu-state'>"
827 " <menu action='menu-group'>"
828 " <menuitem action='action-group_add'/>"
830 " <menu action='menu-layer'>"
831 //" <menuitem action='cut'/>"
832 //" <menuitem action='copy'/>"
833 //" <menuitem action='paste'/>"
834 //" <separator name='bleh06'/>"
835 " <menu action='menu-layer-new'></menu>"
836 " <menuitem action='amount-inc'/>"
837 " <menuitem action='amount-dec'/>"
839 " <menu action='menu-keyframe'>"
840 " <menuitem action='keyframe-properties'/>"
847 " <menubar name='MenuBar'>"
848 " <menu action='MenuFile'>"
849 " <menuitem action='New'/>"
850 " <menuitem action='Open'/>"
852 " <menuitem action='Quit'/>"
854 " <menu action='MenuEdit'>"
855 " <menuitem action='Cut'/>"
856 " <menuitem action='Copy'/>"
857 " <menuitem action='Paste'/>"
860 " <toolbar name='ToolBar'>"
861 " <toolitem action='Open'/>"
862 " <toolitem action='Quit'/>"
868 actions_action_group->set_sensitive(false);
869 App::ui_manager()->set_add_tearoffs(true);
870 App::ui_manager()->insert_action_group(menus_action_group,1);
871 App::ui_manager()->insert_action_group(actions_action_group,1);
872 App::ui_manager()->add_ui_from_string(ui_info);
874 //App::ui_manager()->get_accel_group()->unlock();
876 catch(const Glib::Error& ex)
878 synfig::error("building menus and toolbars failed: " + ex.what());
881 // Add default keyboard accelerators
882 #define ACCEL(path,accel) \
884 Gtk::AccelKey accel_key(accel,path); \
885 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
888 #define ACCEL2(accel) \
890 Gtk::AccelKey accel_key(accel); \
891 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
894 ACCEL("<Actions>//select-all-ducks","<Control>a");
895 ACCEL("<Actions>//unselect-all-layers","<Control>d");
896 ACCEL("<Actions>//render","F9");
897 ACCEL("<Actions>//preview","F11");
898 ACCEL("<Actions>//properties","F8");
899 ACCEL("<Actions>//options","F12");
900 ACCEL("<Actions>//import","<control>i");
901 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
902 ACCEL("<Actions>//toggle-grid-show","<Control>g");
903 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
904 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
905 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
906 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
907 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
908 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
909 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
910 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
912 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
913 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
915 ACCEL("<Actions>//quality-01","<Control>1");
916 ACCEL("<Actions>//quality-02","<Control>2");
917 ACCEL("<Actions>//quality-03","<Control>3");
918 ACCEL("<Actions>//quality-04","<Control>4");
919 ACCEL("<Actions>//quality-05","<Control>5");
920 ACCEL("<Actions>//quality-06","<Control>6");
921 ACCEL("<Actions>//quality-07","<Control>7");
922 ACCEL("<Actions>//quality-08","<Control>8");
923 ACCEL("<Actions>//quality-09","<Control>9");
924 ACCEL("<Actions>//quality-10","<Control>0");
925 ACCEL("<Actions>//undo","<Control>z");
926 ACCEL("<Actions>//redo","<Control>r");
927 ACCEL("<Actions>//action-layer_remove","Delete");
929 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
930 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
931 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
932 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
933 ACCEL("<Actions>//time-zoom-in","+");
934 ACCEL("<Actions>//time-zoom-out","_");
936 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
937 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
939 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
940 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
942 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
943 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
944 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
945 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
946 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
947 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
948 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
949 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
950 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
951 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
952 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
953 ACCEL("<Actions>//play", "<Control>p");
954 ACCEL("<Actions>//seek-begin","Home");
955 ACCEL("<Actions>//seek-end","End");
957 ACCEL("<Actions>//state-normal", "<Mod1>a");
958 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
959 ACCEL("<Actions>//state-scale", "<Mod1>d");
960 ACCEL("<Actions>//state-rotate", "<Mod1>s");
962 ACCEL("<Actions>//state-bline", "<Mod1>b");
963 ACCEL("<Actions>//state-circle", "<Mod1>c");
964 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
965 ACCEL("<Actions>//state-gradient", "<Mod1>g");
967 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
968 ACCEL("<Actions>//state-fill", "<Mod1>f");
969 ACCEL("<Actions>//state-zoom", "<Mod1>z");
970 ACCEL("<Actions>//state-polygon", "<Mod1>p");
972 ACCEL("<Actions>//state-draw", "<Mod1>w");
973 ACCEL("<Actions>//state-sketch", "<Mod1>k");
974 ACCEL("<Actions>//state-width", "<Mod1>t");
975 ACCEL("<Actions>//state-mirror", "<Mod1>m");
977 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
983 #define mkdir(x,y) mkdir(x)
986 /* === M E T H O D S ======================================================= */
988 App::App(int *argc, char ***argv):
989 Gtk::Main(argc,argv),
990 IconController(etl::dirname((*argv)[0]))
992 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
995 ui_interface_=new GlobalUIInterface();
999 // don't call thread_init() if threads are already initialized
1000 // on some machines bonobo_init() initialized threads before we get here
1001 if (!g_thread_supported())
1002 Glib::thread_init();
1004 distance_system=Distance::SYSTEM_UNITS;
1006 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1009 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1013 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1019 if(!SYNFIG_CHECK_VERSION())
1021 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1022 dialog_error_blocking("Synfig Studio",
1023 "This copy of Synfig Studio was compiled against a\n"
1024 "different version of libsynfig than what is currently\n"
1025 "installed. Synfig Studio will now abort. Try downloading\n"
1026 "the latest version from the Synfig website at\n"
1027 "http://synfig.org/Download"
1031 Glib::set_application_name(_("Synfig Studio"));
1033 Splash splash_screen;
1034 splash_screen.set_can_self_destruct(false);
1035 splash_screen.show();
1037 shutdown_in_progress=false;
1038 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1039 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1041 // Initialize the Synfig library
1042 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1045 get_ui_interface()->error(_("Failed to initialize synfig!"));
1049 // add the preferences to the settings
1050 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1054 studio_init_cb.task(_("Init UI Manager..."));
1055 App::ui_manager_=studio::UIManager::create();
1058 studio_init_cb.task(_("Init Dock Manager..."));
1059 dock_manager=new studio::DockManager();
1061 studio_init_cb.task(_("Init State Manager..."));
1062 state_manager=new StateManager();
1064 studio_init_cb.task(_("Init Toolbox..."));
1065 toolbox=new studio::Toolbox();
1067 studio_init_cb.task(_("Init About Dialog..."));
1068 about=new studio::About();
1070 studio_init_cb.task(_("Init Tool Options..."));
1071 dialog_tool_options=new studio::Dialog_ToolOptions();
1072 dock_manager->register_dockable(*dialog_tool_options);
1074 studio_init_cb.task(_("Init History..."));
1075 dock_history=new studio::Dock_History();
1076 dock_manager->register_dockable(*dock_history);
1078 studio_init_cb.task(_("Init Canvases..."));
1079 dock_canvases=new studio::Dock_Canvases();
1080 dock_manager->register_dockable(*dock_canvases);
1082 studio_init_cb.task(_("Init Keyframes..."));
1083 dock_keyframes=new studio::Dock_Keyframes();
1084 dock_manager->register_dockable(*dock_keyframes);
1086 studio_init_cb.task(_("Init Layers..."));
1087 dock_layers=new studio::Dock_Layers();
1088 dock_manager->register_dockable(*dock_layers);
1090 studio_init_cb.task(_("Init Params..."));
1091 dock_params=new studio::Dock_Params();
1092 dock_manager->register_dockable(*dock_params);
1094 studio_init_cb.task(_("Init MetaData..."));
1095 dock_meta_data=new studio::Dock_MetaData();
1096 dock_manager->register_dockable(*dock_meta_data);
1098 studio_init_cb.task(_("Init Children..."));
1099 dock_children=new studio::Dock_Children();
1100 dock_manager->register_dockable(*dock_children);
1102 studio_init_cb.task(_("Init Info..."));
1103 dock_info = new studio::Dock_Info();
1104 dock_manager->register_dockable(*dock_info);
1106 studio_init_cb.task(_("Init Navigator..."));
1107 dock_navigator = new studio::Dock_Navigator();
1108 dock_manager->register_dockable(*dock_navigator);
1110 studio_init_cb.task(_("Init Timetrack..."));
1111 dock_timetrack = new studio::Dock_Timetrack();
1112 dock_manager->register_dockable(*dock_timetrack);
1114 studio_init_cb.task(_("Init Curve Editor..."));
1115 dock_curves = new studio::Dock_Curves();
1116 dock_manager->register_dockable(*dock_curves);
1118 studio_init_cb.task(_("Init Layer Groups..."));
1119 dock_layer_groups = new studio::Dock_LayerGroups();
1120 dock_manager->register_dockable(*dock_layer_groups);
1123 studio_init_cb.task(_("Init Color Dialog..."));
1124 dialog_color=new studio::Dialog_Color();
1126 studio_init_cb.task(_("Init Gradient Dialog..."));
1127 dialog_gradient=new studio::Dialog_Gradient();
1129 studio_init_cb.task(_("Init DeviceTracker..."));
1130 device_tracker=new studio::DeviceTracker();
1132 studio_init_cb.task(_("Init Tools..."));
1135 state_manager->add_state(&state_normal);
1136 state_manager->add_state(&state_smooth_move);
1137 state_manager->add_state(&state_scale);
1138 state_manager->add_state(&state_rotate);
1139 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1142 state_manager->add_state(&state_bline);
1143 state_manager->add_state(&state_circle);
1144 state_manager->add_state(&state_rectangle);
1145 state_manager->add_state(&state_gradient);
1146 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1149 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1150 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1151 state_manager->add_state(&state_fill);
1152 state_manager->add_state(&state_eyedrop);
1153 state_manager->add_state(&state_zoom);
1155 // Disabled by default - it doesn't work properly?
1156 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1158 studio_init_cb.task(_("Init ModPalette..."));
1159 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1161 studio_init_cb.task(_("Init Setup Dialog..."));
1162 dialog_setup=new studio::Dialog_Setup();
1164 studio_init_cb.task(_("Init Input Dialog..."));
1165 dialog_input=new Gtk::InputDialog();
1166 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1167 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1169 studio_init_cb.task(_("Init auto recovery..."));
1170 auto_recover=new AutoRecover();
1172 studio_init_cb.amount_complete(9250,10000);
1173 studio_init_cb.task(_("Loading Settings..."));
1175 studio_init_cb.task(_("Checking auto-recover..."));
1177 studio_init_cb.amount_complete(9900,10000);
1179 bool opened_any = false;
1180 if(auto_recover->recovery_needed())
1182 splash_screen.hide();
1183 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1184 _("Synfig Studio seems to have crashed\n"
1185 "before you could save all your files.\n"
1186 "Would you like to re-open those files\n"
1187 "and recover your unsaved changes?")) ==
1188 synfigapp::UIInterface::RESPONSE_YES)
1190 int number_recovered;
1191 if(!auto_recover->recover(number_recovered))
1192 if (number_recovered)
1193 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1195 get_ui_interface()->error(_("Unable to recover from previous crash"));
1197 get_ui_interface()->error(
1198 _("Synfig Studio has attempted to recover\n"
1199 "from a previous crash. The files that it has\n"
1200 "recovered are NOT YET SAVED. It would be a good\n"
1201 "idea to review them and save them now."));
1203 if (number_recovered)
1206 splash_screen.show();
1209 // Look for any files given on the command line,
1210 // and load them if found.
1211 for(;*argc>=1;(*argc)--)
1212 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1214 studio_init_cb.task(_("Loading files..."));
1215 splash_screen.hide();
1216 open((*argv)[*argc]);
1218 splash_screen.show();
1221 // if no file was specified to be opened, create a new document to help new users get started more easily
1222 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1225 studio_init_cb.task(_("Done."));
1226 studio_init_cb.amount_complete(10000,10000);
1232 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1236 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1240 StateManager* App::get_state_manager() { return state_manager; }
1244 shutdown_in_progress=true;
1248 synfigapp::Main::settings().remove_domain("pref");
1250 selected_instance=0;
1252 // Unload all of the modules
1253 for(;!module_list_.empty();module_list_.pop_back())
1256 delete state_manager;
1260 delete auto_recover;
1266 // studio::App::iteration(false);
1270 // studio::App::iteration(false);
1272 // studio::App::iteration(false);
1274 delete dialog_setup;
1276 delete dialog_gradient;
1278 delete dialog_color;
1280 delete dialog_input;
1282 delete dock_manager;
1284 instance_list.clear();
1286 // studio::App::iteration(false);
1290 App::get_user_app_directory()
1292 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1296 App::get_config_file(const synfig::String& file)
1298 return Glib::build_filename(get_user_app_directory(),file);
1302 App::add_recent_file(const std::string &file_name)
1304 std::string filename(file_name);
1306 assert(!filename.empty());
1308 if(filename.empty())
1311 // Toss out any "hidden" files
1312 if(basename(filename)[0]=='.')
1315 // If we aren't an absolute path, turn ourselves into one
1316 if(!is_absolute_path(filename))
1317 filename=absolute_path(filename);
1319 list<string>::iterator iter;
1320 // Check to see if the file is already on the list.
1321 // If it is, then remove it from the list
1322 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1325 recent_files.erase(iter);
1330 // Push the filename to the front of the list
1331 recent_files.push_front(filename);
1333 // Clean out the files at the end of the list.
1334 while(recent_files.size()>(unsigned)get_max_recent_files())
1335 recent_files.pop_back();
1337 signal_recent_files_changed_();
1342 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1345 App::get_time_format()
1347 return _App_time_format;
1351 App::set_time_format(synfig::Time::Format x)
1358 App::save_settings()
1363 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1364 setlocale(LC_NUMERIC, "C");
1366 std::string filename=get_config_file("accelrc");
1367 Gtk::AccelMap::save(filename);
1370 std::string filename=get_config_file("recentfiles");
1372 std::ofstream file(filename.c_str());
1376 synfig::warning("Unable to save %s",filename.c_str());
1380 list<string>::reverse_iterator iter;
1382 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1386 std::string filename=get_config_file("settings");
1387 synfigapp::Main::settings().save_to_file(filename);
1388 setlocale(LC_NUMERIC,old_locale);
1392 synfig::warning("Caught exception when attempting to save settings.");
1397 App::load_settings()
1402 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1403 setlocale(LC_NUMERIC, "C");
1405 std::string filename=get_config_file("accelrc");
1406 Gtk::AccelMap::load(filename);
1409 std::string filename=get_config_file("recentfiles");
1411 std::ifstream file(filename.c_str());
1415 std::string recent_file;
1416 getline(file,recent_file);
1417 if(!recent_file.empty())
1418 add_recent_file(recent_file);
1421 std::string filename=get_config_file("settings");
1422 if(!synfigapp::Main::settings().load_from_file(filename))
1424 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1425 //if(!synfigapp::Main::settings().load_from_file(filename))
1427 gamma.set_gamma(1.0/2.2);
1428 reset_initial_window_configuration();
1431 setlocale(LC_NUMERIC,old_locale);
1435 synfig::warning("Caught exception when attempting to load settings.");
1440 App::reset_initial_window_configuration()
1442 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1443 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1444 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1445 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1446 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1447 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1448 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1449 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1450 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1451 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1452 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1453 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1454 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1455 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1459 App::shutdown_request(GdkEventAny*)
1463 //return !shutdown_in_progress;
1469 if(shutdown_in_progress)return;
1472 get_ui_interface()->task(_("Quit Request"));
1475 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1479 std::list<etl::handle<Instance> >::iterator iter;
1480 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1482 if(!(*iter)->safe_close())
1486 if((*iter)->synfigapp::Instance::get_action_count())
1488 handle<synfigapp::UIInterface> uim;
1489 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1491 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1492 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1494 case synfigapp::UIInterface::RESPONSE_NO:
1496 case synfigapp::UIInterface::RESPONSE_YES:
1499 case synfigapp::UIInterface::RESPONSE_CANCEL:
1508 if((*iter)->synfigapp::Instance::is_modified())
1510 handle<synfigapp::UIInterface> uim;
1511 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1513 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() );
1514 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1516 case synfigapp::UIInterface::RESPONSE_NO:
1518 case synfigapp::UIInterface::RESPONSE_YES:
1519 (*iter)->dialog_cvs_commit();
1521 case synfigapp::UIInterface::RESPONSE_CANCEL:
1530 // This next line causes things to crash for some reason
1534 shutdown_in_progress=true;
1536 instance_list.clear();
1538 while(studio::App::events_pending())studio::App::iteration(false);
1541 auto_recover->normal_shutdown();
1543 get_ui_interface()->task(_("Quit Request sent"));
1549 dialog_setup->refresh();
1550 dialog_setup->show();
1553 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1554 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1557 //#define USE_WIN32_FILE_DIALOGS 1
1560 #ifdef USE_WIN32_FILE_DIALOGS
1561 static OPENFILENAME ofn={};
1565 #include <gdk/gdkwin32.h>
1569 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1571 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1573 #ifdef USE_WIN32_FILE_DIALOGS
1574 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1576 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1577 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1578 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1580 ofn.lStructSize=sizeof(OPENFILENAME);
1581 ofn.hwndOwner = hWnd;
1582 ofn.hInstance = hInstance;
1583 ofn.lpstrFilter = szFilter;
1584 // ofn.lpstrCustomFilter=NULL;
1585 // ofn.nMaxCustFilter=0;
1586 // ofn.nFilterIndex=0;
1587 // ofn.lpstrFile=NULL;
1588 ofn.nMaxFile=MAX_PATH;
1589 // ofn.lpstrFileTitle=NULL;
1590 // ofn.lpstrInitialDir=NULL;
1591 // ofn.lpstrTitle=NULL;
1592 ofn.Flags=OFN_HIDEREADONLY;
1593 // ofn.nFileOffset=0;
1594 // ofn.nFileExtension=0;
1595 ofn.lpstrDefExt=TEXT("sif");
1596 // ofn.lCustData = 0l;
1598 // ofn.lpTemplateName=NULL;
1600 CHAR szFilename[MAX_PATH];
1602 strcpy(szFilename,filename.c_str());
1603 strcpy(szTitle,title.c_str());
1605 ofn.lpstrFile=szFilename;
1606 ofn.lpstrFileTitle=szTitle;
1608 if(GetOpenFileName(&ofn))
1610 filename=szFilename;
1616 synfig::String prev_path;
1618 if(!_preferences.get_value(preference, prev_path))
1621 prev_path = absolute_path(prev_path);
1623 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1625 dialog->set_current_folder(prev_path);
1626 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1627 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1629 if (filename.empty())
1630 dialog->set_filename(prev_path);
1631 else if (is_absolute_path(filename))
1632 dialog->set_filename(filename);
1634 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1636 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1637 filename = dialog->get_filename();
1638 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1639 _preferences.set_value(preference, dirname(filename));
1653 GtkWidget *fileselection;
1654 fileselection = gtk_file_selection_new(title.c_str());
1657 if(basename(filename)==filename)
1659 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1662 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1664 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1666 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1667 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1669 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1670 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1672 gtk_widget_show(fileselection);
1680 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1681 _preferences.set_value(preference,dirname(filename));
1685 gtk_widget_destroy(fileselection);
1688 gtk_widget_destroy(fileselection);
1695 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1697 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1699 #if USE_WIN32_FILE_DIALOGS
1700 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1702 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1703 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1704 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1706 ofn.lStructSize=sizeof(OPENFILENAME);
1707 ofn.hwndOwner = hWnd;
1708 ofn.hInstance = hInstance;
1709 ofn.lpstrFilter = szFilter;
1710 // ofn.lpstrCustomFilter=NULL;
1711 // ofn.nMaxCustFilter=0;
1712 // ofn.nFilterIndex=0;
1713 // ofn.lpstrFile=NULL;
1714 ofn.nMaxFile=MAX_PATH;
1715 // ofn.lpstrFileTitle=NULL;
1716 // ofn.lpstrInitialDir=NULL;
1717 // ofn.lpstrTitle=NULL;
1718 ofn.Flags=OFN_OVERWRITEPROMPT;
1719 // ofn.nFileOffset=0;
1720 // ofn.nFileExtension=0;
1721 ofn.lpstrDefExt=TEXT("sif");
1722 // ofn.lCustData = 0l;
1724 // ofn.lpTemplateName=NULL;
1726 CHAR szFilename[MAX_PATH];
1728 strcpy(szFilename,filename.c_str());
1729 strcpy(szTitle,title.c_str());
1731 ofn.lpstrFile=szFilename;
1732 ofn.lpstrFileTitle=szTitle;
1734 if(GetSaveFileName(&ofn))
1736 filename=szFilename;
1737 _preferences.set_value(preference,dirname(filename));
1742 synfig::String prev_path;
1744 if(!_preferences.get_value(preference, prev_path))
1747 prev_path = absolute_path(prev_path);
1749 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1751 dialog->set_current_folder(prev_path);
1752 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1753 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1755 Widget_Enum *file_type_enum;
1756 if (preference == ANIMATION_DIR_PREFERENCE)
1758 file_type_enum = manage(new Widget_Enum());
1759 file_type_enum->set_param_desc(ParamDesc("filetype")
1761 .add_enum_value(synfig::FILE_VERSION_0_61_08, "0.61.08", "0.61.08")
1762 .add_enum_value(synfig::FILE_VERSION_0_61_07, "0.61.07", "0.61.07"));
1763 file_type_enum->set_value(0);
1765 Gtk::HBox *hbox = manage(new Gtk::HBox);
1766 hbox->pack_start(*manage(new Gtk::Label(_("File Type: "))),Gtk::PACK_SHRINK,0);
1767 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1770 dialog->set_extra_widget(*hbox);
1773 if (filename.empty())
1774 dialog->set_filename(prev_path);
1777 std::string full_path;
1778 if (is_absolute_path(filename))
1779 full_path = filename;
1781 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1783 // select the file if it exists
1784 dialog->set_filename(full_path);
1786 // if the file doesn't exist, put its name into the filename box
1788 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1789 dialog->set_current_name(basename(filename));
1792 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1793 if (preference == ANIMATION_DIR_PREFERENCE)
1794 set_file_version(synfig::FileVersion(file_type_enum->get_value()));
1795 filename = dialog->get_filename();
1796 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1797 _preferences.set_value(preference, dirname(filename));
1808 App::dialog_error_blocking(const std::string &title, const std::string &message)
1810 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1811 dialog.set_title(title);
1817 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1819 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1820 dialog.set_title(title);
1826 App::dialog_yes_no(const std::string &title, const std::string &message)
1831 true // use_separator
1833 Gtk::Label label(message);
1836 dialog.get_vbox()->pack_start(label);
1837 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1838 dialog.add_button(Gtk::StockID("gtk-no"),0);
1840 return dialog.run();
1844 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1849 true // use_separator
1851 Gtk::Label label(message);
1854 dialog.get_vbox()->pack_start(label);
1855 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1856 dialog.add_button(Gtk::StockID("gtk-no"),0);
1857 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1859 return dialog.run();
1863 App::dialog_not_implemented()
1865 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1866 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1871 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1876 true // use_separator
1878 Gtk::Label label(message);
1880 dialog.get_vbox()->pack_start(label);
1883 entry.set_text(text);
1885 entry.set_activates_default(true);
1886 dialog.get_vbox()->pack_start(entry);
1888 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1889 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1890 dialog.set_default_response(Gtk::RESPONSE_OK);
1891 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1894 if(dialog.run()!=Gtk::RESPONSE_OK)
1897 text=entry.get_text();
1906 App::open(std::string filename)
1908 return open_as(filename,filename);
1911 // this is called from autorecover.cpp:
1912 // App::open_as(get_shadow_file_name(filename),filename)
1913 // other than that, 'filename' and 'as' are the same
1915 App::open_as(std::string filename,std::string as)
1918 char long_name[1024];
1919 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1925 OneMoment one_moment;
1927 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1928 if(canvas && get_instance(canvas))
1930 get_instance(canvas)->find_canvas_view(canvas)->present();
1931 info("%s is already open", filename.c_str());
1932 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1937 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1939 add_recent_file(as);
1941 handle<Instance> instance(Instance::create(canvas));
1944 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1948 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)")))
1949 instance->dialog_cvs_update();
1954 dialog_error_blocking(_("Error"), x);
1959 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1970 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1971 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1973 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1975 canvas->rend_desc().set_frame_rate(24.0);
1976 canvas->rend_desc().set_time_start(0.0);
1977 canvas->rend_desc().set_time_end(5.0);
1978 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1979 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1980 canvas->rend_desc().set_tl(Vector(-4,2.25));
1981 canvas->rend_desc().set_br(Vector(4,-2.25));
1982 canvas->rend_desc().set_w(480);
1983 canvas->rend_desc().set_h(270);
1984 canvas->rend_desc().set_antialias(1);
1985 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1986 canvas->set_file_name(file_name);
1988 handle<Instance> instance = Instance::create(canvas);
1990 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1991 instance->find_canvas_view(canvas)->canvas_properties.present();
1997 string filename="*.sif";
1999 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2001 // If the filename still has wildcards, then we should
2002 // continue looking for the file we want
2003 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2009 get_ui_interface()->error(_("Unable to open file"));
2014 App::set_selected_instance(etl::loose_handle<Instance> instance)
2016 /* if(get_selected_instance()==instance)
2018 selected_instance=instance;
2019 signal_instance_selected()(instance);
2025 selected_instance=instance;
2026 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2030 instance->focus(instance->get_canvas());
2033 set_selected_canvas_view(0);
2035 signal_instance_selected()(instance);
2039 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2041 selected_canvas_view=canvas_view;
2042 signal_canvas_view_focus()(selected_canvas_view);
2045 selected_instance=canvas_view->get_instance();
2046 signal_instance_selected()(canvas_view->get_instance());
2049 if(get_selected_canvas_view()==canvas_view)
2051 signal_canvas_view_focus()(selected_canvas_view);
2052 signal_instance_selected()(canvas_view->get_instance());
2055 selected_canvas_view=canvas_view;
2056 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2057 set_selected_instance(canvas_view->get_instance());
2058 signal_canvas_view_focus()(selected_canvas_view);
2062 etl::loose_handle<Instance>
2063 App::get_instance(etl::handle<synfig::Canvas> canvas)
2065 if(!canvas) return 0;
2066 canvas=canvas->get_root();
2068 std::list<etl::handle<Instance> >::iterator iter;
2069 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2071 if((*iter)->get_canvas()==canvas)
2087 if(selected_instance)
2088 selected_instance->undo();
2094 if(selected_instance)
2095 selected_instance->redo();
2099 studio::App::get_base_path()
2101 return app_base_path_;