1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
38 #ifdef HAVE_SYS_ERRNO_H
39 #include <sys/errno.h>
41 #include <gtkmm/fileselection.h>
42 #include <gtkmm/dialog.h>
43 #include <gtkmm/messagedialog.h>
44 #include <gtkmm/label.h>
45 #include <gtkmm/stock.h>
46 #include <gtkmm/stockitem.h>
47 #include <gtkmm/iconsource.h>
48 #include <gtkmm/inputdialog.h>
49 #include <gtkmm/accelmap.h>
50 #include <gtkmm/uimanager.h>
54 #include <synfig/loadcanvas.h>
59 #include "canvasview.h"
60 #include "dialog_setup.h"
61 #include "dialog_gradient.h"
62 #include "dialog_color.h"
65 #include "onemoment.h"
67 #include "dockmanager.h"
69 #include "state_eyedrop.h"
70 #include "state_normal.h"
71 #include "state_draw.h"
72 #include "state_fill.h"
73 #include "state_bline.h"
74 #include "state_polygon.h"
75 #include "state_sketch.h"
76 #include "state_gradient.h"
77 #include "state_circle.h"
78 #include "state_rectangle.h"
79 #include "state_smoothmove.h"
80 #include "state_scale.h"
81 #include "state_width.h"
82 #include "state_rotate.h"
83 #include "state_zoom.h"
85 #include "devicetracker.h"
86 #include "dialog_tooloptions.h"
88 #include "autorecover.h"
90 #include <synfigapp/settings.h>
91 #include "dock_history.h"
92 #include "dock_canvases.h"
93 #include "dock_keyframes.h"
94 #include "dock_layers.h"
95 #include "dock_params.h"
96 #include "dock_metadata.h"
97 #include "dock_children.h"
98 #include "dock_info.h"
99 #include "dock_navigator.h"
100 #include "dock_layergroups.h"
101 #include "dock_timetrack.h"
102 #include "dock_curves.h"
104 #include "mod_palette/mod_palette.h"
105 #include "mod_mirror/mod_mirror.h"
107 #include <sys/stat.h>
113 #include "statemanager.h"
120 #define _WIN32_WINNT 0x0500
123 #include <gtkmm/accelmap.h>
124 #include <gtkmm/filechooser.h>
125 #include <gtkmm/filechooserdialog.h>
131 /* === U S I N G =========================================================== */
135 using namespace synfig;
136 using namespace studio;
138 /* === M A C R O S ========================================================= */
140 #ifndef SYNFIG_USER_APP_DIR
142 #define SYNFIG_USER_APP_DIR "Library/Synfig"
143 #elif defined(_WIN32)
144 #define SYNFIG_USER_APP_DIR "Synfig"
146 #define SYNFIG_USER_APP_DIR ".synfig"
151 #define DPM2DPI(x) (float(x)/39.3700787402f)
152 #define DPI2DPM(x) (float(x)*39.3700787402f)
158 # define IMAGE_DIR "share\\pixmaps"
163 # define IMAGE_DIR "/usr/local/share/pixmaps"
167 # define IMAGE_EXT "tif"
170 #include <synfigapp/main.h>
172 /* === S I G N A L S ======================================================= */
174 static sigc::signal<void> signal_present_all_;
176 App::signal_present_all() { return signal_present_all_; }
178 static sigc::signal<void> signal_recent_files_changed_;
180 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
182 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
183 sigc::signal<void,etl::loose_handle<CanvasView> >&
184 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
186 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
187 sigc::signal<void,etl::handle<Instance> >&
188 App::signal_instance_selected() { return signal_instance_selected_; }
190 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
191 sigc::signal<void,etl::handle<Instance> >&
192 App::signal_instance_created() { return signal_instance_created_; }
194 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
195 sigc::signal<void,etl::handle<Instance> >&
196 App::signal_instance_deleted() { return signal_instance_deleted_; }
198 /* === G L O B A L S ======================================================= */
200 static std::list<std::string> recent_files;
201 const std::list<std::string>& App::get_recent_files() { return recent_files; }
203 int App::Busy::count;
204 bool App::shutdown_in_progress;
206 synfig::Gamma App::gamma;
208 Glib::RefPtr<studio::UIManager> App::ui_manager_;
210 synfig::Distance::System App::distance_system;
212 studio::Dialog_Setup* App::dialog_setup;
214 etl::handle< studio::ModPalette > mod_palette_;
215 //studio::Dialog_Palette* App::dialog_palette;
217 std::list<etl::handle<Instance> > App::instance_list;
219 static etl::handle<synfigapp::UIInterface> ui_interface_;
220 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
222 etl::handle<Instance> App::selected_instance;
223 etl::handle<CanvasView> App::selected_canvas_view;
225 studio::Toolbox *studio::App::toolbox=NULL;
227 studio::AutoRecover *studio::App::auto_recover=NULL;
229 studio::IPC *ipc=NULL;
231 studio::DockManager* studio::App::dock_manager=0;
233 studio::DeviceTracker* studio::App::device_tracker=0;
235 studio::Dialog_Gradient* studio::App::dialog_gradient;
237 studio::Dialog_Color* studio::App::dialog_color;
239 Gtk::InputDialog* studio::App::dialog_input;
241 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
243 studio::Dock_History* dock_history;
244 studio::Dock_Canvases* dock_canvases;
245 studio::Dock_Keyframes* dock_keyframes;
246 studio::Dock_Layers* dock_layers;
247 studio::Dock_Params* dock_params;
248 studio::Dock_MetaData* dock_meta_data;
249 studio::Dock_Children* dock_children;
250 studio::Dock_Info* dock_info;
251 studio::Dock_LayerGroups* dock_layer_groups;
252 studio::Dock_Navigator* dock_navigator;
253 studio::Dock_Timetrack* dock_timetrack;
254 studio::Dock_Curves* dock_curves;
256 std::list< etl::handle< studio::Module > > module_list_;
258 bool studio::App::use_colorspace_gamma=true;
259 bool studio::App::single_threaded=false;
261 static int max_recent_files_=25;
262 int studio::App::get_max_recent_files() { return max_recent_files_; }
263 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
265 static synfig::String app_base_path_;
270 really_delete_widget(Gtk::Widget *widget)
272 // synfig::info("really delete %p", (void*)widget);
277 // nasty workaround - when we've finished with a popup menu, we want to delete it
278 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
279 // so schedule the real delete to happen in 50ms, giving the action a chance to run
281 delete_widget(Gtk::Widget *widget)
283 // synfig::info("delete %p", (void*)widget);
284 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
287 }; // END of namespace studio
288 studio::StateManager* state_manager;
293 class GlobalUIInterface : public synfigapp::UIInterface
297 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
302 true // use_separator
304 Gtk::Label label(message);
307 dialog.get_vbox()->pack_start(label);
308 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
309 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
311 dialog.set_default_response(dflt);
313 return (Response)dialog.run();
315 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
320 true // use_separator
322 Gtk::Label label(message);
325 dialog.get_vbox()->pack_start(label);
326 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
327 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
328 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
330 dialog.set_default_response(dflt);
332 return (Response)dialog.run();
334 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
339 true // use_separator
341 Gtk::Label label(message);
344 dialog.get_vbox()->pack_start(label);
345 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
346 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
348 dialog.set_default_response(dflt);
350 return (Response)dialog.run();
354 task(const std::string &task)
356 std::cerr<<task<<std::endl;
357 while(studio::App::events_pending())studio::App::iteration(false);
362 error(const std::string &err)
364 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
371 warning(const std::string &err)
373 std::cerr<<"warning: "<<err<<std::endl;
374 while(studio::App::events_pending())studio::App::iteration(false);
379 amount_complete(int /*current*/, int /*total*/)
381 while(studio::App::events_pending())studio::App::iteration(false);
386 /* === P R O C E D U R E S ================================================= */
390 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
392 action_group_list.push_back(action_group);
393 Gtk::UIManager::insert_action_group(action_group, pos);
397 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
399 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
400 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
401 if(*iter==action_group)
403 action_group_list.erase(iter);
404 Gtk::UIManager::remove_action_group(action_group);
407 synfig::error("Unable to find action group");
411 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
413 ui_manager->insert_action_group(group,0);
415 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
416 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
418 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
420 if(*iter && (*iter)->get_name()!="menus")
422 synfig::info("Removing action group "+(*iter)->get_name());
423 ui_manager->remove_action_group(*iter);
426 ui_manager->insert_action_group(group,0);
428 for(;!prev_groups.empty();prev_groups.pop_front())
430 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
431 ui_manager->insert_action_group(prev_groups.front(),1);
435 class Preferences : public synfigapp::Settings
438 virtual bool get_value(const synfig::String& key, synfig::String& value)const
442 value=strprintf("%f %f %f %f",
443 App::gamma.get_gamma_r(),
444 App::gamma.get_gamma_g(),
445 App::gamma.get_gamma_b(),
446 App::gamma.get_black_level()
450 if(key=="time_format")
452 value=strprintf("%i",App::get_time_format());
455 if(key=="file_history.size")
457 value=strprintf("%i",App::get_max_recent_files());
460 if(key=="use_colorspace_gamma")
462 value=strprintf("%i",(int)App::use_colorspace_gamma);
465 if(key=="distance_system")
467 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
470 if(key=="single_threaded")
472 value=strprintf("%i",(int)App::single_threaded);
475 if(key=="auto_recover_backup_interval")
477 value=strprintf("%i",App::auto_recover->get_timeout());
481 return synfigapp::Settings::get_value(key,value);
484 virtual bool set_value(const synfig::String& key,const synfig::String& value)
490 strscanf(value,"%f %f %f %f",
497 App::gamma.set_all(r,g,b,blk);
501 if(key=="time_format")
503 int i(atoi(value.c_str()));
504 App::set_time_format(static_cast<synfig::Time::Format>(i));
507 if(key=="auto_recover_backup_interval")
509 int i(atoi(value.c_str()));
510 App::auto_recover->set_timeout(i);
513 if(key=="file_history.size")
515 int i(atoi(value.c_str()));
516 App::set_max_recent_files(i);
519 if(key=="use_colorspace_gamma")
521 int i(atoi(value.c_str()));
522 App::use_colorspace_gamma=i;
525 if(key=="distance_system")
527 App::distance_system=Distance::ident_system(value);;
530 if(key=="single_threaded")
532 int i(atoi(value.c_str()));
533 App::single_threaded=i;
537 return synfigapp::Settings::set_value(key,value);
540 virtual KeyList get_key_list()const
542 KeyList ret(synfigapp::Settings::get_key_list());
543 ret.push_back("gamma");
544 ret.push_back("time_format");
545 ret.push_back("distance_system");
546 ret.push_back("file_history.size");
547 ret.push_back("use_colorspace_gamma");
548 ret.push_back("single_threaded");
549 ret.push_back("auto_recover_backup_interval");
554 static ::Preferences _preferences;
559 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
561 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
563 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
565 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
566 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
567 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
568 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
569 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
570 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
571 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
572 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
573 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
574 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
575 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
576 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
577 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
579 // Add the synfigapp actions...
580 synfigapp::Action::Book::iterator iter;
581 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
583 actions_action_group->add(Gtk::Action::create(
584 "action-"+iter->second.name,
585 get_action_stock_id(iter->second),
586 iter->second.local_name,iter->second.local_name
590 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
591 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
592 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ group->add(action,sig); }
594 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
595 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
596 DEFINE_ACTION("new", Gtk::Stock::NEW);
597 DEFINE_ACTION("open", Gtk::Stock::OPEN);
598 DEFINE_ACTION("save", Gtk::Stock::SAVE);
599 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
600 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
601 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
602 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
603 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
604 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
605 DEFINE_ACTION("import", _("Import"));
606 DEFINE_ACTION("render", _("Render"));
607 DEFINE_ACTION("preview", _("Preview"));
608 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
609 DEFINE_ACTION("sound", _("Sound File"));
610 DEFINE_ACTION("options", _("Options"));
611 DEFINE_ACTION("close", _("Close View"));
612 DEFINE_ACTION("close-document", _("Close Document"));
613 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
616 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
617 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
618 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
619 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
620 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
621 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
622 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
623 DEFINE_ACTION("properties", _("Properties"));
625 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
626 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
627 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
628 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
629 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
630 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
631 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
632 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
633 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
634 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
635 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
636 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
637 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
638 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
639 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
640 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
641 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
642 DEFINE_ACTION("lowres-pixel-2", _("Set Low-Res pixel size to 2"));
643 DEFINE_ACTION("lowres-pixel-3", _("Set Low-Res pixel size to 3"));
644 DEFINE_ACTION("lowres-pixel-4", _("Set Low-Res pixel size to 4"));
645 DEFINE_ACTION("lowres-pixel-5", _("Set Low-Res pixel size to 5"));
646 DEFINE_ACTION("lowres-pixel-6", _("Set Low-Res pixel size to 6"));
647 DEFINE_ACTION("lowres-pixel-8", _("Set Low-Res pixel size to 8"));
648 DEFINE_ACTION("lowres-pixel-10", _("Set Low-Res pixel size to 10"));
649 DEFINE_ACTION("lowres-pixel-12", _("Set Low-Res pixel size to 12"));
650 DEFINE_ACTION("lowres-pixel-15", _("Set Low-Res pixel size to 15"));
651 DEFINE_ACTION("lowres-pixel-20", _("Set Low-Res pixel size to 20"));
652 DEFINE_ACTION("lowres-pixel-24", _("Set Low-Res pixel size to 24"));
653 DEFINE_ACTION("lowres-pixel-30", _("Set Low-Res pixel size to 30"));
654 DEFINE_ACTION("lowres-pixel-40", _("Set Low-Res pixel size to 40"));
655 DEFINE_ACTION("lowres-pixel-60", _("Set Low-Res pixel size to 60"));
656 DEFINE_ACTION("lowres-pixel-120", _("Set Low-Res pixel size to 120"));
657 DEFINE_ACTION("play", _("Play"));
658 // DEFINE_ACTION("pause", _("Pause"));
659 DEFINE_ACTION("stop", _("Stop"));
660 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
661 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
662 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
663 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
664 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
665 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
666 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
667 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
668 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
669 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
670 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
671 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
672 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
673 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
674 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
675 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
676 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
677 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
678 DEFINE_ACTION("seek-end", _("Seek to End"));
680 DEFINE_ACTION("action-group_add", _("Add group"));
682 DEFINE_ACTION("canvas-new", _("New Canvas"));
684 DEFINE_ACTION("amount-inc", _("Increase Amount"));
685 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
690 // Set up synfigapp actions
692 synfigapp::Action::Book::iterator iter;
694 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
696 Gtk::StockID stock_id;
698 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
700 //Gtk::Image* image(manage(new Gtk::Image()));
701 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
702 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
703 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
704 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
705 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
706 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
707 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
708 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
709 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
710 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
712 actions_action_group->add(Gtk::Action::create(
713 "action-"+iter->second.name,
715 iter->second.local_name,iter->second.local_name
723 Glib::ustring ui_info =
725 " <popup name='menu-toolbox' action='menu-toolbox'>"
726 " <menu action='menu-file'>"
729 " <popup name='menu-main' action='menu-main'>"
730 " <menu action='menu-file'>"
731 " <menuitem action='new' />"
732 " <menuitem action='open' />"
733 " <menuitem action='save' />"
734 " <menuitem action='save-as' />"
735 " <menuitem action='revert' />"
736 " <separator name='bleh01'/>"
737 " <menuitem action='cvs-add' />"
738 " <menuitem action='cvs-update' />"
739 " <menuitem action='cvs-commit' />"
740 " <menuitem action='cvs-revert' />"
741 " <separator name='bleh02'/>"
742 " <menuitem action='import' />"
743 " <separator name='bleh03'/>"
744 " <menuitem action='render' />"
745 " <menuitem action='preview' />"
746 " <menuitem action='sound' />"
747 " <separator name='bleh04'/>"
748 " <menuitem action='options' />"
749 " <menuitem action='close' />"
750 " <menuitem action='close-document' />"
751 " <menuitem action='quit' />"
753 " <menu action='menu-edit'>"
754 " <menuitem action='undo'/>"
755 " <menuitem action='redo'/>"
756 " <separator name='bleh05'/>"
757 " <menuitem action='cut'/>"
758 " <menuitem action='copy'/>"
759 " <menuitem action='paste'/>"
760 " <separator name='bleh06'/>"
761 " <menuitem action='select-all-ducks'/>"
762 " <menuitem action='unselect-all-layers'/>"
763 " <separator name='bleh07'/>"
764 " <menuitem action='properties'/>"
766 " <menu action='menu-view'>"
767 " <menu action='menu-duck-mask'>"
768 " <menuitem action='mask-position-ducks' />"
769 " <menuitem action='mask-vertex-ducks' />"
770 " <menuitem action='mask-tangent-ducks' />"
771 " <menuitem action='mask-radius-ducks' />"
772 " <menuitem action='mask-width-ducks' />"
773 " <menuitem action='mask-angle-ducks' />"
775 " <menu action='menu-preview-quality'>"
776 " <menuitem action='quality-00' />"
777 " <menuitem action='quality-01' />"
778 " <menuitem action='quality-02' />"
779 " <menuitem action='quality-03' />"
780 " <menuitem action='quality-04' />"
781 " <menuitem action='quality-05' />"
782 " <menuitem action='quality-06' />"
783 " <menuitem action='quality-07' />"
784 " <menuitem action='quality-08' />"
785 " <menuitem action='quality-09' />"
786 " <menuitem action='quality-10' />"
788 " <menu action='menu-lowres-pixel'>"
789 " <menuitem action='lowres-pixel-2' />"
790 " <menuitem action='lowres-pixel-3' />"
791 " <menuitem action='lowres-pixel-4' />"
792 " <menuitem action='lowres-pixel-5' />"
793 " <menuitem action='lowres-pixel-6' />"
794 " <menuitem action='lowres-pixel-8' />"
795 " <menuitem action='lowres-pixel-10' />"
796 " <menuitem action='lowres-pixel-12' />"
797 " <menuitem action='lowres-pixel-15' />"
798 " <menuitem action='lowres-pixel-20' />"
799 " <menuitem action='lowres-pixel-24' />"
800 " <menuitem action='lowres-pixel-30' />"
801 " <menuitem action='lowres-pixel-40' />"
802 " <menuitem action='lowres-pixel-60' />"
803 " <menuitem action='lowres-pixel-120' />"
805 " <separator name='bleh08'/>"
806 " <menuitem action='play'/>"
807 //" <menuitem action='pause'/>"
808 " <menuitem action='stop'/>"
809 " <menuitem action='dialog-flipbook'/>"
810 " <separator name='bleh09'/>"
811 " <menuitem action='toggle-grid-show'/>"
812 " <menuitem action='toggle-grid-snap'/>"
813 " <menuitem action='toggle-guide-show'/>"
814 " <menuitem action='toggle-low-res'/>"
815 " <menuitem action='toggle-onion-skin'/>"
816 " <separator name='bleh10'/>"
817 " <menuitem action='canvas-zoom-in'/>"
818 " <menuitem action='canvas-zoom-out'/>"
819 " <menuitem action='canvas-zoom-fit'/>"
820 " <menuitem action='canvas-zoom-100'/>"
821 " <separator name='bleh11'/>"
822 " <menuitem action='time-zoom-in'/>"
823 " <menuitem action='time-zoom-out'/>"
824 " <separator name='bleh12'/>"
825 " <menuitem action='jump-next-keyframe'/>"
826 " <menuitem action='jump-prev-keyframe'/>"
827 " <menuitem action='seek-next-frame'/>"
828 " <menuitem action='seek-prev-frame'/>"
829 " <menuitem action='seek-next-second'/>"
830 " <menuitem action='seek-prev-second'/>"
831 " <menuitem action='seek-begin'/>"
832 " <menuitem action='seek-end'/>"
834 " <menu action='menu-canvas'>"
835 " <menuitem action='canvas-new'/>"
837 " <menu name='menu-state' action='menu-state'>"
839 " <menu action='menu-group'>"
840 " <menuitem action='action-group_add'/>"
842 " <menu action='menu-layer'>"
843 //" <menuitem action='cut'/>"
844 //" <menuitem action='copy'/>"
845 //" <menuitem action='paste'/>"
846 //" <separator name='bleh06'/>"
847 " <menu action='menu-layer-new'></menu>"
848 " <menuitem action='amount-inc'/>"
849 " <menuitem action='amount-dec'/>"
851 " <menu action='menu-keyframe'>"
852 " <menuitem action='keyframe-properties'/>"
859 " <menubar name='MenuBar'>"
860 " <menu action='MenuFile'>"
861 " <menuitem action='New'/>"
862 " <menuitem action='Open'/>"
864 " <menuitem action='Quit'/>"
866 " <menu action='MenuEdit'>"
867 " <menuitem action='Cut'/>"
868 " <menuitem action='Copy'/>"
869 " <menuitem action='Paste'/>"
872 " <toolbar name='ToolBar'>"
873 " <toolitem action='Open'/>"
874 " <toolitem action='Quit'/>"
880 actions_action_group->set_sensitive(false);
881 App::ui_manager()->set_add_tearoffs(true);
882 App::ui_manager()->insert_action_group(menus_action_group,1);
883 App::ui_manager()->insert_action_group(actions_action_group,1);
884 App::ui_manager()->add_ui_from_string(ui_info);
886 //App::ui_manager()->get_accel_group()->unlock();
888 catch(const Glib::Error& ex)
890 synfig::error("building menus and toolbars failed: " + ex.what());
893 // Add default keyboard accelerators
894 #define ACCEL(path,accel) \
896 Gtk::AccelKey accel_key(accel,path); \
897 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
900 #define ACCEL2(accel) \
902 Gtk::AccelKey accel_key(accel); \
903 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
906 ACCEL("<Actions>//select-all-ducks","<Control>a");
907 ACCEL("<Actions>//unselect-all-layers","<Control>d");
908 ACCEL("<Actions>//render","F9");
909 ACCEL("<Actions>//preview","F11");
910 ACCEL("<Actions>//properties","F8");
911 ACCEL("<Actions>//options","F12");
912 ACCEL("<Actions>//import","<control>i");
913 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
914 ACCEL("<Actions>//toggle-grid-show","<Control>g");
915 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
916 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
917 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
918 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
919 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
920 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
921 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
922 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
924 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
925 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
927 ACCEL("<Actions>//quality-01","<Control>1");
928 ACCEL("<Actions>//quality-02","<Control>2");
929 ACCEL("<Actions>//quality-03","<Control>3");
930 ACCEL("<Actions>//quality-04","<Control>4");
931 ACCEL("<Actions>//quality-05","<Control>5");
932 ACCEL("<Actions>//quality-06","<Control>6");
933 ACCEL("<Actions>//quality-07","<Control>7");
934 ACCEL("<Actions>//quality-08","<Control>8");
935 ACCEL("<Actions>//quality-09","<Control>9");
936 ACCEL("<Actions>//quality-10","<Control>0");
937 ACCEL("<Actions>//undo","<Control>z");
938 ACCEL("<Actions>//redo","<Control>r");
939 ACCEL("<Actions>//action-layer_remove","Delete");
941 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
942 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
943 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
944 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
945 ACCEL("<Actions>//time-zoom-in","+");
946 ACCEL("<Actions>//time-zoom-out","_");
948 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
949 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
951 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
952 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
953 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
954 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
955 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
956 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
957 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
958 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
959 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
960 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
961 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
962 ACCEL("<Actions>//play", "<Control>p");
963 ACCEL("<Actions>//seek-begin","Home");
964 ACCEL("<Actions>//seek-end","End");
966 ACCEL("<Actions>//state-normal", "<Mod1>a");
967 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
968 ACCEL("<Actions>//state-scale", "<Mod1>d");
969 ACCEL("<Actions>//state-rotate", "<Mod1>s");
971 ACCEL("<Actions>//state-bline", "<Mod1>b");
972 ACCEL("<Actions>//state-circle", "<Mod1>c");
973 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
974 ACCEL("<Actions>//state-gradient", "<Mod1>g");
976 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
977 ACCEL("<Actions>//state-fill", "<Mod1>f");
978 ACCEL("<Actions>//state-zoom", "<Mod1>z");
979 ACCEL("<Actions>//state-polygon", "<Mod1>p");
981 ACCEL("<Actions>//state-draw", "<Mod1>w");
982 ACCEL("<Actions>//state-sketch", "<Mod1>k");
983 ACCEL("<Actions>//state-width", "<Mod1>t");
984 ACCEL("<Actions>//state-mirror", "<Mod1>m");
986 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
992 #define mkdir(x,y) mkdir(x)
995 /* === M E T H O D S ======================================================= */
997 App::App(int *argc, char ***argv):
998 Gtk::Main(argc,argv),
999 IconController(etl::dirname((*argv)[0]))
1001 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1004 ui_interface_=new GlobalUIInterface();
1008 // don't call thread_init() if threads are already initialized
1009 // on some machines bonobo_init() initialized threads before we get here
1010 if (!g_thread_supported())
1011 Glib::thread_init();
1013 distance_system=Distance::SYSTEM_UNITS;
1015 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1018 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1022 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1028 if(!SYNFIG_CHECK_VERSION())
1030 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1031 dialog_error_blocking("Synfig Studio",
1032 "This copy of Synfig Studio was compiled against a\n"
1033 "different version of libsynfig than what is currently\n"
1034 "installed. Synfig Studio will now abort. Try downloading\n"
1035 "the latest version from the Synfig website at\n"
1036 "http://synfig.org/Download"
1040 Glib::set_application_name(_("Synfig Studio"));
1043 about_window.set_can_self_destruct(false);
1044 about_window.show();
1046 shutdown_in_progress=false;
1047 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1048 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1050 // Initialize the Synfig library
1051 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1054 get_ui_interface()->error(_("Failed to initialize synfig!"));
1058 // add the preferences to the settings
1059 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1063 studio_init_cb.task(_("Init UI Manager..."));
1064 App::ui_manager_=studio::UIManager::create();
1067 studio_init_cb.task(_("Init Dock Manager..."));
1068 dock_manager=new studio::DockManager();
1070 studio_init_cb.task(_("Init State Manager..."));
1071 state_manager=new StateManager();
1073 studio_init_cb.task(_("Init Toolbox..."));
1074 toolbox=new studio::Toolbox();
1076 studio_init_cb.task(_("Init Tool Options..."));
1077 dialog_tool_options=new studio::Dialog_ToolOptions();
1078 dock_manager->register_dockable(*dialog_tool_options);
1080 studio_init_cb.task(_("Init History..."));
1081 dock_history=new studio::Dock_History();
1082 dock_manager->register_dockable(*dock_history);
1084 studio_init_cb.task(_("Init Canvases..."));
1085 dock_canvases=new studio::Dock_Canvases();
1086 dock_manager->register_dockable(*dock_canvases);
1088 studio_init_cb.task(_("Init Keyframes..."));
1089 dock_keyframes=new studio::Dock_Keyframes();
1090 dock_manager->register_dockable(*dock_keyframes);
1092 studio_init_cb.task(_("Init Layers..."));
1093 dock_layers=new studio::Dock_Layers();
1094 dock_manager->register_dockable(*dock_layers);
1096 studio_init_cb.task(_("Init Params..."));
1097 dock_params=new studio::Dock_Params();
1098 dock_manager->register_dockable(*dock_params);
1100 studio_init_cb.task(_("Init MetaData..."));
1101 dock_meta_data=new studio::Dock_MetaData();
1102 dock_manager->register_dockable(*dock_meta_data);
1104 studio_init_cb.task(_("Init Children..."));
1105 dock_children=new studio::Dock_Children();
1106 dock_manager->register_dockable(*dock_children);
1108 studio_init_cb.task(_("Init Info..."));
1109 dock_info = new studio::Dock_Info();
1110 dock_manager->register_dockable(*dock_info);
1112 studio_init_cb.task(_("Init Navigator..."));
1113 dock_navigator = new studio::Dock_Navigator();
1114 dock_manager->register_dockable(*dock_navigator);
1116 studio_init_cb.task(_("Init Timetrack..."));
1117 dock_timetrack = new studio::Dock_Timetrack();
1118 dock_manager->register_dockable(*dock_timetrack);
1120 studio_init_cb.task(_("Init Curve Editor..."));
1121 dock_curves = new studio::Dock_Curves();
1122 dock_manager->register_dockable(*dock_curves);
1124 studio_init_cb.task(_("Init Layer Groups..."));
1125 dock_layer_groups = new studio::Dock_LayerGroups();
1126 dock_manager->register_dockable(*dock_layer_groups);
1129 studio_init_cb.task(_("Init Color Dialog..."));
1130 dialog_color=new studio::Dialog_Color();
1132 studio_init_cb.task(_("Init Gradient Dialog..."));
1133 dialog_gradient=new studio::Dialog_Gradient();
1135 studio_init_cb.task(_("Init DeviceTracker..."));
1136 device_tracker=new studio::DeviceTracker();
1138 studio_init_cb.task(_("Init Tools..."));
1139 state_manager->add_state(&state_normal);
1140 state_manager->add_state(&state_smooth_move);
1141 state_manager->add_state(&state_scale);
1142 state_manager->add_state(&state_rotate);
1144 state_manager->add_state(&state_bline);
1147 state_manager->add_state(&state_circle);
1148 state_manager->add_state(&state_rectangle);
1150 state_manager->add_state(&state_gradient);
1151 state_manager->add_state(&state_eyedrop);
1152 state_manager->add_state(&state_fill);
1154 state_manager->add_state(&state_zoom);
1156 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1157 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1158 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1160 // Enabled for now. Let's see whether they're good enough yet.
1161 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1162 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1164 // Disabled by default - it doesn't work properly?
1165 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1167 studio_init_cb.task(_("Init ModPalette..."));
1168 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1170 studio_init_cb.task(_("Init ModMirror..."));
1171 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1174 studio_init_cb.task(_("Init Setup Dialog..."));
1175 dialog_setup=new studio::Dialog_Setup();
1177 studio_init_cb.task(_("Init Input Dialog..."));
1178 dialog_input=new Gtk::InputDialog();
1179 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1180 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1182 studio_init_cb.task(_("Init auto recovery..."));
1183 auto_recover=new AutoRecover();
1185 studio_init_cb.amount_complete(9250,10000);
1186 studio_init_cb.task(_("Loading Settings..."));
1188 studio_init_cb.task(_("Checking auto-recover..."));
1190 studio_init_cb.amount_complete(9900,10000);
1192 if(auto_recover->recovery_needed())
1194 about_window.hide();
1196 get_ui_interface()->yes_no(
1198 _("Synfig Studio seems to have crashed\n"
1199 "before you could save all your files.\n"
1200 "Would you like to re-open those files\n"
1201 "and recover your unsaved changes?")
1202 )==synfigapp::UIInterface::RESPONSE_YES
1205 if(!auto_recover->recover())
1207 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1210 get_ui_interface()->error(
1211 _("Synfig Studio has attempted to recover\n"
1212 "from a previous crash. The files that it has\n"
1213 "recovered are NOT YET SAVED. It would be a good\n"
1214 "idea to review them and save them now.")
1217 about_window.show();
1220 // Look for any files given on the command line,
1221 // and load them if found.
1222 bool opened_any = false;
1223 for(;*argc>=1;(*argc)--)
1224 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1226 studio_init_cb.task(_("Loading files..."));
1227 about_window.hide();
1228 open((*argv)[*argc]);
1230 about_window.show();
1233 // if no file was specified to be opened, create a new document to help new users get started more easily
1234 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1237 studio_init_cb.task(_("Done."));
1238 studio_init_cb.amount_complete(10000,10000);
1244 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1248 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1252 StateManager* App::get_state_manager() { return state_manager; }
1256 shutdown_in_progress=true;
1260 synfigapp::Main::settings().remove_domain("pref");
1262 selected_instance=0;
1264 // Unload all of the modules
1265 for(;!module_list_.empty();module_list_.pop_back())
1268 delete state_manager;
1272 delete auto_recover;
1276 // studio::App::iteration(false);
1280 // studio::App::iteration(false);
1282 // studio::App::iteration(false);
1284 delete dialog_setup;
1286 delete dialog_gradient;
1288 delete dialog_color;
1290 delete dialog_input;
1292 delete dock_manager;
1294 instance_list.clear();
1296 // studio::App::iteration(false);
1300 App::get_user_app_directory()
1302 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1306 App::get_config_file(const synfig::String& file)
1308 return Glib::build_filename(get_user_app_directory(),file);
1312 App::add_recent_file(const std::string &file_name)
1314 std::string filename(file_name);
1316 assert(!filename.empty());
1318 if(filename.empty())
1321 // Toss out any "hidden" files
1322 if(basename(filename)[0]=='.')
1325 // If we aren't an absolute path, turn ourselves into one
1326 if(!is_absolute_path(filename))
1327 filename=absolute_path(filename);
1329 list<string>::iterator iter;
1330 // Check to see if the file is already on the list.
1331 // If it is, then remove it from the list
1332 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1335 recent_files.erase(iter);
1340 // Push the filename to the front of the list
1341 recent_files.push_front(filename);
1343 // Clean out the files at the end of the list.
1344 while(recent_files.size()>(unsigned)get_max_recent_files())
1345 recent_files.pop_back();
1347 signal_recent_files_changed_();
1352 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1355 App::get_time_format()
1357 return _App_time_format;
1361 App::set_time_format(synfig::Time::Format x)
1368 App::save_settings()
1373 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1374 setlocale(LC_NUMERIC, "C");
1376 std::string filename=get_config_file("accelrc");
1377 Gtk::AccelMap::save(filename);
1380 std::string filename=get_config_file("recentfiles");
1382 std::ofstream file(filename.c_str());
1386 synfig::warning("Unable to save %s",filename.c_str());
1390 list<string>::reverse_iterator iter;
1392 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1396 std::string filename=get_config_file("settings");
1397 synfigapp::Main::settings().save_to_file(filename);
1398 setlocale(LC_NUMERIC,old_locale);
1402 synfig::warning("Caught exception when attempting to save settings.");
1407 App::load_settings()
1412 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1413 setlocale(LC_NUMERIC, "C");
1415 std::string filename=get_config_file("accelrc");
1416 Gtk::AccelMap::load(filename);
1419 std::string filename=get_config_file("recentfiles");
1421 std::ifstream file(filename.c_str());
1425 std::string recent_file;
1426 getline(file,recent_file);
1427 if(!recent_file.empty())
1428 add_recent_file(recent_file);
1431 std::string filename=get_config_file("settings");
1432 if(!synfigapp::Main::settings().load_from_file(filename))
1434 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1435 //if(!synfigapp::Main::settings().load_from_file(filename))
1437 gamma.set_gamma(1.0/2.2);
1438 reset_initial_window_configuration();
1441 setlocale(LC_NUMERIC,old_locale);
1445 synfig::warning("Caught exception when attempting to load settings.");
1450 App::reset_initial_window_configuration()
1452 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1453 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1454 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1455 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1456 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1457 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1458 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1459 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1460 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1461 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1462 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1463 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1464 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1465 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1469 App::shutdown_request(GdkEventAny*)
1473 //return !shutdown_in_progress;
1479 if(shutdown_in_progress)return;
1482 get_ui_interface()->task(_("Quit Request"));
1485 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1489 std::list<etl::handle<Instance> >::iterator iter;
1490 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1492 if(!(*iter)->safe_close())
1496 if((*iter)->synfigapp::Instance::get_action_count())
1498 handle<synfigapp::UIInterface> uim;
1499 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1501 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1502 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1504 case synfigapp::UIInterface::RESPONSE_NO:
1506 case synfigapp::UIInterface::RESPONSE_YES:
1509 case synfigapp::UIInterface::RESPONSE_CANCEL:
1518 if((*iter)->synfigapp::Instance::is_modified())
1520 handle<synfigapp::UIInterface> uim;
1521 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1523 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() );
1524 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1526 case synfigapp::UIInterface::RESPONSE_NO:
1528 case synfigapp::UIInterface::RESPONSE_YES:
1529 (*iter)->dialog_cvs_commit();
1531 case synfigapp::UIInterface::RESPONSE_CANCEL:
1540 // This next line causes things to crash for some reason
1544 shutdown_in_progress=true;
1546 instance_list.clear();
1548 while(studio::App::events_pending())studio::App::iteration(false);
1551 auto_recover->normal_shutdown();
1553 get_ui_interface()->task(_("Quit Request sent"));
1559 dialog_setup->refresh();
1560 dialog_setup->show();
1563 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1564 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1567 //#define USE_WIN32_FILE_DIALOGS 1
1570 #ifdef USE_WIN32_FILE_DIALOGS
1571 static OPENFILENAME ofn={};
1575 #include <gdk/gdkwin32.h>
1579 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1581 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1583 #ifdef USE_WIN32_FILE_DIALOGS
1584 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1586 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1587 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1588 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1590 ofn.lStructSize=sizeof(OPENFILENAME);
1591 ofn.hwndOwner = hWnd;
1592 ofn.hInstance = hInstance;
1593 ofn.lpstrFilter = szFilter;
1594 // ofn.lpstrCustomFilter=NULL;
1595 // ofn.nMaxCustFilter=0;
1596 // ofn.nFilterIndex=0;
1597 // ofn.lpstrFile=NULL;
1598 ofn.nMaxFile=MAX_PATH;
1599 // ofn.lpstrFileTitle=NULL;
1600 // ofn.lpstrInitialDir=NULL;
1601 // ofn.lpstrTitle=NULL;
1602 ofn.Flags=OFN_HIDEREADONLY;
1603 // ofn.nFileOffset=0;
1604 // ofn.nFileExtension=0;
1605 ofn.lpstrDefExt=TEXT("sif");
1606 // ofn.lCustData = 0l;
1608 // ofn.lpTemplateName=NULL;
1610 CHAR szFilename[MAX_PATH];
1612 strcpy(szFilename,filename.c_str());
1613 strcpy(szTitle,title.c_str());
1615 ofn.lpstrFile=szFilename;
1616 ofn.lpstrFileTitle=szTitle;
1618 if(GetOpenFileName(&ofn))
1620 filename=szFilename;
1626 synfig::String prev_path;
1628 if(!_preferences.get_value(preference, prev_path))
1631 prev_path = absolute_path(prev_path);
1633 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1635 dialog->set_current_folder(prev_path);
1636 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1637 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1639 if (filename.empty())
1640 dialog->set_filename(prev_path);
1641 else if (is_absolute_path(filename))
1642 dialog->set_filename(filename);
1644 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1646 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1647 filename = dialog->get_filename();
1648 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1649 _preferences.set_value(preference, dirname(filename));
1663 GtkWidget *fileselection;
1664 fileselection = gtk_file_selection_new(title.c_str());
1667 if(basename(filename)==filename)
1669 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1672 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1674 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1676 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1677 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1679 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1680 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1682 gtk_widget_show(fileselection);
1690 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1691 _preferences.set_value(preference,dirname(filename));
1695 gtk_widget_destroy(fileselection);
1698 gtk_widget_destroy(fileselection);
1705 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1707 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1709 #if USE_WIN32_FILE_DIALOGS
1710 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1712 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1713 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1714 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1716 ofn.lStructSize=sizeof(OPENFILENAME);
1717 ofn.hwndOwner = hWnd;
1718 ofn.hInstance = hInstance;
1719 ofn.lpstrFilter = szFilter;
1720 // ofn.lpstrCustomFilter=NULL;
1721 // ofn.nMaxCustFilter=0;
1722 // ofn.nFilterIndex=0;
1723 // ofn.lpstrFile=NULL;
1724 ofn.nMaxFile=MAX_PATH;
1725 // ofn.lpstrFileTitle=NULL;
1726 // ofn.lpstrInitialDir=NULL;
1727 // ofn.lpstrTitle=NULL;
1728 ofn.Flags=OFN_OVERWRITEPROMPT;
1729 // ofn.nFileOffset=0;
1730 // ofn.nFileExtension=0;
1731 ofn.lpstrDefExt=TEXT("sif");
1732 // ofn.lCustData = 0l;
1734 // ofn.lpTemplateName=NULL;
1736 CHAR szFilename[MAX_PATH];
1738 strcpy(szFilename,filename.c_str());
1739 strcpy(szTitle,title.c_str());
1741 ofn.lpstrFile=szFilename;
1742 ofn.lpstrFileTitle=szTitle;
1744 if(GetSaveFileName(&ofn))
1746 filename=szFilename;
1747 _preferences.set_value(preference,dirname(filename));
1752 synfig::String prev_path;
1754 if(!_preferences.get_value(preference, prev_path))
1757 prev_path = absolute_path(prev_path);
1759 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1761 dialog->set_current_folder(prev_path);
1762 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1763 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1765 if (filename.empty())
1766 dialog->set_filename(prev_path);
1769 std::string full_path;
1770 if (is_absolute_path(filename))
1771 full_path = filename;
1773 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1775 // select the file if it exists
1776 dialog->set_filename(full_path);
1778 // if the file doesn't exist, put its name into the filename box
1780 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1781 dialog->set_current_name(basename(filename));
1784 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1785 filename = dialog->get_filename();
1786 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1787 _preferences.set_value(preference, dirname(filename));
1798 App::dialog_error_blocking(const std::string &title, const std::string &message)
1800 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1801 dialog.set_title(title);
1807 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1809 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1810 dialog.set_title(title);
1816 App::dialog_yes_no(const std::string &title, const std::string &message)
1821 true // use_separator
1823 Gtk::Label label(message);
1826 dialog.get_vbox()->pack_start(label);
1827 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1828 dialog.add_button(Gtk::StockID("gtk-no"),0);
1830 return dialog.run();
1834 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1839 true // use_separator
1841 Gtk::Label label(message);
1844 dialog.get_vbox()->pack_start(label);
1845 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1846 dialog.add_button(Gtk::StockID("gtk-no"),0);
1847 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1849 return dialog.run();
1853 App::dialog_not_implemented()
1855 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1856 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1861 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1866 true // use_separator
1868 Gtk::Label label(message);
1870 dialog.get_vbox()->pack_start(label);
1873 entry.set_text(text);
1875 entry.set_activates_default(true);
1876 dialog.get_vbox()->pack_start(entry);
1878 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1879 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1880 dialog.set_default_response(Gtk::RESPONSE_OK);
1881 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1884 if(dialog.run()!=Gtk::RESPONSE_OK)
1887 text=entry.get_text();
1896 App::open(std::string filename)
1898 return open_as(filename,filename);
1901 // this is called from autorecover.cpp:
1902 // App::open_as(get_shadow_file_name(filename),filename)
1903 // other than that, 'filename' and 'as' are the same
1905 App::open_as(std::string filename,std::string as)
1908 char long_name[1024];
1909 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1915 OneMoment one_moment;
1917 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1918 if(canvas && get_instance(canvas))
1920 get_instance(canvas)->find_canvas_view(canvas)->present();
1921 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1924 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1926 add_recent_file(as);
1928 handle<Instance> instance(Instance::create(canvas));
1931 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1935 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)")))
1936 instance->dialog_cvs_update();
1940 dialog_error_blocking(_("Error"), x);
1945 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1956 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1957 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1959 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1961 canvas->rend_desc().set_frame_rate(24.0);
1962 canvas->rend_desc().set_time_start(0.0);
1963 canvas->rend_desc().set_time_end(5.0);
1964 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1965 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1966 canvas->rend_desc().set_tl(Vector(-4,2.25));
1967 canvas->rend_desc().set_br(Vector(4,-2.25));
1968 canvas->rend_desc().set_w(480);
1969 canvas->rend_desc().set_h(270);
1970 canvas->rend_desc().set_antialias(1);
1971 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1972 canvas->set_file_name(file_name);
1974 handle<Instance> instance = Instance::create(canvas);
1976 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1977 instance->find_canvas_view(canvas)->canvas_properties.present();
1983 string filename="*.sif";
1985 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
1987 // If the filename still has wildcards, then we should
1988 // continue looking for the file we want
1989 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1995 get_ui_interface()->error(_("Unable to open file"));
2000 App::set_selected_instance(etl::loose_handle<Instance> instance)
2002 /* if(get_selected_instance()==instance)
2004 selected_instance=instance;
2005 signal_instance_selected()(instance);
2011 selected_instance=instance;
2012 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2016 instance->focus(instance->get_canvas());
2019 set_selected_canvas_view(0);
2021 signal_instance_selected()(instance);
2025 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2027 selected_canvas_view=canvas_view;
2028 signal_canvas_view_focus()(selected_canvas_view);
2031 selected_instance=canvas_view->get_instance();
2032 signal_instance_selected()(canvas_view->get_instance());
2035 if(get_selected_canvas_view()==canvas_view)
2037 signal_canvas_view_focus()(selected_canvas_view);
2038 signal_instance_selected()(canvas_view->get_instance());
2041 selected_canvas_view=canvas_view;
2042 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2043 set_selected_instance(canvas_view->get_instance());
2044 signal_canvas_view_focus()(selected_canvas_view);
2048 etl::loose_handle<Instance>
2049 App::get_instance(etl::handle<synfig::Canvas> canvas)
2051 if(!canvas) return 0;
2052 canvas=canvas->get_root();
2054 std::list<etl::handle<Instance> >::iterator iter;
2055 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2057 if((*iter)->get_canvas()==canvas)
2066 (new class About())->show();
2072 if(selected_instance)
2073 selected_instance->undo();
2079 if(selected_instance)
2080 selected_instance->redo();
2084 studio::App::get_base_path()
2086 return app_base_path_;