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;
256 bool studio::App::single_threaded=false;
258 static int max_recent_files_=25;
259 int studio::App::get_max_recent_files() { return max_recent_files_; }
260 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
262 static synfig::String app_base_path_;
265 }; // END of namespace studio
266 studio::StateManager* state_manager;
271 class GlobalUIInterface : public synfigapp::UIInterface
275 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
280 true // use_separator
282 Gtk::Label label(message);
285 dialog.get_vbox()->pack_start(label);
286 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
287 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
289 dialog.set_default_response(dflt);
291 return (Response)dialog.run();
293 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
298 true // use_separator
300 Gtk::Label label(message);
303 dialog.get_vbox()->pack_start(label);
304 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
305 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
306 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
308 dialog.set_default_response(dflt);
310 return (Response)dialog.run();
312 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
317 true // use_separator
319 Gtk::Label label(message);
322 dialog.get_vbox()->pack_start(label);
323 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
324 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
326 dialog.set_default_response(dflt);
328 return (Response)dialog.run();
332 task(const std::string &task)
334 std::cerr<<task<<std::endl;
335 while(studio::App::events_pending())studio::App::iteration(false);
340 error(const std::string &err)
342 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
349 warning(const std::string &err)
351 std::cerr<<"warning: "<<err<<std::endl;
352 while(studio::App::events_pending())studio::App::iteration(false);
357 amount_complete(int /*current*/, int /*total*/)
359 while(studio::App::events_pending())studio::App::iteration(false);
364 /* === P R O C E D U R E S ================================================= */
366 typedef unsigned char U8;
367 typedef unsigned short U16;
368 typedef unsigned long U32;
378 static inline U32 hash_U32(U32 i)
380 i=i*1664525+1013904223;
381 i=i*1664525+1013904223;
382 i=i*1664525+1013904223;
387 static const int endian_fix_table[8] = { 3, 2, 1, 0, 7, 6, 5, 4 } ;
388 #define endian_fix(x) (endian_fix_table[x])
390 #define endian_fix(x) (x)
393 int v_unwind_key(V_KeyUnwound* unwound, const char* key)
396 unwound->element.serial=0;
397 unwound->element.checksum=0;
405 case '0': data=0; break;
406 case '1': data=1; break;
407 case '2': data=2; break;
408 case '3': data=3; break;
409 case '4': data=4; break;
410 case '5': data=5; break;
411 case '6': data=6; break;
412 case '7': data=7; break;
413 case '8': data=8; break;
414 case '9': data=9; break;
415 case 'a': case 'A': data=10; break;
416 case 'b': case 'B': data=11; break;
417 case 'c': case 'C': data=12; break;
418 case 'd': case 'D': data=13; break;
419 case 'e': case 'E': data=14; break;
420 case 'f': case 'F': data=15; break;
421 default: return 0; break;
424 unwound->element.checksum|=(((U32)data&3)<<bit);
425 unwound->element.serial|=(((U32)(data>>2)&3)<<bit);
430 int v_key_check(const char* key, U32* serial, U32 appid)
432 V_KeyUnwound unwound_key;
433 U32 appid_mask_a=hash_U32(appid);
434 U32 appid_mask_b=hash_U32(appid_mask_a);
436 if(!v_unwind_key(&unwound_key, key))
438 // Invalid characters in key
443 // Undo obfuscation pass
445 U32 next=hash_U32(unwound_key.raw[endian_fix(7)]);
450 unwound_key.raw[endian_fix(i)]^=(next>>24);
454 unwound_key.element.serial^=appid_mask_a;
455 unwound_key.element.checksum^=appid_mask_b;
457 *serial=unwound_key.element.serial;
459 return unwound_key.element.checksum==hash_U32(unwound_key.element.serial);
464 # ifdef LICENSE_KEY_REQUIRED
465 int check_license(String basedir)
467 int check_license(String /*basedir*/)
470 int check_license(String /*basedir*/)
473 #ifdef LICENSE_KEY_REQUIRED
478 license_file="/usr/local/etc/.synfiglicense";
480 license_file=basedir+"\\etc\\.synfiglicense";
484 key=Glib::file_get_contents(license_file);
485 } catch (Glib::FileError) { }
487 if(!v_key_check(key.c_str(),&serial,0xdeadbeef))
489 while(!v_key_check(key.c_str(),&serial,0xdeadbeef))
493 if(!App::dialog_entry(
494 _("Synfig Studio Authentication"),
495 _("Please enter your license key below. You will not\nbe able to use this software without a valid license key."),
498 throw String("No License");
501 FILE* file=fopen(license_file.c_str(),"w");
504 fprintf(file,"%s",key.c_str());
508 synfig::error("Unable to save license key!");
510 synfig::info("License Authenticated -- Serial #%05d",serial);
519 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
521 action_group_list.push_back(action_group);
522 Gtk::UIManager::insert_action_group(action_group, pos);
526 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
528 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
529 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
530 if(*iter==action_group)
532 action_group_list.erase(iter);
533 Gtk::UIManager::remove_action_group(action_group);
536 synfig::error("Unable to find action group");
540 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
542 ui_manager->insert_action_group(group,0);
545 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
546 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
549 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
552 if(*iter && (*iter)->get_name()!="menus")
554 synfig::info("Removing action group "+(*iter)->get_name());
555 ui_manager->remove_action_group(*iter);
559 ui_manager->insert_action_group(group,0);
562 for(;!prev_groups.empty();prev_groups.pop_front())
564 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
565 ui_manager->insert_action_group(prev_groups.front(),1);
570 class Preferences : public synfigapp::Settings
573 virtual bool get_value(const synfig::String& key, synfig::String& value)const
577 value=strprintf("%f %f %f %f",
578 App::gamma.get_gamma_r(),
579 App::gamma.get_gamma_g(),
580 App::gamma.get_gamma_b(),
581 App::gamma.get_black_level()
585 if(key=="time_format")
587 value=strprintf("%i",App::get_time_format());
590 if(key=="file_history.size")
592 value=strprintf("%i",App::get_max_recent_files());
595 if(key=="use_colorspace_gamma")
597 value=strprintf("%i",(int)App::use_colorspace_gamma);
600 if(key=="distance_system")
602 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
605 if(key=="single_threaded")
607 value=strprintf("%i",(int)App::single_threaded);
610 if(key=="auto_recover_backup_interval")
612 value=strprintf("%i",App::auto_recover->get_timeout());
616 return synfigapp::Settings::get_value(key,value);
619 virtual bool set_value(const synfig::String& key,const synfig::String& value)
625 strscanf(value,"%f %f %f %f",
632 App::gamma.set_all(r,g,b,blk);
636 if(key=="time_format")
638 int i(atoi(value.c_str()));
639 App::set_time_format(static_cast<synfig::Time::Format>(i));
642 if(key=="auto_recover_backup_interval")
644 int i(atoi(value.c_str()));
645 App::auto_recover->set_timeout(i);
648 if(key=="file_history.size")
650 int i(atoi(value.c_str()));
651 App::set_max_recent_files(i);
654 if(key=="use_colorspace_gamma")
656 int i(atoi(value.c_str()));
657 App::use_colorspace_gamma=i;
660 if(key=="distance_system")
662 App::distance_system=Distance::ident_system(value);;
665 if(key=="single_threaded")
667 int i(atoi(value.c_str()));
668 App::single_threaded=i;
672 return synfigapp::Settings::set_value(key,value);
675 virtual KeyList get_key_list()const
677 KeyList ret(synfigapp::Settings::get_key_list());
678 ret.push_back("gamma");
679 ret.push_back("time_format");
680 ret.push_back("distance_system");
681 ret.push_back("file_history.size");
682 ret.push_back("use_colorspace_gamma");
683 ret.push_back("single_threaded");
684 ret.push_back("auto_recover_backup_interval");
689 static ::Preferences _preferences;
694 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
696 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
698 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
700 menus_action_group->add( Gtk::Action::create("menu-file", "_File") );
701 menus_action_group->add( Gtk::Action::create("menu-edit", "_Edit") );
702 menus_action_group->add( Gtk::Action::create("menu-view", "_View") );
703 menus_action_group->add( Gtk::Action::create("menu-canvas", "_Canvas") );
704 menus_action_group->add( Gtk::Action::create("menu-layer", "_Layer") );
705 menus_action_group->add( Gtk::Action::create("menu-duck-mask", "Show/Hide Ducks") );
706 menus_action_group->add( Gtk::Action::create("menu-preview-quality", "Preview Quality") );
707 menus_action_group->add( Gtk::Action::create("menu-layer-new", "New Layer") );
708 menus_action_group->add( Gtk::Action::create("menu-keyframe", "Keyframe") );
709 menus_action_group->add( Gtk::Action::create("menu-group", "Group") );
710 menus_action_group->add( Gtk::Action::create("menu-state", "State") );
711 menus_action_group->add( Gtk::Action::create("menu-toolbox", "Toolbox") );
713 // Add the synfigapp actions...
714 synfigapp::Action::Book::iterator iter;
715 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
717 actions_action_group->add(Gtk::Action::create(
718 "action-"+iter->second.name,
719 get_action_stock_id(iter->second),
720 iter->second.local_name,iter->second.local_name
724 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
725 #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); }
726 #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); }
728 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
729 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
730 DEFINE_ACTION("open", Gtk::Stock::OPEN);
731 DEFINE_ACTION("save", Gtk::Stock::SAVE);
732 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
733 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
734 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
735 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
736 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
737 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
738 DEFINE_ACTION("import", _("Import"));
739 DEFINE_ACTION("render", _("Render"));
740 DEFINE_ACTION("preview", _("Preview"));
741 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
742 DEFINE_ACTION("sound", _("Sound File"));
743 DEFINE_ACTION("options", _("Options"));
744 DEFINE_ACTION("close", _("Close"));
747 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
748 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
749 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
750 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
751 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
752 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
753 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
754 DEFINE_ACTION("properties", _("Properties"));
756 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
757 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
758 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
759 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
760 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
761 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
762 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
763 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
764 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
765 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
766 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
767 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
768 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
769 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
770 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
771 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
772 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
773 DEFINE_ACTION("play", _("Play"));
774 // DEFINE_ACTION("pause", _("Pause"));
775 DEFINE_ACTION("stop", _("Stop"));
776 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
777 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
778 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
779 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
780 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
781 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
782 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
783 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
784 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
785 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
786 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
787 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
788 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
789 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
790 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
791 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
792 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
793 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
794 DEFINE_ACTION("seek-end", _("Seek to End"));
796 DEFINE_ACTION("action-group_add", _("Add group"));
798 DEFINE_ACTION("canvas-new", _("New Canvas"));
800 DEFINE_ACTION("amount-inc", _("Increase Amount"));
801 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
806 // Set up synfigapp actions
808 synfigapp::Action::Book::iterator iter;
810 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
812 Gtk::StockID stock_id;
814 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
816 //Gtk::Image* image(manage(new Gtk::Image()));
817 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
818 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
819 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
820 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
821 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
822 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
823 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
824 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
825 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
826 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
828 actions_action_group->add(Gtk::Action::create(
829 "action-"+iter->second.name,
831 iter->second.local_name,iter->second.local_name
839 Glib::ustring ui_info =
841 " <popup name='menu-toolbox' action='menu-toolbox'>"
842 " <menu action='menu-file'>"
845 " <popup name='menu-main' action='menu-main'>"
846 " <menu action='menu-file'>"
847 " <menuitem action='save' />"
848 " <menuitem action='save-as' />"
849 " <menuitem action='revert' />"
850 " <separator name='bleh01'/>"
851 " <menuitem action='cvs-add' />"
852 " <menuitem action='cvs-update' />"
853 " <menuitem action='cvs-commit' />"
854 " <menuitem action='cvs-revert' />"
855 " <separator name='bleh02'/>"
856 " <menuitem action='import' />"
857 " <separator name='bleh03'/>"
858 " <menuitem action='render' />"
859 " <menuitem action='preview' />"
860 " <menuitem action='sound' />"
861 " <separator name='bleh04'/>"
862 " <menuitem action='options' />"
863 " <menuitem action='close' />"
865 " <menu action='menu-edit'>"
866 " <menuitem action='undo'/>"
867 " <menuitem action='redo'/>"
868 " <separator name='bleh05'/>"
869 " <menuitem action='cut'/>"
870 " <menuitem action='copy'/>"
871 " <menuitem action='paste'/>"
872 " <separator name='bleh06'/>"
873 " <menuitem action='select-all-ducks'/>"
874 " <menuitem action='unselect-all-layers'/>"
875 " <separator name='bleh07'/>"
876 " <menuitem action='properties'/>"
878 " <menu action='menu-view'>"
879 " <menu action='menu-duck-mask'>"
880 " <menuitem action='mask-position-ducks' />"
881 " <menuitem action='mask-vertex-ducks' />"
882 " <menuitem action='mask-tangent-ducks' />"
883 " <menuitem action='mask-radius-ducks' />"
884 " <menuitem action='mask-width-ducks' />"
885 " <menuitem action='mask-angle-ducks' />"
887 " <menu action='menu-preview-quality'>"
888 " <menuitem action='quality-00' />"
889 " <menuitem action='quality-01' />"
890 " <menuitem action='quality-02' />"
891 " <menuitem action='quality-03' />"
892 " <menuitem action='quality-04' />"
893 " <menuitem action='quality-05' />"
894 " <menuitem action='quality-06' />"
895 " <menuitem action='quality-07' />"
896 " <menuitem action='quality-08' />"
897 " <menuitem action='quality-09' />"
898 " <menuitem action='quality-10' />"
900 " <separator name='bleh08'/>"
901 " <menuitem action='play'/>"
902 //" <menuitem action='pause'/>"
903 " <menuitem action='stop'/>"
904 " <menuitem action='dialog-flipbook'/>"
905 " <separator name='bleh09'/>"
906 " <menuitem action='toggle-grid-show'/>"
907 " <menuitem action='toggle-grid-snap'/>"
908 " <menuitem action='toggle-guide-show'/>"
909 " <menuitem action='toggle-low-res'/>"
910 " <menuitem action='toggle-onion-skin'/>"
911 " <separator name='bleh10'/>"
912 " <menuitem action='canvas-zoom-in'/>"
913 " <menuitem action='canvas-zoom-out'/>"
914 " <menuitem action='canvas-zoom-fit'/>"
915 " <menuitem action='canvas-zoom-100'/>"
916 " <separator name='bleh11'/>"
917 " <menuitem action='time-zoom-in'/>"
918 " <menuitem action='time-zoom-out'/>"
919 " <separator name='bleh12'/>"
920 " <menuitem action='jump-next-keyframe'/>"
921 " <menuitem action='jump-prev-keyframe'/>"
922 " <menuitem action='seek-next-frame'/>"
923 " <menuitem action='seek-prev-frame'/>"
924 " <menuitem action='seek-next-second'/>"
925 " <menuitem action='seek-prev-second'/>"
926 " <menuitem action='seek-begin'/>"
927 " <menuitem action='seek-end'/>"
929 " <menu action='menu-canvas'>"
930 " <menuitem action='canvas-new'/>"
932 " <menu name='menu-state' action='menu-state'>"
934 " <menu action='menu-group'>"
935 " <menuitem action='action-group_add'/>"
937 " <menu action='menu-layer'>"
938 //" <menuitem action='cut'/>"
939 //" <menuitem action='copy'/>"
940 //" <menuitem action='paste'/>"
941 //" <separator name='bleh06'/>"
942 " <menu action='menu-layer-new'></menu>"
943 " <menuitem action='amount-inc'/>"
944 " <menuitem action='amount-dec'/>"
946 " <menu action='menu-keyframe'>"
947 " <menuitem action='keyframe-properties'/>"
954 " <menubar name='MenuBar'>"
955 " <menu action='MenuFile'>"
956 " <menuitem action='New'/>"
957 " <menuitem action='Open'/>"
959 " <menuitem action='Quit'/>"
961 " <menu action='MenuEdit'>"
962 " <menuitem action='Cut'/>"
963 " <menuitem action='Copy'/>"
964 " <menuitem action='Paste'/>"
967 " <toolbar name='ToolBar'>"
968 " <toolitem action='Open'/>"
969 " <toolitem action='Quit'/>"
975 actions_action_group->set_sensitive(false);
976 App::ui_manager()->set_add_tearoffs(true);
977 App::ui_manager()->insert_action_group(menus_action_group,1);
978 App::ui_manager()->insert_action_group(actions_action_group,1);
979 App::ui_manager()->add_ui_from_string(ui_info);
981 //App::ui_manager()->get_accel_group()->unlock();
983 catch(const Glib::Error& ex)
985 synfig::error("building menus and toolbars failed: " + ex.what());
988 // Add default keyboard accelerators
989 #define ACCEL(path,accel) \
991 Gtk::AccelKey accel_key(accel,path); \
992 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
995 #define ACCEL2(accel) \
997 Gtk::AccelKey accel_key(accel); \
998 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1001 ACCEL("<Actions>//select-all-ducks","<Control>a");
1002 ACCEL("<Actions>//unselect-all-layers","<Control>d");
1003 ACCEL("<Actions>//render","F9");
1004 ACCEL("<Actions>//preview","F11");
1005 ACCEL("<Actions>//properties","F8");
1006 ACCEL("<Actions>//options","F12");
1007 ACCEL("<Actions>//import","<control>i");
1008 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
1009 ACCEL("<Actions>//toggle-grid-show","<Control>g");
1010 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
1011 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
1012 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
1013 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1014 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1015 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1016 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1017 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1019 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1020 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1022 ACCEL("<Actions>//quality-01","<Control>1");
1023 ACCEL("<Actions>//quality-02","<Control>2");
1024 ACCEL("<Actions>//quality-03","<Control>3");
1025 ACCEL("<Actions>//quality-04","<Control>4");
1026 ACCEL("<Actions>//quality-05","<Control>5");
1027 ACCEL("<Actions>//quality-06","<Control>6");
1028 ACCEL("<Actions>//quality-07","<Control>7");
1029 ACCEL("<Actions>//quality-08","<Control>8");
1030 ACCEL("<Actions>//quality-09","<Control>9");
1031 ACCEL("<Actions>//quality-10","<Control>0");
1032 ACCEL("<Actions>//undo","<Control>z");
1033 ACCEL("<Actions>//redo","<Control>r");
1034 ACCEL("<Actions>//action-layer_remove","Delete");
1036 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1037 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1038 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1039 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1040 ACCEL("<Actions>//time-zoom-in","+");
1041 ACCEL("<Actions>//time-zoom-out","_");
1043 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1044 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1046 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1047 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1048 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1049 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1050 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1051 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1052 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1053 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1054 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1055 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1056 ACCEL2(Gtk::AccelKey('o',Gdk::CONTROL_MASK,"<Actions>//toggle-onion-skin"));
1057 ACCEL("<Actions>//play", "<Control>p");
1058 ACCEL("<Actions>//seek-begin","Home");
1059 ACCEL("<Actions>//seek-end","End");
1061 ACCEL("<Actions>//state-normal", "<Mod1>a");
1062 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1063 ACCEL("<Actions>//state-scale", "<Mod1>d");
1064 ACCEL("<Actions>//state-rotate", "<Mod1>s");
1066 ACCEL("<Actions>//state-bline", "<Mod1>b");
1067 ACCEL("<Actions>//state-circle", "<Mod1>c");
1068 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1069 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1071 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1072 ACCEL("<Actions>//state-fill", "<Mod1>f");
1073 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1074 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1076 ACCEL("<Actions>//state-draw", "<Mod1>w");
1077 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1078 ACCEL("<Actions>//state-width", "<Mod1>t");
1079 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1081 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1087 #define mkdir(x,y) mkdir(x)
1090 /* === M E T H O D S ======================================================= */
1092 App::App(int *argc, char ***argv):
1093 Gtk::Main(argc,argv),
1094 IconControler(etl::dirname((*argv)[0]))
1096 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1099 serial_=check_license(app_base_path_);
1102 ui_interface_=new GlobalUIInterface();
1106 // don't call thread_init() if threads are already initialised
1107 // on some machines bonobo_init() initialised threads before we get here
1108 if (!g_thread_supported())
1109 Glib::thread_init();
1111 distance_system=Distance::SYSTEM_UNITS;
1113 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1116 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1120 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1128 if(!SYNFIG_CHECK_VERSION())
1130 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1131 dialog_error_blocking("Synfig Studio",
1132 "This copy of Synfig Studio was compiled against a\n"
1133 "different version of libsynfig than what is currently\n"
1134 "installed. Synfig Studio will now abort. Try downloading\n"
1135 "the latest version from the Synfig website at\n"
1136 "http://www.synfig.com/ "
1141 catch(synfig::SoftwareExpired)
1143 cerr<<"FATAL: Software Expired"<<endl;
1144 dialog_error_blocking("Synfig Studio",
1145 "This copy of Synfig Studio has expired.\n"
1146 "Please erase this copy, or download and\n"
1147 "install the latest copy from the Synfig\n"
1148 "website at http://www.synfig.com/ ."
1152 Glib::set_application_name(_("Synfig Studio"));
1155 about_window.set_can_self_destruct(false);
1156 about_window.show();
1158 shutdown_in_progress=false;
1159 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1160 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1162 // Initialize the Synfig library
1163 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1166 get_ui_interface()->error("Failed to initialize synfig!");
1170 // add the preferences to the settings
1171 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1175 studio_init_cb.task("Init UI Manager...");
1176 App::ui_manager_=studio::UIManager::create();
1179 studio_init_cb.task("Init Dock Manager...");
1180 dock_manager=new studio::DockManager();
1182 studio_init_cb.task("Init State Manager...");
1183 state_manager=new StateManager();
1185 studio_init_cb.task("Init Toolbox...");
1186 toolbox=new studio::Toolbox();
1188 studio_init_cb.task("Init Tool Options...");
1189 dialog_tool_options=new studio::Dialog_ToolOptions();
1190 dock_manager->register_dockable(*dialog_tool_options);
1192 studio_init_cb.task("Init History...");
1193 dock_history=new studio::Dock_History();
1194 dock_manager->register_dockable(*dock_history);
1196 studio_init_cb.task("Init Canvases...");
1197 dock_canvases=new studio::Dock_Canvases();
1198 dock_manager->register_dockable(*dock_canvases);
1200 studio_init_cb.task("Init Keyframes...");
1201 dock_keyframes=new studio::Dock_Keyframes();
1202 dock_manager->register_dockable(*dock_keyframes);
1204 studio_init_cb.task("Init Layers...");
1205 dock_layers=new studio::Dock_Layers();
1206 dock_manager->register_dockable(*dock_layers);
1208 studio_init_cb.task("Init Params...");
1209 dock_params=new studio::Dock_Params();
1210 dock_manager->register_dockable(*dock_params);
1212 studio_init_cb.task("Init MetaData...");
1213 dock_meta_data=new studio::Dock_MetaData();
1214 dock_manager->register_dockable(*dock_meta_data);
1216 studio_init_cb.task("Init Children...");
1217 dock_children=new studio::Dock_Children();
1218 dock_manager->register_dockable(*dock_children);
1220 studio_init_cb.task("Init Info...");
1221 dock_info = new studio::Dock_Info();
1222 dock_manager->register_dockable(*dock_info);
1224 studio_init_cb.task("Init Navigator...");
1225 dock_navigator = new studio::Dock_Navigator();
1226 dock_manager->register_dockable(*dock_navigator);
1228 studio_init_cb.task("Init Timetrack...");
1229 dock_timetrack = new studio::Dock_Timetrack();
1230 dock_manager->register_dockable(*dock_timetrack);
1232 studio_init_cb.task("Init Curve Editor...");
1233 dock_curves = new studio::Dock_Curves();
1234 dock_manager->register_dockable(*dock_curves);
1236 studio_init_cb.task("Init Layer Groups...");
1237 dock_layer_groups = new studio::Dock_LayerGroups();
1238 dock_manager->register_dockable(*dock_layer_groups);
1241 studio_init_cb.task("Init Color Dialog...");
1242 dialog_color=new studio::Dialog_Color();
1244 studio_init_cb.task("Init Gradient Dialog...");
1245 dialog_gradient=new studio::Dialog_Gradient();
1247 studio_init_cb.task("Init DeviceTracker...");
1248 device_tracker=new studio::DeviceTracker();
1250 studio_init_cb.task("Init Tools...");
1251 state_manager->add_state(&state_normal);
1252 state_manager->add_state(&state_smooth_move);
1253 state_manager->add_state(&state_scale);
1254 state_manager->add_state(&state_rotate);
1256 state_manager->add_state(&state_bline);
1259 state_manager->add_state(&state_circle);
1260 state_manager->add_state(&state_rectangle);
1262 state_manager->add_state(&state_gradient);
1263 state_manager->add_state(&state_eyedrop);
1264 state_manager->add_state(&state_fill);
1266 state_manager->add_state(&state_zoom);
1268 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1269 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1270 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1272 // Enabled for now. Let's see whether they're good enough yet.
1273 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1274 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1276 // Disabled by default - it doesn't work properly?
1277 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1279 studio_init_cb.task("Init ModPalette...");
1280 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1282 studio_init_cb.task("Init ModMirror...");
1283 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1286 studio_init_cb.task("Init Setup Dialog...");
1287 dialog_setup=new studio::Dialog_Setup();
1289 studio_init_cb.task("Init Input Dialog...");
1290 dialog_input=new Gtk::InputDialog();
1291 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1292 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1294 studio_init_cb.task("Init auto recovery...");
1295 auto_recover=new AutoRecover();
1297 studio_init_cb.amount_complete(9250,10000);
1298 studio_init_cb.task("Loading Settings...");
1300 studio_init_cb.task("Checking auto-recover...");
1302 studio_init_cb.amount_complete(9900,10000);
1304 if(auto_recover->recovery_needed())
1306 about_window.hide();
1308 get_ui_interface()->yes_no(
1310 "Synfig Studio seems to have crashed\n"
1311 "before you could save all your files.\n"
1312 "Would you like to re-open those files\n"
1313 "and recover your unsaved changes?"
1314 )==synfigapp::UIInterface::RESPONSE_YES
1317 if(!auto_recover->recover())
1319 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1322 get_ui_interface()->error(
1323 _("Synfig Studio has attempted to recover\n"
1324 "from a previous crash. The files that it has\n"
1325 "recovered are NOT YET SAVED. It would be a good\n"
1326 "idea to review them and save them now.")
1329 about_window.show();
1332 // Look for any files given on the command line,
1333 // and load them if found.
1334 for(;*argc>=1;(*argc)--)
1335 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1337 studio_init_cb.task("Loading files...");
1338 about_window.hide();
1339 open((*argv)[*argc]);
1340 about_window.show();
1343 studio_init_cb.task("Done.");
1344 studio_init_cb.amount_complete(10000,10000);
1350 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1354 StateManager* App::get_state_manager() { return state_manager; }
1358 shutdown_in_progress=true;
1362 synfigapp::Main::settings().remove_domain("pref");
1364 selected_instance=0;
1366 // Unload all of the modules
1367 for(;!module_list_.empty();module_list_.pop_back());
1369 delete state_manager;
1373 delete auto_recover;
1377 // studio::App::iteration(false);
1381 // studio::App::iteration(false);
1383 // studio::App::iteration(false);
1385 delete dialog_setup;
1387 delete dialog_gradient;
1389 delete dialog_color;
1391 delete dialog_input;
1393 delete dock_manager;
1395 instance_list.clear();
1397 // studio::App::iteration(false);
1401 App::get_user_app_directory()
1403 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1407 App::get_config_file(const synfig::String& file)
1409 return Glib::build_filename(get_user_app_directory(),file);
1413 App::add_recent_file(const std::string &file_name)
1415 std::string filename(file_name);
1417 assert(!filename.empty());
1419 if(filename.empty())
1422 // Toss out any "hidden" files
1423 if(basename(filename)[0]=='.')
1426 // If we aren't an absolute path, turn outselves into one
1427 if(!is_absolute_path(filename))
1428 filename=absolute_path(filename);
1430 list<string>::iterator iter;
1431 // Check to see if the file is already on the list.
1432 // If it is, then remove it from the list
1433 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1436 recent_files.erase(iter);
1441 // Push the filename to the front of the list
1442 recent_files.push_front(filename);
1444 // Clean out the files at the end of the list.
1445 while(recent_files.size()>(unsigned)get_max_recent_files())
1446 recent_files.pop_back();
1448 signal_recent_files_changed_();
1453 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1456 App::get_time_format()
1458 return _App_time_format;
1462 App::set_time_format(synfig::Time::Format x)
1469 App::save_settings()
1474 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1475 setlocale(LC_NUMERIC, "C");
1477 std::string filename=get_config_file("accelrc");
1478 Gtk::AccelMap::save(filename);
1481 std::string filename=get_config_file("recentfiles");
1483 std::ofstream file(filename.c_str());
1487 synfig::warning("Unable to save %s",filename.c_str());
1491 list<string>::reverse_iterator iter;
1493 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1497 std::string filename=get_config_file("settings");
1498 synfigapp::Main::settings().save_to_file(filename);
1499 setlocale(LC_NUMERIC,old_locale);
1503 synfig::warning("Caught exception when attempting to save settings.");
1508 App::load_settings()
1513 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1514 setlocale(LC_NUMERIC, "C");
1516 std::string filename=get_config_file("accelrc");
1517 Gtk::AccelMap::load(filename);
1520 std::string filename=get_config_file("recentfiles");
1522 std::ifstream file(filename.c_str());
1526 std::string recent_file;
1527 getline(file,recent_file);
1528 if(!recent_file.empty())
1529 add_recent_file(recent_file);
1532 std::string filename=get_config_file("settings");
1533 if(!synfigapp::Main::settings().load_from_file(filename))
1535 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1536 //if(!synfigapp::Main::settings().load_from_file(filename))
1538 gamma.set_gamma(1.0/2.2);
1539 reset_initial_window_configuration();
1542 setlocale(LC_NUMERIC,old_locale);
1546 synfig::warning("Caught exception when attempting to load settings.");
1551 App::reset_initial_window_configuration()
1553 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1554 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1555 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1556 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1557 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1558 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1559 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1560 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1561 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1562 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1563 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1564 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1565 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1566 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1570 App::shutdown_request(GdkEventAny*)
1574 //return !shutdown_in_progress;
1580 if(shutdown_in_progress)return;
1583 get_ui_interface()->task("Quit Request");
1586 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1590 std::list<etl::handle<Instance> >::iterator iter;
1591 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1593 if(!(*iter)->safe_close())
1597 if((*iter)->synfigapp::Instance::get_action_count())
1599 handle<synfigapp::UIInterface> uim;
1600 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1602 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1603 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1605 case synfigapp::UIInterface::RESPONSE_NO:
1607 case synfigapp::UIInterface::RESPONSE_YES:
1610 case synfigapp::UIInterface::RESPONSE_CANCEL:
1619 if((*iter)->synfigapp::Instance::is_modified())
1621 handle<synfigapp::UIInterface> uim;
1622 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1624 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() );
1625 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1627 case synfigapp::UIInterface::RESPONSE_NO:
1629 case synfigapp::UIInterface::RESPONSE_YES:
1630 (*iter)->dialog_cvs_commit();
1632 case synfigapp::UIInterface::RESPONSE_CANCEL:
1641 // This next line causes things to crash for some reason
1645 shutdown_in_progress=true;
1647 instance_list.clear();
1649 while(studio::App::events_pending())studio::App::iteration(false);
1652 auto_recover->normal_shutdown();
1654 get_ui_interface()->task("Quit Request sent");
1660 dialog_setup->refresh();
1661 dialog_setup->show();
1664 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1665 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1668 //#define USE_WIN32_FILE_DIALOGS 1
1671 #ifdef USE_WIN32_FILE_DIALOGS
1672 static OPENFILENAME ofn={};
1676 #include <gdk/gdkwin32.h>
1680 App::dialog_open_file(const std::string &title, std::string &filename)
1682 #ifdef USE_WIN32_FILE_DIALOGS
1683 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1685 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1686 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1687 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1689 ofn.lStructSize=sizeof(OPENFILENAME);
1690 ofn.hwndOwner = hWnd;
1691 ofn.hInstance = hInstance;
1692 ofn.lpstrFilter = szFilter;
1693 // ofn.lpstrCustomFilter=NULL;
1694 // ofn.nMaxCustFilter=0;
1695 // ofn.nFilterIndex=0;
1696 // ofn.lpstrFile=NULL;
1697 ofn.nMaxFile=MAX_PATH;
1698 // ofn.lpstrFileTitle=NULL;
1699 // ofn.lpstrInitialDir=NULL;
1700 // ofn.lpstrTitle=NULL;
1701 ofn.Flags=OFN_HIDEREADONLY;
1702 // ofn.nFileOffset=0;
1703 // ofn.nFileExtension=0;
1704 ofn.lpstrDefExt=TEXT("sif");
1705 // ofn.lCustData = 0l;
1707 // ofn.lpTemplateName=NULL;
1709 CHAR szFilename[MAX_PATH];
1711 strcpy(szFilename,filename.c_str());
1712 strcpy(szTitle,title.c_str());
1714 ofn.lpstrFile=szFilename;
1715 ofn.lpstrFileTitle=szTitle;
1717 if(GetOpenFileName(&ofn))
1719 filename=szFilename;
1725 synfig::String prev_path;
1726 if(!_preferences.get_value("curr_path",prev_path))
1728 prev_path = absolute_path(prev_path);
1730 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1731 dialog->set_current_folder(prev_path);
1732 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1733 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1734 if(!filename.empty())
1735 if (is_absolute_path(filename))
1736 dialog->set_filename(filename);
1738 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1739 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1740 filename=dialog->get_filename();
1752 GtkWidget *fileselection;
1753 fileselection = gtk_file_selection_new(title.c_str());
1756 if(basename(filename)==filename)
1758 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1761 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1763 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1765 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1766 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1768 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1769 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1771 gtk_widget_show(fileselection);
1779 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1780 _preferences.set_value("curr_path",dirname(filename));
1784 gtk_widget_destroy(fileselection);
1787 gtk_widget_destroy(fileselection);
1794 App::dialog_save_file(const std::string &title, std::string &filename)
1796 #if USE_WIN32_FILE_DIALOGS
1797 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1799 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1800 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1801 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1803 ofn.lStructSize=sizeof(OPENFILENAME);
1804 ofn.hwndOwner = hWnd;
1805 ofn.hInstance = hInstance;
1806 ofn.lpstrFilter = szFilter;
1807 // ofn.lpstrCustomFilter=NULL;
1808 // ofn.nMaxCustFilter=0;
1809 // ofn.nFilterIndex=0;
1810 // ofn.lpstrFile=NULL;
1811 ofn.nMaxFile=MAX_PATH;
1812 // ofn.lpstrFileTitle=NULL;
1813 // ofn.lpstrInitialDir=NULL;
1814 // ofn.lpstrTitle=NULL;
1815 ofn.Flags=OFN_OVERWRITEPROMPT;
1816 // ofn.nFileOffset=0;
1817 // ofn.nFileExtension=0;
1818 ofn.lpstrDefExt=TEXT("sif");
1819 // ofn.lCustData = 0l;
1821 // ofn.lpTemplateName=NULL;
1823 CHAR szFilename[MAX_PATH];
1825 strcpy(szFilename,filename.c_str());
1826 strcpy(szTitle,title.c_str());
1828 ofn.lpstrFile=szFilename;
1829 ofn.lpstrFileTitle=szTitle;
1831 if(GetSaveFileName(&ofn))
1833 filename=szFilename;
1834 _preferences.set_value("curr_path",dirname(filename));
1839 synfig::String prev_path;
1840 if(!_preferences.get_value("curr_path",prev_path))
1842 prev_path = absolute_path(prev_path);
1844 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1845 dialog->set_current_folder(prev_path);
1846 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1847 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1848 if(!filename.empty())
1850 std::string full_path;
1851 if (is_absolute_path(filename))
1852 full_path = filename;
1854 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1855 // select the file if it exists
1856 dialog->set_filename(full_path);
1858 // if the file doesn't exist, put its name into the filename box
1860 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1861 dialog->set_current_name(basename(filename));
1863 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1864 filename=dialog->get_filename();
1866 _preferences.set_value("curr_path",dirname(filename));
1871 // return dialog_open_file(title, filename);
1876 App::dialog_error_blocking(const std::string &title, const std::string &message)
1878 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1879 dialog.set_title(title);
1885 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1887 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1888 dialog.set_title(title);
1894 App::dialog_yes_no(const std::string &title, const std::string &message)
1899 true // use_separator
1901 Gtk::Label label(message);
1904 dialog.get_vbox()->pack_start(label);
1905 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1906 dialog.add_button(Gtk::StockID("gtk-no"),0);
1908 return dialog.run();
1912 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1917 true // use_separator
1919 Gtk::Label label(message);
1922 dialog.get_vbox()->pack_start(label);
1923 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1924 dialog.add_button(Gtk::StockID("gtk-no"),0);
1925 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1927 return dialog.run();
1931 App::dialog_not_implemented()
1933 Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1934 dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
1939 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1944 true // use_separator
1946 Gtk::Label label(message);
1948 dialog.get_vbox()->pack_start(label);
1951 entry.set_text(text);
1953 entry.set_activates_default(true);
1954 dialog.get_vbox()->pack_start(entry);
1956 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1957 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1958 dialog.set_default_response(Gtk::RESPONSE_OK);
1959 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1962 if(dialog.run()!=Gtk::RESPONSE_OK)
1965 text=entry.get_text();
1974 App::open(std::string filename)
1976 return open_as(filename,filename);
1979 // this is called from autorecover.cpp:
1980 // App::open_as(get_shadow_file_name(filename),filename)
1981 // other than that, 'filename' and 'as' are the same
1983 App::open_as(std::string filename,std::string as)
1986 char long_name[1024];
1987 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1993 OneMoment one_moment;
1995 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1996 if(canvas && get_instance(canvas))
1998 get_instance(canvas)->find_canvas_view(canvas)->present();
1999 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2002 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2004 add_recent_file(as);
2006 handle<Instance> instance(Instance::create(canvas));
2009 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2013 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)")))
2014 instance->dialog_cvs_update();
2018 dialog_error_blocking(_("Error"), x);
2023 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2027 _preferences.set_value("curr_path",dirname(as));
2036 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2037 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2039 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2041 canvas->rend_desc().set_frame_rate(24.0);
2042 canvas->rend_desc().set_time_start(0.0);
2043 canvas->rend_desc().set_time_end(00.0);
2044 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2045 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2046 canvas->rend_desc().set_tl(Vector(-4,2.25));
2047 canvas->rend_desc().set_br(Vector(4,-2.25));
2048 canvas->rend_desc().set_w(480);
2049 canvas->rend_desc().set_h(270);
2050 canvas->rend_desc().set_antialias(1);
2051 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2052 canvas->set_file_name(file_name);
2054 Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2060 string filename="*.sif";
2062 while(dialog_open_file("Open", filename))
2064 // If the filename still has wildcards, then we should
2065 // continue looking for the file we want
2066 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2072 get_ui_interface()->error(_("Unable to open file"));
2077 App::set_selected_instance(etl::loose_handle<Instance> instance)
2079 /* if(get_selected_instance()==instance)
2081 selected_instance=instance;
2082 signal_instance_selected()(instance);
2088 selected_instance=instance;
2089 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2093 instance->focus(instance->get_canvas());
2096 set_selected_canvas_view(0);
2098 signal_instance_selected()(instance);
2102 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2104 selected_canvas_view=canvas_view;
2105 signal_canvas_view_focus()(selected_canvas_view);
2108 selected_instance=canvas_view->get_instance();
2109 signal_instance_selected()(canvas_view->get_instance());
2112 if(get_selected_canvas_view()==canvas_view)
2114 signal_canvas_view_focus()(selected_canvas_view);
2115 signal_instance_selected()(canvas_view->get_instance());
2118 selected_canvas_view=canvas_view;
2119 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2120 set_selected_instance(canvas_view->get_instance());
2121 signal_canvas_view_focus()(selected_canvas_view);
2125 etl::loose_handle<Instance>
2126 App::get_instance(Canvas::Handle canvas)
2128 if(!canvas) return 0;
2129 canvas=canvas->get_root();
2131 std::list<etl::handle<Instance> >::iterator iter;
2132 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2134 if((*iter)->get_canvas()==canvas)
2143 (new class About())->show();
2149 if(selected_instance)
2150 selected_instance->undo();
2156 if(selected_instance)
2157 selected_instance->redo();
2161 studio::App::get_base_path()
2163 return app_base_path_;