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 ======================================================= */
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
40 #include <gtkmm/fileselection.h>
41 #include <gtkmm/dialog.h>
42 #include <gtkmm/messagedialog.h>
43 #include <gtkmm/label.h>
44 #include <gtkmm/stock.h>
45 #include <gtkmm/stockitem.h>
46 #include <gtkmm/iconsource.h>
47 #include <gtkmm/inputdialog.h>
48 #include <gtkmm/accelmap.h>
49 #include <gtkmm/uimanager.h>
53 #include <synfig/loadcanvas.h>
58 #include "canvasview.h"
59 #include "dialog_setup.h"
60 #include "dialog_gradient.h"
61 #include "dialog_color.h"
64 #include "onemoment.h"
66 #include "dockmanager.h"
68 #include "state_eyedrop.h"
69 #include "state_normal.h"
70 #include "state_draw.h"
71 #include "state_fill.h"
72 #include "state_bline.h"
73 #include "state_polygon.h"
74 #include "state_sketch.h"
75 #include "state_gradient.h"
76 #include "state_circle.h"
77 #include "state_rectangle.h"
78 #include "state_smoothmove.h"
79 #include "state_scale.h"
80 #include "state_width.h"
81 #include "state_rotate.h"
82 #include "state_zoom.h"
84 #include "devicetracker.h"
85 #include "dialog_tooloptions.h"
87 #include "autorecover.h"
89 #include <synfigapp/settings.h>
90 #include "dock_history.h"
91 #include "dock_canvases.h"
92 #include "dock_keyframes.h"
93 #include "dock_layers.h"
94 #include "dock_params.h"
95 #include "dock_metadata.h"
96 #include "dock_children.h"
97 #include "dock_info.h"
98 #include "dock_navigator.h"
99 #include "dock_layergroups.h"
100 #include "dock_timetrack.h"
101 #include "dock_curves.h"
103 #include "mod_palette/mod_palette.h"
104 #include "mod_mirror/mod_mirror.h"
106 #include <sys/stat.h>
112 #include "statemanager.h"
119 #define _WIN32_WINNT 0x0500
122 #include <gtkmm/accelmap.h>
123 #include <gtkmm/filechooser.h>
124 #include <gtkmm/filechooserdialog.h>
128 /* === U S I N G =========================================================== */
132 using namespace synfig;
133 using namespace studio;
135 /* === M A C R O S ========================================================= */
137 #ifndef SYNFIG_USER_APP_DIR
139 #define SYNFIG_USER_APP_DIR "Library/Synfig"
140 #elif defined(_WIN32)
141 #define SYNFIG_USER_APP_DIR "Synfig"
143 #define SYNFIG_USER_APP_DIR ".synfig"
148 #define DPM2DPI(x) (float(x)/39.3700787402f)
149 #define DPI2DPM(x) (float(x)*39.3700787402f)
155 # define IMAGE_DIR "share\\pixmaps"
160 # define IMAGE_DIR "/usr/local/share/pixmaps"
164 # define IMAGE_EXT "tif"
167 #include <synfigapp/main.h>
169 /* === S I G N A L S ======================================================= */
171 static sigc::signal<void> signal_present_all_;
173 App::signal_present_all() { return signal_present_all_; }
175 static sigc::signal<void> signal_recent_files_changed_;
177 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
179 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
180 sigc::signal<void,etl::loose_handle<CanvasView> >&
181 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
183 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
184 sigc::signal<void,etl::handle<Instance> >&
185 App::signal_instance_selected() { return signal_instance_selected_; }
187 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
188 sigc::signal<void,etl::handle<Instance> >&
189 App::signal_instance_created() { return signal_instance_created_; }
191 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
192 sigc::signal<void,etl::handle<Instance> >&
193 App::signal_instance_deleted() { return signal_instance_deleted_; }
195 /* === G L O B A L S ======================================================= */
197 static std::list<std::string> recent_files;
198 const std::list<std::string>& App::get_recent_files() { return recent_files; }
200 int App::Busy::count;
201 bool App::shutdown_in_progress;
203 synfig::Gamma App::gamma;
205 Glib::RefPtr<studio::UIManager> App::ui_manager_;
207 synfig::Distance::System App::distance_system;
209 studio::Dialog_Setup* App::dialog_setup;
211 etl::handle< studio::ModPalette > mod_palette_;
212 //studio::Dialog_Palette* App::dialog_palette;
214 std::list<etl::handle<Instance> > App::instance_list;
216 static etl::handle<synfigapp::UIInterface> ui_interface_;
217 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
219 etl::handle<Instance> App::selected_instance;
220 etl::handle<CanvasView> App::selected_canvas_view;
222 studio::Toolbox *studio::App::toolbox=NULL;
224 studio::AutoRecover *studio::App::auto_recover=NULL;
226 studio::IPC *ipc=NULL;
228 studio::DockManager* studio::App::dock_manager=0;
230 studio::DeviceTracker* studio::App::device_tracker=0;
232 studio::Dialog_Gradient* studio::App::dialog_gradient;
234 studio::Dialog_Color* studio::App::dialog_color;
236 Gtk::InputDialog* studio::App::dialog_input;
238 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
240 studio::Dock_History* dock_history;
241 studio::Dock_Canvases* dock_canvases;
242 studio::Dock_Keyframes* dock_keyframes;
243 studio::Dock_Layers* dock_layers;
244 studio::Dock_Params* dock_params;
245 studio::Dock_MetaData* dock_meta_data;
246 studio::Dock_Children* dock_children;
247 studio::Dock_Info* dock_info;
248 studio::Dock_LayerGroups* dock_layer_groups;
249 studio::Dock_Navigator* dock_navigator;
250 studio::Dock_Timetrack* dock_timetrack;
251 studio::Dock_Curves* dock_curves;
253 std::list< etl::handle< studio::Module > > module_list_;
255 bool studio::App::use_colorspace_gamma=true;
257 static int max_recent_files_=25;
258 int studio::App::get_max_recent_files() { return max_recent_files_; }
259 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
261 static synfig::String app_base_path_;
264 }; // END of namespace studio
265 studio::StateManager* state_manager;
270 class GlobalUIInterface : public synfigapp::UIInterface
274 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
279 true // use_separator
281 Gtk::Label label(message);
284 dialog.get_vbox()->pack_start(label);
285 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
286 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
288 dialog.set_default_response(dflt);
290 return (Response)dialog.run();
292 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
297 true // use_separator
299 Gtk::Label label(message);
302 dialog.get_vbox()->pack_start(label);
303 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
304 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
305 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
307 dialog.set_default_response(dflt);
309 return (Response)dialog.run();
311 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
316 true // use_separator
318 Gtk::Label label(message);
321 dialog.get_vbox()->pack_start(label);
322 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
323 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
325 dialog.set_default_response(dflt);
327 return (Response)dialog.run();
331 task(const std::string &task)
333 std::cerr<<task<<std::endl;
334 while(studio::App::events_pending())studio::App::iteration(false);
339 error(const std::string &err)
341 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
348 warning(const std::string &err)
350 std::cerr<<"warning: "<<err<<std::endl;
351 while(studio::App::events_pending())studio::App::iteration(false);
356 amount_complete(int /*current*/, int /*total*/)
358 while(studio::App::events_pending())studio::App::iteration(false);
363 /* === P R O C E D U R E S ================================================= */
365 typedef unsigned char U8;
366 typedef unsigned short U16;
367 typedef unsigned long U32;
377 static inline U32 hash_U32(U32 i)
379 i=i*1664525+1013904223;
380 i=i*1664525+1013904223;
381 i=i*1664525+1013904223;
386 static const int endian_fix_table[8] = { 3, 2, 1, 0, 7, 6, 5, 4 } ;
387 #define endian_fix(x) (endian_fix_table[x])
389 #define endian_fix(x) (x)
392 int v_unwind_key(V_KeyUnwound* unwound, const char* key)
395 unwound->element.serial=0;
396 unwound->element.checksum=0;
404 case '0': data=0; break;
405 case '1': data=1; break;
406 case '2': data=2; break;
407 case '3': data=3; break;
408 case '4': data=4; break;
409 case '5': data=5; break;
410 case '6': data=6; break;
411 case '7': data=7; break;
412 case '8': data=8; break;
413 case '9': data=9; break;
414 case 'a': case 'A': data=10; break;
415 case 'b': case 'B': data=11; break;
416 case 'c': case 'C': data=12; break;
417 case 'd': case 'D': data=13; break;
418 case 'e': case 'E': data=14; break;
419 case 'f': case 'F': data=15; break;
420 default: return 0; break;
423 unwound->element.checksum|=(((U32)data&3)<<bit);
424 unwound->element.serial|=(((U32)(data>>2)&3)<<bit);
429 int v_key_check(const char* key, U32* serial, U32 appid)
431 V_KeyUnwound unwound_key;
432 U32 appid_mask_a=hash_U32(appid);
433 U32 appid_mask_b=hash_U32(appid_mask_a);
435 if(!v_unwind_key(&unwound_key, key))
437 // Invalid characters in key
442 // Undo obfuscation pass
444 U32 next=hash_U32(unwound_key.raw[endian_fix(7)]);
449 unwound_key.raw[endian_fix(i)]^=(next>>24);
453 unwound_key.element.serial^=appid_mask_a;
454 unwound_key.element.checksum^=appid_mask_b;
456 *serial=unwound_key.element.serial;
458 return unwound_key.element.checksum==hash_U32(unwound_key.element.serial);
463 # ifdef LICENSE_KEY_REQUIRED
464 int check_license(String basedir)
466 int check_license(String /*basedir*/)
469 int check_license(String /*basedir*/)
472 #ifdef LICENSE_KEY_REQUIRED
477 license_file="/usr/local/etc/.synfiglicense";
479 license_file=basedir+"\\etc\\.synfiglicense";
483 key=Glib::file_get_contents(license_file);
484 } catch (Glib::FileError) { }
486 if(!v_key_check(key.c_str(),&serial,0xdeadbeef))
488 while(!v_key_check(key.c_str(),&serial,0xdeadbeef))
492 if(!App::dialog_entry(
493 _("Synfig Studio Authentication"),
494 _("Please enter your license key below. You will not\nbe able to use this software without a valid license key."),
497 throw String("No License");
500 FILE* file=fopen(license_file.c_str(),"w");
503 fprintf(file,"%s",key.c_str());
507 synfig::error("Unable to save license key!");
509 synfig::info("License Authenticated -- Serial #%05d",serial);
518 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
520 action_group_list.push_back(action_group);
521 Gtk::UIManager::insert_action_group(action_group, pos);
525 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
527 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
528 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
529 if(*iter==action_group)
531 action_group_list.erase(iter);
532 Gtk::UIManager::remove_action_group(action_group);
535 synfig::error("Unable to find action group");
539 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
541 ui_manager->insert_action_group(group,0);
544 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
545 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
548 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
551 if(*iter && (*iter)->get_name()!="menus")
553 synfig::info("Removing action group "+(*iter)->get_name());
554 ui_manager->remove_action_group(*iter);
558 ui_manager->insert_action_group(group,0);
561 for(;!prev_groups.empty();prev_groups.pop_front())
563 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
564 ui_manager->insert_action_group(prev_groups.front(),1);
569 class Preferences : public synfigapp::Settings
572 virtual bool get_value(const synfig::String& key, synfig::String& value)const
576 value=strprintf("%f %f %f %f",
577 App::gamma.get_gamma_r(),
578 App::gamma.get_gamma_g(),
579 App::gamma.get_gamma_b(),
580 App::gamma.get_black_level()
584 if(key=="time_format")
586 value=strprintf("%i",App::get_time_format());
589 if(key=="file_history.size")
591 value=strprintf("%i",App::get_max_recent_files());
594 if(key=="use_colorspace_gamma")
596 value=strprintf("%i",(int)App::use_colorspace_gamma);
599 if(key=="distance_system")
601 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
604 if(key=="auto_recover_backup_interval")
606 value=strprintf("%i",App::auto_recover->get_timeout());
610 return synfigapp::Settings::get_value(key,value);
613 virtual bool set_value(const synfig::String& key,const synfig::String& value)
619 strscanf(value,"%f %f %f %f",
626 App::gamma.set_all(r,g,b,blk);
630 if(key=="time_format")
632 int i(atoi(value.c_str()));
633 App::set_time_format(static_cast<synfig::Time::Format>(i));
636 if(key=="auto_recover_backup_interval")
638 int i(atoi(value.c_str()));
639 App::auto_recover->set_timeout(i);
642 if(key=="file_history.size")
644 int i(atoi(value.c_str()));
645 App::set_max_recent_files(i);
648 if(key=="use_colorspace_gamma")
650 int i(atoi(value.c_str()));
651 App::use_colorspace_gamma=i;
654 if(key=="distance_system")
656 App::distance_system=Distance::ident_system(value);;
660 return synfigapp::Settings::set_value(key,value);
663 virtual KeyList get_key_list()const
665 KeyList ret(synfigapp::Settings::get_key_list());
666 ret.push_back("gamma");
667 ret.push_back("time_format");
668 ret.push_back("distance_system");
669 ret.push_back("file_history.size");
670 ret.push_back("use_colorspace_gamma");
671 ret.push_back("auto_recover_backup_interval");
676 static ::Preferences _preferences;
681 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
683 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
685 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
687 menus_action_group->add( Gtk::Action::create("menu-file", "_File") );
688 menus_action_group->add( Gtk::Action::create("menu-edit", "_Edit") );
689 menus_action_group->add( Gtk::Action::create("menu-view", "_View") );
690 menus_action_group->add( Gtk::Action::create("menu-canvas", "_Canvas") );
691 menus_action_group->add( Gtk::Action::create("menu-layer", "_Layer") );
692 menus_action_group->add( Gtk::Action::create("menu-duck-mask", "Show/Hide Ducks") );
693 menus_action_group->add( Gtk::Action::create("menu-preview-quality", "Preview Quality") );
694 menus_action_group->add( Gtk::Action::create("menu-layer-new", "New Layer") );
695 menus_action_group->add( Gtk::Action::create("menu-keyframe", "Keyframe") );
696 menus_action_group->add( Gtk::Action::create("menu-group", "Group") );
697 menus_action_group->add( Gtk::Action::create("menu-state", "State") );
698 menus_action_group->add( Gtk::Action::create("menu-toolbox", "Toolbox") );
700 // Add the synfigapp actions...
701 synfigapp::Action::Book::iterator iter;
702 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
704 actions_action_group->add(Gtk::Action::create(
705 "action-"+iter->second.name,
706 get_action_stock_id(iter->second),
707 iter->second.local_name,iter->second.local_name
711 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
712 #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); }
713 #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); }
715 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
716 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
717 DEFINE_ACTION("open", Gtk::Stock::OPEN);
718 DEFINE_ACTION("save", Gtk::Stock::SAVE);
719 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
720 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
721 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
722 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
723 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
724 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
725 DEFINE_ACTION("import", _("Import"));
726 DEFINE_ACTION("render", _("Render"));
727 DEFINE_ACTION("preview", _("Preview"));
728 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
729 DEFINE_ACTION("sound", _("Sound File"));
730 DEFINE_ACTION("options", _("Options"));
731 DEFINE_ACTION("close", _("Close"));
734 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
735 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
736 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
737 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
738 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
739 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
740 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
741 DEFINE_ACTION("properties", _("Properties"));
743 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
744 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
745 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
746 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
747 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
748 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
749 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
750 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
751 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
752 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
753 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
754 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
755 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
756 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
757 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
758 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
759 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
760 DEFINE_ACTION("play", _("Play"));
761 // DEFINE_ACTION("pause", _("Pause"));
762 DEFINE_ACTION("stop", _("Stop"));
763 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
764 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
765 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
766 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
767 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
768 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
769 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
770 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
771 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
772 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
773 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
774 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
775 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
776 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
777 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
778 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
779 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
780 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
781 DEFINE_ACTION("seek-end", _("Seek to End"));
783 DEFINE_ACTION("action-group_add", _("Add group"));
785 DEFINE_ACTION("canvas-new", _("New Canvas"));
787 DEFINE_ACTION("amount-inc", _("Increase Amount"));
788 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
793 // Set up synfigapp actions
795 synfigapp::Action::Book::iterator iter;
797 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
799 Gtk::StockID stock_id;
801 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
803 //Gtk::Image* image(manage(new Gtk::Image()));
804 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
805 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
806 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
807 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
808 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
809 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
810 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
811 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
812 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
813 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
815 actions_action_group->add(Gtk::Action::create(
816 "action-"+iter->second.name,
818 iter->second.local_name,iter->second.local_name
826 Glib::ustring ui_info =
828 " <popup name='menu-toolbox' action='menu-toolbox'>"
829 " <menu action='menu-file'>"
832 " <popup name='menu-main' action='menu-main'>"
833 " <menu action='menu-file'>"
834 " <menuitem action='save' />"
835 " <menuitem action='save-as' />"
836 " <menuitem action='revert' />"
837 " <separator name='bleh01'/>"
838 " <menuitem action='cvs-add' />"
839 " <menuitem action='cvs-update' />"
840 " <menuitem action='cvs-commit' />"
841 " <menuitem action='cvs-revert' />"
842 " <separator name='bleh02'/>"
843 " <menuitem action='import' />"
844 " <separator name='bleh03'/>"
845 " <menuitem action='render' />"
846 " <menuitem action='preview' />"
847 " <menuitem action='sound' />"
848 " <separator name='bleh04'/>"
849 " <menuitem action='options' />"
850 " <menuitem action='close' />"
852 " <menu action='menu-edit'>"
853 " <menuitem action='undo'/>"
854 " <menuitem action='redo'/>"
855 " <separator name='bleh05'/>"
856 " <menuitem action='cut'/>"
857 " <menuitem action='copy'/>"
858 " <menuitem action='paste'/>"
859 " <separator name='bleh06'/>"
860 " <menuitem action='select-all-ducks'/>"
861 " <menuitem action='unselect-all-layers'/>"
862 " <separator name='bleh07'/>"
863 " <menuitem action='properties'/>"
865 " <menu action='menu-view'>"
866 " <menu action='menu-duck-mask'>"
867 " <menuitem action='mask-position-ducks' />"
868 " <menuitem action='mask-vertex-ducks' />"
869 " <menuitem action='mask-tangent-ducks' />"
870 " <menuitem action='mask-radius-ducks' />"
871 " <menuitem action='mask-width-ducks' />"
872 " <menuitem action='mask-angle-ducks' />"
874 " <menu action='menu-preview-quality'>"
875 " <menuitem action='quality-00' />"
876 " <menuitem action='quality-01' />"
877 " <menuitem action='quality-02' />"
878 " <menuitem action='quality-03' />"
879 " <menuitem action='quality-04' />"
880 " <menuitem action='quality-05' />"
881 " <menuitem action='quality-06' />"
882 " <menuitem action='quality-07' />"
883 " <menuitem action='quality-08' />"
884 " <menuitem action='quality-09' />"
885 " <menuitem action='quality-10' />"
887 " <separator name='bleh08'/>"
888 " <menuitem action='play'/>"
889 //" <menuitem action='pause'/>"
890 " <menuitem action='stop'/>"
891 " <menuitem action='dialog-flipbook'/>"
892 " <separator name='bleh09'/>"
893 " <menuitem action='toggle-grid-show'/>"
894 " <menuitem action='toggle-grid-snap'/>"
895 " <menuitem action='toggle-guide-show'/>"
896 " <menuitem action='toggle-low-res'/>"
897 " <menuitem action='toggle-onion-skin'/>"
898 " <separator name='bleh10'/>"
899 " <menuitem action='canvas-zoom-in'/>"
900 " <menuitem action='canvas-zoom-out'/>"
901 " <menuitem action='canvas-zoom-fit'/>"
902 " <menuitem action='canvas-zoom-100'/>"
903 " <separator name='bleh11'/>"
904 " <menuitem action='time-zoom-in'/>"
905 " <menuitem action='time-zoom-out'/>"
906 " <separator name='bleh12'/>"
907 " <menuitem action='jump-next-keyframe'/>"
908 " <menuitem action='jump-prev-keyframe'/>"
909 " <menuitem action='seek-next-frame'/>"
910 " <menuitem action='seek-prev-frame'/>"
911 " <menuitem action='seek-next-second'/>"
912 " <menuitem action='seek-prev-second'/>"
913 " <menuitem action='seek-begin'/>"
914 " <menuitem action='seek-end'/>"
916 " <menu action='menu-canvas'>"
917 " <menuitem action='canvas-new'/>"
919 " <menu name='menu-state' action='menu-state'>"
921 " <menu action='menu-group'>"
922 " <menuitem action='action-group_add'/>"
924 " <menu action='menu-layer'>"
925 //" <menuitem action='cut'/>"
926 //" <menuitem action='copy'/>"
927 //" <menuitem action='paste'/>"
928 //" <separator name='bleh06'/>"
929 " <menu action='menu-layer-new'></menu>"
930 " <menuitem action='amount-inc'/>"
931 " <menuitem action='amount-dec'/>"
933 " <menu action='menu-keyframe'>"
934 " <menuitem action='keyframe-properties'/>"
941 " <menubar name='MenuBar'>"
942 " <menu action='MenuFile'>"
943 " <menuitem action='New'/>"
944 " <menuitem action='Open'/>"
946 " <menuitem action='Quit'/>"
948 " <menu action='MenuEdit'>"
949 " <menuitem action='Cut'/>"
950 " <menuitem action='Copy'/>"
951 " <menuitem action='Paste'/>"
954 " <toolbar name='ToolBar'>"
955 " <toolitem action='Open'/>"
956 " <toolitem action='Quit'/>"
962 actions_action_group->set_sensitive(false);
963 App::ui_manager()->set_add_tearoffs(true);
964 App::ui_manager()->insert_action_group(menus_action_group,1);
965 App::ui_manager()->insert_action_group(actions_action_group,1);
966 App::ui_manager()->add_ui_from_string(ui_info);
968 //App::ui_manager()->get_accel_group()->unlock();
970 catch(const Glib::Error& ex)
972 synfig::error("building menus and toolbars failed: " + ex.what());
975 // Add default keyboard accelerators
976 #define ACCEL(path,accel) \
978 Gtk::AccelKey accel_key(accel,path); \
979 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
982 #define ACCEL2(accel) \
984 Gtk::AccelKey accel_key(accel); \
985 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
988 ACCEL("<Actions>//select-all-ducks","<Control>a");
989 ACCEL("<Actions>//unselect-all-layers","<Control>d");
990 ACCEL("<Actions>//render","F9");
991 ACCEL("<Actions>//preview","F11");
992 ACCEL("<Actions>//properties","F8");
993 ACCEL("<Actions>//options","F12");
994 ACCEL("<Actions>//import","<control>i");
995 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
996 ACCEL("<Actions>//toggle-grid-show","<Control>g");
997 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
998 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
999 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
1000 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1001 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1002 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1003 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1004 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1006 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1007 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1009 ACCEL("<Actions>//quality-01","<Control>1");
1010 ACCEL("<Actions>//quality-02","<Control>2");
1011 ACCEL("<Actions>//quality-03","<Control>3");
1012 ACCEL("<Actions>//quality-04","<Control>4");
1013 ACCEL("<Actions>//quality-05","<Control>5");
1014 ACCEL("<Actions>//quality-06","<Control>6");
1015 ACCEL("<Actions>//quality-07","<Control>7");
1016 ACCEL("<Actions>//quality-08","<Control>8");
1017 ACCEL("<Actions>//quality-09","<Control>9");
1018 ACCEL("<Actions>//quality-10","<Control>0");
1019 ACCEL("<Actions>//undo","<Control>z");
1020 ACCEL("<Actions>//redo","<Control>r");
1021 ACCEL("<Actions>//action-layer_remove","Delete");
1023 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1024 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1025 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1026 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1027 ACCEL("<Actions>//time-zoom-in","+");
1028 ACCEL("<Actions>//time-zoom-out","_");
1030 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1031 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1033 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1034 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1035 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1036 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1037 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1038 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1039 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1040 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1041 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1042 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1043 ACCEL2(Gtk::AccelKey('o',Gdk::CONTROL_MASK,"<Actions>//toggle-onion-skin"));
1044 ACCEL("<Actions>//play", "<Control>p");
1045 ACCEL("<Actions>//seek-begin","Home");
1046 ACCEL("<Actions>//seek-end","End");
1048 ACCEL("<Actions>//state-normal", "<Mod1>a");
1049 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1050 ACCEL("<Actions>//state-scale", "<Mod1>d");
1051 ACCEL("<Actions>//state-rotate", "<Mod1>s");
1053 ACCEL("<Actions>//state-bline", "<Mod1>b");
1054 ACCEL("<Actions>//state-circle", "<Mod1>c");
1055 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1056 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1058 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1059 ACCEL("<Actions>//state-fill", "<Mod1>f");
1060 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1061 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1063 ACCEL("<Actions>//state-draw", "<Mod1>w");
1064 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1065 ACCEL("<Actions>//state-width", "<Mod1>t");
1066 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1068 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1074 #define mkdir(x,y) mkdir(x)
1077 /* === M E T H O D S ======================================================= */
1079 App::App(int *argc, char ***argv):
1080 Gtk::Main(argc,argv),
1081 IconControler(etl::dirname((*argv)[0]))
1083 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1086 serial_=check_license(app_base_path_);
1089 ui_interface_=new GlobalUIInterface();
1093 Glib::thread_init();
1095 distance_system=Distance::SYSTEM_UNITS;
1097 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1100 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1104 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1112 if(!SYNFIG_CHECK_VERSION())
1114 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1115 dialog_error_blocking("Synfig Studio",
1116 "This copy of Synfig Studio was compiled against a\n"
1117 "different version of libsynfig than what is currently\n"
1118 "installed. Synfig Studio will now abort. Try downloading\n"
1119 "the latest version from the Synfig website at\n"
1120 "http://www.synfig.com/ "
1125 catch(synfig::SoftwareExpired)
1127 cerr<<"FATAL: Software Expired"<<endl;
1128 dialog_error_blocking("Synfig Studio",
1129 "This copy of Synfig Studio has expired.\n"
1130 "Please erase this copy, or download and\n"
1131 "install the latest copy from the Synfig\n"
1132 "website at http://www.synfig.com/ ."
1136 Glib::set_application_name(_("Synfig Studio"));
1139 about_window.set_can_self_destruct(false);
1140 about_window.show();
1142 shutdown_in_progress=false;
1143 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1144 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1146 // Initialize the Synfig library
1147 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1150 get_ui_interface()->error("Failed to initialize synfig!");
1154 // add the preferences to the settings
1155 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1159 studio_init_cb.task("Init UI Manager...");
1160 App::ui_manager_=studio::UIManager::create();
1163 studio_init_cb.task("Init Dock Manager...");
1164 dock_manager=new studio::DockManager();
1166 studio_init_cb.task("Init State Manager...");
1167 state_manager=new StateManager();
1169 studio_init_cb.task("Init Toolbox...");
1170 toolbox=new studio::Toolbox();
1172 studio_init_cb.task("Init Tool Options...");
1173 dialog_tool_options=new studio::Dialog_ToolOptions();
1174 dock_manager->register_dockable(*dialog_tool_options);
1176 studio_init_cb.task("Init History...");
1177 dock_history=new studio::Dock_History();
1178 dock_manager->register_dockable(*dock_history);
1180 studio_init_cb.task("Init Canvases...");
1181 dock_canvases=new studio::Dock_Canvases();
1182 dock_manager->register_dockable(*dock_canvases);
1184 studio_init_cb.task("Init Keyframes...");
1185 dock_keyframes=new studio::Dock_Keyframes();
1186 dock_manager->register_dockable(*dock_keyframes);
1188 studio_init_cb.task("Init Layers...");
1189 dock_layers=new studio::Dock_Layers();
1190 dock_manager->register_dockable(*dock_layers);
1192 studio_init_cb.task("Init Params...");
1193 dock_params=new studio::Dock_Params();
1194 dock_manager->register_dockable(*dock_params);
1196 studio_init_cb.task("Init MetaData...");
1197 dock_meta_data=new studio::Dock_MetaData();
1198 dock_manager->register_dockable(*dock_meta_data);
1200 studio_init_cb.task("Init Children...");
1201 dock_children=new studio::Dock_Children();
1202 dock_manager->register_dockable(*dock_children);
1204 studio_init_cb.task("Init Info...");
1205 dock_info = new studio::Dock_Info();
1206 dock_manager->register_dockable(*dock_info);
1208 studio_init_cb.task("Init Navigator...");
1209 dock_navigator = new studio::Dock_Navigator();
1210 dock_manager->register_dockable(*dock_navigator);
1212 studio_init_cb.task("Init Timetrack...");
1213 dock_timetrack = new studio::Dock_Timetrack();
1214 dock_manager->register_dockable(*dock_timetrack);
1216 studio_init_cb.task("Init Curve Editor...");
1217 dock_curves = new studio::Dock_Curves();
1218 dock_manager->register_dockable(*dock_curves);
1220 studio_init_cb.task("Init Layer Groups...");
1221 dock_layer_groups = new studio::Dock_LayerGroups();
1222 dock_manager->register_dockable(*dock_layer_groups);
1225 studio_init_cb.task("Init Color Dialog...");
1226 dialog_color=new studio::Dialog_Color();
1228 studio_init_cb.task("Init Gradient Dialog...");
1229 dialog_gradient=new studio::Dialog_Gradient();
1231 studio_init_cb.task("Init DeviceTracker...");
1232 device_tracker=new studio::DeviceTracker();
1234 studio_init_cb.task("Init Tools...");
1235 state_manager->add_state(&state_normal);
1236 state_manager->add_state(&state_smooth_move);
1237 state_manager->add_state(&state_scale);
1238 state_manager->add_state(&state_rotate);
1240 state_manager->add_state(&state_bline);
1243 state_manager->add_state(&state_circle);
1244 state_manager->add_state(&state_rectangle);
1246 state_manager->add_state(&state_gradient);
1247 state_manager->add_state(&state_eyedrop);
1248 state_manager->add_state(&state_fill);
1250 state_manager->add_state(&state_zoom);
1252 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1253 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1254 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1256 // Enabled for now. Let's see whether they're good enough yet.
1257 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1258 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1260 // Disabled by default - it doesn't work properly?
1261 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1263 studio_init_cb.task("Init ModPalette...");
1264 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1266 studio_init_cb.task("Init ModMirror...");
1267 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1270 studio_init_cb.task("Init Setup Dialog...");
1271 dialog_setup=new studio::Dialog_Setup();
1273 studio_init_cb.task("Init Input Dialog...");
1274 dialog_input=new Gtk::InputDialog();
1275 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1276 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1278 studio_init_cb.task("Init auto recovery...");
1279 auto_recover=new AutoRecover();
1281 studio_init_cb.amount_complete(9250,10000);
1282 studio_init_cb.task("Loading Settings...");
1284 studio_init_cb.task("Checking auto-recover...");
1286 studio_init_cb.amount_complete(9900,10000);
1288 if(auto_recover->recovery_needed())
1290 about_window.hide();
1292 get_ui_interface()->yes_no(
1294 "Synfig Studio seems to have crashed\n"
1295 "before you could save all your files.\n"
1296 "Would you like to re-open those files\n"
1297 "and recover your unsaved changes?"
1298 )==synfigapp::UIInterface::RESPONSE_YES
1301 if(!auto_recover->recover())
1303 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1306 get_ui_interface()->error(
1307 _("Synfig Studio has attempted to recover\n"
1308 "from a previous crash. The files that it has\n"
1309 "recovered are NOT YET SAVED. It would be a good\n"
1310 "idea to review them and save them now.")
1313 about_window.show();
1316 // Look for any files given on the command line,
1317 // and load them if found.
1318 for(;*argc>=1;(*argc)--)
1319 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1321 studio_init_cb.task("Loading files...");
1322 about_window.hide();
1323 open((*argv)[*argc]);
1324 about_window.show();
1327 studio_init_cb.task("Done.");
1328 studio_init_cb.amount_complete(10000,10000);
1334 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1338 StateManager* App::get_state_manager() { return state_manager; }
1342 shutdown_in_progress=true;
1346 synfigapp::Main::settings().remove_domain("pref");
1348 selected_instance=0;
1350 // Unload all of the modules
1351 for(;!module_list_.empty();module_list_.pop_back());
1353 delete state_manager;
1357 delete auto_recover;
1361 // studio::App::iteration(false);
1365 // studio::App::iteration(false);
1367 // studio::App::iteration(false);
1369 delete dialog_setup;
1371 delete dialog_gradient;
1373 delete dialog_color;
1375 delete dialog_input;
1377 delete dock_manager;
1379 instance_list.clear();
1381 // studio::App::iteration(false);
1385 App::get_user_app_directory()
1387 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1391 App::get_config_file(const synfig::String& file)
1393 return Glib::build_filename(get_user_app_directory(),file);
1397 App::add_recent_file(const std::string &file_name)
1399 std::string filename(file_name);
1401 assert(!filename.empty());
1403 if(filename.empty())
1406 // Toss out any "hidden" files
1407 if(basename(filename)[0]=='.')
1410 // If we aren't an absolute path, turn outselves into one
1411 if(!is_absolute_path(filename))
1412 filename=absolute_path(filename);
1414 list<string>::iterator iter;
1415 // Check to see if the file is already on the list.
1416 // If it is, then remove it from the list
1417 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1420 recent_files.erase(iter);
1425 // Push the filename to the front of the list
1426 recent_files.push_front(filename);
1428 // Clean out the files at the end of the list.
1429 while(recent_files.size()>(unsigned)get_max_recent_files())
1430 recent_files.pop_back();
1432 signal_recent_files_changed_();
1437 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1440 App::get_time_format()
1442 return _App_time_format;
1446 App::set_time_format(synfig::Time::Format x)
1453 App::save_settings()
1458 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1459 setlocale(LC_NUMERIC, "C");
1461 std::string filename=get_config_file("accelrc");
1462 Gtk::AccelMap::save(filename);
1465 std::string filename=get_config_file("recentfiles");
1467 std::ofstream file(filename.c_str());
1471 synfig::warning("Unable to save %s",filename.c_str());
1475 list<string>::reverse_iterator iter;
1477 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1481 std::string filename=get_config_file("settings");
1482 synfigapp::Main::settings().save_to_file(filename);
1483 setlocale(LC_NUMERIC,old_locale);
1487 synfig::warning("Caught exception when attempting to save settings.");
1492 App::load_settings()
1497 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1498 setlocale(LC_NUMERIC, "C");
1500 std::string filename=get_config_file("accelrc");
1501 Gtk::AccelMap::load(filename);
1504 std::string filename=get_config_file("recentfiles");
1506 std::ifstream file(filename.c_str());
1510 std::string recent_file;
1511 getline(file,recent_file);
1512 if(!recent_file.empty())
1513 add_recent_file(recent_file);
1516 std::string filename=get_config_file("settings");
1517 if(!synfigapp::Main::settings().load_from_file(filename))
1519 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1520 //if(!synfigapp::Main::settings().load_from_file(filename))
1522 gamma.set_gamma(1.0/2.2);
1523 reset_initial_window_configuration();
1526 setlocale(LC_NUMERIC,old_locale);
1530 synfig::warning("Caught exception when attempting to load settings.");
1535 App::reset_initial_window_configuration()
1537 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1538 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1539 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1540 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1541 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1542 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1543 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1544 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1545 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1546 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1547 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1548 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1549 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1553 App::shutdown_request(GdkEventAny*)
1557 //return !shutdown_in_progress;
1563 if(shutdown_in_progress)return;
1566 get_ui_interface()->task("Quit Request");
1569 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1573 std::list<etl::handle<Instance> >::iterator iter;
1574 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1576 if(!(*iter)->safe_close())
1580 if((*iter)->synfigapp::Instance::get_action_count())
1582 handle<synfigapp::UIInterface> uim;
1583 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1585 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1586 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1588 case synfigapp::UIInterface::RESPONSE_NO:
1590 case synfigapp::UIInterface::RESPONSE_YES:
1593 case synfigapp::UIInterface::RESPONSE_CANCEL:
1602 if((*iter)->synfigapp::Instance::is_modified())
1604 handle<synfigapp::UIInterface> uim;
1605 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1607 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() );
1608 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1610 case synfigapp::UIInterface::RESPONSE_NO:
1612 case synfigapp::UIInterface::RESPONSE_YES:
1613 (*iter)->dialog_cvs_commit();
1615 case synfigapp::UIInterface::RESPONSE_CANCEL:
1624 // This next line causes things to crash for some reason
1628 shutdown_in_progress=true;
1630 instance_list.clear();
1632 while(studio::App::events_pending())studio::App::iteration(false);
1635 auto_recover->normal_shutdown();
1637 get_ui_interface()->task("Quit Request sent");
1643 dialog_setup->refresh();
1644 dialog_setup->show();
1647 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1648 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1651 //#define USE_WIN32_FILE_DIALOGS 1
1654 #ifdef USE_WIN32_FILE_DIALOGS
1655 static OPENFILENAME ofn={};
1659 #include <gdk/gdkwin32.h>
1663 App::dialog_open_file(const std::string &title, std::string &filename)
1665 #ifdef USE_WIN32_FILE_DIALOGS
1666 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1668 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1669 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1670 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1672 ofn.lStructSize=sizeof(OPENFILENAME);
1673 ofn.hwndOwner = hWnd;
1674 ofn.hInstance = hInstance;
1675 ofn.lpstrFilter = szFilter;
1676 // ofn.lpstrCustomFilter=NULL;
1677 // ofn.nMaxCustFilter=0;
1678 // ofn.nFilterIndex=0;
1679 // ofn.lpstrFile=NULL;
1680 ofn.nMaxFile=MAX_PATH;
1681 // ofn.lpstrFileTitle=NULL;
1682 // ofn.lpstrInitialDir=NULL;
1683 // ofn.lpstrTitle=NULL;
1684 ofn.Flags=OFN_HIDEREADONLY;
1685 // ofn.nFileOffset=0;
1686 // ofn.nFileExtension=0;
1687 ofn.lpstrDefExt=TEXT("sif");
1688 // ofn.lCustData = 0l;
1690 // ofn.lpTemplateName=NULL;
1692 CHAR szFilename[MAX_PATH];
1694 strcpy(szFilename,filename.c_str());
1695 strcpy(szTitle,title.c_str());
1697 ofn.lpstrFile=szFilename;
1698 ofn.lpstrFileTitle=szTitle;
1700 if(GetOpenFileName(&ofn))
1702 filename=szFilename;
1708 synfig::String prev_path;
1709 if(!_preferences.get_value("curr_path",prev_path))
1711 prev_path = absolute_path(prev_path);
1713 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1714 dialog->set_current_folder(prev_path);
1715 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1716 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1717 if(!filename.empty())
1718 if (is_absolute_path(filename))
1719 dialog->set_filename(filename);
1721 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1722 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1723 filename=dialog->get_filename();
1735 GtkWidget *fileselection;
1736 fileselection = gtk_file_selection_new(title.c_str());
1739 if(basename(filename)==filename)
1741 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1744 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1746 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1748 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1749 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1751 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1752 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1754 gtk_widget_show(fileselection);
1762 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1763 _preferences.set_value("curr_path",dirname(filename));
1767 gtk_widget_destroy(fileselection);
1770 gtk_widget_destroy(fileselection);
1777 App::dialog_save_file(const std::string &title, std::string &filename)
1779 #if USE_WIN32_FILE_DIALOGS
1780 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1782 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1783 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1784 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1786 ofn.lStructSize=sizeof(OPENFILENAME);
1787 ofn.hwndOwner = hWnd;
1788 ofn.hInstance = hInstance;
1789 ofn.lpstrFilter = szFilter;
1790 // ofn.lpstrCustomFilter=NULL;
1791 // ofn.nMaxCustFilter=0;
1792 // ofn.nFilterIndex=0;
1793 // ofn.lpstrFile=NULL;
1794 ofn.nMaxFile=MAX_PATH;
1795 // ofn.lpstrFileTitle=NULL;
1796 // ofn.lpstrInitialDir=NULL;
1797 // ofn.lpstrTitle=NULL;
1798 ofn.Flags=OFN_OVERWRITEPROMPT;
1799 // ofn.nFileOffset=0;
1800 // ofn.nFileExtension=0;
1801 ofn.lpstrDefExt=TEXT("sif");
1802 // ofn.lCustData = 0l;
1804 // ofn.lpTemplateName=NULL;
1806 CHAR szFilename[MAX_PATH];
1808 strcpy(szFilename,filename.c_str());
1809 strcpy(szTitle,title.c_str());
1811 ofn.lpstrFile=szFilename;
1812 ofn.lpstrFileTitle=szTitle;
1814 if(GetSaveFileName(&ofn))
1816 filename=szFilename;
1817 _preferences.set_value("curr_path",dirname(filename));
1822 synfig::String prev_path;
1823 if(!_preferences.get_value("curr_path",prev_path))
1825 prev_path = absolute_path(prev_path);
1827 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1828 dialog->set_current_folder(prev_path);
1829 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1830 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1831 if(!filename.empty())
1833 std::string full_path;
1834 if (is_absolute_path(filename))
1835 full_path = filename;
1837 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1838 // select the file if it exists
1839 dialog->set_filename(full_path);
1841 // if the file doesn't exist, put its name into the filename box
1843 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1844 dialog->set_current_name(basename(filename));
1846 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1847 filename=dialog->get_filename();
1849 _preferences.set_value("curr_path",dirname(filename));
1854 // return dialog_open_file(title, filename);
1859 App::dialog_error_blocking(const std::string &title, const std::string &message)
1861 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1862 dialog.set_title(title);
1868 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1870 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1871 dialog.set_title(title);
1877 App::dialog_yes_no(const std::string &title, const std::string &message)
1882 true // use_separator
1884 Gtk::Label label(message);
1887 dialog.get_vbox()->pack_start(label);
1888 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1889 dialog.add_button(Gtk::StockID("gtk-no"),0);
1891 return dialog.run();
1895 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1900 true // use_separator
1902 Gtk::Label label(message);
1905 dialog.get_vbox()->pack_start(label);
1906 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1907 dialog.add_button(Gtk::StockID("gtk-no"),0);
1908 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1910 return dialog.run();
1914 App::dialog_not_implemented()
1916 Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1917 dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
1922 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1927 true // use_separator
1929 Gtk::Label label(message);
1931 dialog.get_vbox()->pack_start(label);
1934 entry.set_text(text);
1936 entry.set_activates_default(true);
1937 dialog.get_vbox()->pack_start(entry);
1939 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1940 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1941 dialog.set_default_response(Gtk::RESPONSE_OK);
1942 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1945 if(dialog.run()!=Gtk::RESPONSE_OK)
1948 text=entry.get_text();
1957 App::open(std::string filename)
1959 return open_as(filename,filename);
1962 // this is called from autorecover.cpp:
1963 // App::open_as(get_shadow_file_name(filename),filename)
1964 // other than that, 'filename' and 'as' are the same
1966 App::open_as(std::string filename,std::string as)
1969 char long_name[1024];
1970 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1976 OneMoment one_moment;
1978 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1979 if(canvas && get_instance(canvas))
1981 get_instance(canvas)->find_canvas_view(canvas)->present();
1982 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1985 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1987 add_recent_file(as);
1989 handle<Instance> instance(Instance::create(canvas));
1992 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1996 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)")))
1997 instance->dialog_cvs_update();
2001 dialog_error_blocking(_("Error"), x);
2006 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2010 _preferences.set_value("curr_path",dirname(as));
2019 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2020 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2022 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2024 canvas->rend_desc().set_frame_rate(24.0);
2025 canvas->rend_desc().set_time_start(0.0);
2026 canvas->rend_desc().set_time_end(00.0);
2027 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2028 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2029 canvas->rend_desc().set_tl(Vector(-4,2.25));
2030 canvas->rend_desc().set_br(Vector(4,-2.25));
2031 canvas->rend_desc().set_w(480);
2032 canvas->rend_desc().set_h(270);
2033 canvas->rend_desc().set_antialias(1);
2034 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2035 canvas->set_file_name(file_name);
2037 Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2043 string filename="*.sif";
2045 while(dialog_open_file("Open", filename))
2047 // If the filename still has wildcards, then we should
2048 // continue looking for the file we want
2049 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2055 get_ui_interface()->error(_("Unable to open file"));
2060 App::set_selected_instance(etl::loose_handle<Instance> instance)
2062 /* if(get_selected_instance()==instance)
2064 selected_instance=instance;
2065 signal_instance_selected()(instance);
2071 selected_instance=instance;
2072 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2076 instance->focus(instance->get_canvas());
2079 set_selected_canvas_view(0);
2081 signal_instance_selected()(instance);
2085 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2087 selected_canvas_view=canvas_view;
2088 signal_canvas_view_focus()(selected_canvas_view);
2091 selected_instance=canvas_view->get_instance();
2092 signal_instance_selected()(canvas_view->get_instance());
2095 if(get_selected_canvas_view()==canvas_view)
2097 signal_canvas_view_focus()(selected_canvas_view);
2098 signal_instance_selected()(canvas_view->get_instance());
2101 selected_canvas_view=canvas_view;
2102 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2103 set_selected_instance(canvas_view->get_instance());
2104 signal_canvas_view_focus()(selected_canvas_view);
2108 etl::loose_handle<Instance>
2109 App::get_instance(Canvas::Handle canvas)
2111 if(!canvas) return 0;
2112 canvas=canvas->get_root();
2114 std::list<etl::handle<Instance> >::iterator iter;
2115 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2117 if((*iter)->get_canvas()==canvas)
2126 (new class About())->show();
2132 if(selected_instance)
2133 selected_instance->undo();
2139 if(selected_instance)
2140 selected_instance->redo();
2144 studio::App::get_base_path()
2146 return app_base_path_;