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("toggle-onion-skin", _("Toggle Onion Skin"));
652 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
653 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
654 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
655 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
656 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
657 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
658 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
659 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
660 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
661 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
662 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
663 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
664 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
665 DEFINE_ACTION("seek-end", _("Seek to End"));
667 DEFINE_ACTION("action-group_add", _("Add group"));
669 DEFINE_ACTION("canvas-new", _("New Canvas"));
671 DEFINE_ACTION("amount-inc", _("Increase Amount"));
672 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
677 // Set up synfigapp actions
679 synfigapp::Action::Book::iterator iter;
681 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
683 Gtk::StockID stock_id;
685 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
687 //Gtk::Image* image(manage(new Gtk::Image()));
688 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
689 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
690 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
691 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
692 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
693 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
694 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
695 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
696 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
697 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
699 actions_action_group->add(Gtk::Action::create(
700 "action-"+iter->second.name,
702 iter->second.local_name,iter->second.local_name
710 Glib::ustring ui_info =
712 " <popup name='menu-toolbox' action='menu-toolbox'>"
713 " <menu action='menu-file'>"
716 " <popup name='menu-main' action='menu-main'>"
717 " <menu action='menu-file'>"
718 " <menuitem action='new' />"
719 " <menuitem action='open' />"
720 " <menuitem action='save' />"
721 " <menuitem action='save-as' />"
722 " <menuitem action='revert' />"
723 " <separator name='bleh01'/>"
724 " <menuitem action='cvs-add' />"
725 " <menuitem action='cvs-update' />"
726 " <menuitem action='cvs-commit' />"
727 " <menuitem action='cvs-revert' />"
728 " <separator name='bleh02'/>"
729 " <menuitem action='import' />"
730 " <separator name='bleh03'/>"
731 " <menuitem action='render' />"
732 " <menuitem action='preview' />"
733 " <menuitem action='sound' />"
734 " <separator name='bleh04'/>"
735 " <menuitem action='options' />"
736 " <menuitem action='close' />"
737 " <menuitem action='close-document' />"
738 " <menuitem action='quit' />"
740 " <menu action='menu-edit'>"
741 " <menuitem action='undo'/>"
742 " <menuitem action='redo'/>"
743 " <separator name='bleh05'/>"
744 " <menuitem action='cut'/>"
745 " <menuitem action='copy'/>"
746 " <menuitem action='paste'/>"
747 " <separator name='bleh06'/>"
748 " <menuitem action='select-all-ducks'/>"
749 " <menuitem action='unselect-all-layers'/>"
750 " <separator name='bleh07'/>"
751 " <menuitem action='properties'/>"
753 " <menu action='menu-view'>"
754 " <menu action='menu-duck-mask'>"
755 " <menuitem action='mask-position-ducks' />"
756 " <menuitem action='mask-vertex-ducks' />"
757 " <menuitem action='mask-tangent-ducks' />"
758 " <menuitem action='mask-radius-ducks' />"
759 " <menuitem action='mask-width-ducks' />"
760 " <menuitem action='mask-angle-ducks' />"
762 " <menu action='menu-preview-quality'>"
763 " <menuitem action='quality-00' />"
764 " <menuitem action='quality-01' />"
765 " <menuitem action='quality-02' />"
766 " <menuitem action='quality-03' />"
767 " <menuitem action='quality-04' />"
768 " <menuitem action='quality-05' />"
769 " <menuitem action='quality-06' />"
770 " <menuitem action='quality-07' />"
771 " <menuitem action='quality-08' />"
772 " <menuitem action='quality-09' />"
773 " <menuitem action='quality-10' />"
775 " <menu action='menu-lowres-pixel'>";
777 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
778 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
782 " <separator name='bleh08'/>"
783 " <menuitem action='play'/>"
784 //" <menuitem action='pause'/>"
785 " <menuitem action='stop'/>"
786 " <menuitem action='dialog-flipbook'/>"
787 " <separator name='bleh09'/>"
788 " <menuitem action='toggle-grid-show'/>"
789 " <menuitem action='toggle-grid-snap'/>"
790 " <menuitem action='toggle-guide-show'/>"
791 " <menuitem action='toggle-low-res'/>"
792 " <menuitem action='toggle-onion-skin'/>"
793 " <separator name='bleh10'/>"
794 " <menuitem action='canvas-zoom-in'/>"
795 " <menuitem action='canvas-zoom-out'/>"
796 " <menuitem action='canvas-zoom-fit'/>"
797 " <menuitem action='canvas-zoom-100'/>"
798 " <separator name='bleh11'/>"
799 " <menuitem action='time-zoom-in'/>"
800 " <menuitem action='time-zoom-out'/>"
801 " <separator name='bleh12'/>"
802 " <menuitem action='jump-next-keyframe'/>"
803 " <menuitem action='jump-prev-keyframe'/>"
804 " <menuitem action='seek-next-frame'/>"
805 " <menuitem action='seek-prev-frame'/>"
806 " <menuitem action='seek-next-second'/>"
807 " <menuitem action='seek-prev-second'/>"
808 " <menuitem action='seek-begin'/>"
809 " <menuitem action='seek-end'/>"
811 " <menu action='menu-canvas'>"
812 " <menuitem action='canvas-new'/>"
814 " <menu name='menu-state' action='menu-state'>"
816 " <menu action='menu-group'>"
817 " <menuitem action='action-group_add'/>"
819 " <menu action='menu-layer'>"
820 //" <menuitem action='cut'/>"
821 //" <menuitem action='copy'/>"
822 //" <menuitem action='paste'/>"
823 //" <separator name='bleh06'/>"
824 " <menu action='menu-layer-new'></menu>"
825 " <menuitem action='amount-inc'/>"
826 " <menuitem action='amount-dec'/>"
828 " <menu action='menu-keyframe'>"
829 " <menuitem action='keyframe-properties'/>"
836 " <menubar name='MenuBar'>"
837 " <menu action='MenuFile'>"
838 " <menuitem action='New'/>"
839 " <menuitem action='Open'/>"
841 " <menuitem action='Quit'/>"
843 " <menu action='MenuEdit'>"
844 " <menuitem action='Cut'/>"
845 " <menuitem action='Copy'/>"
846 " <menuitem action='Paste'/>"
849 " <toolbar name='ToolBar'>"
850 " <toolitem action='Open'/>"
851 " <toolitem action='Quit'/>"
857 actions_action_group->set_sensitive(false);
858 App::ui_manager()->set_add_tearoffs(true);
859 App::ui_manager()->insert_action_group(menus_action_group,1);
860 App::ui_manager()->insert_action_group(actions_action_group,1);
861 App::ui_manager()->add_ui_from_string(ui_info);
863 //App::ui_manager()->get_accel_group()->unlock();
865 catch(const Glib::Error& ex)
867 synfig::error("building menus and toolbars failed: " + ex.what());
870 // Add default keyboard accelerators
871 #define ACCEL(path,accel) \
873 Gtk::AccelKey accel_key(accel,path); \
874 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
877 #define ACCEL2(accel) \
879 Gtk::AccelKey accel_key(accel); \
880 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
883 ACCEL("<Actions>//select-all-ducks","<Control>a");
884 ACCEL("<Actions>//unselect-all-layers","<Control>d");
885 ACCEL("<Actions>//render","F9");
886 ACCEL("<Actions>//preview","F11");
887 ACCEL("<Actions>//properties","F8");
888 ACCEL("<Actions>//options","F12");
889 ACCEL("<Actions>//import","<control>i");
890 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
891 ACCEL("<Actions>//toggle-grid-show","<Control>g");
892 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
893 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
894 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
895 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
896 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
897 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
898 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
899 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
901 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
902 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
904 ACCEL("<Actions>//quality-01","<Control>1");
905 ACCEL("<Actions>//quality-02","<Control>2");
906 ACCEL("<Actions>//quality-03","<Control>3");
907 ACCEL("<Actions>//quality-04","<Control>4");
908 ACCEL("<Actions>//quality-05","<Control>5");
909 ACCEL("<Actions>//quality-06","<Control>6");
910 ACCEL("<Actions>//quality-07","<Control>7");
911 ACCEL("<Actions>//quality-08","<Control>8");
912 ACCEL("<Actions>//quality-09","<Control>9");
913 ACCEL("<Actions>//quality-10","<Control>0");
914 ACCEL("<Actions>//undo","<Control>z");
915 ACCEL("<Actions>//redo","<Control>r");
916 ACCEL("<Actions>//action-layer_remove","Delete");
918 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
919 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
920 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
921 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
922 ACCEL("<Actions>//time-zoom-in","+");
923 ACCEL("<Actions>//time-zoom-out","_");
925 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
926 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
928 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
929 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
930 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
931 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
932 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
933 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
934 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
935 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
936 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
937 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
938 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
939 ACCEL("<Actions>//play", "<Control>p");
940 ACCEL("<Actions>//seek-begin","Home");
941 ACCEL("<Actions>//seek-end","End");
943 ACCEL("<Actions>//state-normal", "<Mod1>a");
944 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
945 ACCEL("<Actions>//state-scale", "<Mod1>d");
946 ACCEL("<Actions>//state-rotate", "<Mod1>s");
948 ACCEL("<Actions>//state-bline", "<Mod1>b");
949 ACCEL("<Actions>//state-circle", "<Mod1>c");
950 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
951 ACCEL("<Actions>//state-gradient", "<Mod1>g");
953 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
954 ACCEL("<Actions>//state-fill", "<Mod1>f");
955 ACCEL("<Actions>//state-zoom", "<Mod1>z");
956 ACCEL("<Actions>//state-polygon", "<Mod1>p");
958 ACCEL("<Actions>//state-draw", "<Mod1>w");
959 ACCEL("<Actions>//state-sketch", "<Mod1>k");
960 ACCEL("<Actions>//state-width", "<Mod1>t");
961 ACCEL("<Actions>//state-mirror", "<Mod1>m");
963 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
969 #define mkdir(x,y) mkdir(x)
972 /* === M E T H O D S ======================================================= */
974 App::App(int *argc, char ***argv):
975 Gtk::Main(argc,argv),
976 IconController(etl::dirname((*argv)[0]))
978 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
981 ui_interface_=new GlobalUIInterface();
985 // don't call thread_init() if threads are already initialized
986 // on some machines bonobo_init() initialized threads before we get here
987 if (!g_thread_supported())
990 distance_system=Distance::SYSTEM_UNITS;
992 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
995 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
999 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1005 if(!SYNFIG_CHECK_VERSION())
1007 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1008 dialog_error_blocking("Synfig Studio",
1009 "This copy of Synfig Studio was compiled against a\n"
1010 "different version of libsynfig than what is currently\n"
1011 "installed. Synfig Studio will now abort. Try downloading\n"
1012 "the latest version from the Synfig website at\n"
1013 "http://synfig.org/Download"
1017 Glib::set_application_name(_("Synfig Studio"));
1020 about_window.set_can_self_destruct(false);
1021 about_window.show();
1023 shutdown_in_progress=false;
1024 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1025 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1027 // Initialize the Synfig library
1028 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1031 get_ui_interface()->error(_("Failed to initialize synfig!"));
1035 // add the preferences to the settings
1036 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1040 studio_init_cb.task(_("Init UI Manager..."));
1041 App::ui_manager_=studio::UIManager::create();
1044 studio_init_cb.task(_("Init Dock Manager..."));
1045 dock_manager=new studio::DockManager();
1047 studio_init_cb.task(_("Init State Manager..."));
1048 state_manager=new StateManager();
1050 studio_init_cb.task(_("Init Toolbox..."));
1051 toolbox=new studio::Toolbox();
1053 studio_init_cb.task(_("Init Tool Options..."));
1054 dialog_tool_options=new studio::Dialog_ToolOptions();
1055 dock_manager->register_dockable(*dialog_tool_options);
1057 studio_init_cb.task(_("Init History..."));
1058 dock_history=new studio::Dock_History();
1059 dock_manager->register_dockable(*dock_history);
1061 studio_init_cb.task(_("Init Canvases..."));
1062 dock_canvases=new studio::Dock_Canvases();
1063 dock_manager->register_dockable(*dock_canvases);
1065 studio_init_cb.task(_("Init Keyframes..."));
1066 dock_keyframes=new studio::Dock_Keyframes();
1067 dock_manager->register_dockable(*dock_keyframes);
1069 studio_init_cb.task(_("Init Layers..."));
1070 dock_layers=new studio::Dock_Layers();
1071 dock_manager->register_dockable(*dock_layers);
1073 studio_init_cb.task(_("Init Params..."));
1074 dock_params=new studio::Dock_Params();
1075 dock_manager->register_dockable(*dock_params);
1077 studio_init_cb.task(_("Init MetaData..."));
1078 dock_meta_data=new studio::Dock_MetaData();
1079 dock_manager->register_dockable(*dock_meta_data);
1081 studio_init_cb.task(_("Init Children..."));
1082 dock_children=new studio::Dock_Children();
1083 dock_manager->register_dockable(*dock_children);
1085 studio_init_cb.task(_("Init Info..."));
1086 dock_info = new studio::Dock_Info();
1087 dock_manager->register_dockable(*dock_info);
1089 studio_init_cb.task(_("Init Navigator..."));
1090 dock_navigator = new studio::Dock_Navigator();
1091 dock_manager->register_dockable(*dock_navigator);
1093 studio_init_cb.task(_("Init Timetrack..."));
1094 dock_timetrack = new studio::Dock_Timetrack();
1095 dock_manager->register_dockable(*dock_timetrack);
1097 studio_init_cb.task(_("Init Curve Editor..."));
1098 dock_curves = new studio::Dock_Curves();
1099 dock_manager->register_dockable(*dock_curves);
1101 studio_init_cb.task(_("Init Layer Groups..."));
1102 dock_layer_groups = new studio::Dock_LayerGroups();
1103 dock_manager->register_dockable(*dock_layer_groups);
1106 studio_init_cb.task(_("Init Color Dialog..."));
1107 dialog_color=new studio::Dialog_Color();
1109 studio_init_cb.task(_("Init Gradient Dialog..."));
1110 dialog_gradient=new studio::Dialog_Gradient();
1112 studio_init_cb.task(_("Init DeviceTracker..."));
1113 device_tracker=new studio::DeviceTracker();
1115 studio_init_cb.task(_("Init Tools..."));
1116 state_manager->add_state(&state_normal);
1117 state_manager->add_state(&state_smooth_move);
1118 state_manager->add_state(&state_scale);
1119 state_manager->add_state(&state_rotate);
1121 state_manager->add_state(&state_bline);
1124 state_manager->add_state(&state_circle);
1125 state_manager->add_state(&state_rectangle);
1127 state_manager->add_state(&state_gradient);
1128 state_manager->add_state(&state_eyedrop);
1129 state_manager->add_state(&state_fill);
1131 state_manager->add_state(&state_zoom);
1133 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1134 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1135 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1137 // Enabled for now. Let's see whether they're good enough yet.
1138 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1139 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1141 // Disabled by default - it doesn't work properly?
1142 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1144 studio_init_cb.task(_("Init ModPalette..."));
1145 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1147 studio_init_cb.task(_("Init ModMirror..."));
1148 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1151 studio_init_cb.task(_("Init Setup Dialog..."));
1152 dialog_setup=new studio::Dialog_Setup();
1154 studio_init_cb.task(_("Init Input Dialog..."));
1155 dialog_input=new Gtk::InputDialog();
1156 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1157 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1159 studio_init_cb.task(_("Init auto recovery..."));
1160 auto_recover=new AutoRecover();
1162 studio_init_cb.amount_complete(9250,10000);
1163 studio_init_cb.task(_("Loading Settings..."));
1165 studio_init_cb.task(_("Checking auto-recover..."));
1167 studio_init_cb.amount_complete(9900,10000);
1169 if(auto_recover->recovery_needed())
1171 about_window.hide();
1173 get_ui_interface()->yes_no(
1175 _("Synfig Studio seems to have crashed\n"
1176 "before you could save all your files.\n"
1177 "Would you like to re-open those files\n"
1178 "and recover your unsaved changes?")
1179 )==synfigapp::UIInterface::RESPONSE_YES
1182 if(!auto_recover->recover())
1184 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1187 get_ui_interface()->error(
1188 _("Synfig Studio has attempted to recover\n"
1189 "from a previous crash. The files that it has\n"
1190 "recovered are NOT YET SAVED. It would be a good\n"
1191 "idea to review them and save them now.")
1194 about_window.show();
1197 // Look for any files given on the command line,
1198 // and load them if found.
1199 bool opened_any = false;
1200 for(;*argc>=1;(*argc)--)
1201 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1203 studio_init_cb.task(_("Loading files..."));
1204 about_window.hide();
1205 open((*argv)[*argc]);
1207 about_window.show();
1210 // if no file was specified to be opened, create a new document to help new users get started more easily
1211 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1214 studio_init_cb.task(_("Done."));
1215 studio_init_cb.amount_complete(10000,10000);
1221 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1225 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1229 StateManager* App::get_state_manager() { return state_manager; }
1233 shutdown_in_progress=true;
1237 synfigapp::Main::settings().remove_domain("pref");
1239 selected_instance=0;
1241 // Unload all of the modules
1242 for(;!module_list_.empty();module_list_.pop_back())
1245 delete state_manager;
1249 delete auto_recover;
1253 // studio::App::iteration(false);
1257 // studio::App::iteration(false);
1259 // studio::App::iteration(false);
1261 delete dialog_setup;
1263 delete dialog_gradient;
1265 delete dialog_color;
1267 delete dialog_input;
1269 delete dock_manager;
1271 instance_list.clear();
1273 // studio::App::iteration(false);
1277 App::get_user_app_directory()
1279 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1283 App::get_config_file(const synfig::String& file)
1285 return Glib::build_filename(get_user_app_directory(),file);
1289 App::add_recent_file(const std::string &file_name)
1291 std::string filename(file_name);
1293 assert(!filename.empty());
1295 if(filename.empty())
1298 // Toss out any "hidden" files
1299 if(basename(filename)[0]=='.')
1302 // If we aren't an absolute path, turn ourselves into one
1303 if(!is_absolute_path(filename))
1304 filename=absolute_path(filename);
1306 list<string>::iterator iter;
1307 // Check to see if the file is already on the list.
1308 // If it is, then remove it from the list
1309 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1312 recent_files.erase(iter);
1317 // Push the filename to the front of the list
1318 recent_files.push_front(filename);
1320 // Clean out the files at the end of the list.
1321 while(recent_files.size()>(unsigned)get_max_recent_files())
1322 recent_files.pop_back();
1324 signal_recent_files_changed_();
1329 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1332 App::get_time_format()
1334 return _App_time_format;
1338 App::set_time_format(synfig::Time::Format x)
1345 App::save_settings()
1350 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1351 setlocale(LC_NUMERIC, "C");
1353 std::string filename=get_config_file("accelrc");
1354 Gtk::AccelMap::save(filename);
1357 std::string filename=get_config_file("recentfiles");
1359 std::ofstream file(filename.c_str());
1363 synfig::warning("Unable to save %s",filename.c_str());
1367 list<string>::reverse_iterator iter;
1369 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1373 std::string filename=get_config_file("settings");
1374 synfigapp::Main::settings().save_to_file(filename);
1375 setlocale(LC_NUMERIC,old_locale);
1379 synfig::warning("Caught exception when attempting to save settings.");
1384 App::load_settings()
1389 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1390 setlocale(LC_NUMERIC, "C");
1392 std::string filename=get_config_file("accelrc");
1393 Gtk::AccelMap::load(filename);
1396 std::string filename=get_config_file("recentfiles");
1398 std::ifstream file(filename.c_str());
1402 std::string recent_file;
1403 getline(file,recent_file);
1404 if(!recent_file.empty())
1405 add_recent_file(recent_file);
1408 std::string filename=get_config_file("settings");
1409 if(!synfigapp::Main::settings().load_from_file(filename))
1411 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1412 //if(!synfigapp::Main::settings().load_from_file(filename))
1414 gamma.set_gamma(1.0/2.2);
1415 reset_initial_window_configuration();
1418 setlocale(LC_NUMERIC,old_locale);
1422 synfig::warning("Caught exception when attempting to load settings.");
1427 App::reset_initial_window_configuration()
1429 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1430 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1431 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1432 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1433 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1434 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1435 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1436 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1437 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1438 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1439 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1440 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1441 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1442 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1446 App::shutdown_request(GdkEventAny*)
1450 //return !shutdown_in_progress;
1456 if(shutdown_in_progress)return;
1459 get_ui_interface()->task(_("Quit Request"));
1462 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1466 std::list<etl::handle<Instance> >::iterator iter;
1467 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1469 if(!(*iter)->safe_close())
1473 if((*iter)->synfigapp::Instance::get_action_count())
1475 handle<synfigapp::UIInterface> uim;
1476 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1478 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1479 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1481 case synfigapp::UIInterface::RESPONSE_NO:
1483 case synfigapp::UIInterface::RESPONSE_YES:
1486 case synfigapp::UIInterface::RESPONSE_CANCEL:
1495 if((*iter)->synfigapp::Instance::is_modified())
1497 handle<synfigapp::UIInterface> uim;
1498 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1500 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() );
1501 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1503 case synfigapp::UIInterface::RESPONSE_NO:
1505 case synfigapp::UIInterface::RESPONSE_YES:
1506 (*iter)->dialog_cvs_commit();
1508 case synfigapp::UIInterface::RESPONSE_CANCEL:
1517 // This next line causes things to crash for some reason
1521 shutdown_in_progress=true;
1523 instance_list.clear();
1525 while(studio::App::events_pending())studio::App::iteration(false);
1528 auto_recover->normal_shutdown();
1530 get_ui_interface()->task(_("Quit Request sent"));
1536 dialog_setup->refresh();
1537 dialog_setup->show();
1540 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1541 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1544 //#define USE_WIN32_FILE_DIALOGS 1
1547 #ifdef USE_WIN32_FILE_DIALOGS
1548 static OPENFILENAME ofn={};
1552 #include <gdk/gdkwin32.h>
1556 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1558 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1560 #ifdef USE_WIN32_FILE_DIALOGS
1561 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1563 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1564 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1565 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1567 ofn.lStructSize=sizeof(OPENFILENAME);
1568 ofn.hwndOwner = hWnd;
1569 ofn.hInstance = hInstance;
1570 ofn.lpstrFilter = szFilter;
1571 // ofn.lpstrCustomFilter=NULL;
1572 // ofn.nMaxCustFilter=0;
1573 // ofn.nFilterIndex=0;
1574 // ofn.lpstrFile=NULL;
1575 ofn.nMaxFile=MAX_PATH;
1576 // ofn.lpstrFileTitle=NULL;
1577 // ofn.lpstrInitialDir=NULL;
1578 // ofn.lpstrTitle=NULL;
1579 ofn.Flags=OFN_HIDEREADONLY;
1580 // ofn.nFileOffset=0;
1581 // ofn.nFileExtension=0;
1582 ofn.lpstrDefExt=TEXT("sif");
1583 // ofn.lCustData = 0l;
1585 // ofn.lpTemplateName=NULL;
1587 CHAR szFilename[MAX_PATH];
1589 strcpy(szFilename,filename.c_str());
1590 strcpy(szTitle,title.c_str());
1592 ofn.lpstrFile=szFilename;
1593 ofn.lpstrFileTitle=szTitle;
1595 if(GetOpenFileName(&ofn))
1597 filename=szFilename;
1603 synfig::String prev_path;
1605 if(!_preferences.get_value(preference, prev_path))
1608 prev_path = absolute_path(prev_path);
1610 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1612 dialog->set_current_folder(prev_path);
1613 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1614 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1616 if (filename.empty())
1617 dialog->set_filename(prev_path);
1618 else if (is_absolute_path(filename))
1619 dialog->set_filename(filename);
1621 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1623 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1624 filename = dialog->get_filename();
1625 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1626 _preferences.set_value(preference, dirname(filename));
1640 GtkWidget *fileselection;
1641 fileselection = gtk_file_selection_new(title.c_str());
1644 if(basename(filename)==filename)
1646 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1649 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1651 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1653 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1654 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1656 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1657 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1659 gtk_widget_show(fileselection);
1667 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1668 _preferences.set_value(preference,dirname(filename));
1672 gtk_widget_destroy(fileselection);
1675 gtk_widget_destroy(fileselection);
1682 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1684 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1686 #if USE_WIN32_FILE_DIALOGS
1687 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1689 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1690 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1691 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1693 ofn.lStructSize=sizeof(OPENFILENAME);
1694 ofn.hwndOwner = hWnd;
1695 ofn.hInstance = hInstance;
1696 ofn.lpstrFilter = szFilter;
1697 // ofn.lpstrCustomFilter=NULL;
1698 // ofn.nMaxCustFilter=0;
1699 // ofn.nFilterIndex=0;
1700 // ofn.lpstrFile=NULL;
1701 ofn.nMaxFile=MAX_PATH;
1702 // ofn.lpstrFileTitle=NULL;
1703 // ofn.lpstrInitialDir=NULL;
1704 // ofn.lpstrTitle=NULL;
1705 ofn.Flags=OFN_OVERWRITEPROMPT;
1706 // ofn.nFileOffset=0;
1707 // ofn.nFileExtension=0;
1708 ofn.lpstrDefExt=TEXT("sif");
1709 // ofn.lCustData = 0l;
1711 // ofn.lpTemplateName=NULL;
1713 CHAR szFilename[MAX_PATH];
1715 strcpy(szFilename,filename.c_str());
1716 strcpy(szTitle,title.c_str());
1718 ofn.lpstrFile=szFilename;
1719 ofn.lpstrFileTitle=szTitle;
1721 if(GetSaveFileName(&ofn))
1723 filename=szFilename;
1724 _preferences.set_value(preference,dirname(filename));
1729 synfig::String prev_path;
1731 if(!_preferences.get_value(preference, prev_path))
1734 prev_path = absolute_path(prev_path);
1736 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1738 dialog->set_current_folder(prev_path);
1739 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1740 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1742 if (filename.empty())
1743 dialog->set_filename(prev_path);
1746 std::string full_path;
1747 if (is_absolute_path(filename))
1748 full_path = filename;
1750 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1752 // select the file if it exists
1753 dialog->set_filename(full_path);
1755 // if the file doesn't exist, put its name into the filename box
1757 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1758 dialog->set_current_name(basename(filename));
1761 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1762 filename = dialog->get_filename();
1763 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1764 _preferences.set_value(preference, dirname(filename));
1775 App::dialog_error_blocking(const std::string &title, const std::string &message)
1777 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1778 dialog.set_title(title);
1784 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1786 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1787 dialog.set_title(title);
1793 App::dialog_yes_no(const std::string &title, const std::string &message)
1798 true // use_separator
1800 Gtk::Label label(message);
1803 dialog.get_vbox()->pack_start(label);
1804 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1805 dialog.add_button(Gtk::StockID("gtk-no"),0);
1807 return dialog.run();
1811 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1816 true // use_separator
1818 Gtk::Label label(message);
1821 dialog.get_vbox()->pack_start(label);
1822 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1823 dialog.add_button(Gtk::StockID("gtk-no"),0);
1824 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1826 return dialog.run();
1830 App::dialog_not_implemented()
1832 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1833 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1838 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1843 true // use_separator
1845 Gtk::Label label(message);
1847 dialog.get_vbox()->pack_start(label);
1850 entry.set_text(text);
1852 entry.set_activates_default(true);
1853 dialog.get_vbox()->pack_start(entry);
1855 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1856 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1857 dialog.set_default_response(Gtk::RESPONSE_OK);
1858 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1861 if(dialog.run()!=Gtk::RESPONSE_OK)
1864 text=entry.get_text();
1873 App::open(std::string filename)
1875 return open_as(filename,filename);
1878 // this is called from autorecover.cpp:
1879 // App::open_as(get_shadow_file_name(filename),filename)
1880 // other than that, 'filename' and 'as' are the same
1882 App::open_as(std::string filename,std::string as)
1885 char long_name[1024];
1886 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1892 OneMoment one_moment;
1894 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1895 if(canvas && get_instance(canvas))
1897 get_instance(canvas)->find_canvas_view(canvas)->present();
1898 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1901 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1903 add_recent_file(as);
1905 handle<Instance> instance(Instance::create(canvas));
1908 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1912 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)")))
1913 instance->dialog_cvs_update();
1917 dialog_error_blocking(_("Error"), x);
1922 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1933 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1934 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1936 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1938 canvas->rend_desc().set_frame_rate(24.0);
1939 canvas->rend_desc().set_time_start(0.0);
1940 canvas->rend_desc().set_time_end(5.0);
1941 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1942 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1943 canvas->rend_desc().set_tl(Vector(-4,2.25));
1944 canvas->rend_desc().set_br(Vector(4,-2.25));
1945 canvas->rend_desc().set_w(480);
1946 canvas->rend_desc().set_h(270);
1947 canvas->rend_desc().set_antialias(1);
1948 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1949 canvas->set_file_name(file_name);
1951 handle<Instance> instance = Instance::create(canvas);
1953 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1954 instance->find_canvas_view(canvas)->canvas_properties.present();
1960 string filename="*.sif";
1962 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
1964 // If the filename still has wildcards, then we should
1965 // continue looking for the file we want
1966 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1972 get_ui_interface()->error(_("Unable to open file"));
1977 App::set_selected_instance(etl::loose_handle<Instance> instance)
1979 /* if(get_selected_instance()==instance)
1981 selected_instance=instance;
1982 signal_instance_selected()(instance);
1988 selected_instance=instance;
1989 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
1993 instance->focus(instance->get_canvas());
1996 set_selected_canvas_view(0);
1998 signal_instance_selected()(instance);
2002 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2004 selected_canvas_view=canvas_view;
2005 signal_canvas_view_focus()(selected_canvas_view);
2008 selected_instance=canvas_view->get_instance();
2009 signal_instance_selected()(canvas_view->get_instance());
2012 if(get_selected_canvas_view()==canvas_view)
2014 signal_canvas_view_focus()(selected_canvas_view);
2015 signal_instance_selected()(canvas_view->get_instance());
2018 selected_canvas_view=canvas_view;
2019 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2020 set_selected_instance(canvas_view->get_instance());
2021 signal_canvas_view_focus()(selected_canvas_view);
2025 etl::loose_handle<Instance>
2026 App::get_instance(etl::handle<synfig::Canvas> canvas)
2028 if(!canvas) return 0;
2029 canvas=canvas->get_root();
2031 std::list<etl::handle<Instance> >::iterator iter;
2032 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2034 if((*iter)->get_canvas()==canvas)
2043 (new class About())->show();
2049 if(selected_instance)
2050 selected_instance->undo();
2056 if(selected_instance)
2057 selected_instance->redo();
2061 studio::App::get_base_path()
2063 return app_base_path_;