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_;
267 really_delete_widget(Gtk::Widget *widget)
269 synfig::info("really delete %x", (unsigned int)widget);
274 // nasty workaround - when we've finished with a popup menu, we want to delete it
275 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
276 // so schedule the real delete to happen in 50ms, giving the action a chance to run
278 delete_widget(Gtk::Widget *widget)
280 synfig::info("delete %x", (unsigned int)widget);
281 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
284 }; // END of namespace studio
285 studio::StateManager* state_manager;
290 class GlobalUIInterface : public synfigapp::UIInterface
294 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
299 true // use_separator
301 Gtk::Label label(message);
304 dialog.get_vbox()->pack_start(label);
305 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
306 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
308 dialog.set_default_response(dflt);
310 return (Response)dialog.run();
312 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
317 true // use_separator
319 Gtk::Label label(message);
322 dialog.get_vbox()->pack_start(label);
323 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
324 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
325 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
327 dialog.set_default_response(dflt);
329 return (Response)dialog.run();
331 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
336 true // use_separator
338 Gtk::Label label(message);
341 dialog.get_vbox()->pack_start(label);
342 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
343 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
345 dialog.set_default_response(dflt);
347 return (Response)dialog.run();
351 task(const std::string &task)
353 std::cerr<<task<<std::endl;
354 while(studio::App::events_pending())studio::App::iteration(false);
359 error(const std::string &err)
361 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
368 warning(const std::string &err)
370 std::cerr<<"warning: "<<err<<std::endl;
371 while(studio::App::events_pending())studio::App::iteration(false);
376 amount_complete(int /*current*/, int /*total*/)
378 while(studio::App::events_pending())studio::App::iteration(false);
383 /* === P R O C E D U R E S ================================================= */
385 typedef unsigned char U8;
386 typedef unsigned short U16;
387 typedef unsigned long U32;
397 static inline U32 hash_U32(U32 i)
399 i=i*1664525+1013904223;
400 i=i*1664525+1013904223;
401 i=i*1664525+1013904223;
406 static const int endian_fix_table[8] = { 3, 2, 1, 0, 7, 6, 5, 4 } ;
407 #define endian_fix(x) (endian_fix_table[x])
409 #define endian_fix(x) (x)
412 int v_unwind_key(V_KeyUnwound* unwound, const char* key)
415 unwound->element.serial=0;
416 unwound->element.checksum=0;
424 case '0': data=0; break;
425 case '1': data=1; break;
426 case '2': data=2; break;
427 case '3': data=3; break;
428 case '4': data=4; break;
429 case '5': data=5; break;
430 case '6': data=6; break;
431 case '7': data=7; break;
432 case '8': data=8; break;
433 case '9': data=9; break;
434 case 'a': case 'A': data=10; break;
435 case 'b': case 'B': data=11; break;
436 case 'c': case 'C': data=12; break;
437 case 'd': case 'D': data=13; break;
438 case 'e': case 'E': data=14; break;
439 case 'f': case 'F': data=15; break;
440 default: return 0; break;
443 unwound->element.checksum|=(((U32)data&3)<<bit);
444 unwound->element.serial|=(((U32)(data>>2)&3)<<bit);
449 int v_key_check(const char* key, U32* serial, U32 appid)
451 V_KeyUnwound unwound_key;
452 U32 appid_mask_a=hash_U32(appid);
453 U32 appid_mask_b=hash_U32(appid_mask_a);
455 if(!v_unwind_key(&unwound_key, key))
457 // Invalid characters in key
462 // Undo obfuscation pass
464 U32 next=hash_U32(unwound_key.raw[endian_fix(7)]);
469 unwound_key.raw[endian_fix(i)]^=(next>>24);
473 unwound_key.element.serial^=appid_mask_a;
474 unwound_key.element.checksum^=appid_mask_b;
476 *serial=unwound_key.element.serial;
478 return unwound_key.element.checksum==hash_U32(unwound_key.element.serial);
483 # ifdef LICENSE_KEY_REQUIRED
484 int check_license(String basedir)
486 int check_license(String /*basedir*/)
489 int check_license(String /*basedir*/)
492 #ifdef LICENSE_KEY_REQUIRED
497 license_file="/usr/local/etc/.synfiglicense";
499 license_file=basedir+"\\etc\\.synfiglicense";
503 key=Glib::file_get_contents(license_file);
504 } catch (Glib::FileError) { }
506 if(!v_key_check(key.c_str(),&serial,0xdeadbeef))
508 while(!v_key_check(key.c_str(),&serial,0xdeadbeef))
512 if(!App::dialog_entry(
513 _("Synfig Studio Authentication"),
514 _("Please enter your license key below. You will not\nbe able to use this software without a valid license key."),
517 throw String("No License");
520 FILE* file=fopen(license_file.c_str(),"w");
523 fprintf(file,"%s",key.c_str());
527 synfig::error("Unable to save license key!");
529 synfig::info("License Authenticated -- Serial #%05d",serial);
538 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
540 action_group_list.push_back(action_group);
541 Gtk::UIManager::insert_action_group(action_group, pos);
545 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
547 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
548 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
549 if(*iter==action_group)
551 action_group_list.erase(iter);
552 Gtk::UIManager::remove_action_group(action_group);
555 synfig::error("Unable to find action group");
559 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
561 ui_manager->insert_action_group(group,0);
564 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
565 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
568 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
571 if(*iter && (*iter)->get_name()!="menus")
573 synfig::info("Removing action group "+(*iter)->get_name());
574 ui_manager->remove_action_group(*iter);
578 ui_manager->insert_action_group(group,0);
581 for(;!prev_groups.empty();prev_groups.pop_front())
583 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
584 ui_manager->insert_action_group(prev_groups.front(),1);
589 class Preferences : public synfigapp::Settings
592 virtual bool get_value(const synfig::String& key, synfig::String& value)const
596 value=strprintf("%f %f %f %f",
597 App::gamma.get_gamma_r(),
598 App::gamma.get_gamma_g(),
599 App::gamma.get_gamma_b(),
600 App::gamma.get_black_level()
604 if(key=="time_format")
606 value=strprintf("%i",App::get_time_format());
609 if(key=="file_history.size")
611 value=strprintf("%i",App::get_max_recent_files());
614 if(key=="use_colorspace_gamma")
616 value=strprintf("%i",(int)App::use_colorspace_gamma);
619 if(key=="distance_system")
621 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
624 if(key=="single_threaded")
626 value=strprintf("%i",(int)App::single_threaded);
629 if(key=="auto_recover_backup_interval")
631 value=strprintf("%i",App::auto_recover->get_timeout());
635 return synfigapp::Settings::get_value(key,value);
638 virtual bool set_value(const synfig::String& key,const synfig::String& value)
644 strscanf(value,"%f %f %f %f",
651 App::gamma.set_all(r,g,b,blk);
655 if(key=="time_format")
657 int i(atoi(value.c_str()));
658 App::set_time_format(static_cast<synfig::Time::Format>(i));
661 if(key=="auto_recover_backup_interval")
663 int i(atoi(value.c_str()));
664 App::auto_recover->set_timeout(i);
667 if(key=="file_history.size")
669 int i(atoi(value.c_str()));
670 App::set_max_recent_files(i);
673 if(key=="use_colorspace_gamma")
675 int i(atoi(value.c_str()));
676 App::use_colorspace_gamma=i;
679 if(key=="distance_system")
681 App::distance_system=Distance::ident_system(value);;
684 if(key=="single_threaded")
686 int i(atoi(value.c_str()));
687 App::single_threaded=i;
691 return synfigapp::Settings::set_value(key,value);
694 virtual KeyList get_key_list()const
696 KeyList ret(synfigapp::Settings::get_key_list());
697 ret.push_back("gamma");
698 ret.push_back("time_format");
699 ret.push_back("distance_system");
700 ret.push_back("file_history.size");
701 ret.push_back("use_colorspace_gamma");
702 ret.push_back("single_threaded");
703 ret.push_back("auto_recover_backup_interval");
708 static ::Preferences _preferences;
713 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
715 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
717 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
719 menus_action_group->add( Gtk::Action::create("menu-file", "_File") );
720 menus_action_group->add( Gtk::Action::create("menu-edit", "_Edit") );
721 menus_action_group->add( Gtk::Action::create("menu-view", "_View") );
722 menus_action_group->add( Gtk::Action::create("menu-canvas", "_Canvas") );
723 menus_action_group->add( Gtk::Action::create("menu-layer", "_Layer") );
724 menus_action_group->add( Gtk::Action::create("menu-duck-mask", "Show/Hide Ducks") );
725 menus_action_group->add( Gtk::Action::create("menu-preview-quality", "Preview Quality") );
726 menus_action_group->add( Gtk::Action::create("menu-layer-new", "New Layer") );
727 menus_action_group->add( Gtk::Action::create("menu-keyframe", "Keyframe") );
728 menus_action_group->add( Gtk::Action::create("menu-group", "Group") );
729 menus_action_group->add( Gtk::Action::create("menu-state", "State") );
730 menus_action_group->add( Gtk::Action::create("menu-toolbox", "Toolbox") );
732 // Add the synfigapp actions...
733 synfigapp::Action::Book::iterator iter;
734 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
736 actions_action_group->add(Gtk::Action::create(
737 "action-"+iter->second.name,
738 get_action_stock_id(iter->second),
739 iter->second.local_name,iter->second.local_name
743 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
744 #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); }
745 #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); }
747 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
748 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
749 DEFINE_ACTION("open", Gtk::Stock::OPEN);
750 DEFINE_ACTION("save", Gtk::Stock::SAVE);
751 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
752 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
753 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
754 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
755 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
756 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
757 DEFINE_ACTION("import", _("Import"));
758 DEFINE_ACTION("render", _("Render"));
759 DEFINE_ACTION("preview", _("Preview"));
760 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
761 DEFINE_ACTION("sound", _("Sound File"));
762 DEFINE_ACTION("options", _("Options"));
763 DEFINE_ACTION("close", _("Close View"));
764 DEFINE_ACTION("close-document", _("Close Document"));
767 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
768 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
769 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
770 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
771 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
772 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
773 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
774 DEFINE_ACTION("properties", _("Properties"));
776 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
777 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
778 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
779 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
780 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
781 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
782 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
783 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
784 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
785 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
786 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
787 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
788 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
789 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
790 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
791 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
792 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
793 DEFINE_ACTION("play", _("Play"));
794 // DEFINE_ACTION("pause", _("Pause"));
795 DEFINE_ACTION("stop", _("Stop"));
796 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
797 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
798 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
799 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
800 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
801 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
802 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
803 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
804 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
805 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
806 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
807 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
808 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
809 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
810 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
811 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
812 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
813 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
814 DEFINE_ACTION("seek-end", _("Seek to End"));
816 DEFINE_ACTION("action-group_add", _("Add group"));
818 DEFINE_ACTION("canvas-new", _("New Canvas"));
820 DEFINE_ACTION("amount-inc", _("Increase Amount"));
821 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
826 // Set up synfigapp actions
828 synfigapp::Action::Book::iterator iter;
830 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
832 Gtk::StockID stock_id;
834 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
836 //Gtk::Image* image(manage(new Gtk::Image()));
837 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
838 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
839 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
840 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
841 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
842 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
843 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
844 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
845 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
846 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
848 actions_action_group->add(Gtk::Action::create(
849 "action-"+iter->second.name,
851 iter->second.local_name,iter->second.local_name
859 Glib::ustring ui_info =
861 " <popup name='menu-toolbox' action='menu-toolbox'>"
862 " <menu action='menu-file'>"
865 " <popup name='menu-main' action='menu-main'>"
866 " <menu action='menu-file'>"
867 " <menuitem action='save' />"
868 " <menuitem action='save-as' />"
869 " <menuitem action='revert' />"
870 " <separator name='bleh01'/>"
871 " <menuitem action='cvs-add' />"
872 " <menuitem action='cvs-update' />"
873 " <menuitem action='cvs-commit' />"
874 " <menuitem action='cvs-revert' />"
875 " <separator name='bleh02'/>"
876 " <menuitem action='import' />"
877 " <separator name='bleh03'/>"
878 " <menuitem action='render' />"
879 " <menuitem action='preview' />"
880 " <menuitem action='sound' />"
881 " <separator name='bleh04'/>"
882 " <menuitem action='options' />"
883 " <menuitem action='close' />"
884 " <menuitem action='close-document' />"
886 " <menu action='menu-edit'>"
887 " <menuitem action='undo'/>"
888 " <menuitem action='redo'/>"
889 " <separator name='bleh05'/>"
890 " <menuitem action='cut'/>"
891 " <menuitem action='copy'/>"
892 " <menuitem action='paste'/>"
893 " <separator name='bleh06'/>"
894 " <menuitem action='select-all-ducks'/>"
895 " <menuitem action='unselect-all-layers'/>"
896 " <separator name='bleh07'/>"
897 " <menuitem action='properties'/>"
899 " <menu action='menu-view'>"
900 " <menu action='menu-duck-mask'>"
901 " <menuitem action='mask-position-ducks' />"
902 " <menuitem action='mask-vertex-ducks' />"
903 " <menuitem action='mask-tangent-ducks' />"
904 " <menuitem action='mask-radius-ducks' />"
905 " <menuitem action='mask-width-ducks' />"
906 " <menuitem action='mask-angle-ducks' />"
908 " <menu action='menu-preview-quality'>"
909 " <menuitem action='quality-00' />"
910 " <menuitem action='quality-01' />"
911 " <menuitem action='quality-02' />"
912 " <menuitem action='quality-03' />"
913 " <menuitem action='quality-04' />"
914 " <menuitem action='quality-05' />"
915 " <menuitem action='quality-06' />"
916 " <menuitem action='quality-07' />"
917 " <menuitem action='quality-08' />"
918 " <menuitem action='quality-09' />"
919 " <menuitem action='quality-10' />"
921 " <separator name='bleh08'/>"
922 " <menuitem action='play'/>"
923 //" <menuitem action='pause'/>"
924 " <menuitem action='stop'/>"
925 " <menuitem action='dialog-flipbook'/>"
926 " <separator name='bleh09'/>"
927 " <menuitem action='toggle-grid-show'/>"
928 " <menuitem action='toggle-grid-snap'/>"
929 " <menuitem action='toggle-guide-show'/>"
930 " <menuitem action='toggle-low-res'/>"
931 " <menuitem action='toggle-onion-skin'/>"
932 " <separator name='bleh10'/>"
933 " <menuitem action='canvas-zoom-in'/>"
934 " <menuitem action='canvas-zoom-out'/>"
935 " <menuitem action='canvas-zoom-fit'/>"
936 " <menuitem action='canvas-zoom-100'/>"
937 " <separator name='bleh11'/>"
938 " <menuitem action='time-zoom-in'/>"
939 " <menuitem action='time-zoom-out'/>"
940 " <separator name='bleh12'/>"
941 " <menuitem action='jump-next-keyframe'/>"
942 " <menuitem action='jump-prev-keyframe'/>"
943 " <menuitem action='seek-next-frame'/>"
944 " <menuitem action='seek-prev-frame'/>"
945 " <menuitem action='seek-next-second'/>"
946 " <menuitem action='seek-prev-second'/>"
947 " <menuitem action='seek-begin'/>"
948 " <menuitem action='seek-end'/>"
950 " <menu action='menu-canvas'>"
951 " <menuitem action='canvas-new'/>"
953 " <menu name='menu-state' action='menu-state'>"
955 " <menu action='menu-group'>"
956 " <menuitem action='action-group_add'/>"
958 " <menu action='menu-layer'>"
959 //" <menuitem action='cut'/>"
960 //" <menuitem action='copy'/>"
961 //" <menuitem action='paste'/>"
962 //" <separator name='bleh06'/>"
963 " <menu action='menu-layer-new'></menu>"
964 " <menuitem action='amount-inc'/>"
965 " <menuitem action='amount-dec'/>"
967 " <menu action='menu-keyframe'>"
968 " <menuitem action='keyframe-properties'/>"
975 " <menubar name='MenuBar'>"
976 " <menu action='MenuFile'>"
977 " <menuitem action='New'/>"
978 " <menuitem action='Open'/>"
980 " <menuitem action='Quit'/>"
982 " <menu action='MenuEdit'>"
983 " <menuitem action='Cut'/>"
984 " <menuitem action='Copy'/>"
985 " <menuitem action='Paste'/>"
988 " <toolbar name='ToolBar'>"
989 " <toolitem action='Open'/>"
990 " <toolitem action='Quit'/>"
996 actions_action_group->set_sensitive(false);
997 App::ui_manager()->set_add_tearoffs(true);
998 App::ui_manager()->insert_action_group(menus_action_group,1);
999 App::ui_manager()->insert_action_group(actions_action_group,1);
1000 App::ui_manager()->add_ui_from_string(ui_info);
1002 //App::ui_manager()->get_accel_group()->unlock();
1004 catch(const Glib::Error& ex)
1006 synfig::error("building menus and toolbars failed: " + ex.what());
1009 // Add default keyboard accelerators
1010 #define ACCEL(path,accel) \
1012 Gtk::AccelKey accel_key(accel,path); \
1013 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1016 #define ACCEL2(accel) \
1018 Gtk::AccelKey accel_key(accel); \
1019 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1022 ACCEL("<Actions>//select-all-ducks","<Control>a");
1023 ACCEL("<Actions>//unselect-all-layers","<Control>d");
1024 ACCEL("<Actions>//render","F9");
1025 ACCEL("<Actions>//preview","F11");
1026 ACCEL("<Actions>//properties","F8");
1027 ACCEL("<Actions>//options","F12");
1028 ACCEL("<Actions>//import","<control>i");
1029 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
1030 ACCEL("<Actions>//toggle-grid-show","<Control>g");
1031 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
1032 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
1033 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
1034 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1035 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1036 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1037 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1038 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1040 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1041 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1043 ACCEL("<Actions>//quality-01","<Control>1");
1044 ACCEL("<Actions>//quality-02","<Control>2");
1045 ACCEL("<Actions>//quality-03","<Control>3");
1046 ACCEL("<Actions>//quality-04","<Control>4");
1047 ACCEL("<Actions>//quality-05","<Control>5");
1048 ACCEL("<Actions>//quality-06","<Control>6");
1049 ACCEL("<Actions>//quality-07","<Control>7");
1050 ACCEL("<Actions>//quality-08","<Control>8");
1051 ACCEL("<Actions>//quality-09","<Control>9");
1052 ACCEL("<Actions>//quality-10","<Control>0");
1053 ACCEL("<Actions>//undo","<Control>z");
1054 ACCEL("<Actions>//redo","<Control>r");
1055 ACCEL("<Actions>//action-layer_remove","Delete");
1057 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1058 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1059 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1060 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1061 ACCEL("<Actions>//time-zoom-in","+");
1062 ACCEL("<Actions>//time-zoom-out","_");
1064 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1065 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1067 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1068 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1069 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1070 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1071 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1072 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1073 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1074 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1075 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1076 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1077 ACCEL2(Gtk::AccelKey('o',Gdk::CONTROL_MASK,"<Actions>//toggle-onion-skin"));
1078 ACCEL("<Actions>//play", "<Control>p");
1079 ACCEL("<Actions>//seek-begin","Home");
1080 ACCEL("<Actions>//seek-end","End");
1082 ACCEL("<Actions>//state-normal", "<Mod1>a");
1083 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1084 ACCEL("<Actions>//state-scale", "<Mod1>d");
1085 ACCEL("<Actions>//state-rotate", "<Mod1>s");
1087 ACCEL("<Actions>//state-bline", "<Mod1>b");
1088 ACCEL("<Actions>//state-circle", "<Mod1>c");
1089 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1090 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1092 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1093 ACCEL("<Actions>//state-fill", "<Mod1>f");
1094 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1095 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1097 ACCEL("<Actions>//state-draw", "<Mod1>w");
1098 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1099 ACCEL("<Actions>//state-width", "<Mod1>t");
1100 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1102 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1108 #define mkdir(x,y) mkdir(x)
1111 /* === M E T H O D S ======================================================= */
1113 App::App(int *argc, char ***argv):
1114 Gtk::Main(argc,argv),
1115 IconController(etl::dirname((*argv)[0]))
1117 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1120 serial_=check_license(app_base_path_);
1123 ui_interface_=new GlobalUIInterface();
1127 // don't call thread_init() if threads are already initialized
1128 // on some machines bonobo_init() initialized threads before we get here
1129 if (!g_thread_supported())
1130 Glib::thread_init();
1132 distance_system=Distance::SYSTEM_UNITS;
1134 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1137 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1141 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1149 if(!SYNFIG_CHECK_VERSION())
1151 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1152 dialog_error_blocking("Synfig Studio",
1153 "This copy of Synfig Studio was compiled against a\n"
1154 "different version of libsynfig than what is currently\n"
1155 "installed. Synfig Studio will now abort. Try downloading\n"
1156 "the latest version from the Synfig website at\n"
1157 "http://www.synfig.com/ "
1162 catch(synfig::SoftwareExpired)
1164 cerr<<"FATAL: Software Expired"<<endl;
1165 dialog_error_blocking("Synfig Studio",
1166 "This copy of Synfig Studio has expired.\n"
1167 "Please erase this copy, or download and\n"
1168 "install the latest copy from the Synfig\n"
1169 "website at http://www.synfig.com/ ."
1173 Glib::set_application_name(_("Synfig Studio"));
1176 about_window.set_can_self_destruct(false);
1177 about_window.show();
1179 shutdown_in_progress=false;
1180 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1181 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1183 // Initialize the Synfig library
1184 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1187 get_ui_interface()->error("Failed to initialize synfig!");
1191 // add the preferences to the settings
1192 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1196 studio_init_cb.task("Init UI Manager...");
1197 App::ui_manager_=studio::UIManager::create();
1200 studio_init_cb.task("Init Dock Manager...");
1201 dock_manager=new studio::DockManager();
1203 studio_init_cb.task("Init State Manager...");
1204 state_manager=new StateManager();
1206 studio_init_cb.task("Init Toolbox...");
1207 toolbox=new studio::Toolbox();
1209 studio_init_cb.task("Init Tool Options...");
1210 dialog_tool_options=new studio::Dialog_ToolOptions();
1211 dock_manager->register_dockable(*dialog_tool_options);
1213 studio_init_cb.task("Init History...");
1214 dock_history=new studio::Dock_History();
1215 dock_manager->register_dockable(*dock_history);
1217 studio_init_cb.task("Init Canvases...");
1218 dock_canvases=new studio::Dock_Canvases();
1219 dock_manager->register_dockable(*dock_canvases);
1221 studio_init_cb.task("Init Keyframes...");
1222 dock_keyframes=new studio::Dock_Keyframes();
1223 dock_manager->register_dockable(*dock_keyframes);
1225 studio_init_cb.task("Init Layers...");
1226 dock_layers=new studio::Dock_Layers();
1227 dock_manager->register_dockable(*dock_layers);
1229 studio_init_cb.task("Init Params...");
1230 dock_params=new studio::Dock_Params();
1231 dock_manager->register_dockable(*dock_params);
1233 studio_init_cb.task("Init MetaData...");
1234 dock_meta_data=new studio::Dock_MetaData();
1235 dock_manager->register_dockable(*dock_meta_data);
1237 studio_init_cb.task("Init Children...");
1238 dock_children=new studio::Dock_Children();
1239 dock_manager->register_dockable(*dock_children);
1241 studio_init_cb.task("Init Info...");
1242 dock_info = new studio::Dock_Info();
1243 dock_manager->register_dockable(*dock_info);
1245 studio_init_cb.task("Init Navigator...");
1246 dock_navigator = new studio::Dock_Navigator();
1247 dock_manager->register_dockable(*dock_navigator);
1249 studio_init_cb.task("Init Timetrack...");
1250 dock_timetrack = new studio::Dock_Timetrack();
1251 dock_manager->register_dockable(*dock_timetrack);
1253 studio_init_cb.task("Init Curve Editor...");
1254 dock_curves = new studio::Dock_Curves();
1255 dock_manager->register_dockable(*dock_curves);
1257 studio_init_cb.task("Init Layer Groups...");
1258 dock_layer_groups = new studio::Dock_LayerGroups();
1259 dock_manager->register_dockable(*dock_layer_groups);
1262 studio_init_cb.task("Init Color Dialog...");
1263 dialog_color=new studio::Dialog_Color();
1265 studio_init_cb.task("Init Gradient Dialog...");
1266 dialog_gradient=new studio::Dialog_Gradient();
1268 studio_init_cb.task("Init DeviceTracker...");
1269 device_tracker=new studio::DeviceTracker();
1271 studio_init_cb.task("Init Tools...");
1272 state_manager->add_state(&state_normal);
1273 state_manager->add_state(&state_smooth_move);
1274 state_manager->add_state(&state_scale);
1275 state_manager->add_state(&state_rotate);
1277 state_manager->add_state(&state_bline);
1280 state_manager->add_state(&state_circle);
1281 state_manager->add_state(&state_rectangle);
1283 state_manager->add_state(&state_gradient);
1284 state_manager->add_state(&state_eyedrop);
1285 state_manager->add_state(&state_fill);
1287 state_manager->add_state(&state_zoom);
1289 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1290 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1291 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1293 // Enabled for now. Let's see whether they're good enough yet.
1294 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1295 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1297 // Disabled by default - it doesn't work properly?
1298 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1300 studio_init_cb.task("Init ModPalette...");
1301 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1303 studio_init_cb.task("Init ModMirror...");
1304 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1307 studio_init_cb.task("Init Setup Dialog...");
1308 dialog_setup=new studio::Dialog_Setup();
1310 studio_init_cb.task("Init Input Dialog...");
1311 dialog_input=new Gtk::InputDialog();
1312 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1313 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1315 studio_init_cb.task("Init auto recovery...");
1316 auto_recover=new AutoRecover();
1318 studio_init_cb.amount_complete(9250,10000);
1319 studio_init_cb.task("Loading Settings...");
1321 studio_init_cb.task("Checking auto-recover...");
1323 studio_init_cb.amount_complete(9900,10000);
1325 if(auto_recover->recovery_needed())
1327 about_window.hide();
1329 get_ui_interface()->yes_no(
1331 "Synfig Studio seems to have crashed\n"
1332 "before you could save all your files.\n"
1333 "Would you like to re-open those files\n"
1334 "and recover your unsaved changes?"
1335 )==synfigapp::UIInterface::RESPONSE_YES
1338 if(!auto_recover->recover())
1340 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1343 get_ui_interface()->error(
1344 _("Synfig Studio has attempted to recover\n"
1345 "from a previous crash. The files that it has\n"
1346 "recovered are NOT YET SAVED. It would be a good\n"
1347 "idea to review them and save them now.")
1350 about_window.show();
1353 // Look for any files given on the command line,
1354 // and load them if found.
1355 for(;*argc>=1;(*argc)--)
1356 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1358 studio_init_cb.task("Loading files...");
1359 about_window.hide();
1360 open((*argv)[*argc]);
1361 about_window.show();
1364 studio_init_cb.task("Done.");
1365 studio_init_cb.amount_complete(10000,10000);
1371 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1375 StateManager* App::get_state_manager() { return state_manager; }
1379 shutdown_in_progress=true;
1383 synfigapp::Main::settings().remove_domain("pref");
1385 selected_instance=0;
1387 // Unload all of the modules
1388 for(;!module_list_.empty();module_list_.pop_back());
1390 delete state_manager;
1394 delete auto_recover;
1398 // studio::App::iteration(false);
1402 // studio::App::iteration(false);
1404 // studio::App::iteration(false);
1406 delete dialog_setup;
1408 delete dialog_gradient;
1410 delete dialog_color;
1412 delete dialog_input;
1414 delete dock_manager;
1416 instance_list.clear();
1418 // studio::App::iteration(false);
1422 App::get_user_app_directory()
1424 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1428 App::get_config_file(const synfig::String& file)
1430 return Glib::build_filename(get_user_app_directory(),file);
1434 App::add_recent_file(const std::string &file_name)
1436 std::string filename(file_name);
1438 assert(!filename.empty());
1440 if(filename.empty())
1443 // Toss out any "hidden" files
1444 if(basename(filename)[0]=='.')
1447 // If we aren't an absolute path, turn ourselves into one
1448 if(!is_absolute_path(filename))
1449 filename=absolute_path(filename);
1451 list<string>::iterator iter;
1452 // Check to see if the file is already on the list.
1453 // If it is, then remove it from the list
1454 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1457 recent_files.erase(iter);
1462 // Push the filename to the front of the list
1463 recent_files.push_front(filename);
1465 // Clean out the files at the end of the list.
1466 while(recent_files.size()>(unsigned)get_max_recent_files())
1467 recent_files.pop_back();
1469 signal_recent_files_changed_();
1474 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1477 App::get_time_format()
1479 return _App_time_format;
1483 App::set_time_format(synfig::Time::Format x)
1490 App::save_settings()
1495 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1496 setlocale(LC_NUMERIC, "C");
1498 std::string filename=get_config_file("accelrc");
1499 Gtk::AccelMap::save(filename);
1502 std::string filename=get_config_file("recentfiles");
1504 std::ofstream file(filename.c_str());
1508 synfig::warning("Unable to save %s",filename.c_str());
1512 list<string>::reverse_iterator iter;
1514 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1518 std::string filename=get_config_file("settings");
1519 synfigapp::Main::settings().save_to_file(filename);
1520 setlocale(LC_NUMERIC,old_locale);
1524 synfig::warning("Caught exception when attempting to save settings.");
1529 App::load_settings()
1534 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1535 setlocale(LC_NUMERIC, "C");
1537 std::string filename=get_config_file("accelrc");
1538 Gtk::AccelMap::load(filename);
1541 std::string filename=get_config_file("recentfiles");
1543 std::ifstream file(filename.c_str());
1547 std::string recent_file;
1548 getline(file,recent_file);
1549 if(!recent_file.empty())
1550 add_recent_file(recent_file);
1553 std::string filename=get_config_file("settings");
1554 if(!synfigapp::Main::settings().load_from_file(filename))
1556 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1557 //if(!synfigapp::Main::settings().load_from_file(filename))
1559 gamma.set_gamma(1.0/2.2);
1560 reset_initial_window_configuration();
1563 setlocale(LC_NUMERIC,old_locale);
1567 synfig::warning("Caught exception when attempting to load settings.");
1572 App::reset_initial_window_configuration()
1574 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1575 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1576 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1577 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1578 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1579 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1580 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1581 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1582 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1583 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1584 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1585 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1586 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1587 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1591 App::shutdown_request(GdkEventAny*)
1595 //return !shutdown_in_progress;
1601 if(shutdown_in_progress)return;
1604 get_ui_interface()->task("Quit Request");
1607 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1611 std::list<etl::handle<Instance> >::iterator iter;
1612 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1614 if(!(*iter)->safe_close())
1618 if((*iter)->synfigapp::Instance::get_action_count())
1620 handle<synfigapp::UIInterface> uim;
1621 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1623 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1624 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1626 case synfigapp::UIInterface::RESPONSE_NO:
1628 case synfigapp::UIInterface::RESPONSE_YES:
1631 case synfigapp::UIInterface::RESPONSE_CANCEL:
1640 if((*iter)->synfigapp::Instance::is_modified())
1642 handle<synfigapp::UIInterface> uim;
1643 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1645 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() );
1646 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1648 case synfigapp::UIInterface::RESPONSE_NO:
1650 case synfigapp::UIInterface::RESPONSE_YES:
1651 (*iter)->dialog_cvs_commit();
1653 case synfigapp::UIInterface::RESPONSE_CANCEL:
1662 // This next line causes things to crash for some reason
1666 shutdown_in_progress=true;
1668 instance_list.clear();
1670 while(studio::App::events_pending())studio::App::iteration(false);
1673 auto_recover->normal_shutdown();
1675 get_ui_interface()->task("Quit Request sent");
1681 dialog_setup->refresh();
1682 dialog_setup->show();
1685 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1686 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1689 //#define USE_WIN32_FILE_DIALOGS 1
1692 #ifdef USE_WIN32_FILE_DIALOGS
1693 static OPENFILENAME ofn={};
1697 #include <gdk/gdkwin32.h>
1701 App::dialog_open_file(const std::string &title, std::string &filename)
1703 #ifdef USE_WIN32_FILE_DIALOGS
1704 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1706 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1707 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1708 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1710 ofn.lStructSize=sizeof(OPENFILENAME);
1711 ofn.hwndOwner = hWnd;
1712 ofn.hInstance = hInstance;
1713 ofn.lpstrFilter = szFilter;
1714 // ofn.lpstrCustomFilter=NULL;
1715 // ofn.nMaxCustFilter=0;
1716 // ofn.nFilterIndex=0;
1717 // ofn.lpstrFile=NULL;
1718 ofn.nMaxFile=MAX_PATH;
1719 // ofn.lpstrFileTitle=NULL;
1720 // ofn.lpstrInitialDir=NULL;
1721 // ofn.lpstrTitle=NULL;
1722 ofn.Flags=OFN_HIDEREADONLY;
1723 // ofn.nFileOffset=0;
1724 // ofn.nFileExtension=0;
1725 ofn.lpstrDefExt=TEXT("sif");
1726 // ofn.lCustData = 0l;
1728 // ofn.lpTemplateName=NULL;
1730 CHAR szFilename[MAX_PATH];
1732 strcpy(szFilename,filename.c_str());
1733 strcpy(szTitle,title.c_str());
1735 ofn.lpstrFile=szFilename;
1736 ofn.lpstrFileTitle=szTitle;
1738 if(GetOpenFileName(&ofn))
1740 filename=szFilename;
1746 synfig::String prev_path;
1747 if(!_preferences.get_value("curr_path",prev_path))
1749 prev_path = absolute_path(prev_path);
1751 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1752 dialog->set_current_folder(prev_path);
1753 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1754 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1755 if(!filename.empty())
1756 if (is_absolute_path(filename))
1757 dialog->set_filename(filename);
1759 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1760 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1761 filename=dialog->get_filename();
1773 GtkWidget *fileselection;
1774 fileselection = gtk_file_selection_new(title.c_str());
1777 if(basename(filename)==filename)
1779 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1782 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1784 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1786 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1787 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1789 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1790 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1792 gtk_widget_show(fileselection);
1800 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1801 _preferences.set_value("curr_path",dirname(filename));
1805 gtk_widget_destroy(fileselection);
1808 gtk_widget_destroy(fileselection);
1815 App::dialog_save_file(const std::string &title, std::string &filename)
1817 #if USE_WIN32_FILE_DIALOGS
1818 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1820 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1821 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1822 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1824 ofn.lStructSize=sizeof(OPENFILENAME);
1825 ofn.hwndOwner = hWnd;
1826 ofn.hInstance = hInstance;
1827 ofn.lpstrFilter = szFilter;
1828 // ofn.lpstrCustomFilter=NULL;
1829 // ofn.nMaxCustFilter=0;
1830 // ofn.nFilterIndex=0;
1831 // ofn.lpstrFile=NULL;
1832 ofn.nMaxFile=MAX_PATH;
1833 // ofn.lpstrFileTitle=NULL;
1834 // ofn.lpstrInitialDir=NULL;
1835 // ofn.lpstrTitle=NULL;
1836 ofn.Flags=OFN_OVERWRITEPROMPT;
1837 // ofn.nFileOffset=0;
1838 // ofn.nFileExtension=0;
1839 ofn.lpstrDefExt=TEXT("sif");
1840 // ofn.lCustData = 0l;
1842 // ofn.lpTemplateName=NULL;
1844 CHAR szFilename[MAX_PATH];
1846 strcpy(szFilename,filename.c_str());
1847 strcpy(szTitle,title.c_str());
1849 ofn.lpstrFile=szFilename;
1850 ofn.lpstrFileTitle=szTitle;
1852 if(GetSaveFileName(&ofn))
1854 filename=szFilename;
1855 _preferences.set_value("curr_path",dirname(filename));
1860 synfig::String prev_path;
1861 if(!_preferences.get_value("curr_path",prev_path))
1863 prev_path = absolute_path(prev_path);
1865 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1866 dialog->set_current_folder(prev_path);
1867 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1868 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1869 if(!filename.empty())
1871 std::string full_path;
1872 if (is_absolute_path(filename))
1873 full_path = filename;
1875 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1876 // select the file if it exists
1877 dialog->set_filename(full_path);
1879 // if the file doesn't exist, put its name into the filename box
1881 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1882 dialog->set_current_name(basename(filename));
1884 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1885 filename=dialog->get_filename();
1887 _preferences.set_value("curr_path",dirname(filename));
1892 // return dialog_open_file(title, filename);
1897 App::dialog_error_blocking(const std::string &title, const std::string &message)
1899 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1900 dialog.set_title(title);
1906 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1908 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1909 dialog.set_title(title);
1915 App::dialog_yes_no(const std::string &title, const std::string &message)
1920 true // use_separator
1922 Gtk::Label label(message);
1925 dialog.get_vbox()->pack_start(label);
1926 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1927 dialog.add_button(Gtk::StockID("gtk-no"),0);
1929 return dialog.run();
1933 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1938 true // use_separator
1940 Gtk::Label label(message);
1943 dialog.get_vbox()->pack_start(label);
1944 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1945 dialog.add_button(Gtk::StockID("gtk-no"),0);
1946 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1948 return dialog.run();
1952 App::dialog_not_implemented()
1954 Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1955 dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
1960 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1965 true // use_separator
1967 Gtk::Label label(message);
1969 dialog.get_vbox()->pack_start(label);
1972 entry.set_text(text);
1974 entry.set_activates_default(true);
1975 dialog.get_vbox()->pack_start(entry);
1977 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1978 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1979 dialog.set_default_response(Gtk::RESPONSE_OK);
1980 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1983 if(dialog.run()!=Gtk::RESPONSE_OK)
1986 text=entry.get_text();
1995 App::open(std::string filename)
1997 return open_as(filename,filename);
2000 // this is called from autorecover.cpp:
2001 // App::open_as(get_shadow_file_name(filename),filename)
2002 // other than that, 'filename' and 'as' are the same
2004 App::open_as(std::string filename,std::string as)
2007 char long_name[1024];
2008 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2014 OneMoment one_moment;
2016 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2017 if(canvas && get_instance(canvas))
2019 get_instance(canvas)->find_canvas_view(canvas)->present();
2020 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2023 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2025 add_recent_file(as);
2027 handle<Instance> instance(Instance::create(canvas));
2030 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2034 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)")))
2035 instance->dialog_cvs_update();
2039 dialog_error_blocking(_("Error"), x);
2044 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2048 _preferences.set_value("curr_path",dirname(as));
2057 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2058 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2060 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2062 canvas->rend_desc().set_frame_rate(24.0);
2063 canvas->rend_desc().set_time_start(0.0);
2064 canvas->rend_desc().set_time_end(00.0);
2065 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2066 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2067 canvas->rend_desc().set_tl(Vector(-4,2.25));
2068 canvas->rend_desc().set_br(Vector(4,-2.25));
2069 canvas->rend_desc().set_w(480);
2070 canvas->rend_desc().set_h(270);
2071 canvas->rend_desc().set_antialias(1);
2072 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2073 canvas->set_file_name(file_name);
2075 Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2081 string filename="*.sif";
2083 while(dialog_open_file("Open", filename))
2085 // If the filename still has wildcards, then we should
2086 // continue looking for the file we want
2087 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2093 get_ui_interface()->error(_("Unable to open file"));
2098 App::set_selected_instance(etl::loose_handle<Instance> instance)
2100 /* if(get_selected_instance()==instance)
2102 selected_instance=instance;
2103 signal_instance_selected()(instance);
2109 selected_instance=instance;
2110 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2114 instance->focus(instance->get_canvas());
2117 set_selected_canvas_view(0);
2119 signal_instance_selected()(instance);
2123 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2125 selected_canvas_view=canvas_view;
2126 signal_canvas_view_focus()(selected_canvas_view);
2129 selected_instance=canvas_view->get_instance();
2130 signal_instance_selected()(canvas_view->get_instance());
2133 if(get_selected_canvas_view()==canvas_view)
2135 signal_canvas_view_focus()(selected_canvas_view);
2136 signal_instance_selected()(canvas_view->get_instance());
2139 selected_canvas_view=canvas_view;
2140 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2141 set_selected_instance(canvas_view->get_instance());
2142 signal_canvas_view_focus()(selected_canvas_view);
2146 etl::loose_handle<Instance>
2147 App::get_instance(Canvas::Handle canvas)
2149 if(!canvas) return 0;
2150 canvas=canvas->get_root();
2152 std::list<etl::handle<Instance> >::iterator iter;
2153 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2155 if((*iter)->get_canvas()==canvas)
2164 (new class About())->show();
2170 if(selected_instance)
2171 selected_instance->undo();
2177 if(selected_instance)
2178 selected_instance->redo();
2182 studio::App::get_base_path()
2184 return app_base_path_;