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>
59 #include "canvasview.h"
60 #include "dialog_setup.h"
61 #include "dialog_gradient.h"
62 #include "dialog_color.h"
65 #include "onemoment.h"
67 #include "dockmanager.h"
69 #include "state_eyedrop.h"
70 #include "state_normal.h"
71 #include "state_draw.h"
72 #include "state_fill.h"
73 #include "state_bline.h"
74 #include "state_polygon.h"
75 #include "state_sketch.h"
76 #include "state_gradient.h"
77 #include "state_circle.h"
78 #include "state_rectangle.h"
79 #include "state_smoothmove.h"
80 #include "state_scale.h"
81 #include "state_width.h"
82 #include "state_rotate.h"
83 #include "state_zoom.h"
85 #include "devicetracker.h"
86 #include "dialog_tooloptions.h"
88 #include "autorecover.h"
90 #include <synfigapp/settings.h>
91 #include "dock_history.h"
92 #include "dock_canvases.h"
93 #include "dock_keyframes.h"
94 #include "dock_layers.h"
95 #include "dock_params.h"
96 #include "dock_metadata.h"
97 #include "dock_children.h"
98 #include "dock_info.h"
99 #include "dock_navigator.h"
100 #include "dock_layergroups.h"
101 #include "dock_timetrack.h"
102 #include "dock_curves.h"
104 #include "mod_palette/mod_palette.h"
105 #include "mod_mirror/mod_mirror.h"
107 #include <sys/stat.h>
113 #include "statemanager.h"
120 #define _WIN32_WINNT 0x0500
123 #include <gtkmm/accelmap.h>
124 #include <gtkmm/filechooser.h>
125 #include <gtkmm/filechooserdialog.h>
131 /* === U S I N G =========================================================== */
135 using namespace synfig;
136 using namespace studio;
138 /* === M A C R O S ========================================================= */
140 #ifndef SYNFIG_USER_APP_DIR
142 #define SYNFIG_USER_APP_DIR "Library/Synfig"
143 #elif defined(_WIN32)
144 #define SYNFIG_USER_APP_DIR "Synfig"
146 #define SYNFIG_USER_APP_DIR ".synfig"
151 #define DPM2DPI(x) (float(x)/39.3700787402f)
152 #define DPI2DPM(x) (float(x)*39.3700787402f)
158 # define IMAGE_DIR "share\\pixmaps"
163 # define IMAGE_DIR "/usr/local/share/pixmaps"
167 # define IMAGE_EXT "tif"
170 #include <synfigapp/main.h>
172 /* === S I G N A L S ======================================================= */
174 static sigc::signal<void> signal_present_all_;
176 App::signal_present_all() { return signal_present_all_; }
178 static sigc::signal<void> signal_recent_files_changed_;
180 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
182 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
183 sigc::signal<void,etl::loose_handle<CanvasView> >&
184 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
186 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
187 sigc::signal<void,etl::handle<Instance> >&
188 App::signal_instance_selected() { return signal_instance_selected_; }
190 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
191 sigc::signal<void,etl::handle<Instance> >&
192 App::signal_instance_created() { return signal_instance_created_; }
194 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
195 sigc::signal<void,etl::handle<Instance> >&
196 App::signal_instance_deleted() { return signal_instance_deleted_; }
198 /* === G L O B A L S ======================================================= */
200 static std::list<std::string> recent_files;
201 const std::list<std::string>& App::get_recent_files() { return recent_files; }
203 int App::Busy::count;
204 bool App::shutdown_in_progress;
206 synfig::Gamma App::gamma;
208 Glib::RefPtr<studio::UIManager> App::ui_manager_;
210 synfig::Distance::System App::distance_system;
212 studio::Dialog_Setup* App::dialog_setup;
214 etl::handle< studio::ModPalette > mod_palette_;
215 //studio::Dialog_Palette* App::dialog_palette;
217 std::list<etl::handle<Instance> > App::instance_list;
219 static etl::handle<synfigapp::UIInterface> ui_interface_;
220 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
222 etl::handle<Instance> App::selected_instance;
223 etl::handle<CanvasView> App::selected_canvas_view;
225 studio::Toolbox *studio::App::toolbox=NULL;
227 studio::AutoRecover *studio::App::auto_recover=NULL;
229 studio::IPC *ipc=NULL;
231 studio::DockManager* studio::App::dock_manager=0;
233 studio::DeviceTracker* studio::App::device_tracker=0;
235 studio::Dialog_Gradient* studio::App::dialog_gradient;
237 studio::Dialog_Color* studio::App::dialog_color;
239 Gtk::InputDialog* studio::App::dialog_input;
241 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
243 studio::Dock_History* dock_history;
244 studio::Dock_Canvases* dock_canvases;
245 studio::Dock_Keyframes* dock_keyframes;
246 studio::Dock_Layers* dock_layers;
247 studio::Dock_Params* dock_params;
248 studio::Dock_MetaData* dock_meta_data;
249 studio::Dock_Children* dock_children;
250 studio::Dock_Info* dock_info;
251 studio::Dock_LayerGroups* dock_layer_groups;
252 studio::Dock_Navigator* dock_navigator;
253 studio::Dock_Timetrack* dock_timetrack;
254 studio::Dock_Curves* dock_curves;
256 std::list< etl::handle< studio::Module > > module_list_;
258 bool studio::App::use_colorspace_gamma=true;
259 bool studio::App::single_threaded=false;
261 static int max_recent_files_=25;
262 int studio::App::get_max_recent_files() { return max_recent_files_; }
263 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
265 static synfig::String app_base_path_;
270 really_delete_widget(Gtk::Widget *widget)
272 // synfig::info("really delete %p", (void*)widget);
277 // nasty workaround - when we've finished with a popup menu, we want to delete it
278 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
279 // so schedule the real delete to happen in 50ms, giving the action a chance to run
281 delete_widget(Gtk::Widget *widget)
283 // synfig::info("delete %p", (void*)widget);
284 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
287 }; // END of namespace studio
288 studio::StateManager* state_manager;
293 class GlobalUIInterface : public synfigapp::UIInterface
297 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
302 true // use_separator
304 Gtk::Label label(message);
307 dialog.get_vbox()->pack_start(label);
308 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
309 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
311 dialog.set_default_response(dflt);
313 return (Response)dialog.run();
315 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
320 true // use_separator
322 Gtk::Label label(message);
325 dialog.get_vbox()->pack_start(label);
326 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
327 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
328 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
330 dialog.set_default_response(dflt);
332 return (Response)dialog.run();
334 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
339 true // use_separator
341 Gtk::Label label(message);
344 dialog.get_vbox()->pack_start(label);
345 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
346 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
348 dialog.set_default_response(dflt);
350 return (Response)dialog.run();
354 task(const std::string &task)
356 std::cerr<<task<<std::endl;
357 while(studio::App::events_pending())studio::App::iteration(false);
362 error(const std::string &err)
364 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
371 warning(const std::string &err)
373 std::cerr<<"warning: "<<err<<std::endl;
374 while(studio::App::events_pending())studio::App::iteration(false);
379 amount_complete(int /*current*/, int /*total*/)
381 while(studio::App::events_pending())studio::App::iteration(false);
386 /* === P R O C E D U R E S ================================================= */
390 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
392 action_group_list.push_back(action_group);
393 Gtk::UIManager::insert_action_group(action_group, pos);
397 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
399 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
400 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
401 if(*iter==action_group)
403 action_group_list.erase(iter);
404 Gtk::UIManager::remove_action_group(action_group);
407 synfig::error("Unable to find action group");
411 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
413 ui_manager->insert_action_group(group,0);
415 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
416 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
418 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
420 if(*iter && (*iter)->get_name()!="menus")
422 synfig::info("Removing action group "+(*iter)->get_name());
423 ui_manager->remove_action_group(*iter);
426 ui_manager->insert_action_group(group,0);
428 for(;!prev_groups.empty();prev_groups.pop_front())
430 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
431 ui_manager->insert_action_group(prev_groups.front(),1);
435 class Preferences : public synfigapp::Settings
438 virtual bool get_value(const synfig::String& key, synfig::String& value)const
442 value=strprintf("%f %f %f %f",
443 App::gamma.get_gamma_r(),
444 App::gamma.get_gamma_g(),
445 App::gamma.get_gamma_b(),
446 App::gamma.get_black_level()
450 if(key=="time_format")
452 value=strprintf("%i",App::get_time_format());
455 if(key=="file_history.size")
457 value=strprintf("%i",App::get_max_recent_files());
460 if(key=="use_colorspace_gamma")
462 value=strprintf("%i",(int)App::use_colorspace_gamma);
465 if(key=="distance_system")
467 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
470 if(key=="single_threaded")
472 value=strprintf("%i",(int)App::single_threaded);
475 if(key=="auto_recover_backup_interval")
477 value=strprintf("%i",App::auto_recover->get_timeout());
481 return synfigapp::Settings::get_value(key,value);
484 virtual bool set_value(const synfig::String& key,const synfig::String& value)
490 strscanf(value,"%f %f %f %f",
497 App::gamma.set_all(r,g,b,blk);
501 if(key=="time_format")
503 int i(atoi(value.c_str()));
504 App::set_time_format(static_cast<synfig::Time::Format>(i));
507 if(key=="auto_recover_backup_interval")
509 int i(atoi(value.c_str()));
510 App::auto_recover->set_timeout(i);
513 if(key=="file_history.size")
515 int i(atoi(value.c_str()));
516 App::set_max_recent_files(i);
519 if(key=="use_colorspace_gamma")
521 int i(atoi(value.c_str()));
522 App::use_colorspace_gamma=i;
525 if(key=="distance_system")
527 App::distance_system=Distance::ident_system(value);;
530 if(key=="single_threaded")
532 int i(atoi(value.c_str()));
533 App::single_threaded=i;
537 return synfigapp::Settings::set_value(key,value);
540 virtual KeyList get_key_list()const
542 KeyList ret(synfigapp::Settings::get_key_list());
543 ret.push_back("gamma");
544 ret.push_back("time_format");
545 ret.push_back("distance_system");
546 ret.push_back("file_history.size");
547 ret.push_back("use_colorspace_gamma");
548 ret.push_back("single_threaded");
549 ret.push_back("auto_recover_backup_interval");
554 static ::Preferences _preferences;
559 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
561 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
563 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
565 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
566 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
567 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
568 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
569 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
570 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
571 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
572 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
573 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
574 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
575 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
576 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
577 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
579 // Add the synfigapp actions...
580 synfigapp::Action::Book::iterator iter;
581 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
583 actions_action_group->add(Gtk::Action::create(
584 "action-"+iter->second.name,
585 get_action_stock_id(iter->second),
586 iter->second.local_name,iter->second.local_name
590 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
591 #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); }
592 #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); }
594 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
595 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
596 DEFINE_ACTION("new", Gtk::Stock::NEW);
597 DEFINE_ACTION("open", Gtk::Stock::OPEN);
598 DEFINE_ACTION("save", Gtk::Stock::SAVE);
599 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
600 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
601 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
602 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
603 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
604 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
605 DEFINE_ACTION("import", _("Import"));
606 DEFINE_ACTION("render", _("Render"));
607 DEFINE_ACTION("preview", _("Preview"));
608 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
609 DEFINE_ACTION("sound", _("Sound File"));
610 DEFINE_ACTION("options", _("Options"));
611 DEFINE_ACTION("close", _("Close View"));
612 DEFINE_ACTION("close-document", _("Close Document"));
613 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
616 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
617 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
618 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
619 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
620 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
621 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
622 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
623 DEFINE_ACTION("properties", _("Properties"));
625 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
626 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
627 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
628 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
629 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
630 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
631 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
632 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
633 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
634 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
635 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
636 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
637 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
638 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
639 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
640 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
641 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
642 DEFINE_ACTION("lowres-pixel-01", _("Set Low-Res pixel size to 2^1"));
643 DEFINE_ACTION("lowres-pixel-02", _("Set Low-Res pixel size to 2^2"));
644 DEFINE_ACTION("lowres-pixel-03", _("Set Low-Res pixel size to 2^3"));
645 DEFINE_ACTION("lowres-pixel-04", _("Set Low-Res pixel size to 2^4"));
646 DEFINE_ACTION("lowres-pixel-05", _("Set Low-Res pixel size to 2^5"));
647 DEFINE_ACTION("lowres-pixel-06", _("Set Low-Res pixel size to 2^6"));
648 DEFINE_ACTION("play", _("Play"));
649 // DEFINE_ACTION("pause", _("Pause"));
650 DEFINE_ACTION("stop", _("Stop"));
651 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
652 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
653 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
654 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
655 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
656 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
657 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
658 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
659 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
660 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
661 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
662 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
663 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
664 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
665 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
666 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
667 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
668 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
669 DEFINE_ACTION("seek-end", _("Seek to End"));
671 DEFINE_ACTION("action-group_add", _("Add group"));
673 DEFINE_ACTION("canvas-new", _("New Canvas"));
675 DEFINE_ACTION("amount-inc", _("Increase Amount"));
676 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
681 // Set up synfigapp actions
683 synfigapp::Action::Book::iterator iter;
685 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
687 Gtk::StockID stock_id;
689 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
691 //Gtk::Image* image(manage(new Gtk::Image()));
692 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
693 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
694 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
695 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
696 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
697 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
698 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
699 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
700 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
701 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
703 actions_action_group->add(Gtk::Action::create(
704 "action-"+iter->second.name,
706 iter->second.local_name,iter->second.local_name
714 Glib::ustring ui_info =
716 " <popup name='menu-toolbox' action='menu-toolbox'>"
717 " <menu action='menu-file'>"
720 " <popup name='menu-main' action='menu-main'>"
721 " <menu action='menu-file'>"
722 " <menuitem action='new' />"
723 " <menuitem action='open' />"
724 " <menuitem action='save' />"
725 " <menuitem action='save-as' />"
726 " <menuitem action='revert' />"
727 " <separator name='bleh01'/>"
728 " <menuitem action='cvs-add' />"
729 " <menuitem action='cvs-update' />"
730 " <menuitem action='cvs-commit' />"
731 " <menuitem action='cvs-revert' />"
732 " <separator name='bleh02'/>"
733 " <menuitem action='import' />"
734 " <separator name='bleh03'/>"
735 " <menuitem action='render' />"
736 " <menuitem action='preview' />"
737 " <menuitem action='sound' />"
738 " <separator name='bleh04'/>"
739 " <menuitem action='options' />"
740 " <menuitem action='close' />"
741 " <menuitem action='close-document' />"
742 " <menuitem action='quit' />"
744 " <menu action='menu-edit'>"
745 " <menuitem action='undo'/>"
746 " <menuitem action='redo'/>"
747 " <separator name='bleh05'/>"
748 " <menuitem action='cut'/>"
749 " <menuitem action='copy'/>"
750 " <menuitem action='paste'/>"
751 " <separator name='bleh06'/>"
752 " <menuitem action='select-all-ducks'/>"
753 " <menuitem action='unselect-all-layers'/>"
754 " <separator name='bleh07'/>"
755 " <menuitem action='properties'/>"
757 " <menu action='menu-view'>"
758 " <menu action='menu-duck-mask'>"
759 " <menuitem action='mask-position-ducks' />"
760 " <menuitem action='mask-vertex-ducks' />"
761 " <menuitem action='mask-tangent-ducks' />"
762 " <menuitem action='mask-radius-ducks' />"
763 " <menuitem action='mask-width-ducks' />"
764 " <menuitem action='mask-angle-ducks' />"
766 " <menu action='menu-preview-quality'>"
767 " <menuitem action='quality-00' />"
768 " <menuitem action='quality-01' />"
769 " <menuitem action='quality-02' />"
770 " <menuitem action='quality-03' />"
771 " <menuitem action='quality-04' />"
772 " <menuitem action='quality-05' />"
773 " <menuitem action='quality-06' />"
774 " <menuitem action='quality-07' />"
775 " <menuitem action='quality-08' />"
776 " <menuitem action='quality-09' />"
777 " <menuitem action='quality-10' />"
779 " <menu action='menu-lowres-pixel'>"
780 " <menuitem action='lowres-pixel-01' />"
781 " <menuitem action='lowres-pixel-02' />"
782 " <menuitem action='lowres-pixel-03' />"
783 " <menuitem action='lowres-pixel-04' />"
784 " <menuitem action='lowres-pixel-05' />"
785 " <menuitem action='lowres-pixel-06' />"
787 " <separator name='bleh08'/>"
788 " <menuitem action='play'/>"
789 //" <menuitem action='pause'/>"
790 " <menuitem action='stop'/>"
791 " <menuitem action='dialog-flipbook'/>"
792 " <separator name='bleh09'/>"
793 " <menuitem action='toggle-grid-show'/>"
794 " <menuitem action='toggle-grid-snap'/>"
795 " <menuitem action='toggle-guide-show'/>"
796 " <menuitem action='toggle-low-res'/>"
797 " <menuitem action='toggle-onion-skin'/>"
798 " <separator name='bleh10'/>"
799 " <menuitem action='canvas-zoom-in'/>"
800 " <menuitem action='canvas-zoom-out'/>"
801 " <menuitem action='canvas-zoom-fit'/>"
802 " <menuitem action='canvas-zoom-100'/>"
803 " <separator name='bleh11'/>"
804 " <menuitem action='time-zoom-in'/>"
805 " <menuitem action='time-zoom-out'/>"
806 " <separator name='bleh12'/>"
807 " <menuitem action='jump-next-keyframe'/>"
808 " <menuitem action='jump-prev-keyframe'/>"
809 " <menuitem action='seek-next-frame'/>"
810 " <menuitem action='seek-prev-frame'/>"
811 " <menuitem action='seek-next-second'/>"
812 " <menuitem action='seek-prev-second'/>"
813 " <menuitem action='seek-begin'/>"
814 " <menuitem action='seek-end'/>"
816 " <menu action='menu-canvas'>"
817 " <menuitem action='canvas-new'/>"
819 " <menu name='menu-state' action='menu-state'>"
821 " <menu action='menu-group'>"
822 " <menuitem action='action-group_add'/>"
824 " <menu action='menu-layer'>"
825 //" <menuitem action='cut'/>"
826 //" <menuitem action='copy'/>"
827 //" <menuitem action='paste'/>"
828 //" <separator name='bleh06'/>"
829 " <menu action='menu-layer-new'></menu>"
830 " <menuitem action='amount-inc'/>"
831 " <menuitem action='amount-dec'/>"
833 " <menu action='menu-keyframe'>"
834 " <menuitem action='keyframe-properties'/>"
841 " <menubar name='MenuBar'>"
842 " <menu action='MenuFile'>"
843 " <menuitem action='New'/>"
844 " <menuitem action='Open'/>"
846 " <menuitem action='Quit'/>"
848 " <menu action='MenuEdit'>"
849 " <menuitem action='Cut'/>"
850 " <menuitem action='Copy'/>"
851 " <menuitem action='Paste'/>"
854 " <toolbar name='ToolBar'>"
855 " <toolitem action='Open'/>"
856 " <toolitem action='Quit'/>"
862 actions_action_group->set_sensitive(false);
863 App::ui_manager()->set_add_tearoffs(true);
864 App::ui_manager()->insert_action_group(menus_action_group,1);
865 App::ui_manager()->insert_action_group(actions_action_group,1);
866 App::ui_manager()->add_ui_from_string(ui_info);
868 //App::ui_manager()->get_accel_group()->unlock();
870 catch(const Glib::Error& ex)
872 synfig::error("building menus and toolbars failed: " + ex.what());
875 // Add default keyboard accelerators
876 #define ACCEL(path,accel) \
878 Gtk::AccelKey accel_key(accel,path); \
879 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
882 #define ACCEL2(accel) \
884 Gtk::AccelKey accel_key(accel); \
885 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
888 ACCEL("<Actions>//select-all-ducks","<Control>a");
889 ACCEL("<Actions>//unselect-all-layers","<Control>d");
890 ACCEL("<Actions>//render","F9");
891 ACCEL("<Actions>//preview","F11");
892 ACCEL("<Actions>//properties","F8");
893 ACCEL("<Actions>//options","F12");
894 ACCEL("<Actions>//import","<control>i");
895 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
896 ACCEL("<Actions>//toggle-grid-show","<Control>g");
897 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
898 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
899 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
900 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
901 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
902 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
903 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
904 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
906 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
907 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
909 ACCEL("<Actions>//quality-01","<Control>1");
910 ACCEL("<Actions>//quality-02","<Control>2");
911 ACCEL("<Actions>//quality-03","<Control>3");
912 ACCEL("<Actions>//quality-04","<Control>4");
913 ACCEL("<Actions>//quality-05","<Control>5");
914 ACCEL("<Actions>//quality-06","<Control>6");
915 ACCEL("<Actions>//quality-07","<Control>7");
916 ACCEL("<Actions>//quality-08","<Control>8");
917 ACCEL("<Actions>//quality-09","<Control>9");
918 ACCEL("<Actions>//quality-10","<Control>0");
919 ACCEL("<Actions>//undo","<Control>z");
920 ACCEL("<Actions>//redo","<Control>r");
921 ACCEL("<Actions>//action-layer_remove","Delete");
923 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
924 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
925 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
926 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
927 ACCEL("<Actions>//time-zoom-in","+");
928 ACCEL("<Actions>//time-zoom-out","_");
930 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
931 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
933 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
934 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
935 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
936 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
937 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
938 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
939 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
940 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
941 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
942 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
943 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
944 ACCEL("<Actions>//play", "<Control>p");
945 ACCEL("<Actions>//seek-begin","Home");
946 ACCEL("<Actions>//seek-end","End");
948 ACCEL("<Actions>//state-normal", "<Mod1>a");
949 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
950 ACCEL("<Actions>//state-scale", "<Mod1>d");
951 ACCEL("<Actions>//state-rotate", "<Mod1>s");
953 ACCEL("<Actions>//state-bline", "<Mod1>b");
954 ACCEL("<Actions>//state-circle", "<Mod1>c");
955 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
956 ACCEL("<Actions>//state-gradient", "<Mod1>g");
958 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
959 ACCEL("<Actions>//state-fill", "<Mod1>f");
960 ACCEL("<Actions>//state-zoom", "<Mod1>z");
961 ACCEL("<Actions>//state-polygon", "<Mod1>p");
963 ACCEL("<Actions>//state-draw", "<Mod1>w");
964 ACCEL("<Actions>//state-sketch", "<Mod1>k");
965 ACCEL("<Actions>//state-width", "<Mod1>t");
966 ACCEL("<Actions>//state-mirror", "<Mod1>m");
968 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
974 #define mkdir(x,y) mkdir(x)
977 /* === M E T H O D S ======================================================= */
979 App::App(int *argc, char ***argv):
980 Gtk::Main(argc,argv),
981 IconController(etl::dirname((*argv)[0]))
983 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
986 ui_interface_=new GlobalUIInterface();
990 // don't call thread_init() if threads are already initialized
991 // on some machines bonobo_init() initialized threads before we get here
992 if (!g_thread_supported())
995 distance_system=Distance::SYSTEM_UNITS;
997 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1000 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1004 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1010 if(!SYNFIG_CHECK_VERSION())
1012 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1013 dialog_error_blocking("Synfig Studio",
1014 "This copy of Synfig Studio was compiled against a\n"
1015 "different version of libsynfig than what is currently\n"
1016 "installed. Synfig Studio will now abort. Try downloading\n"
1017 "the latest version from the Synfig website at\n"
1018 "http://synfig.org/Download"
1022 Glib::set_application_name(_("Synfig Studio"));
1025 about_window.set_can_self_destruct(false);
1026 about_window.show();
1028 shutdown_in_progress=false;
1029 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1030 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1032 // Initialize the Synfig library
1033 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1036 get_ui_interface()->error(_("Failed to initialize synfig!"));
1040 // add the preferences to the settings
1041 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1045 studio_init_cb.task(_("Init UI Manager..."));
1046 App::ui_manager_=studio::UIManager::create();
1049 studio_init_cb.task(_("Init Dock Manager..."));
1050 dock_manager=new studio::DockManager();
1052 studio_init_cb.task(_("Init State Manager..."));
1053 state_manager=new StateManager();
1055 studio_init_cb.task(_("Init Toolbox..."));
1056 toolbox=new studio::Toolbox();
1058 studio_init_cb.task(_("Init Tool Options..."));
1059 dialog_tool_options=new studio::Dialog_ToolOptions();
1060 dock_manager->register_dockable(*dialog_tool_options);
1062 studio_init_cb.task(_("Init History..."));
1063 dock_history=new studio::Dock_History();
1064 dock_manager->register_dockable(*dock_history);
1066 studio_init_cb.task(_("Init Canvases..."));
1067 dock_canvases=new studio::Dock_Canvases();
1068 dock_manager->register_dockable(*dock_canvases);
1070 studio_init_cb.task(_("Init Keyframes..."));
1071 dock_keyframes=new studio::Dock_Keyframes();
1072 dock_manager->register_dockable(*dock_keyframes);
1074 studio_init_cb.task(_("Init Layers..."));
1075 dock_layers=new studio::Dock_Layers();
1076 dock_manager->register_dockable(*dock_layers);
1078 studio_init_cb.task(_("Init Params..."));
1079 dock_params=new studio::Dock_Params();
1080 dock_manager->register_dockable(*dock_params);
1082 studio_init_cb.task(_("Init MetaData..."));
1083 dock_meta_data=new studio::Dock_MetaData();
1084 dock_manager->register_dockable(*dock_meta_data);
1086 studio_init_cb.task(_("Init Children..."));
1087 dock_children=new studio::Dock_Children();
1088 dock_manager->register_dockable(*dock_children);
1090 studio_init_cb.task(_("Init Info..."));
1091 dock_info = new studio::Dock_Info();
1092 dock_manager->register_dockable(*dock_info);
1094 studio_init_cb.task(_("Init Navigator..."));
1095 dock_navigator = new studio::Dock_Navigator();
1096 dock_manager->register_dockable(*dock_navigator);
1098 studio_init_cb.task(_("Init Timetrack..."));
1099 dock_timetrack = new studio::Dock_Timetrack();
1100 dock_manager->register_dockable(*dock_timetrack);
1102 studio_init_cb.task(_("Init Curve Editor..."));
1103 dock_curves = new studio::Dock_Curves();
1104 dock_manager->register_dockable(*dock_curves);
1106 studio_init_cb.task(_("Init Layer Groups..."));
1107 dock_layer_groups = new studio::Dock_LayerGroups();
1108 dock_manager->register_dockable(*dock_layer_groups);
1111 studio_init_cb.task(_("Init Color Dialog..."));
1112 dialog_color=new studio::Dialog_Color();
1114 studio_init_cb.task(_("Init Gradient Dialog..."));
1115 dialog_gradient=new studio::Dialog_Gradient();
1117 studio_init_cb.task(_("Init DeviceTracker..."));
1118 device_tracker=new studio::DeviceTracker();
1120 studio_init_cb.task(_("Init Tools..."));
1121 state_manager->add_state(&state_normal);
1122 state_manager->add_state(&state_smooth_move);
1123 state_manager->add_state(&state_scale);
1124 state_manager->add_state(&state_rotate);
1126 state_manager->add_state(&state_bline);
1129 state_manager->add_state(&state_circle);
1130 state_manager->add_state(&state_rectangle);
1132 state_manager->add_state(&state_gradient);
1133 state_manager->add_state(&state_eyedrop);
1134 state_manager->add_state(&state_fill);
1136 state_manager->add_state(&state_zoom);
1138 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1139 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1140 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1142 // Enabled for now. Let's see whether they're good enough yet.
1143 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1144 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1146 // Disabled by default - it doesn't work properly?
1147 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1149 studio_init_cb.task(_("Init ModPalette..."));
1150 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1152 studio_init_cb.task(_("Init ModMirror..."));
1153 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1156 studio_init_cb.task(_("Init Setup Dialog..."));
1157 dialog_setup=new studio::Dialog_Setup();
1159 studio_init_cb.task(_("Init Input Dialog..."));
1160 dialog_input=new Gtk::InputDialog();
1161 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1162 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1164 studio_init_cb.task(_("Init auto recovery..."));
1165 auto_recover=new AutoRecover();
1167 studio_init_cb.amount_complete(9250,10000);
1168 studio_init_cb.task(_("Loading Settings..."));
1170 studio_init_cb.task(_("Checking auto-recover..."));
1172 studio_init_cb.amount_complete(9900,10000);
1174 if(auto_recover->recovery_needed())
1176 about_window.hide();
1178 get_ui_interface()->yes_no(
1180 _("Synfig Studio seems to have crashed\n"
1181 "before you could save all your files.\n"
1182 "Would you like to re-open those files\n"
1183 "and recover your unsaved changes?")
1184 )==synfigapp::UIInterface::RESPONSE_YES
1187 if(!auto_recover->recover())
1189 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1192 get_ui_interface()->error(
1193 _("Synfig Studio has attempted to recover\n"
1194 "from a previous crash. The files that it has\n"
1195 "recovered are NOT YET SAVED. It would be a good\n"
1196 "idea to review them and save them now.")
1199 about_window.show();
1202 // Look for any files given on the command line,
1203 // and load them if found.
1204 bool opened_any = false;
1205 for(;*argc>=1;(*argc)--)
1206 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1208 studio_init_cb.task(_("Loading files..."));
1209 about_window.hide();
1210 open((*argv)[*argc]);
1212 about_window.show();
1215 // if no file was specified to be opened, create a new document to help new users get started more easily
1216 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1219 studio_init_cb.task(_("Done."));
1220 studio_init_cb.amount_complete(10000,10000);
1226 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1230 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1234 StateManager* App::get_state_manager() { return state_manager; }
1238 shutdown_in_progress=true;
1242 synfigapp::Main::settings().remove_domain("pref");
1244 selected_instance=0;
1246 // Unload all of the modules
1247 for(;!module_list_.empty();module_list_.pop_back())
1250 delete state_manager;
1254 delete auto_recover;
1258 // studio::App::iteration(false);
1262 // studio::App::iteration(false);
1264 // studio::App::iteration(false);
1266 delete dialog_setup;
1268 delete dialog_gradient;
1270 delete dialog_color;
1272 delete dialog_input;
1274 delete dock_manager;
1276 instance_list.clear();
1278 // studio::App::iteration(false);
1282 App::get_user_app_directory()
1284 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1288 App::get_config_file(const synfig::String& file)
1290 return Glib::build_filename(get_user_app_directory(),file);
1294 App::add_recent_file(const std::string &file_name)
1296 std::string filename(file_name);
1298 assert(!filename.empty());
1300 if(filename.empty())
1303 // Toss out any "hidden" files
1304 if(basename(filename)[0]=='.')
1307 // If we aren't an absolute path, turn ourselves into one
1308 if(!is_absolute_path(filename))
1309 filename=absolute_path(filename);
1311 list<string>::iterator iter;
1312 // Check to see if the file is already on the list.
1313 // If it is, then remove it from the list
1314 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1317 recent_files.erase(iter);
1322 // Push the filename to the front of the list
1323 recent_files.push_front(filename);
1325 // Clean out the files at the end of the list.
1326 while(recent_files.size()>(unsigned)get_max_recent_files())
1327 recent_files.pop_back();
1329 signal_recent_files_changed_();
1334 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1337 App::get_time_format()
1339 return _App_time_format;
1343 App::set_time_format(synfig::Time::Format x)
1350 App::save_settings()
1355 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1356 setlocale(LC_NUMERIC, "C");
1358 std::string filename=get_config_file("accelrc");
1359 Gtk::AccelMap::save(filename);
1362 std::string filename=get_config_file("recentfiles");
1364 std::ofstream file(filename.c_str());
1368 synfig::warning("Unable to save %s",filename.c_str());
1372 list<string>::reverse_iterator iter;
1374 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1378 std::string filename=get_config_file("settings");
1379 synfigapp::Main::settings().save_to_file(filename);
1380 setlocale(LC_NUMERIC,old_locale);
1384 synfig::warning("Caught exception when attempting to save settings.");
1389 App::load_settings()
1394 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1395 setlocale(LC_NUMERIC, "C");
1397 std::string filename=get_config_file("accelrc");
1398 Gtk::AccelMap::load(filename);
1401 std::string filename=get_config_file("recentfiles");
1403 std::ifstream file(filename.c_str());
1407 std::string recent_file;
1408 getline(file,recent_file);
1409 if(!recent_file.empty())
1410 add_recent_file(recent_file);
1413 std::string filename=get_config_file("settings");
1414 if(!synfigapp::Main::settings().load_from_file(filename))
1416 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1417 //if(!synfigapp::Main::settings().load_from_file(filename))
1419 gamma.set_gamma(1.0/2.2);
1420 reset_initial_window_configuration();
1423 setlocale(LC_NUMERIC,old_locale);
1427 synfig::warning("Caught exception when attempting to load settings.");
1432 App::reset_initial_window_configuration()
1434 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1435 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1436 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1437 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1438 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1439 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1440 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1441 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1442 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1443 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1444 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1445 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1446 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1447 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1451 App::shutdown_request(GdkEventAny*)
1455 //return !shutdown_in_progress;
1461 if(shutdown_in_progress)return;
1464 get_ui_interface()->task(_("Quit Request"));
1467 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1471 std::list<etl::handle<Instance> >::iterator iter;
1472 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1474 if(!(*iter)->safe_close())
1478 if((*iter)->synfigapp::Instance::get_action_count())
1480 handle<synfigapp::UIInterface> uim;
1481 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1483 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1484 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1486 case synfigapp::UIInterface::RESPONSE_NO:
1488 case synfigapp::UIInterface::RESPONSE_YES:
1491 case synfigapp::UIInterface::RESPONSE_CANCEL:
1500 if((*iter)->synfigapp::Instance::is_modified())
1502 handle<synfigapp::UIInterface> uim;
1503 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1505 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() );
1506 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1508 case synfigapp::UIInterface::RESPONSE_NO:
1510 case synfigapp::UIInterface::RESPONSE_YES:
1511 (*iter)->dialog_cvs_commit();
1513 case synfigapp::UIInterface::RESPONSE_CANCEL:
1522 // This next line causes things to crash for some reason
1526 shutdown_in_progress=true;
1528 instance_list.clear();
1530 while(studio::App::events_pending())studio::App::iteration(false);
1533 auto_recover->normal_shutdown();
1535 get_ui_interface()->task(_("Quit Request sent"));
1541 dialog_setup->refresh();
1542 dialog_setup->show();
1545 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1546 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1549 //#define USE_WIN32_FILE_DIALOGS 1
1552 #ifdef USE_WIN32_FILE_DIALOGS
1553 static OPENFILENAME ofn={};
1557 #include <gdk/gdkwin32.h>
1561 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1563 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1565 #ifdef USE_WIN32_FILE_DIALOGS
1566 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1568 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1569 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1570 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1572 ofn.lStructSize=sizeof(OPENFILENAME);
1573 ofn.hwndOwner = hWnd;
1574 ofn.hInstance = hInstance;
1575 ofn.lpstrFilter = szFilter;
1576 // ofn.lpstrCustomFilter=NULL;
1577 // ofn.nMaxCustFilter=0;
1578 // ofn.nFilterIndex=0;
1579 // ofn.lpstrFile=NULL;
1580 ofn.nMaxFile=MAX_PATH;
1581 // ofn.lpstrFileTitle=NULL;
1582 // ofn.lpstrInitialDir=NULL;
1583 // ofn.lpstrTitle=NULL;
1584 ofn.Flags=OFN_HIDEREADONLY;
1585 // ofn.nFileOffset=0;
1586 // ofn.nFileExtension=0;
1587 ofn.lpstrDefExt=TEXT("sif");
1588 // ofn.lCustData = 0l;
1590 // ofn.lpTemplateName=NULL;
1592 CHAR szFilename[MAX_PATH];
1594 strcpy(szFilename,filename.c_str());
1595 strcpy(szTitle,title.c_str());
1597 ofn.lpstrFile=szFilename;
1598 ofn.lpstrFileTitle=szTitle;
1600 if(GetOpenFileName(&ofn))
1602 filename=szFilename;
1608 synfig::String prev_path;
1610 if(!_preferences.get_value(preference, prev_path))
1613 prev_path = absolute_path(prev_path);
1615 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1617 dialog->set_current_folder(prev_path);
1618 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1619 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1621 if (filename.empty())
1622 dialog->set_filename(prev_path);
1623 else if (is_absolute_path(filename))
1624 dialog->set_filename(filename);
1626 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1628 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1629 filename = dialog->get_filename();
1630 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1631 _preferences.set_value(preference, dirname(filename));
1645 GtkWidget *fileselection;
1646 fileselection = gtk_file_selection_new(title.c_str());
1649 if(basename(filename)==filename)
1651 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1654 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1656 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1658 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1659 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1661 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1662 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1664 gtk_widget_show(fileselection);
1672 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1673 _preferences.set_value(preference,dirname(filename));
1677 gtk_widget_destroy(fileselection);
1680 gtk_widget_destroy(fileselection);
1687 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1689 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1691 #if USE_WIN32_FILE_DIALOGS
1692 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1694 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1695 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1696 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1698 ofn.lStructSize=sizeof(OPENFILENAME);
1699 ofn.hwndOwner = hWnd;
1700 ofn.hInstance = hInstance;
1701 ofn.lpstrFilter = szFilter;
1702 // ofn.lpstrCustomFilter=NULL;
1703 // ofn.nMaxCustFilter=0;
1704 // ofn.nFilterIndex=0;
1705 // ofn.lpstrFile=NULL;
1706 ofn.nMaxFile=MAX_PATH;
1707 // ofn.lpstrFileTitle=NULL;
1708 // ofn.lpstrInitialDir=NULL;
1709 // ofn.lpstrTitle=NULL;
1710 ofn.Flags=OFN_OVERWRITEPROMPT;
1711 // ofn.nFileOffset=0;
1712 // ofn.nFileExtension=0;
1713 ofn.lpstrDefExt=TEXT("sif");
1714 // ofn.lCustData = 0l;
1716 // ofn.lpTemplateName=NULL;
1718 CHAR szFilename[MAX_PATH];
1720 strcpy(szFilename,filename.c_str());
1721 strcpy(szTitle,title.c_str());
1723 ofn.lpstrFile=szFilename;
1724 ofn.lpstrFileTitle=szTitle;
1726 if(GetSaveFileName(&ofn))
1728 filename=szFilename;
1729 _preferences.set_value(preference,dirname(filename));
1734 synfig::String prev_path;
1736 if(!_preferences.get_value(preference, prev_path))
1739 prev_path = absolute_path(prev_path);
1741 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1743 dialog->set_current_folder(prev_path);
1744 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1745 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1747 if (filename.empty())
1748 dialog->set_filename(prev_path);
1751 std::string full_path;
1752 if (is_absolute_path(filename))
1753 full_path = filename;
1755 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1757 // select the file if it exists
1758 dialog->set_filename(full_path);
1760 // if the file doesn't exist, put its name into the filename box
1762 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1763 dialog->set_current_name(basename(filename));
1766 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1767 filename = dialog->get_filename();
1768 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1769 _preferences.set_value(preference, dirname(filename));
1780 App::dialog_error_blocking(const std::string &title, const std::string &message)
1782 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1783 dialog.set_title(title);
1789 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1791 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1792 dialog.set_title(title);
1798 App::dialog_yes_no(const std::string &title, const std::string &message)
1803 true // use_separator
1805 Gtk::Label label(message);
1808 dialog.get_vbox()->pack_start(label);
1809 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1810 dialog.add_button(Gtk::StockID("gtk-no"),0);
1812 return dialog.run();
1816 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1821 true // use_separator
1823 Gtk::Label label(message);
1826 dialog.get_vbox()->pack_start(label);
1827 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1828 dialog.add_button(Gtk::StockID("gtk-no"),0);
1829 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1831 return dialog.run();
1835 App::dialog_not_implemented()
1837 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1838 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1843 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1848 true // use_separator
1850 Gtk::Label label(message);
1852 dialog.get_vbox()->pack_start(label);
1855 entry.set_text(text);
1857 entry.set_activates_default(true);
1858 dialog.get_vbox()->pack_start(entry);
1860 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1861 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1862 dialog.set_default_response(Gtk::RESPONSE_OK);
1863 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1866 if(dialog.run()!=Gtk::RESPONSE_OK)
1869 text=entry.get_text();
1878 App::open(std::string filename)
1880 return open_as(filename,filename);
1883 // this is called from autorecover.cpp:
1884 // App::open_as(get_shadow_file_name(filename),filename)
1885 // other than that, 'filename' and 'as' are the same
1887 App::open_as(std::string filename,std::string as)
1890 char long_name[1024];
1891 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1897 OneMoment one_moment;
1899 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1900 if(canvas && get_instance(canvas))
1902 get_instance(canvas)->find_canvas_view(canvas)->present();
1903 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1906 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1908 add_recent_file(as);
1910 handle<Instance> instance(Instance::create(canvas));
1913 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1917 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)")))
1918 instance->dialog_cvs_update();
1922 dialog_error_blocking(_("Error"), x);
1927 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1938 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1939 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1941 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1943 canvas->rend_desc().set_frame_rate(24.0);
1944 canvas->rend_desc().set_time_start(0.0);
1945 canvas->rend_desc().set_time_end(5.0);
1946 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1947 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1948 canvas->rend_desc().set_tl(Vector(-4,2.25));
1949 canvas->rend_desc().set_br(Vector(4,-2.25));
1950 canvas->rend_desc().set_w(480);
1951 canvas->rend_desc().set_h(270);
1952 canvas->rend_desc().set_antialias(1);
1953 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1954 canvas->set_file_name(file_name);
1956 handle<Instance> instance = Instance::create(canvas);
1958 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1959 instance->find_canvas_view(canvas)->canvas_properties.present();
1965 string filename="*.sif";
1967 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
1969 // If the filename still has wildcards, then we should
1970 // continue looking for the file we want
1971 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1977 get_ui_interface()->error(_("Unable to open file"));
1982 App::set_selected_instance(etl::loose_handle<Instance> instance)
1984 /* if(get_selected_instance()==instance)
1986 selected_instance=instance;
1987 signal_instance_selected()(instance);
1993 selected_instance=instance;
1994 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
1998 instance->focus(instance->get_canvas());
2001 set_selected_canvas_view(0);
2003 signal_instance_selected()(instance);
2007 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2009 selected_canvas_view=canvas_view;
2010 signal_canvas_view_focus()(selected_canvas_view);
2013 selected_instance=canvas_view->get_instance();
2014 signal_instance_selected()(canvas_view->get_instance());
2017 if(get_selected_canvas_view()==canvas_view)
2019 signal_canvas_view_focus()(selected_canvas_view);
2020 signal_instance_selected()(canvas_view->get_instance());
2023 selected_canvas_view=canvas_view;
2024 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2025 set_selected_instance(canvas_view->get_instance());
2026 signal_canvas_view_focus()(selected_canvas_view);
2030 etl::loose_handle<Instance>
2031 App::get_instance(etl::handle<synfig::Canvas> canvas)
2033 if(!canvas) return 0;
2034 canvas=canvas->get_root();
2036 std::list<etl::handle<Instance> >::iterator iter;
2037 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2039 if((*iter)->get_canvas()==canvas)
2048 (new class About())->show();
2054 if(selected_instance)
2055 selected_instance->undo();
2061 if(selected_instance)
2062 selected_instance->redo();
2066 studio::App::get_base_path()
2068 return app_base_path_;