1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
40 #include <gtkmm/fileselection.h>
41 #include <gtkmm/dialog.h>
42 #include <gtkmm/messagedialog.h>
43 #include <gtkmm/label.h>
44 #include <gtkmm/stock.h>
45 #include <gtkmm/stockitem.h>
46 #include <gtkmm/iconsource.h>
47 #include <gtkmm/inputdialog.h>
48 #include <gtkmm/accelmap.h>
49 #include <gtkmm/uimanager.h>
53 #include <synfig/loadcanvas.h>
58 #include "canvasview.h"
59 #include "dialog_setup.h"
60 #include "dialog_gradient.h"
61 #include "dialog_color.h"
64 #include "onemoment.h"
66 #include "dockmanager.h"
68 #include "state_eyedrop.h"
69 #include "state_normal.h"
70 #include "state_draw.h"
71 #include "state_fill.h"
72 #include "state_bline.h"
73 #include "state_polygon.h"
74 #include "state_sketch.h"
75 #include "state_gradient.h"
76 #include "state_circle.h"
77 #include "state_rectangle.h"
78 #include "state_smoothmove.h"
79 #include "state_scale.h"
80 #include "state_width.h"
81 #include "state_rotate.h"
82 #include "state_zoom.h"
84 #include "devicetracker.h"
85 #include "dialog_tooloptions.h"
87 #include "autorecover.h"
89 #include <synfigapp/settings.h>
90 #include "dock_history.h"
91 #include "dock_canvases.h"
92 #include "dock_keyframes.h"
93 #include "dock_layers.h"
94 #include "dock_params.h"
95 #include "dock_metadata.h"
96 #include "dock_children.h"
97 #include "dock_info.h"
98 #include "dock_navigator.h"
99 #include "dock_layergroups.h"
100 #include "dock_timetrack.h"
101 #include "dock_curves.h"
103 #include "mod_palette/mod_palette.h"
104 #include "mod_mirror/mod_mirror.h"
106 #include <sys/stat.h>
112 #include "statemanager.h"
119 #define _WIN32_WINNT 0x0500
122 #include <gtkmm/accelmap.h>
123 #include <gtkmm/filechooser.h>
124 #include <gtkmm/filechooserdialog.h>
128 /* === U S I N G =========================================================== */
132 using namespace synfig;
133 using namespace studio;
135 /* === M A C R O S ========================================================= */
137 #ifndef SYNFIG_USER_APP_DIR
139 #define SYNFIG_USER_APP_DIR "Library/Synfig"
140 #elif defined(_WIN32)
141 #define SYNFIG_USER_APP_DIR "Synfig"
143 #define SYNFIG_USER_APP_DIR ".synfig"
148 #define DPM2DPI(x) (float(x)/39.3700787402f)
149 #define DPI2DPM(x) (float(x)*39.3700787402f)
155 # define IMAGE_DIR "share\\pixmaps"
160 # define IMAGE_DIR "/usr/local/share/pixmaps"
164 # define IMAGE_EXT "tif"
167 #include <synfigapp/main.h>
169 /* === S I G N A L S ======================================================= */
171 static sigc::signal<void> signal_present_all_;
173 App::signal_present_all() { return signal_present_all_; }
175 static sigc::signal<void> signal_recent_files_changed_;
177 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
179 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
180 sigc::signal<void,etl::loose_handle<CanvasView> >&
181 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
183 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
184 sigc::signal<void,etl::handle<Instance> >&
185 App::signal_instance_selected() { return signal_instance_selected_; }
187 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
188 sigc::signal<void,etl::handle<Instance> >&
189 App::signal_instance_created() { return signal_instance_created_; }
191 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
192 sigc::signal<void,etl::handle<Instance> >&
193 App::signal_instance_deleted() { return signal_instance_deleted_; }
195 /* === G L O B A L S ======================================================= */
197 static std::list<std::string> recent_files;
198 const std::list<std::string>& App::get_recent_files() { return recent_files; }
200 int App::Busy::count;
201 bool App::shutdown_in_progress;
203 synfig::Gamma App::gamma;
205 Glib::RefPtr<studio::UIManager> App::ui_manager_;
207 synfig::Distance::System App::distance_system;
209 studio::Dialog_Setup* App::dialog_setup;
211 etl::handle< studio::ModPalette > mod_palette_;
212 //studio::Dialog_Palette* App::dialog_palette;
214 std::list<etl::handle<Instance> > App::instance_list;
216 static etl::handle<synfigapp::UIInterface> ui_interface_;
217 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
219 etl::handle<Instance> App::selected_instance;
220 etl::handle<CanvasView> App::selected_canvas_view;
222 studio::Toolbox *studio::App::toolbox=NULL;
224 studio::AutoRecover *studio::App::auto_recover=NULL;
226 studio::IPC *ipc=NULL;
228 studio::DockManager* studio::App::dock_manager=0;
230 studio::DeviceTracker* studio::App::device_tracker=0;
232 studio::Dialog_Gradient* studio::App::dialog_gradient;
234 studio::Dialog_Color* studio::App::dialog_color;
236 Gtk::InputDialog* studio::App::dialog_input;
238 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
240 studio::Dock_History* dock_history;
241 studio::Dock_Canvases* dock_canvases;
242 studio::Dock_Keyframes* dock_keyframes;
243 studio::Dock_Layers* dock_layers;
244 studio::Dock_Params* dock_params;
245 studio::Dock_MetaData* dock_meta_data;
246 studio::Dock_Children* dock_children;
247 studio::Dock_Info* dock_info;
248 studio::Dock_LayerGroups* dock_layer_groups;
249 studio::Dock_Navigator* dock_navigator;
250 studio::Dock_Timetrack* dock_timetrack;
251 studio::Dock_Curves* dock_curves;
253 std::list< etl::handle< studio::Module > > module_list_;
255 bool studio::App::use_colorspace_gamma=true;
256 bool studio::App::single_threaded=false;
258 static int max_recent_files_=25;
259 int studio::App::get_max_recent_files() { return max_recent_files_; }
260 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
262 static synfig::String app_base_path_;
265 }; // END of namespace studio
266 studio::StateManager* state_manager;
271 class GlobalUIInterface : public synfigapp::UIInterface
275 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
280 true // use_separator
282 Gtk::Label label(message);
285 dialog.get_vbox()->pack_start(label);
286 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
287 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
289 dialog.set_default_response(dflt);
291 return (Response)dialog.run();
293 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
298 true // use_separator
300 Gtk::Label label(message);
303 dialog.get_vbox()->pack_start(label);
304 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
305 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
306 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
308 dialog.set_default_response(dflt);
310 return (Response)dialog.run();
312 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
317 true // use_separator
319 Gtk::Label label(message);
322 dialog.get_vbox()->pack_start(label);
323 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
324 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
326 dialog.set_default_response(dflt);
328 return (Response)dialog.run();
332 task(const std::string &task)
334 std::cerr<<task<<std::endl;
335 while(studio::App::events_pending())studio::App::iteration(false);
340 error(const std::string &err)
342 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
349 warning(const std::string &err)
351 std::cerr<<"warning: "<<err<<std::endl;
352 while(studio::App::events_pending())studio::App::iteration(false);
357 amount_complete(int /*current*/, int /*total*/)
359 while(studio::App::events_pending())studio::App::iteration(false);
364 /* === P R O C E D U R E S ================================================= */
366 typedef unsigned char U8;
367 typedef unsigned short U16;
368 typedef unsigned long U32;
378 static inline U32 hash_U32(U32 i)
380 i=i*1664525+1013904223;
381 i=i*1664525+1013904223;
382 i=i*1664525+1013904223;
387 static const int endian_fix_table[8] = { 3, 2, 1, 0, 7, 6, 5, 4 } ;
388 #define endian_fix(x) (endian_fix_table[x])
390 #define endian_fix(x) (x)
393 int v_unwind_key(V_KeyUnwound* unwound, const char* key)
396 unwound->element.serial=0;
397 unwound->element.checksum=0;
405 case '0': data=0; break;
406 case '1': data=1; break;
407 case '2': data=2; break;
408 case '3': data=3; break;
409 case '4': data=4; break;
410 case '5': data=5; break;
411 case '6': data=6; break;
412 case '7': data=7; break;
413 case '8': data=8; break;
414 case '9': data=9; break;
415 case 'a': case 'A': data=10; break;
416 case 'b': case 'B': data=11; break;
417 case 'c': case 'C': data=12; break;
418 case 'd': case 'D': data=13; break;
419 case 'e': case 'E': data=14; break;
420 case 'f': case 'F': data=15; break;
421 default: return 0; break;
424 unwound->element.checksum|=(((U32)data&3)<<bit);
425 unwound->element.serial|=(((U32)(data>>2)&3)<<bit);
430 int v_key_check(const char* key, U32* serial, U32 appid)
432 V_KeyUnwound unwound_key;
433 U32 appid_mask_a=hash_U32(appid);
434 U32 appid_mask_b=hash_U32(appid_mask_a);
436 if(!v_unwind_key(&unwound_key, key))
438 // Invalid characters in key
443 // Undo obfuscation pass
445 U32 next=hash_U32(unwound_key.raw[endian_fix(7)]);
450 unwound_key.raw[endian_fix(i)]^=(next>>24);
454 unwound_key.element.serial^=appid_mask_a;
455 unwound_key.element.checksum^=appid_mask_b;
457 *serial=unwound_key.element.serial;
459 return unwound_key.element.checksum==hash_U32(unwound_key.element.serial);
464 # ifdef LICENSE_KEY_REQUIRED
465 int check_license(String basedir)
467 int check_license(String /*basedir*/)
470 int check_license(String /*basedir*/)
473 #ifdef LICENSE_KEY_REQUIRED
478 license_file="/usr/local/etc/.synfiglicense";
480 license_file=basedir+"\\etc\\.synfiglicense";
484 key=Glib::file_get_contents(license_file);
485 } catch (Glib::FileError) { }
487 if(!v_key_check(key.c_str(),&serial,0xdeadbeef))
489 while(!v_key_check(key.c_str(),&serial,0xdeadbeef))
493 if(!App::dialog_entry(
494 _("Synfig Studio Authentication"),
495 _("Please enter your license key below. You will not\nbe able to use this software without a valid license key."),
498 throw String("No License");
501 FILE* file=fopen(license_file.c_str(),"w");
504 fprintf(file,"%s",key.c_str());
508 synfig::error("Unable to save license key!");
510 synfig::info("License Authenticated -- Serial #%05d",serial);
519 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
521 action_group_list.push_back(action_group);
522 Gtk::UIManager::insert_action_group(action_group, pos);
526 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
528 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
529 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
530 if(*iter==action_group)
532 action_group_list.erase(iter);
533 Gtk::UIManager::remove_action_group(action_group);
536 synfig::error("Unable to find action group");
540 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
542 ui_manager->insert_action_group(group,0);
545 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
546 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
549 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
552 if(*iter && (*iter)->get_name()!="menus")
554 synfig::info("Removing action group "+(*iter)->get_name());
555 ui_manager->remove_action_group(*iter);
559 ui_manager->insert_action_group(group,0);
562 for(;!prev_groups.empty();prev_groups.pop_front())
564 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
565 ui_manager->insert_action_group(prev_groups.front(),1);
570 class Preferences : public synfigapp::Settings
573 virtual bool get_value(const synfig::String& key, synfig::String& value)const
577 value=strprintf("%f %f %f %f",
578 App::gamma.get_gamma_r(),
579 App::gamma.get_gamma_g(),
580 App::gamma.get_gamma_b(),
581 App::gamma.get_black_level()
585 if(key=="time_format")
587 value=strprintf("%i",App::get_time_format());
590 if(key=="file_history.size")
592 value=strprintf("%i",App::get_max_recent_files());
595 if(key=="use_colorspace_gamma")
597 value=strprintf("%i",(int)App::use_colorspace_gamma);
600 if(key=="distance_system")
602 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
605 if(key=="single_threaded")
607 value=strprintf("%i",(int)App::single_threaded);
610 if(key=="auto_recover_backup_interval")
612 value=strprintf("%i",App::auto_recover->get_timeout());
616 return synfigapp::Settings::get_value(key,value);
619 virtual bool set_value(const synfig::String& key,const synfig::String& value)
625 strscanf(value,"%f %f %f %f",
632 App::gamma.set_all(r,g,b,blk);
636 if(key=="time_format")
638 int i(atoi(value.c_str()));
639 App::set_time_format(static_cast<synfig::Time::Format>(i));
642 if(key=="auto_recover_backup_interval")
644 int i(atoi(value.c_str()));
645 App::auto_recover->set_timeout(i);
648 if(key=="file_history.size")
650 int i(atoi(value.c_str()));
651 App::set_max_recent_files(i);
654 if(key=="use_colorspace_gamma")
656 int i(atoi(value.c_str()));
657 App::use_colorspace_gamma=i;
660 if(key=="distance_system")
662 App::distance_system=Distance::ident_system(value);;
665 if(key=="single_threaded")
667 int i(atoi(value.c_str()));
668 App::single_threaded=i;
672 return synfigapp::Settings::set_value(key,value);
675 virtual KeyList get_key_list()const
677 KeyList ret(synfigapp::Settings::get_key_list());
678 ret.push_back("gamma");
679 ret.push_back("time_format");
680 ret.push_back("distance_system");
681 ret.push_back("file_history.size");
682 ret.push_back("use_colorspace_gamma");
683 ret.push_back("single_threaded");
684 ret.push_back("auto_recover_backup_interval");
689 static ::Preferences _preferences;
694 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
696 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
698 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
700 menus_action_group->add( Gtk::Action::create("menu-file", "_File") );
701 menus_action_group->add( Gtk::Action::create("menu-edit", "_Edit") );
702 menus_action_group->add( Gtk::Action::create("menu-view", "_View") );
703 menus_action_group->add( Gtk::Action::create("menu-canvas", "_Canvas") );
704 menus_action_group->add( Gtk::Action::create("menu-layer", "_Layer") );
705 menus_action_group->add( Gtk::Action::create("menu-duck-mask", "Show/Hide Ducks") );
706 menus_action_group->add( Gtk::Action::create("menu-preview-quality", "Preview Quality") );
707 menus_action_group->add( Gtk::Action::create("menu-layer-new", "New Layer") );
708 menus_action_group->add( Gtk::Action::create("menu-keyframe", "Keyframe") );
709 menus_action_group->add( Gtk::Action::create("menu-group", "Group") );
710 menus_action_group->add( Gtk::Action::create("menu-state", "State") );
711 menus_action_group->add( Gtk::Action::create("menu-toolbox", "Toolbox") );
713 // Add the synfigapp actions...
714 synfigapp::Action::Book::iterator iter;
715 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
717 actions_action_group->add(Gtk::Action::create(
718 "action-"+iter->second.name,
719 get_action_stock_id(iter->second),
720 iter->second.local_name,iter->second.local_name
724 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
725 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
726 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ group->add(action,sig); }
728 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
729 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
730 DEFINE_ACTION("open", Gtk::Stock::OPEN);
731 DEFINE_ACTION("save", Gtk::Stock::SAVE);
732 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
733 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
734 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
735 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
736 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
737 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
738 DEFINE_ACTION("import", _("Import"));
739 DEFINE_ACTION("render", _("Render"));
740 DEFINE_ACTION("preview", _("Preview"));
741 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
742 DEFINE_ACTION("sound", _("Sound File"));
743 DEFINE_ACTION("options", _("Options"));
744 DEFINE_ACTION("close", _("Close View"));
745 DEFINE_ACTION("close-document", _("Close Document"));
748 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
749 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
750 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
751 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
752 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
753 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
754 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
755 DEFINE_ACTION("properties", _("Properties"));
757 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
758 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
759 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
760 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
761 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
762 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
763 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
764 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
765 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
766 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
767 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
768 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
769 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
770 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
771 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
772 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
773 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
774 DEFINE_ACTION("play", _("Play"));
775 // DEFINE_ACTION("pause", _("Pause"));
776 DEFINE_ACTION("stop", _("Stop"));
777 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
778 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
779 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
780 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
781 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
782 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
783 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
784 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
785 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
786 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
787 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
788 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
789 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
790 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
791 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
792 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
793 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
794 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
795 DEFINE_ACTION("seek-end", _("Seek to End"));
797 DEFINE_ACTION("action-group_add", _("Add group"));
799 DEFINE_ACTION("canvas-new", _("New Canvas"));
801 DEFINE_ACTION("amount-inc", _("Increase Amount"));
802 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
807 // Set up synfigapp actions
809 synfigapp::Action::Book::iterator iter;
811 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
813 Gtk::StockID stock_id;
815 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
817 //Gtk::Image* image(manage(new Gtk::Image()));
818 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
819 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
820 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
821 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
822 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
823 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
824 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
825 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
826 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
827 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
829 actions_action_group->add(Gtk::Action::create(
830 "action-"+iter->second.name,
832 iter->second.local_name,iter->second.local_name
840 Glib::ustring ui_info =
842 " <popup name='menu-toolbox' action='menu-toolbox'>"
843 " <menu action='menu-file'>"
846 " <popup name='menu-main' action='menu-main'>"
847 " <menu action='menu-file'>"
848 " <menuitem action='save' />"
849 " <menuitem action='save-as' />"
850 " <menuitem action='revert' />"
851 " <separator name='bleh01'/>"
852 " <menuitem action='cvs-add' />"
853 " <menuitem action='cvs-update' />"
854 " <menuitem action='cvs-commit' />"
855 " <menuitem action='cvs-revert' />"
856 " <separator name='bleh02'/>"
857 " <menuitem action='import' />"
858 " <separator name='bleh03'/>"
859 " <menuitem action='render' />"
860 " <menuitem action='preview' />"
861 " <menuitem action='sound' />"
862 " <separator name='bleh04'/>"
863 " <menuitem action='options' />"
864 " <menuitem action='close' />"
865 " <menuitem action='close-document' />"
867 " <menu action='menu-edit'>"
868 " <menuitem action='undo'/>"
869 " <menuitem action='redo'/>"
870 " <separator name='bleh05'/>"
871 " <menuitem action='cut'/>"
872 " <menuitem action='copy'/>"
873 " <menuitem action='paste'/>"
874 " <separator name='bleh06'/>"
875 " <menuitem action='select-all-ducks'/>"
876 " <menuitem action='unselect-all-layers'/>"
877 " <separator name='bleh07'/>"
878 " <menuitem action='properties'/>"
880 " <menu action='menu-view'>"
881 " <menu action='menu-duck-mask'>"
882 " <menuitem action='mask-position-ducks' />"
883 " <menuitem action='mask-vertex-ducks' />"
884 " <menuitem action='mask-tangent-ducks' />"
885 " <menuitem action='mask-radius-ducks' />"
886 " <menuitem action='mask-width-ducks' />"
887 " <menuitem action='mask-angle-ducks' />"
889 " <menu action='menu-preview-quality'>"
890 " <menuitem action='quality-00' />"
891 " <menuitem action='quality-01' />"
892 " <menuitem action='quality-02' />"
893 " <menuitem action='quality-03' />"
894 " <menuitem action='quality-04' />"
895 " <menuitem action='quality-05' />"
896 " <menuitem action='quality-06' />"
897 " <menuitem action='quality-07' />"
898 " <menuitem action='quality-08' />"
899 " <menuitem action='quality-09' />"
900 " <menuitem action='quality-10' />"
902 " <separator name='bleh08'/>"
903 " <menuitem action='play'/>"
904 //" <menuitem action='pause'/>"
905 " <menuitem action='stop'/>"
906 " <menuitem action='dialog-flipbook'/>"
907 " <separator name='bleh09'/>"
908 " <menuitem action='toggle-grid-show'/>"
909 " <menuitem action='toggle-grid-snap'/>"
910 " <menuitem action='toggle-guide-show'/>"
911 " <menuitem action='toggle-low-res'/>"
912 " <menuitem action='toggle-onion-skin'/>"
913 " <separator name='bleh10'/>"
914 " <menuitem action='canvas-zoom-in'/>"
915 " <menuitem action='canvas-zoom-out'/>"
916 " <menuitem action='canvas-zoom-fit'/>"
917 " <menuitem action='canvas-zoom-100'/>"
918 " <separator name='bleh11'/>"
919 " <menuitem action='time-zoom-in'/>"
920 " <menuitem action='time-zoom-out'/>"
921 " <separator name='bleh12'/>"
922 " <menuitem action='jump-next-keyframe'/>"
923 " <menuitem action='jump-prev-keyframe'/>"
924 " <menuitem action='seek-next-frame'/>"
925 " <menuitem action='seek-prev-frame'/>"
926 " <menuitem action='seek-next-second'/>"
927 " <menuitem action='seek-prev-second'/>"
928 " <menuitem action='seek-begin'/>"
929 " <menuitem action='seek-end'/>"
931 " <menu action='menu-canvas'>"
932 " <menuitem action='canvas-new'/>"
934 " <menu name='menu-state' action='menu-state'>"
936 " <menu action='menu-group'>"
937 " <menuitem action='action-group_add'/>"
939 " <menu action='menu-layer'>"
940 //" <menuitem action='cut'/>"
941 //" <menuitem action='copy'/>"
942 //" <menuitem action='paste'/>"
943 //" <separator name='bleh06'/>"
944 " <menu action='menu-layer-new'></menu>"
945 " <menuitem action='amount-inc'/>"
946 " <menuitem action='amount-dec'/>"
948 " <menu action='menu-keyframe'>"
949 " <menuitem action='keyframe-properties'/>"
956 " <menubar name='MenuBar'>"
957 " <menu action='MenuFile'>"
958 " <menuitem action='New'/>"
959 " <menuitem action='Open'/>"
961 " <menuitem action='Quit'/>"
963 " <menu action='MenuEdit'>"
964 " <menuitem action='Cut'/>"
965 " <menuitem action='Copy'/>"
966 " <menuitem action='Paste'/>"
969 " <toolbar name='ToolBar'>"
970 " <toolitem action='Open'/>"
971 " <toolitem action='Quit'/>"
977 actions_action_group->set_sensitive(false);
978 App::ui_manager()->set_add_tearoffs(true);
979 App::ui_manager()->insert_action_group(menus_action_group,1);
980 App::ui_manager()->insert_action_group(actions_action_group,1);
981 App::ui_manager()->add_ui_from_string(ui_info);
983 //App::ui_manager()->get_accel_group()->unlock();
985 catch(const Glib::Error& ex)
987 synfig::error("building menus and toolbars failed: " + ex.what());
990 // Add default keyboard accelerators
991 #define ACCEL(path,accel) \
993 Gtk::AccelKey accel_key(accel,path); \
994 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
997 #define ACCEL2(accel) \
999 Gtk::AccelKey accel_key(accel); \
1000 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1003 ACCEL("<Actions>//select-all-ducks","<Control>a");
1004 ACCEL("<Actions>//unselect-all-layers","<Control>d");
1005 ACCEL("<Actions>//render","F9");
1006 ACCEL("<Actions>//preview","F11");
1007 ACCEL("<Actions>//properties","F8");
1008 ACCEL("<Actions>//options","F12");
1009 ACCEL("<Actions>//import","<control>i");
1010 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
1011 ACCEL("<Actions>//toggle-grid-show","<Control>g");
1012 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
1013 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
1014 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
1015 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1016 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1017 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1018 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1019 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1021 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1022 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1024 ACCEL("<Actions>//quality-01","<Control>1");
1025 ACCEL("<Actions>//quality-02","<Control>2");
1026 ACCEL("<Actions>//quality-03","<Control>3");
1027 ACCEL("<Actions>//quality-04","<Control>4");
1028 ACCEL("<Actions>//quality-05","<Control>5");
1029 ACCEL("<Actions>//quality-06","<Control>6");
1030 ACCEL("<Actions>//quality-07","<Control>7");
1031 ACCEL("<Actions>//quality-08","<Control>8");
1032 ACCEL("<Actions>//quality-09","<Control>9");
1033 ACCEL("<Actions>//quality-10","<Control>0");
1034 ACCEL("<Actions>//undo","<Control>z");
1035 ACCEL("<Actions>//redo","<Control>r");
1036 ACCEL("<Actions>//action-layer_remove","Delete");
1038 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1039 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1040 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1041 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1042 ACCEL("<Actions>//time-zoom-in","+");
1043 ACCEL("<Actions>//time-zoom-out","_");
1045 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1046 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1048 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1049 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1050 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1051 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1052 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1053 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1054 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1055 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1056 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1057 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1058 ACCEL2(Gtk::AccelKey('o',Gdk::CONTROL_MASK,"<Actions>//toggle-onion-skin"));
1059 ACCEL("<Actions>//play", "<Control>p");
1060 ACCEL("<Actions>//seek-begin","Home");
1061 ACCEL("<Actions>//seek-end","End");
1063 ACCEL("<Actions>//state-normal", "<Mod1>a");
1064 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1065 ACCEL("<Actions>//state-scale", "<Mod1>d");
1066 ACCEL("<Actions>//state-rotate", "<Mod1>s");
1068 ACCEL("<Actions>//state-bline", "<Mod1>b");
1069 ACCEL("<Actions>//state-circle", "<Mod1>c");
1070 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1071 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1073 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1074 ACCEL("<Actions>//state-fill", "<Mod1>f");
1075 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1076 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1078 ACCEL("<Actions>//state-draw", "<Mod1>w");
1079 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1080 ACCEL("<Actions>//state-width", "<Mod1>t");
1081 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1083 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1089 #define mkdir(x,y) mkdir(x)
1092 /* === M E T H O D S ======================================================= */
1094 App::App(int *argc, char ***argv):
1095 Gtk::Main(argc,argv),
1096 IconControler(etl::dirname((*argv)[0]))
1098 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1101 serial_=check_license(app_base_path_);
1104 ui_interface_=new GlobalUIInterface();
1108 // don't call thread_init() if threads are already initialised
1109 // on some machines bonobo_init() initialised threads before we get here
1110 if (!g_thread_supported())
1111 Glib::thread_init();
1113 distance_system=Distance::SYSTEM_UNITS;
1115 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1118 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1122 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1130 if(!SYNFIG_CHECK_VERSION())
1132 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1133 dialog_error_blocking("Synfig Studio",
1134 "This copy of Synfig Studio was compiled against a\n"
1135 "different version of libsynfig than what is currently\n"
1136 "installed. Synfig Studio will now abort. Try downloading\n"
1137 "the latest version from the Synfig website at\n"
1138 "http://www.synfig.com/ "
1143 catch(synfig::SoftwareExpired)
1145 cerr<<"FATAL: Software Expired"<<endl;
1146 dialog_error_blocking("Synfig Studio",
1147 "This copy of Synfig Studio has expired.\n"
1148 "Please erase this copy, or download and\n"
1149 "install the latest copy from the Synfig\n"
1150 "website at http://www.synfig.com/ ."
1154 Glib::set_application_name(_("Synfig Studio"));
1157 about_window.set_can_self_destruct(false);
1158 about_window.show();
1160 shutdown_in_progress=false;
1161 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1162 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1164 // Initialize the Synfig library
1165 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1168 get_ui_interface()->error("Failed to initialize synfig!");
1172 // add the preferences to the settings
1173 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1177 studio_init_cb.task("Init UI Manager...");
1178 App::ui_manager_=studio::UIManager::create();
1181 studio_init_cb.task("Init Dock Manager...");
1182 dock_manager=new studio::DockManager();
1184 studio_init_cb.task("Init State Manager...");
1185 state_manager=new StateManager();
1187 studio_init_cb.task("Init Toolbox...");
1188 toolbox=new studio::Toolbox();
1190 studio_init_cb.task("Init Tool Options...");
1191 dialog_tool_options=new studio::Dialog_ToolOptions();
1192 dock_manager->register_dockable(*dialog_tool_options);
1194 studio_init_cb.task("Init History...");
1195 dock_history=new studio::Dock_History();
1196 dock_manager->register_dockable(*dock_history);
1198 studio_init_cb.task("Init Canvases...");
1199 dock_canvases=new studio::Dock_Canvases();
1200 dock_manager->register_dockable(*dock_canvases);
1202 studio_init_cb.task("Init Keyframes...");
1203 dock_keyframes=new studio::Dock_Keyframes();
1204 dock_manager->register_dockable(*dock_keyframes);
1206 studio_init_cb.task("Init Layers...");
1207 dock_layers=new studio::Dock_Layers();
1208 dock_manager->register_dockable(*dock_layers);
1210 studio_init_cb.task("Init Params...");
1211 dock_params=new studio::Dock_Params();
1212 dock_manager->register_dockable(*dock_params);
1214 studio_init_cb.task("Init MetaData...");
1215 dock_meta_data=new studio::Dock_MetaData();
1216 dock_manager->register_dockable(*dock_meta_data);
1218 studio_init_cb.task("Init Children...");
1219 dock_children=new studio::Dock_Children();
1220 dock_manager->register_dockable(*dock_children);
1222 studio_init_cb.task("Init Info...");
1223 dock_info = new studio::Dock_Info();
1224 dock_manager->register_dockable(*dock_info);
1226 studio_init_cb.task("Init Navigator...");
1227 dock_navigator = new studio::Dock_Navigator();
1228 dock_manager->register_dockable(*dock_navigator);
1230 studio_init_cb.task("Init Timetrack...");
1231 dock_timetrack = new studio::Dock_Timetrack();
1232 dock_manager->register_dockable(*dock_timetrack);
1234 studio_init_cb.task("Init Curve Editor...");
1235 dock_curves = new studio::Dock_Curves();
1236 dock_manager->register_dockable(*dock_curves);
1238 studio_init_cb.task("Init Layer Groups...");
1239 dock_layer_groups = new studio::Dock_LayerGroups();
1240 dock_manager->register_dockable(*dock_layer_groups);
1243 studio_init_cb.task("Init Color Dialog...");
1244 dialog_color=new studio::Dialog_Color();
1246 studio_init_cb.task("Init Gradient Dialog...");
1247 dialog_gradient=new studio::Dialog_Gradient();
1249 studio_init_cb.task("Init DeviceTracker...");
1250 device_tracker=new studio::DeviceTracker();
1252 studio_init_cb.task("Init Tools...");
1253 state_manager->add_state(&state_normal);
1254 state_manager->add_state(&state_smooth_move);
1255 state_manager->add_state(&state_scale);
1256 state_manager->add_state(&state_rotate);
1258 state_manager->add_state(&state_bline);
1261 state_manager->add_state(&state_circle);
1262 state_manager->add_state(&state_rectangle);
1264 state_manager->add_state(&state_gradient);
1265 state_manager->add_state(&state_eyedrop);
1266 state_manager->add_state(&state_fill);
1268 state_manager->add_state(&state_zoom);
1270 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1271 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1272 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1274 // Enabled for now. Let's see whether they're good enough yet.
1275 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1276 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1278 // Disabled by default - it doesn't work properly?
1279 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1281 studio_init_cb.task("Init ModPalette...");
1282 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1284 studio_init_cb.task("Init ModMirror...");
1285 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1288 studio_init_cb.task("Init Setup Dialog...");
1289 dialog_setup=new studio::Dialog_Setup();
1291 studio_init_cb.task("Init Input Dialog...");
1292 dialog_input=new Gtk::InputDialog();
1293 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1294 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1296 studio_init_cb.task("Init auto recovery...");
1297 auto_recover=new AutoRecover();
1299 studio_init_cb.amount_complete(9250,10000);
1300 studio_init_cb.task("Loading Settings...");
1302 studio_init_cb.task("Checking auto-recover...");
1304 studio_init_cb.amount_complete(9900,10000);
1306 if(auto_recover->recovery_needed())
1308 about_window.hide();
1310 get_ui_interface()->yes_no(
1312 "Synfig Studio seems to have crashed\n"
1313 "before you could save all your files.\n"
1314 "Would you like to re-open those files\n"
1315 "and recover your unsaved changes?"
1316 )==synfigapp::UIInterface::RESPONSE_YES
1319 if(!auto_recover->recover())
1321 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1324 get_ui_interface()->error(
1325 _("Synfig Studio has attempted to recover\n"
1326 "from a previous crash. The files that it has\n"
1327 "recovered are NOT YET SAVED. It would be a good\n"
1328 "idea to review them and save them now.")
1331 about_window.show();
1334 // Look for any files given on the command line,
1335 // and load them if found.
1336 for(;*argc>=1;(*argc)--)
1337 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1339 studio_init_cb.task("Loading files...");
1340 about_window.hide();
1341 open((*argv)[*argc]);
1342 about_window.show();
1345 studio_init_cb.task("Done.");
1346 studio_init_cb.amount_complete(10000,10000);
1352 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1356 StateManager* App::get_state_manager() { return state_manager; }
1360 shutdown_in_progress=true;
1364 synfigapp::Main::settings().remove_domain("pref");
1366 selected_instance=0;
1368 // Unload all of the modules
1369 for(;!module_list_.empty();module_list_.pop_back());
1371 delete state_manager;
1375 delete auto_recover;
1379 // studio::App::iteration(false);
1383 // studio::App::iteration(false);
1385 // studio::App::iteration(false);
1387 delete dialog_setup;
1389 delete dialog_gradient;
1391 delete dialog_color;
1393 delete dialog_input;
1395 delete dock_manager;
1397 instance_list.clear();
1399 // studio::App::iteration(false);
1403 App::get_user_app_directory()
1405 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1409 App::get_config_file(const synfig::String& file)
1411 return Glib::build_filename(get_user_app_directory(),file);
1415 App::add_recent_file(const std::string &file_name)
1417 std::string filename(file_name);
1419 assert(!filename.empty());
1421 if(filename.empty())
1424 // Toss out any "hidden" files
1425 if(basename(filename)[0]=='.')
1428 // If we aren't an absolute path, turn outselves into one
1429 if(!is_absolute_path(filename))
1430 filename=absolute_path(filename);
1432 list<string>::iterator iter;
1433 // Check to see if the file is already on the list.
1434 // If it is, then remove it from the list
1435 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1438 recent_files.erase(iter);
1443 // Push the filename to the front of the list
1444 recent_files.push_front(filename);
1446 // Clean out the files at the end of the list.
1447 while(recent_files.size()>(unsigned)get_max_recent_files())
1448 recent_files.pop_back();
1450 signal_recent_files_changed_();
1455 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1458 App::get_time_format()
1460 return _App_time_format;
1464 App::set_time_format(synfig::Time::Format x)
1471 App::save_settings()
1476 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1477 setlocale(LC_NUMERIC, "C");
1479 std::string filename=get_config_file("accelrc");
1480 Gtk::AccelMap::save(filename);
1483 std::string filename=get_config_file("recentfiles");
1485 std::ofstream file(filename.c_str());
1489 synfig::warning("Unable to save %s",filename.c_str());
1493 list<string>::reverse_iterator iter;
1495 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1499 std::string filename=get_config_file("settings");
1500 synfigapp::Main::settings().save_to_file(filename);
1501 setlocale(LC_NUMERIC,old_locale);
1505 synfig::warning("Caught exception when attempting to save settings.");
1510 App::load_settings()
1515 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1516 setlocale(LC_NUMERIC, "C");
1518 std::string filename=get_config_file("accelrc");
1519 Gtk::AccelMap::load(filename);
1522 std::string filename=get_config_file("recentfiles");
1524 std::ifstream file(filename.c_str());
1528 std::string recent_file;
1529 getline(file,recent_file);
1530 if(!recent_file.empty())
1531 add_recent_file(recent_file);
1534 std::string filename=get_config_file("settings");
1535 if(!synfigapp::Main::settings().load_from_file(filename))
1537 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1538 //if(!synfigapp::Main::settings().load_from_file(filename))
1540 gamma.set_gamma(1.0/2.2);
1541 reset_initial_window_configuration();
1544 setlocale(LC_NUMERIC,old_locale);
1548 synfig::warning("Caught exception when attempting to load settings.");
1553 App::reset_initial_window_configuration()
1555 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1556 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1557 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1558 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1559 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1560 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1561 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1562 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1563 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1564 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1565 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1566 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1567 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1568 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1572 App::shutdown_request(GdkEventAny*)
1576 //return !shutdown_in_progress;
1582 if(shutdown_in_progress)return;
1585 get_ui_interface()->task("Quit Request");
1588 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1592 std::list<etl::handle<Instance> >::iterator iter;
1593 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1595 if(!(*iter)->safe_close())
1599 if((*iter)->synfigapp::Instance::get_action_count())
1601 handle<synfigapp::UIInterface> uim;
1602 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1604 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1605 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1607 case synfigapp::UIInterface::RESPONSE_NO:
1609 case synfigapp::UIInterface::RESPONSE_YES:
1612 case synfigapp::UIInterface::RESPONSE_CANCEL:
1621 if((*iter)->synfigapp::Instance::is_modified())
1623 handle<synfigapp::UIInterface> uim;
1624 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1626 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() );
1627 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1629 case synfigapp::UIInterface::RESPONSE_NO:
1631 case synfigapp::UIInterface::RESPONSE_YES:
1632 (*iter)->dialog_cvs_commit();
1634 case synfigapp::UIInterface::RESPONSE_CANCEL:
1643 // This next line causes things to crash for some reason
1647 shutdown_in_progress=true;
1649 instance_list.clear();
1651 while(studio::App::events_pending())studio::App::iteration(false);
1654 auto_recover->normal_shutdown();
1656 get_ui_interface()->task("Quit Request sent");
1662 dialog_setup->refresh();
1663 dialog_setup->show();
1666 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1667 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1670 //#define USE_WIN32_FILE_DIALOGS 1
1673 #ifdef USE_WIN32_FILE_DIALOGS
1674 static OPENFILENAME ofn={};
1678 #include <gdk/gdkwin32.h>
1682 App::dialog_open_file(const std::string &title, std::string &filename)
1684 #ifdef USE_WIN32_FILE_DIALOGS
1685 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1687 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1688 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1689 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1691 ofn.lStructSize=sizeof(OPENFILENAME);
1692 ofn.hwndOwner = hWnd;
1693 ofn.hInstance = hInstance;
1694 ofn.lpstrFilter = szFilter;
1695 // ofn.lpstrCustomFilter=NULL;
1696 // ofn.nMaxCustFilter=0;
1697 // ofn.nFilterIndex=0;
1698 // ofn.lpstrFile=NULL;
1699 ofn.nMaxFile=MAX_PATH;
1700 // ofn.lpstrFileTitle=NULL;
1701 // ofn.lpstrInitialDir=NULL;
1702 // ofn.lpstrTitle=NULL;
1703 ofn.Flags=OFN_HIDEREADONLY;
1704 // ofn.nFileOffset=0;
1705 // ofn.nFileExtension=0;
1706 ofn.lpstrDefExt=TEXT("sif");
1707 // ofn.lCustData = 0l;
1709 // ofn.lpTemplateName=NULL;
1711 CHAR szFilename[MAX_PATH];
1713 strcpy(szFilename,filename.c_str());
1714 strcpy(szTitle,title.c_str());
1716 ofn.lpstrFile=szFilename;
1717 ofn.lpstrFileTitle=szTitle;
1719 if(GetOpenFileName(&ofn))
1721 filename=szFilename;
1727 synfig::String prev_path;
1728 if(!_preferences.get_value("curr_path",prev_path))
1730 prev_path = absolute_path(prev_path);
1732 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1733 dialog->set_current_folder(prev_path);
1734 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1735 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1736 if(!filename.empty())
1737 if (is_absolute_path(filename))
1738 dialog->set_filename(filename);
1740 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1741 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1742 filename=dialog->get_filename();
1754 GtkWidget *fileselection;
1755 fileselection = gtk_file_selection_new(title.c_str());
1758 if(basename(filename)==filename)
1760 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1763 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1765 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1767 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1768 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1770 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1771 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1773 gtk_widget_show(fileselection);
1781 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1782 _preferences.set_value("curr_path",dirname(filename));
1786 gtk_widget_destroy(fileselection);
1789 gtk_widget_destroy(fileselection);
1796 App::dialog_save_file(const std::string &title, std::string &filename)
1798 #if USE_WIN32_FILE_DIALOGS
1799 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1801 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1802 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1803 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1805 ofn.lStructSize=sizeof(OPENFILENAME);
1806 ofn.hwndOwner = hWnd;
1807 ofn.hInstance = hInstance;
1808 ofn.lpstrFilter = szFilter;
1809 // ofn.lpstrCustomFilter=NULL;
1810 // ofn.nMaxCustFilter=0;
1811 // ofn.nFilterIndex=0;
1812 // ofn.lpstrFile=NULL;
1813 ofn.nMaxFile=MAX_PATH;
1814 // ofn.lpstrFileTitle=NULL;
1815 // ofn.lpstrInitialDir=NULL;
1816 // ofn.lpstrTitle=NULL;
1817 ofn.Flags=OFN_OVERWRITEPROMPT;
1818 // ofn.nFileOffset=0;
1819 // ofn.nFileExtension=0;
1820 ofn.lpstrDefExt=TEXT("sif");
1821 // ofn.lCustData = 0l;
1823 // ofn.lpTemplateName=NULL;
1825 CHAR szFilename[MAX_PATH];
1827 strcpy(szFilename,filename.c_str());
1828 strcpy(szTitle,title.c_str());
1830 ofn.lpstrFile=szFilename;
1831 ofn.lpstrFileTitle=szTitle;
1833 if(GetSaveFileName(&ofn))
1835 filename=szFilename;
1836 _preferences.set_value("curr_path",dirname(filename));
1841 synfig::String prev_path;
1842 if(!_preferences.get_value("curr_path",prev_path))
1844 prev_path = absolute_path(prev_path);
1846 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1847 dialog->set_current_folder(prev_path);
1848 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1849 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1850 if(!filename.empty())
1852 std::string full_path;
1853 if (is_absolute_path(filename))
1854 full_path = filename;
1856 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1857 // select the file if it exists
1858 dialog->set_filename(full_path);
1860 // if the file doesn't exist, put its name into the filename box
1862 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1863 dialog->set_current_name(basename(filename));
1865 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1866 filename=dialog->get_filename();
1868 _preferences.set_value("curr_path",dirname(filename));
1873 // return dialog_open_file(title, filename);
1878 App::dialog_error_blocking(const std::string &title, const std::string &message)
1880 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1881 dialog.set_title(title);
1887 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1889 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1890 dialog.set_title(title);
1896 App::dialog_yes_no(const std::string &title, const std::string &message)
1901 true // use_separator
1903 Gtk::Label label(message);
1906 dialog.get_vbox()->pack_start(label);
1907 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1908 dialog.add_button(Gtk::StockID("gtk-no"),0);
1910 return dialog.run();
1914 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1919 true // use_separator
1921 Gtk::Label label(message);
1924 dialog.get_vbox()->pack_start(label);
1925 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1926 dialog.add_button(Gtk::StockID("gtk-no"),0);
1927 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1929 return dialog.run();
1933 App::dialog_not_implemented()
1935 Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1936 dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
1941 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1946 true // use_separator
1948 Gtk::Label label(message);
1950 dialog.get_vbox()->pack_start(label);
1953 entry.set_text(text);
1955 entry.set_activates_default(true);
1956 dialog.get_vbox()->pack_start(entry);
1958 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1959 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1960 dialog.set_default_response(Gtk::RESPONSE_OK);
1961 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1964 if(dialog.run()!=Gtk::RESPONSE_OK)
1967 text=entry.get_text();
1976 App::open(std::string filename)
1978 return open_as(filename,filename);
1981 // this is called from autorecover.cpp:
1982 // App::open_as(get_shadow_file_name(filename),filename)
1983 // other than that, 'filename' and 'as' are the same
1985 App::open_as(std::string filename,std::string as)
1988 char long_name[1024];
1989 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1995 OneMoment one_moment;
1997 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1998 if(canvas && get_instance(canvas))
2000 get_instance(canvas)->find_canvas_view(canvas)->present();
2001 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2004 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2006 add_recent_file(as);
2008 handle<Instance> instance(Instance::create(canvas));
2011 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2015 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)")))
2016 instance->dialog_cvs_update();
2020 dialog_error_blocking(_("Error"), x);
2025 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2029 _preferences.set_value("curr_path",dirname(as));
2038 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2039 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2041 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2043 canvas->rend_desc().set_frame_rate(24.0);
2044 canvas->rend_desc().set_time_start(0.0);
2045 canvas->rend_desc().set_time_end(00.0);
2046 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2047 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2048 canvas->rend_desc().set_tl(Vector(-4,2.25));
2049 canvas->rend_desc().set_br(Vector(4,-2.25));
2050 canvas->rend_desc().set_w(480);
2051 canvas->rend_desc().set_h(270);
2052 canvas->rend_desc().set_antialias(1);
2053 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2054 canvas->set_file_name(file_name);
2056 Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2062 string filename="*.sif";
2064 while(dialog_open_file("Open", filename))
2066 // If the filename still has wildcards, then we should
2067 // continue looking for the file we want
2068 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2074 get_ui_interface()->error(_("Unable to open file"));
2079 App::set_selected_instance(etl::loose_handle<Instance> instance)
2081 /* if(get_selected_instance()==instance)
2083 selected_instance=instance;
2084 signal_instance_selected()(instance);
2090 selected_instance=instance;
2091 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2095 instance->focus(instance->get_canvas());
2098 set_selected_canvas_view(0);
2100 signal_instance_selected()(instance);
2104 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2106 selected_canvas_view=canvas_view;
2107 signal_canvas_view_focus()(selected_canvas_view);
2110 selected_instance=canvas_view->get_instance();
2111 signal_instance_selected()(canvas_view->get_instance());
2114 if(get_selected_canvas_view()==canvas_view)
2116 signal_canvas_view_focus()(selected_canvas_view);
2117 signal_instance_selected()(canvas_view->get_instance());
2120 selected_canvas_view=canvas_view;
2121 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2122 set_selected_instance(canvas_view->get_instance());
2123 signal_canvas_view_focus()(selected_canvas_view);
2127 etl::loose_handle<Instance>
2128 App::get_instance(Canvas::Handle canvas)
2130 if(!canvas) return 0;
2131 canvas=canvas->get_root();
2133 std::list<etl::handle<Instance> >::iterator iter;
2134 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2136 if((*iter)->get_canvas()==canvas)
2145 (new class About())->show();
2151 if(selected_instance)
2152 selected_instance->undo();
2158 if(selected_instance)
2159 selected_instance->redo();
2163 studio::App::get_base_path()
2165 return app_base_path_;