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=true;
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 Glib::thread_init();
1108 distance_system=Distance::SYSTEM_UNITS;
1110 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1113 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1117 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1125 if(!SYNFIG_CHECK_VERSION())
1127 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1128 dialog_error_blocking("Synfig Studio",
1129 "This copy of Synfig Studio was compiled against a\n"
1130 "different version of libsynfig than what is currently\n"
1131 "installed. Synfig Studio will now abort. Try downloading\n"
1132 "the latest version from the Synfig website at\n"
1133 "http://www.synfig.com/ "
1138 catch(synfig::SoftwareExpired)
1140 cerr<<"FATAL: Software Expired"<<endl;
1141 dialog_error_blocking("Synfig Studio",
1142 "This copy of Synfig Studio has expired.\n"
1143 "Please erase this copy, or download and\n"
1144 "install the latest copy from the Synfig\n"
1145 "website at http://www.synfig.com/ ."
1149 Glib::set_application_name(_("Synfig Studio"));
1152 about_window.set_can_self_destruct(false);
1153 about_window.show();
1155 shutdown_in_progress=false;
1156 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1157 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1159 // Initialize the Synfig library
1160 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1163 get_ui_interface()->error("Failed to initialize synfig!");
1167 // add the preferences to the settings
1168 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1172 studio_init_cb.task("Init UI Manager...");
1173 App::ui_manager_=studio::UIManager::create();
1176 studio_init_cb.task("Init Dock Manager...");
1177 dock_manager=new studio::DockManager();
1179 studio_init_cb.task("Init State Manager...");
1180 state_manager=new StateManager();
1182 studio_init_cb.task("Init Toolbox...");
1183 toolbox=new studio::Toolbox();
1185 studio_init_cb.task("Init Tool Options...");
1186 dialog_tool_options=new studio::Dialog_ToolOptions();
1187 dock_manager->register_dockable(*dialog_tool_options);
1189 studio_init_cb.task("Init History...");
1190 dock_history=new studio::Dock_History();
1191 dock_manager->register_dockable(*dock_history);
1193 studio_init_cb.task("Init Canvases...");
1194 dock_canvases=new studio::Dock_Canvases();
1195 dock_manager->register_dockable(*dock_canvases);
1197 studio_init_cb.task("Init Keyframes...");
1198 dock_keyframes=new studio::Dock_Keyframes();
1199 dock_manager->register_dockable(*dock_keyframes);
1201 studio_init_cb.task("Init Layers...");
1202 dock_layers=new studio::Dock_Layers();
1203 dock_manager->register_dockable(*dock_layers);
1205 studio_init_cb.task("Init Params...");
1206 dock_params=new studio::Dock_Params();
1207 dock_manager->register_dockable(*dock_params);
1209 studio_init_cb.task("Init MetaData...");
1210 dock_meta_data=new studio::Dock_MetaData();
1211 dock_manager->register_dockable(*dock_meta_data);
1213 studio_init_cb.task("Init Children...");
1214 dock_children=new studio::Dock_Children();
1215 dock_manager->register_dockable(*dock_children);
1217 studio_init_cb.task("Init Info...");
1218 dock_info = new studio::Dock_Info();
1219 dock_manager->register_dockable(*dock_info);
1221 studio_init_cb.task("Init Navigator...");
1222 dock_navigator = new studio::Dock_Navigator();
1223 dock_manager->register_dockable(*dock_navigator);
1225 studio_init_cb.task("Init Timetrack...");
1226 dock_timetrack = new studio::Dock_Timetrack();
1227 dock_manager->register_dockable(*dock_timetrack);
1229 studio_init_cb.task("Init Curve Editor...");
1230 dock_curves = new studio::Dock_Curves();
1231 dock_manager->register_dockable(*dock_curves);
1233 studio_init_cb.task("Init Layer Groups...");
1234 dock_layer_groups = new studio::Dock_LayerGroups();
1235 dock_manager->register_dockable(*dock_layer_groups);
1238 studio_init_cb.task("Init Color Dialog...");
1239 dialog_color=new studio::Dialog_Color();
1241 studio_init_cb.task("Init Gradient Dialog...");
1242 dialog_gradient=new studio::Dialog_Gradient();
1244 studio_init_cb.task("Init DeviceTracker...");
1245 device_tracker=new studio::DeviceTracker();
1247 studio_init_cb.task("Init Tools...");
1248 state_manager->add_state(&state_normal);
1249 state_manager->add_state(&state_smooth_move);
1250 state_manager->add_state(&state_scale);
1251 state_manager->add_state(&state_rotate);
1253 state_manager->add_state(&state_bline);
1256 state_manager->add_state(&state_circle);
1257 state_manager->add_state(&state_rectangle);
1259 state_manager->add_state(&state_gradient);
1260 state_manager->add_state(&state_eyedrop);
1261 state_manager->add_state(&state_fill);
1263 state_manager->add_state(&state_zoom);
1265 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1266 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1267 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1269 // Enabled for now. Let's see whether they're good enough yet.
1270 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1271 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1273 // Disabled by default - it doesn't work properly?
1274 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1276 studio_init_cb.task("Init ModPalette...");
1277 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1279 studio_init_cb.task("Init ModMirror...");
1280 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1283 studio_init_cb.task("Init Setup Dialog...");
1284 dialog_setup=new studio::Dialog_Setup();
1286 studio_init_cb.task("Init Input Dialog...");
1287 dialog_input=new Gtk::InputDialog();
1288 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1289 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1291 studio_init_cb.task("Init auto recovery...");
1292 auto_recover=new AutoRecover();
1294 studio_init_cb.amount_complete(9250,10000);
1295 studio_init_cb.task("Loading Settings...");
1297 studio_init_cb.task("Checking auto-recover...");
1299 studio_init_cb.amount_complete(9900,10000);
1301 if(auto_recover->recovery_needed())
1303 about_window.hide();
1305 get_ui_interface()->yes_no(
1307 "Synfig Studio seems to have crashed\n"
1308 "before you could save all your files.\n"
1309 "Would you like to re-open those files\n"
1310 "and recover your unsaved changes?"
1311 )==synfigapp::UIInterface::RESPONSE_YES
1314 if(!auto_recover->recover())
1316 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1319 get_ui_interface()->error(
1320 _("Synfig Studio has attempted to recover\n"
1321 "from a previous crash. The files that it has\n"
1322 "recovered are NOT YET SAVED. It would be a good\n"
1323 "idea to review them and save them now.")
1326 about_window.show();
1329 // Look for any files given on the command line,
1330 // and load them if found.
1331 for(;*argc>=1;(*argc)--)
1332 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1334 studio_init_cb.task("Loading files...");
1335 about_window.hide();
1336 open((*argv)[*argc]);
1337 about_window.show();
1340 studio_init_cb.task("Done.");
1341 studio_init_cb.amount_complete(10000,10000);
1347 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1351 StateManager* App::get_state_manager() { return state_manager; }
1355 shutdown_in_progress=true;
1359 synfigapp::Main::settings().remove_domain("pref");
1361 selected_instance=0;
1363 // Unload all of the modules
1364 for(;!module_list_.empty();module_list_.pop_back());
1366 delete state_manager;
1370 delete auto_recover;
1374 // studio::App::iteration(false);
1378 // studio::App::iteration(false);
1380 // studio::App::iteration(false);
1382 delete dialog_setup;
1384 delete dialog_gradient;
1386 delete dialog_color;
1388 delete dialog_input;
1390 delete dock_manager;
1392 instance_list.clear();
1394 // studio::App::iteration(false);
1398 App::get_user_app_directory()
1400 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1404 App::get_config_file(const synfig::String& file)
1406 return Glib::build_filename(get_user_app_directory(),file);
1410 App::add_recent_file(const std::string &file_name)
1412 std::string filename(file_name);
1414 assert(!filename.empty());
1416 if(filename.empty())
1419 // Toss out any "hidden" files
1420 if(basename(filename)[0]=='.')
1423 // If we aren't an absolute path, turn outselves into one
1424 if(!is_absolute_path(filename))
1425 filename=absolute_path(filename);
1427 list<string>::iterator iter;
1428 // Check to see if the file is already on the list.
1429 // If it is, then remove it from the list
1430 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1433 recent_files.erase(iter);
1438 // Push the filename to the front of the list
1439 recent_files.push_front(filename);
1441 // Clean out the files at the end of the list.
1442 while(recent_files.size()>(unsigned)get_max_recent_files())
1443 recent_files.pop_back();
1445 signal_recent_files_changed_();
1450 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1453 App::get_time_format()
1455 return _App_time_format;
1459 App::set_time_format(synfig::Time::Format x)
1466 App::save_settings()
1471 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1472 setlocale(LC_NUMERIC, "C");
1474 std::string filename=get_config_file("accelrc");
1475 Gtk::AccelMap::save(filename);
1478 std::string filename=get_config_file("recentfiles");
1480 std::ofstream file(filename.c_str());
1484 synfig::warning("Unable to save %s",filename.c_str());
1488 list<string>::reverse_iterator iter;
1490 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1494 std::string filename=get_config_file("settings");
1495 synfigapp::Main::settings().save_to_file(filename);
1496 setlocale(LC_NUMERIC,old_locale);
1500 synfig::warning("Caught exception when attempting to save settings.");
1505 App::load_settings()
1510 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1511 setlocale(LC_NUMERIC, "C");
1513 std::string filename=get_config_file("accelrc");
1514 Gtk::AccelMap::load(filename);
1517 std::string filename=get_config_file("recentfiles");
1519 std::ifstream file(filename.c_str());
1523 std::string recent_file;
1524 getline(file,recent_file);
1525 if(!recent_file.empty())
1526 add_recent_file(recent_file);
1529 std::string filename=get_config_file("settings");
1530 if(!synfigapp::Main::settings().load_from_file(filename))
1532 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1533 //if(!synfigapp::Main::settings().load_from_file(filename))
1535 gamma.set_gamma(1.0/2.2);
1536 reset_initial_window_configuration();
1539 setlocale(LC_NUMERIC,old_locale);
1543 synfig::warning("Caught exception when attempting to load settings.");
1548 App::reset_initial_window_configuration()
1550 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1551 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1552 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1553 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1554 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1555 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1556 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1557 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1558 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1559 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1560 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1561 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1562 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1563 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1567 App::shutdown_request(GdkEventAny*)
1571 //return !shutdown_in_progress;
1577 if(shutdown_in_progress)return;
1580 get_ui_interface()->task("Quit Request");
1583 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1587 std::list<etl::handle<Instance> >::iterator iter;
1588 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1590 if(!(*iter)->safe_close())
1594 if((*iter)->synfigapp::Instance::get_action_count())
1596 handle<synfigapp::UIInterface> uim;
1597 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1599 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1600 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1602 case synfigapp::UIInterface::RESPONSE_NO:
1604 case synfigapp::UIInterface::RESPONSE_YES:
1607 case synfigapp::UIInterface::RESPONSE_CANCEL:
1616 if((*iter)->synfigapp::Instance::is_modified())
1618 handle<synfigapp::UIInterface> uim;
1619 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1621 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() );
1622 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1624 case synfigapp::UIInterface::RESPONSE_NO:
1626 case synfigapp::UIInterface::RESPONSE_YES:
1627 (*iter)->dialog_cvs_commit();
1629 case synfigapp::UIInterface::RESPONSE_CANCEL:
1638 // This next line causes things to crash for some reason
1642 shutdown_in_progress=true;
1644 instance_list.clear();
1646 while(studio::App::events_pending())studio::App::iteration(false);
1649 auto_recover->normal_shutdown();
1651 get_ui_interface()->task("Quit Request sent");
1657 dialog_setup->refresh();
1658 dialog_setup->show();
1661 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1662 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1665 //#define USE_WIN32_FILE_DIALOGS 1
1668 #ifdef USE_WIN32_FILE_DIALOGS
1669 static OPENFILENAME ofn={};
1673 #include <gdk/gdkwin32.h>
1677 App::dialog_open_file(const std::string &title, std::string &filename)
1679 #ifdef USE_WIN32_FILE_DIALOGS
1680 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1682 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1683 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1684 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1686 ofn.lStructSize=sizeof(OPENFILENAME);
1687 ofn.hwndOwner = hWnd;
1688 ofn.hInstance = hInstance;
1689 ofn.lpstrFilter = szFilter;
1690 // ofn.lpstrCustomFilter=NULL;
1691 // ofn.nMaxCustFilter=0;
1692 // ofn.nFilterIndex=0;
1693 // ofn.lpstrFile=NULL;
1694 ofn.nMaxFile=MAX_PATH;
1695 // ofn.lpstrFileTitle=NULL;
1696 // ofn.lpstrInitialDir=NULL;
1697 // ofn.lpstrTitle=NULL;
1698 ofn.Flags=OFN_HIDEREADONLY;
1699 // ofn.nFileOffset=0;
1700 // ofn.nFileExtension=0;
1701 ofn.lpstrDefExt=TEXT("sif");
1702 // ofn.lCustData = 0l;
1704 // ofn.lpTemplateName=NULL;
1706 CHAR szFilename[MAX_PATH];
1708 strcpy(szFilename,filename.c_str());
1709 strcpy(szTitle,title.c_str());
1711 ofn.lpstrFile=szFilename;
1712 ofn.lpstrFileTitle=szTitle;
1714 if(GetOpenFileName(&ofn))
1716 filename=szFilename;
1722 synfig::String prev_path;
1723 if(!_preferences.get_value("curr_path",prev_path))
1725 prev_path = absolute_path(prev_path);
1727 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1728 dialog->set_current_folder(prev_path);
1729 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1730 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1731 if(!filename.empty())
1732 if (is_absolute_path(filename))
1733 dialog->set_filename(filename);
1735 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1736 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1737 filename=dialog->get_filename();
1749 GtkWidget *fileselection;
1750 fileselection = gtk_file_selection_new(title.c_str());
1753 if(basename(filename)==filename)
1755 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1758 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1760 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1762 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1763 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1765 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1766 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1768 gtk_widget_show(fileselection);
1776 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1777 _preferences.set_value("curr_path",dirname(filename));
1781 gtk_widget_destroy(fileselection);
1784 gtk_widget_destroy(fileselection);
1791 App::dialog_save_file(const std::string &title, std::string &filename)
1793 #if USE_WIN32_FILE_DIALOGS
1794 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1796 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1797 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1798 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1800 ofn.lStructSize=sizeof(OPENFILENAME);
1801 ofn.hwndOwner = hWnd;
1802 ofn.hInstance = hInstance;
1803 ofn.lpstrFilter = szFilter;
1804 // ofn.lpstrCustomFilter=NULL;
1805 // ofn.nMaxCustFilter=0;
1806 // ofn.nFilterIndex=0;
1807 // ofn.lpstrFile=NULL;
1808 ofn.nMaxFile=MAX_PATH;
1809 // ofn.lpstrFileTitle=NULL;
1810 // ofn.lpstrInitialDir=NULL;
1811 // ofn.lpstrTitle=NULL;
1812 ofn.Flags=OFN_OVERWRITEPROMPT;
1813 // ofn.nFileOffset=0;
1814 // ofn.nFileExtension=0;
1815 ofn.lpstrDefExt=TEXT("sif");
1816 // ofn.lCustData = 0l;
1818 // ofn.lpTemplateName=NULL;
1820 CHAR szFilename[MAX_PATH];
1822 strcpy(szFilename,filename.c_str());
1823 strcpy(szTitle,title.c_str());
1825 ofn.lpstrFile=szFilename;
1826 ofn.lpstrFileTitle=szTitle;
1828 if(GetSaveFileName(&ofn))
1830 filename=szFilename;
1831 _preferences.set_value("curr_path",dirname(filename));
1836 synfig::String prev_path;
1837 if(!_preferences.get_value("curr_path",prev_path))
1839 prev_path = absolute_path(prev_path);
1841 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1842 dialog->set_current_folder(prev_path);
1843 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1844 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1845 if(!filename.empty())
1847 std::string full_path;
1848 if (is_absolute_path(filename))
1849 full_path = filename;
1851 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1852 // select the file if it exists
1853 dialog->set_filename(full_path);
1855 // if the file doesn't exist, put its name into the filename box
1857 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1858 dialog->set_current_name(basename(filename));
1860 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1861 filename=dialog->get_filename();
1863 _preferences.set_value("curr_path",dirname(filename));
1868 // return dialog_open_file(title, filename);
1873 App::dialog_error_blocking(const std::string &title, const std::string &message)
1875 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1876 dialog.set_title(title);
1882 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1884 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1885 dialog.set_title(title);
1891 App::dialog_yes_no(const std::string &title, const std::string &message)
1896 true // use_separator
1898 Gtk::Label label(message);
1901 dialog.get_vbox()->pack_start(label);
1902 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1903 dialog.add_button(Gtk::StockID("gtk-no"),0);
1905 return dialog.run();
1909 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1914 true // use_separator
1916 Gtk::Label label(message);
1919 dialog.get_vbox()->pack_start(label);
1920 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1921 dialog.add_button(Gtk::StockID("gtk-no"),0);
1922 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1924 return dialog.run();
1928 App::dialog_not_implemented()
1930 Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1931 dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
1936 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1941 true // use_separator
1943 Gtk::Label label(message);
1945 dialog.get_vbox()->pack_start(label);
1948 entry.set_text(text);
1950 entry.set_activates_default(true);
1951 dialog.get_vbox()->pack_start(entry);
1953 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1954 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1955 dialog.set_default_response(Gtk::RESPONSE_OK);
1956 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1959 if(dialog.run()!=Gtk::RESPONSE_OK)
1962 text=entry.get_text();
1971 App::open(std::string filename)
1973 return open_as(filename,filename);
1976 // this is called from autorecover.cpp:
1977 // App::open_as(get_shadow_file_name(filename),filename)
1978 // other than that, 'filename' and 'as' are the same
1980 App::open_as(std::string filename,std::string as)
1983 char long_name[1024];
1984 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1990 OneMoment one_moment;
1992 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1993 if(canvas && get_instance(canvas))
1995 get_instance(canvas)->find_canvas_view(canvas)->present();
1996 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1999 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2001 add_recent_file(as);
2003 handle<Instance> instance(Instance::create(canvas));
2006 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2010 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)")))
2011 instance->dialog_cvs_update();
2015 dialog_error_blocking(_("Error"), x);
2020 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2024 _preferences.set_value("curr_path",dirname(as));
2033 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2034 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2036 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2038 canvas->rend_desc().set_frame_rate(24.0);
2039 canvas->rend_desc().set_time_start(0.0);
2040 canvas->rend_desc().set_time_end(00.0);
2041 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2042 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2043 canvas->rend_desc().set_tl(Vector(-4,2.25));
2044 canvas->rend_desc().set_br(Vector(4,-2.25));
2045 canvas->rend_desc().set_w(480);
2046 canvas->rend_desc().set_h(270);
2047 canvas->rend_desc().set_antialias(1);
2048 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2049 canvas->set_file_name(file_name);
2051 Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2057 string filename="*.sif";
2059 while(dialog_open_file("Open", filename))
2061 // If the filename still has wildcards, then we should
2062 // continue looking for the file we want
2063 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2069 get_ui_interface()->error(_("Unable to open file"));
2074 App::set_selected_instance(etl::loose_handle<Instance> instance)
2076 /* if(get_selected_instance()==instance)
2078 selected_instance=instance;
2079 signal_instance_selected()(instance);
2085 selected_instance=instance;
2086 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2090 instance->focus(instance->get_canvas());
2093 set_selected_canvas_view(0);
2095 signal_instance_selected()(instance);
2099 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2101 selected_canvas_view=canvas_view;
2102 signal_canvas_view_focus()(selected_canvas_view);
2105 selected_instance=canvas_view->get_instance();
2106 signal_instance_selected()(canvas_view->get_instance());
2109 if(get_selected_canvas_view()==canvas_view)
2111 signal_canvas_view_focus()(selected_canvas_view);
2112 signal_instance_selected()(canvas_view->get_instance());
2115 selected_canvas_view=canvas_view;
2116 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2117 set_selected_instance(canvas_view->get_instance());
2118 signal_canvas_view_focus()(selected_canvas_view);
2122 etl::loose_handle<Instance>
2123 App::get_instance(Canvas::Handle canvas)
2125 if(!canvas) return 0;
2126 canvas=canvas->get_root();
2128 std::list<etl::handle<Instance> >::iterator iter;
2129 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2131 if((*iter)->get_canvas()==canvas)
2140 (new class About())->show();
2146 if(selected_instance)
2147 selected_instance->undo();
2153 if(selected_instance)
2154 selected_instance->redo();
2158 studio::App::get_base_path()
2160 return app_base_path_;