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 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
643 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
644 DEFINE_ACTION("play", _("Play"));
645 // DEFINE_ACTION("pause", _("Pause"));
646 DEFINE_ACTION("stop", _("Stop"));
647 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
648 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
649 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
650 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
651 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
652 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
653 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
654 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
655 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
656 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
657 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
658 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
659 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
660 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
661 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
662 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
663 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
664 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
665 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
666 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
667 DEFINE_ACTION("seek-end", _("Seek to End"));
669 DEFINE_ACTION("action-group_add", _("Add group"));
671 DEFINE_ACTION("canvas-new", _("New Canvas"));
673 DEFINE_ACTION("amount-inc", _("Increase Amount"));
674 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
679 // Set up synfigapp actions
681 synfigapp::Action::Book::iterator iter;
683 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
685 Gtk::StockID stock_id;
687 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
689 //Gtk::Image* image(manage(new Gtk::Image()));
690 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
691 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
692 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
693 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
694 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
695 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
696 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
697 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
698 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
699 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
701 actions_action_group->add(Gtk::Action::create(
702 "action-"+iter->second.name,
704 iter->second.local_name,iter->second.local_name
712 Glib::ustring ui_info =
714 " <popup name='menu-toolbox' action='menu-toolbox'>"
715 " <menu action='menu-file'>"
718 " <popup name='menu-main' action='menu-main'>"
719 " <menu action='menu-file'>"
720 " <menuitem action='new' />"
721 " <menuitem action='open' />"
722 " <menuitem action='save' />"
723 " <menuitem action='save-as' />"
724 " <menuitem action='revert' />"
725 " <separator name='bleh01'/>"
726 " <menuitem action='cvs-add' />"
727 " <menuitem action='cvs-update' />"
728 " <menuitem action='cvs-commit' />"
729 " <menuitem action='cvs-revert' />"
730 " <separator name='bleh02'/>"
731 " <menuitem action='import' />"
732 " <separator name='bleh03'/>"
733 " <menuitem action='render' />"
734 " <menuitem action='preview' />"
735 " <menuitem action='sound' />"
736 " <separator name='bleh04'/>"
737 " <menuitem action='options' />"
738 " <menuitem action='close' />"
739 " <menuitem action='close-document' />"
740 " <menuitem action='quit' />"
742 " <menu action='menu-edit'>"
743 " <menuitem action='undo'/>"
744 " <menuitem action='redo'/>"
745 " <separator name='bleh05'/>"
746 " <menuitem action='cut'/>"
747 " <menuitem action='copy'/>"
748 " <menuitem action='paste'/>"
749 " <separator name='bleh06'/>"
750 " <menuitem action='select-all-ducks'/>"
751 " <menuitem action='unselect-all-layers'/>"
752 " <separator name='bleh07'/>"
753 " <menuitem action='properties'/>"
755 " <menu action='menu-view'>"
756 " <menu action='menu-duck-mask'>"
757 " <menuitem action='mask-position-ducks' />"
758 " <menuitem action='mask-vertex-ducks' />"
759 " <menuitem action='mask-tangent-ducks' />"
760 " <menuitem action='mask-radius-ducks' />"
761 " <menuitem action='mask-width-ducks' />"
762 " <menuitem action='mask-angle-ducks' />"
764 " <menu action='menu-preview-quality'>"
765 " <menuitem action='quality-00' />"
766 " <menuitem action='quality-01' />"
767 " <menuitem action='quality-02' />"
768 " <menuitem action='quality-03' />"
769 " <menuitem action='quality-04' />"
770 " <menuitem action='quality-05' />"
771 " <menuitem action='quality-06' />"
772 " <menuitem action='quality-07' />"
773 " <menuitem action='quality-08' />"
774 " <menuitem action='quality-09' />"
775 " <menuitem action='quality-10' />"
777 " <menu action='menu-lowres-pixel'>"
778 " <menuitem action='decrease-low-res-pixel-size'/>"
779 " <menuitem action='increase-low-res-pixel-size'/>"
780 " <separator name='pixel-size-separator'/>"
783 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
784 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
788 " <separator name='bleh08'/>"
789 " <menuitem action='play'/>"
790 //" <menuitem action='pause'/>"
791 " <menuitem action='stop'/>"
792 " <menuitem action='dialog-flipbook'/>"
793 " <separator name='bleh09'/>"
794 " <menuitem action='toggle-grid-show'/>"
795 " <menuitem action='toggle-grid-snap'/>"
796 " <menuitem action='toggle-guide-show'/>"
797 " <menuitem action='toggle-low-res'/>"
798 " <menuitem action='toggle-onion-skin'/>"
799 " <separator name='bleh10'/>"
800 " <menuitem action='canvas-zoom-in'/>"
801 " <menuitem action='canvas-zoom-out'/>"
802 " <menuitem action='canvas-zoom-fit'/>"
803 " <menuitem action='canvas-zoom-100'/>"
804 " <separator name='bleh11'/>"
805 " <menuitem action='time-zoom-in'/>"
806 " <menuitem action='time-zoom-out'/>"
807 " <separator name='bleh12'/>"
808 " <menuitem action='jump-next-keyframe'/>"
809 " <menuitem action='jump-prev-keyframe'/>"
810 " <menuitem action='seek-next-frame'/>"
811 " <menuitem action='seek-prev-frame'/>"
812 " <menuitem action='seek-next-second'/>"
813 " <menuitem action='seek-prev-second'/>"
814 " <menuitem action='seek-begin'/>"
815 " <menuitem action='seek-end'/>"
817 " <menu action='menu-canvas'>"
818 " <menuitem action='canvas-new'/>"
820 " <menu name='menu-state' action='menu-state'>"
822 " <menu action='menu-group'>"
823 " <menuitem action='action-group_add'/>"
825 " <menu action='menu-layer'>"
826 //" <menuitem action='cut'/>"
827 //" <menuitem action='copy'/>"
828 //" <menuitem action='paste'/>"
829 //" <separator name='bleh06'/>"
830 " <menu action='menu-layer-new'></menu>"
831 " <menuitem action='amount-inc'/>"
832 " <menuitem action='amount-dec'/>"
834 " <menu action='menu-keyframe'>"
835 " <menuitem action='keyframe-properties'/>"
842 " <menubar name='MenuBar'>"
843 " <menu action='MenuFile'>"
844 " <menuitem action='New'/>"
845 " <menuitem action='Open'/>"
847 " <menuitem action='Quit'/>"
849 " <menu action='MenuEdit'>"
850 " <menuitem action='Cut'/>"
851 " <menuitem action='Copy'/>"
852 " <menuitem action='Paste'/>"
855 " <toolbar name='ToolBar'>"
856 " <toolitem action='Open'/>"
857 " <toolitem action='Quit'/>"
863 actions_action_group->set_sensitive(false);
864 App::ui_manager()->set_add_tearoffs(true);
865 App::ui_manager()->insert_action_group(menus_action_group,1);
866 App::ui_manager()->insert_action_group(actions_action_group,1);
867 App::ui_manager()->add_ui_from_string(ui_info);
869 //App::ui_manager()->get_accel_group()->unlock();
871 catch(const Glib::Error& ex)
873 synfig::error("building menus and toolbars failed: " + ex.what());
876 // Add default keyboard accelerators
877 #define ACCEL(path,accel) \
879 Gtk::AccelKey accel_key(accel,path); \
880 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
883 #define ACCEL2(accel) \
885 Gtk::AccelKey accel_key(accel); \
886 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
889 ACCEL("<Actions>//select-all-ducks","<Control>a");
890 ACCEL("<Actions>//unselect-all-layers","<Control>d");
891 ACCEL("<Actions>//render","F9");
892 ACCEL("<Actions>//preview","F11");
893 ACCEL("<Actions>//properties","F8");
894 ACCEL("<Actions>//options","F12");
895 ACCEL("<Actions>//import","<control>i");
896 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
897 ACCEL("<Actions>//toggle-grid-show","<Control>g");
898 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
899 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
900 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
901 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
902 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
903 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
904 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
905 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
907 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
908 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
910 ACCEL("<Actions>//quality-01","<Control>1");
911 ACCEL("<Actions>//quality-02","<Control>2");
912 ACCEL("<Actions>//quality-03","<Control>3");
913 ACCEL("<Actions>//quality-04","<Control>4");
914 ACCEL("<Actions>//quality-05","<Control>5");
915 ACCEL("<Actions>//quality-06","<Control>6");
916 ACCEL("<Actions>//quality-07","<Control>7");
917 ACCEL("<Actions>//quality-08","<Control>8");
918 ACCEL("<Actions>//quality-09","<Control>9");
919 ACCEL("<Actions>//quality-10","<Control>0");
920 ACCEL("<Actions>//undo","<Control>z");
921 ACCEL("<Actions>//redo","<Control>r");
922 ACCEL("<Actions>//action-layer_remove","Delete");
924 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
925 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
926 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
927 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
928 ACCEL("<Actions>//time-zoom-in","+");
929 ACCEL("<Actions>//time-zoom-out","_");
931 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
932 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
934 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
935 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
937 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
938 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
939 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
940 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
941 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
942 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
943 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
944 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
945 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
946 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
947 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
948 ACCEL("<Actions>//play", "<Control>p");
949 ACCEL("<Actions>//seek-begin","Home");
950 ACCEL("<Actions>//seek-end","End");
952 ACCEL("<Actions>//state-normal", "<Mod1>a");
953 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
954 ACCEL("<Actions>//state-scale", "<Mod1>d");
955 ACCEL("<Actions>//state-rotate", "<Mod1>s");
957 ACCEL("<Actions>//state-bline", "<Mod1>b");
958 ACCEL("<Actions>//state-circle", "<Mod1>c");
959 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
960 ACCEL("<Actions>//state-gradient", "<Mod1>g");
962 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
963 ACCEL("<Actions>//state-fill", "<Mod1>f");
964 ACCEL("<Actions>//state-zoom", "<Mod1>z");
965 ACCEL("<Actions>//state-polygon", "<Mod1>p");
967 ACCEL("<Actions>//state-draw", "<Mod1>w");
968 ACCEL("<Actions>//state-sketch", "<Mod1>k");
969 ACCEL("<Actions>//state-width", "<Mod1>t");
970 ACCEL("<Actions>//state-mirror", "<Mod1>m");
972 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
978 #define mkdir(x,y) mkdir(x)
981 /* === M E T H O D S ======================================================= */
983 App::App(int *argc, char ***argv):
984 Gtk::Main(argc,argv),
985 IconController(etl::dirname((*argv)[0]))
987 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
990 ui_interface_=new GlobalUIInterface();
994 // don't call thread_init() if threads are already initialized
995 // on some machines bonobo_init() initialized threads before we get here
996 if (!g_thread_supported())
999 distance_system=Distance::SYSTEM_UNITS;
1001 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1004 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1008 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1014 if(!SYNFIG_CHECK_VERSION())
1016 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1017 dialog_error_blocking("Synfig Studio",
1018 "This copy of Synfig Studio was compiled against a\n"
1019 "different version of libsynfig than what is currently\n"
1020 "installed. Synfig Studio will now abort. Try downloading\n"
1021 "the latest version from the Synfig website at\n"
1022 "http://synfig.org/Download"
1026 Glib::set_application_name(_("Synfig Studio"));
1029 about_window.set_can_self_destruct(false);
1030 about_window.show();
1032 shutdown_in_progress=false;
1033 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1034 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1036 // Initialize the Synfig library
1037 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1040 get_ui_interface()->error(_("Failed to initialize synfig!"));
1044 // add the preferences to the settings
1045 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1049 studio_init_cb.task(_("Init UI Manager..."));
1050 App::ui_manager_=studio::UIManager::create();
1053 studio_init_cb.task(_("Init Dock Manager..."));
1054 dock_manager=new studio::DockManager();
1056 studio_init_cb.task(_("Init State Manager..."));
1057 state_manager=new StateManager();
1059 studio_init_cb.task(_("Init Toolbox..."));
1060 toolbox=new studio::Toolbox();
1062 studio_init_cb.task(_("Init Tool Options..."));
1063 dialog_tool_options=new studio::Dialog_ToolOptions();
1064 dock_manager->register_dockable(*dialog_tool_options);
1066 studio_init_cb.task(_("Init History..."));
1067 dock_history=new studio::Dock_History();
1068 dock_manager->register_dockable(*dock_history);
1070 studio_init_cb.task(_("Init Canvases..."));
1071 dock_canvases=new studio::Dock_Canvases();
1072 dock_manager->register_dockable(*dock_canvases);
1074 studio_init_cb.task(_("Init Keyframes..."));
1075 dock_keyframes=new studio::Dock_Keyframes();
1076 dock_manager->register_dockable(*dock_keyframes);
1078 studio_init_cb.task(_("Init Layers..."));
1079 dock_layers=new studio::Dock_Layers();
1080 dock_manager->register_dockable(*dock_layers);
1082 studio_init_cb.task(_("Init Params..."));
1083 dock_params=new studio::Dock_Params();
1084 dock_manager->register_dockable(*dock_params);
1086 studio_init_cb.task(_("Init MetaData..."));
1087 dock_meta_data=new studio::Dock_MetaData();
1088 dock_manager->register_dockable(*dock_meta_data);
1090 studio_init_cb.task(_("Init Children..."));
1091 dock_children=new studio::Dock_Children();
1092 dock_manager->register_dockable(*dock_children);
1094 studio_init_cb.task(_("Init Info..."));
1095 dock_info = new studio::Dock_Info();
1096 dock_manager->register_dockable(*dock_info);
1098 studio_init_cb.task(_("Init Navigator..."));
1099 dock_navigator = new studio::Dock_Navigator();
1100 dock_manager->register_dockable(*dock_navigator);
1102 studio_init_cb.task(_("Init Timetrack..."));
1103 dock_timetrack = new studio::Dock_Timetrack();
1104 dock_manager->register_dockable(*dock_timetrack);
1106 studio_init_cb.task(_("Init Curve Editor..."));
1107 dock_curves = new studio::Dock_Curves();
1108 dock_manager->register_dockable(*dock_curves);
1110 studio_init_cb.task(_("Init Layer Groups..."));
1111 dock_layer_groups = new studio::Dock_LayerGroups();
1112 dock_manager->register_dockable(*dock_layer_groups);
1115 studio_init_cb.task(_("Init Color Dialog..."));
1116 dialog_color=new studio::Dialog_Color();
1118 studio_init_cb.task(_("Init Gradient Dialog..."));
1119 dialog_gradient=new studio::Dialog_Gradient();
1121 studio_init_cb.task(_("Init DeviceTracker..."));
1122 device_tracker=new studio::DeviceTracker();
1124 studio_init_cb.task(_("Init Tools..."));
1125 state_manager->add_state(&state_normal);
1126 state_manager->add_state(&state_smooth_move);
1127 state_manager->add_state(&state_scale);
1128 state_manager->add_state(&state_rotate);
1130 state_manager->add_state(&state_bline);
1133 state_manager->add_state(&state_circle);
1134 state_manager->add_state(&state_rectangle);
1136 state_manager->add_state(&state_gradient);
1137 state_manager->add_state(&state_eyedrop);
1138 state_manager->add_state(&state_fill);
1140 state_manager->add_state(&state_zoom);
1142 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1143 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1144 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1146 // Enabled for now. Let's see whether they're good enough yet.
1147 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1148 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1150 // Disabled by default - it doesn't work properly?
1151 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1153 studio_init_cb.task(_("Init ModPalette..."));
1154 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1156 studio_init_cb.task(_("Init ModMirror..."));
1157 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1160 studio_init_cb.task(_("Init Setup Dialog..."));
1161 dialog_setup=new studio::Dialog_Setup();
1163 studio_init_cb.task(_("Init Input Dialog..."));
1164 dialog_input=new Gtk::InputDialog();
1165 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1166 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1168 studio_init_cb.task(_("Init auto recovery..."));
1169 auto_recover=new AutoRecover();
1171 studio_init_cb.amount_complete(9250,10000);
1172 studio_init_cb.task(_("Loading Settings..."));
1174 studio_init_cb.task(_("Checking auto-recover..."));
1176 studio_init_cb.amount_complete(9900,10000);
1178 if(auto_recover->recovery_needed())
1180 about_window.hide();
1182 get_ui_interface()->yes_no(
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
1191 if(!auto_recover->recover())
1193 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1196 get_ui_interface()->error(
1197 _("Synfig Studio has attempted to recover\n"
1198 "from a previous crash. The files that it has\n"
1199 "recovered are NOT YET SAVED. It would be a good\n"
1200 "idea to review them and save them now.")
1203 about_window.show();
1206 // Look for any files given on the command line,
1207 // and load them if found.
1208 bool opened_any = false;
1209 for(;*argc>=1;(*argc)--)
1210 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1212 studio_init_cb.task(_("Loading files..."));
1213 about_window.hide();
1214 open((*argv)[*argc]);
1216 about_window.show();
1219 // if no file was specified to be opened, create a new document to help new users get started more easily
1220 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1223 studio_init_cb.task(_("Done."));
1224 studio_init_cb.amount_complete(10000,10000);
1230 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1234 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1238 StateManager* App::get_state_manager() { return state_manager; }
1242 shutdown_in_progress=true;
1246 synfigapp::Main::settings().remove_domain("pref");
1248 selected_instance=0;
1250 // Unload all of the modules
1251 for(;!module_list_.empty();module_list_.pop_back())
1254 delete state_manager;
1258 delete auto_recover;
1262 // studio::App::iteration(false);
1266 // studio::App::iteration(false);
1268 // studio::App::iteration(false);
1270 delete dialog_setup;
1272 delete dialog_gradient;
1274 delete dialog_color;
1276 delete dialog_input;
1278 delete dock_manager;
1280 instance_list.clear();
1282 // studio::App::iteration(false);
1286 App::get_user_app_directory()
1288 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1292 App::get_config_file(const synfig::String& file)
1294 return Glib::build_filename(get_user_app_directory(),file);
1298 App::add_recent_file(const std::string &file_name)
1300 std::string filename(file_name);
1302 assert(!filename.empty());
1304 if(filename.empty())
1307 // Toss out any "hidden" files
1308 if(basename(filename)[0]=='.')
1311 // If we aren't an absolute path, turn ourselves into one
1312 if(!is_absolute_path(filename))
1313 filename=absolute_path(filename);
1315 list<string>::iterator iter;
1316 // Check to see if the file is already on the list.
1317 // If it is, then remove it from the list
1318 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1321 recent_files.erase(iter);
1326 // Push the filename to the front of the list
1327 recent_files.push_front(filename);
1329 // Clean out the files at the end of the list.
1330 while(recent_files.size()>(unsigned)get_max_recent_files())
1331 recent_files.pop_back();
1333 signal_recent_files_changed_();
1338 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1341 App::get_time_format()
1343 return _App_time_format;
1347 App::set_time_format(synfig::Time::Format x)
1354 App::save_settings()
1359 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1360 setlocale(LC_NUMERIC, "C");
1362 std::string filename=get_config_file("accelrc");
1363 Gtk::AccelMap::save(filename);
1366 std::string filename=get_config_file("recentfiles");
1368 std::ofstream file(filename.c_str());
1372 synfig::warning("Unable to save %s",filename.c_str());
1376 list<string>::reverse_iterator iter;
1378 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1382 std::string filename=get_config_file("settings");
1383 synfigapp::Main::settings().save_to_file(filename);
1384 setlocale(LC_NUMERIC,old_locale);
1388 synfig::warning("Caught exception when attempting to save settings.");
1393 App::load_settings()
1398 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1399 setlocale(LC_NUMERIC, "C");
1401 std::string filename=get_config_file("accelrc");
1402 Gtk::AccelMap::load(filename);
1405 std::string filename=get_config_file("recentfiles");
1407 std::ifstream file(filename.c_str());
1411 std::string recent_file;
1412 getline(file,recent_file);
1413 if(!recent_file.empty())
1414 add_recent_file(recent_file);
1417 std::string filename=get_config_file("settings");
1418 if(!synfigapp::Main::settings().load_from_file(filename))
1420 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1421 //if(!synfigapp::Main::settings().load_from_file(filename))
1423 gamma.set_gamma(1.0/2.2);
1424 reset_initial_window_configuration();
1427 setlocale(LC_NUMERIC,old_locale);
1431 synfig::warning("Caught exception when attempting to load settings.");
1436 App::reset_initial_window_configuration()
1438 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1439 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1440 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1441 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1442 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1443 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1444 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1445 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1446 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1447 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1448 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1449 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1450 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1451 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1455 App::shutdown_request(GdkEventAny*)
1459 //return !shutdown_in_progress;
1465 if(shutdown_in_progress)return;
1468 get_ui_interface()->task(_("Quit Request"));
1471 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1475 std::list<etl::handle<Instance> >::iterator iter;
1476 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1478 if(!(*iter)->safe_close())
1482 if((*iter)->synfigapp::Instance::get_action_count())
1484 handle<synfigapp::UIInterface> uim;
1485 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1487 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1488 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1490 case synfigapp::UIInterface::RESPONSE_NO:
1492 case synfigapp::UIInterface::RESPONSE_YES:
1495 case synfigapp::UIInterface::RESPONSE_CANCEL:
1504 if((*iter)->synfigapp::Instance::is_modified())
1506 handle<synfigapp::UIInterface> uim;
1507 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1509 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() );
1510 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1512 case synfigapp::UIInterface::RESPONSE_NO:
1514 case synfigapp::UIInterface::RESPONSE_YES:
1515 (*iter)->dialog_cvs_commit();
1517 case synfigapp::UIInterface::RESPONSE_CANCEL:
1526 // This next line causes things to crash for some reason
1530 shutdown_in_progress=true;
1532 instance_list.clear();
1534 while(studio::App::events_pending())studio::App::iteration(false);
1537 auto_recover->normal_shutdown();
1539 get_ui_interface()->task(_("Quit Request sent"));
1545 dialog_setup->refresh();
1546 dialog_setup->show();
1549 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1550 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1553 //#define USE_WIN32_FILE_DIALOGS 1
1556 #ifdef USE_WIN32_FILE_DIALOGS
1557 static OPENFILENAME ofn={};
1561 #include <gdk/gdkwin32.h>
1565 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1567 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1569 #ifdef USE_WIN32_FILE_DIALOGS
1570 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1572 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1573 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1574 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1576 ofn.lStructSize=sizeof(OPENFILENAME);
1577 ofn.hwndOwner = hWnd;
1578 ofn.hInstance = hInstance;
1579 ofn.lpstrFilter = szFilter;
1580 // ofn.lpstrCustomFilter=NULL;
1581 // ofn.nMaxCustFilter=0;
1582 // ofn.nFilterIndex=0;
1583 // ofn.lpstrFile=NULL;
1584 ofn.nMaxFile=MAX_PATH;
1585 // ofn.lpstrFileTitle=NULL;
1586 // ofn.lpstrInitialDir=NULL;
1587 // ofn.lpstrTitle=NULL;
1588 ofn.Flags=OFN_HIDEREADONLY;
1589 // ofn.nFileOffset=0;
1590 // ofn.nFileExtension=0;
1591 ofn.lpstrDefExt=TEXT("sif");
1592 // ofn.lCustData = 0l;
1594 // ofn.lpTemplateName=NULL;
1596 CHAR szFilename[MAX_PATH];
1598 strcpy(szFilename,filename.c_str());
1599 strcpy(szTitle,title.c_str());
1601 ofn.lpstrFile=szFilename;
1602 ofn.lpstrFileTitle=szTitle;
1604 if(GetOpenFileName(&ofn))
1606 filename=szFilename;
1612 synfig::String prev_path;
1614 if(!_preferences.get_value(preference, prev_path))
1617 prev_path = absolute_path(prev_path);
1619 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1621 dialog->set_current_folder(prev_path);
1622 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1623 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1625 if (filename.empty())
1626 dialog->set_filename(prev_path);
1627 else if (is_absolute_path(filename))
1628 dialog->set_filename(filename);
1630 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1632 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1633 filename = dialog->get_filename();
1634 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1635 _preferences.set_value(preference, dirname(filename));
1649 GtkWidget *fileselection;
1650 fileselection = gtk_file_selection_new(title.c_str());
1653 if(basename(filename)==filename)
1655 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1658 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1660 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1662 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1663 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1665 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1666 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1668 gtk_widget_show(fileselection);
1676 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1677 _preferences.set_value(preference,dirname(filename));
1681 gtk_widget_destroy(fileselection);
1684 gtk_widget_destroy(fileselection);
1691 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1693 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1695 #if USE_WIN32_FILE_DIALOGS
1696 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1698 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1699 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1700 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1702 ofn.lStructSize=sizeof(OPENFILENAME);
1703 ofn.hwndOwner = hWnd;
1704 ofn.hInstance = hInstance;
1705 ofn.lpstrFilter = szFilter;
1706 // ofn.lpstrCustomFilter=NULL;
1707 // ofn.nMaxCustFilter=0;
1708 // ofn.nFilterIndex=0;
1709 // ofn.lpstrFile=NULL;
1710 ofn.nMaxFile=MAX_PATH;
1711 // ofn.lpstrFileTitle=NULL;
1712 // ofn.lpstrInitialDir=NULL;
1713 // ofn.lpstrTitle=NULL;
1714 ofn.Flags=OFN_OVERWRITEPROMPT;
1715 // ofn.nFileOffset=0;
1716 // ofn.nFileExtension=0;
1717 ofn.lpstrDefExt=TEXT("sif");
1718 // ofn.lCustData = 0l;
1720 // ofn.lpTemplateName=NULL;
1722 CHAR szFilename[MAX_PATH];
1724 strcpy(szFilename,filename.c_str());
1725 strcpy(szTitle,title.c_str());
1727 ofn.lpstrFile=szFilename;
1728 ofn.lpstrFileTitle=szTitle;
1730 if(GetSaveFileName(&ofn))
1732 filename=szFilename;
1733 _preferences.set_value(preference,dirname(filename));
1738 synfig::String prev_path;
1740 if(!_preferences.get_value(preference, prev_path))
1743 prev_path = absolute_path(prev_path);
1745 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1747 dialog->set_current_folder(prev_path);
1748 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1749 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1751 if (filename.empty())
1752 dialog->set_filename(prev_path);
1755 std::string full_path;
1756 if (is_absolute_path(filename))
1757 full_path = filename;
1759 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1761 // select the file if it exists
1762 dialog->set_filename(full_path);
1764 // if the file doesn't exist, put its name into the filename box
1766 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1767 dialog->set_current_name(basename(filename));
1770 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1771 filename = dialog->get_filename();
1772 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1773 _preferences.set_value(preference, dirname(filename));
1784 App::dialog_error_blocking(const std::string &title, const std::string &message)
1786 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1787 dialog.set_title(title);
1793 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1795 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1796 dialog.set_title(title);
1802 App::dialog_yes_no(const std::string &title, const std::string &message)
1807 true // use_separator
1809 Gtk::Label label(message);
1812 dialog.get_vbox()->pack_start(label);
1813 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1814 dialog.add_button(Gtk::StockID("gtk-no"),0);
1816 return dialog.run();
1820 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1825 true // use_separator
1827 Gtk::Label label(message);
1830 dialog.get_vbox()->pack_start(label);
1831 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1832 dialog.add_button(Gtk::StockID("gtk-no"),0);
1833 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1835 return dialog.run();
1839 App::dialog_not_implemented()
1841 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1842 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1847 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1852 true // use_separator
1854 Gtk::Label label(message);
1856 dialog.get_vbox()->pack_start(label);
1859 entry.set_text(text);
1861 entry.set_activates_default(true);
1862 dialog.get_vbox()->pack_start(entry);
1864 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1865 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1866 dialog.set_default_response(Gtk::RESPONSE_OK);
1867 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1870 if(dialog.run()!=Gtk::RESPONSE_OK)
1873 text=entry.get_text();
1882 App::open(std::string filename)
1884 return open_as(filename,filename);
1887 // this is called from autorecover.cpp:
1888 // App::open_as(get_shadow_file_name(filename),filename)
1889 // other than that, 'filename' and 'as' are the same
1891 App::open_as(std::string filename,std::string as)
1894 char long_name[1024];
1895 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1901 OneMoment one_moment;
1903 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1904 if(canvas && get_instance(canvas))
1906 get_instance(canvas)->find_canvas_view(canvas)->present();
1907 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1910 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1912 add_recent_file(as);
1914 handle<Instance> instance(Instance::create(canvas));
1917 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1921 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)")))
1922 instance->dialog_cvs_update();
1926 dialog_error_blocking(_("Error"), x);
1931 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1942 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1943 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1945 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1947 canvas->rend_desc().set_frame_rate(24.0);
1948 canvas->rend_desc().set_time_start(0.0);
1949 canvas->rend_desc().set_time_end(5.0);
1950 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1951 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1952 canvas->rend_desc().set_tl(Vector(-4,2.25));
1953 canvas->rend_desc().set_br(Vector(4,-2.25));
1954 canvas->rend_desc().set_w(480);
1955 canvas->rend_desc().set_h(270);
1956 canvas->rend_desc().set_antialias(1);
1957 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1958 canvas->set_file_name(file_name);
1960 handle<Instance> instance = Instance::create(canvas);
1962 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1963 instance->find_canvas_view(canvas)->canvas_properties.present();
1969 string filename="*.sif";
1971 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
1973 // If the filename still has wildcards, then we should
1974 // continue looking for the file we want
1975 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1981 get_ui_interface()->error(_("Unable to open file"));
1986 App::set_selected_instance(etl::loose_handle<Instance> instance)
1988 /* if(get_selected_instance()==instance)
1990 selected_instance=instance;
1991 signal_instance_selected()(instance);
1997 selected_instance=instance;
1998 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2002 instance->focus(instance->get_canvas());
2005 set_selected_canvas_view(0);
2007 signal_instance_selected()(instance);
2011 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2013 selected_canvas_view=canvas_view;
2014 signal_canvas_view_focus()(selected_canvas_view);
2017 selected_instance=canvas_view->get_instance();
2018 signal_instance_selected()(canvas_view->get_instance());
2021 if(get_selected_canvas_view()==canvas_view)
2023 signal_canvas_view_focus()(selected_canvas_view);
2024 signal_instance_selected()(canvas_view->get_instance());
2027 selected_canvas_view=canvas_view;
2028 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2029 set_selected_instance(canvas_view->get_instance());
2030 signal_canvas_view_focus()(selected_canvas_view);
2034 etl::loose_handle<Instance>
2035 App::get_instance(etl::handle<synfig::Canvas> canvas)
2037 if(!canvas) return 0;
2038 canvas=canvas->get_root();
2040 std::list<etl::handle<Instance> >::iterator iter;
2041 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2043 if((*iter)->get_canvas()==canvas)
2052 (new class About())->show();
2058 if(selected_instance)
2059 selected_instance->undo();
2065 if(selected_instance)
2066 selected_instance->redo();
2070 studio::App::get_base_path()
2072 return app_base_path_;