1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
39 #include <gtkmm/fileselection.h>
40 #include <gtkmm/dialog.h>
41 #include <gtkmm/messagedialog.h>
42 #include <gtkmm/label.h>
43 #include <gtkmm/stock.h>
44 #include <gtkmm/stockitem.h>
45 #include <gtkmm/iconsource.h>
46 #include <gtkmm/inputdialog.h>
47 #include <gtkmm/accelmap.h>
48 #include <gtkmm/uimanager.h>
52 #include <synfig/loadcanvas.h>
57 #include "canvasview.h"
58 #include "dialog_setup.h"
59 #include "dialog_gradient.h"
60 #include "dialog_color.h"
63 #include "onemoment.h"
65 #include "dockmanager.h"
67 #include "state_eyedrop.h"
68 #include "state_normal.h"
69 #include "state_draw.h"
70 #include "state_fill.h"
71 #include "state_bline.h"
72 #include "state_polygon.h"
73 #include "state_sketch.h"
74 #include "state_gradient.h"
75 #include "state_circle.h"
76 #include "state_rectangle.h"
77 #include "state_smoothmove.h"
78 #include "state_scale.h"
79 #include "state_width.h"
80 #include "state_rotate.h"
81 #include "state_zoom.h"
83 #include "devicetracker.h"
84 #include "dialog_tooloptions.h"
86 #include "autorecover.h"
88 #include <synfigapp/settings.h>
89 #include "dock_history.h"
90 #include "dock_canvases.h"
91 #include "dock_keyframes.h"
92 #include "dock_layers.h"
93 #include "dock_params.h"
94 #include "dock_metadata.h"
95 #include "dock_children.h"
96 #include "dock_info.h"
97 #include "dock_navigator.h"
98 #include "dock_layergroups.h"
99 #include "dock_timetrack.h"
100 #include "dock_curves.h"
102 #include "mod_palette/mod_palette.h"
103 #include "mod_mirror/mod_mirror.h"
105 #include <sys/stat.h>
111 #include "statemanager.h"
118 #define _WIN32_WINNT 0x0500
121 #include <gtkmm/accelmap.h>
122 #include <gtkmm/filechooser.h>
123 #include <gtkmm/filechooserdialog.h>
127 /* === U S I N G =========================================================== */
131 using namespace synfig;
132 using namespace studio;
134 /* === M A C R O S ========================================================= */
136 #ifndef SYNFIG_USER_APP_DIR
138 #define SYNFIG_USER_APP_DIR "Library/Synfig"
139 #elif defined(_WIN32)
140 #define SYNFIG_USER_APP_DIR "Synfig"
142 #define SYNFIG_USER_APP_DIR ".synfig"
147 #define DPM2DPI(x) (float(x)/39.3700787402f)
148 #define DPI2DPM(x) (float(x)*39.3700787402f)
154 # define IMAGE_DIR "share\\pixmaps"
159 # define IMAGE_DIR "/usr/local/share/pixmaps"
163 # define IMAGE_EXT "tif"
166 #include <synfigapp/main.h>
168 /* === S I G N A L S ======================================================= */
170 static sigc::signal<void> signal_present_all_;
172 App::signal_present_all() { return signal_present_all_; }
174 static sigc::signal<void> signal_recent_files_changed_;
176 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
178 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
179 sigc::signal<void,etl::loose_handle<CanvasView> >&
180 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
182 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
183 sigc::signal<void,etl::handle<Instance> >&
184 App::signal_instance_selected() { return signal_instance_selected_; }
186 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
187 sigc::signal<void,etl::handle<Instance> >&
188 App::signal_instance_created() { return signal_instance_created_; }
190 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
191 sigc::signal<void,etl::handle<Instance> >&
192 App::signal_instance_deleted() { return signal_instance_deleted_; }
194 /* === G L O B A L S ======================================================= */
196 static std::list<std::string> recent_files;
197 const std::list<std::string>& App::get_recent_files() { return recent_files; }
199 int App::Busy::count;
200 bool App::shutdown_in_progress;
202 synfig::Gamma App::gamma;
204 Glib::RefPtr<studio::UIManager> App::ui_manager_;
206 synfig::Distance::System App::distance_system;
208 studio::Dialog_Setup* App::dialog_setup;
210 etl::handle< studio::ModPalette > mod_palette_;
211 //studio::Dialog_Palette* App::dialog_palette;
213 std::list<etl::handle<Instance> > App::instance_list;
215 static etl::handle<synfigapp::UIInterface> ui_interface_;
216 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
218 etl::handle<Instance> App::selected_instance;
219 etl::handle<CanvasView> App::selected_canvas_view;
221 studio::Toolbox *studio::App::toolbox=NULL;
223 studio::AutoRecover *studio::App::auto_recover=NULL;
225 studio::IPC *ipc=NULL;
227 studio::DockManager* studio::App::dock_manager=0;
229 studio::DeviceTracker* studio::App::device_tracker=0;
231 studio::Dialog_Gradient* studio::App::dialog_gradient;
233 studio::Dialog_Color* studio::App::dialog_color;
235 Gtk::InputDialog* studio::App::dialog_input;
237 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
239 studio::Dock_History* dock_history;
240 studio::Dock_Canvases* dock_canvases;
241 studio::Dock_Keyframes* dock_keyframes;
242 studio::Dock_Layers* dock_layers;
243 studio::Dock_Params* dock_params;
244 studio::Dock_MetaData* dock_meta_data;
245 studio::Dock_Children* dock_children;
246 studio::Dock_Info* dock_info;
247 studio::Dock_LayerGroups* dock_layer_groups;
248 studio::Dock_Navigator* dock_navigator;
249 studio::Dock_Timetrack* dock_timetrack;
250 studio::Dock_Curves* dock_curves;
252 std::list< etl::handle< studio::Module > > module_list_;
254 bool studio::App::use_colorspace_gamma=true;
256 static int max_recent_files_=25;
257 int studio::App::get_max_recent_files() { return max_recent_files_; }
258 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
260 static synfig::String app_base_path_;
263 }; // END of namespace studio
264 studio::StateManager* state_manager;
269 class GlobalUIInterface : public synfigapp::UIInterface
273 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
278 true // use_separator
280 Gtk::Label label(message);
283 dialog.get_vbox()->pack_start(label);
284 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
285 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
287 dialog.set_default_response(dflt);
289 return (Response)dialog.run();
291 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
296 true // use_separator
298 Gtk::Label label(message);
301 dialog.get_vbox()->pack_start(label);
302 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
303 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
304 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
306 dialog.set_default_response(dflt);
308 return (Response)dialog.run();
310 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
315 true // use_separator
317 Gtk::Label label(message);
320 dialog.get_vbox()->pack_start(label);
321 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
322 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
324 dialog.set_default_response(dflt);
326 return (Response)dialog.run();
330 task(const std::string &task)
332 std::cerr<<task<<std::endl;
333 while(studio::App::events_pending())studio::App::iteration(false);
338 error(const std::string &err)
340 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
347 warning(const std::string &err)
349 std::cerr<<"warning: "<<err<<std::endl;
350 while(studio::App::events_pending())studio::App::iteration(false);
355 amount_complete(int /*current*/, int /*total*/)
357 while(studio::App::events_pending())studio::App::iteration(false);
362 /* === P R O C E D U R E S ================================================= */
364 typedef unsigned char U8;
365 typedef unsigned short U16;
366 typedef unsigned long U32;
376 static inline U32 hash_U32(U32 i)
378 i=i*1664525+1013904223;
379 i=i*1664525+1013904223;
380 i=i*1664525+1013904223;
385 static const int endian_fix_table[8] = { 3, 2, 1, 0, 7, 6, 5, 4 } ;
386 #define endian_fix(x) (endian_fix_table[x])
388 #define endian_fix(x) (x)
391 int v_unwind_key(V_KeyUnwound* unwound, const char* key)
394 unwound->element.serial=0;
395 unwound->element.checksum=0;
403 case '0': data=0; break;
404 case '1': data=1; break;
405 case '2': data=2; break;
406 case '3': data=3; break;
407 case '4': data=4; break;
408 case '5': data=5; break;
409 case '6': data=6; break;
410 case '7': data=7; break;
411 case '8': data=8; break;
412 case '9': data=9; break;
413 case 'a': case 'A': data=10; break;
414 case 'b': case 'B': data=11; break;
415 case 'c': case 'C': data=12; break;
416 case 'd': case 'D': data=13; break;
417 case 'e': case 'E': data=14; break;
418 case 'f': case 'F': data=15; break;
419 default: return 0; break;
422 unwound->element.checksum|=(((U32)data&3)<<bit);
423 unwound->element.serial|=(((U32)(data>>2)&3)<<bit);
428 int v_key_check(const char* key, U32* serial, U32 appid)
430 V_KeyUnwound unwound_key;
431 U32 appid_mask_a=hash_U32(appid);
432 U32 appid_mask_b=hash_U32(appid_mask_a);
434 if(!v_unwind_key(&unwound_key, key))
436 // Invalid characters in key
441 // Undo obfuscation pass
443 U32 next=hash_U32(unwound_key.raw[endian_fix(7)]);
448 unwound_key.raw[endian_fix(i)]^=(next>>24);
452 unwound_key.element.serial^=appid_mask_a;
453 unwound_key.element.checksum^=appid_mask_b;
455 *serial=unwound_key.element.serial;
457 return unwound_key.element.checksum==hash_U32(unwound_key.element.serial);
462 # ifdef LICENSE_KEY_REQUIRED
463 int check_license(String basedir)
465 int check_license(String /*basedir*/)
468 int check_license(String /*basedir*/)
471 #ifdef LICENSE_KEY_REQUIRED
476 license_file="/usr/local/etc/.synfiglicense";
478 license_file=basedir+"\\etc\\.synfiglicense";
482 key=Glib::file_get_contents(license_file);
483 } catch (Glib::FileError) { }
485 if(!v_key_check(key.c_str(),&serial,0xdeadbeef))
487 while(!v_key_check(key.c_str(),&serial,0xdeadbeef))
491 if(!App::dialog_entry(
492 _("Synfig Studio Authentication"),
493 _("Please enter your license key below. You will not\nbe able to use this software without a valid license key."),
496 throw String("No License");
499 FILE* file=fopen(license_file.c_str(),"w");
502 fprintf(file,"%s",key.c_str());
506 synfig::error("Unable to save license key!");
508 synfig::info("License Authenticated -- Serial #%05d",serial);
517 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
519 action_group_list.push_back(action_group);
520 Gtk::UIManager::insert_action_group(action_group, pos);
524 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
526 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
527 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
528 if(*iter==action_group)
530 action_group_list.erase(iter);
531 Gtk::UIManager::remove_action_group(action_group);
534 synfig::error("Unable to find action group");
538 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
540 ui_manager->insert_action_group(group,0);
543 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
544 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
547 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
550 if(*iter && (*iter)->get_name()!="menus")
552 synfig::info("Removing action group "+(*iter)->get_name());
553 ui_manager->remove_action_group(*iter);
557 ui_manager->insert_action_group(group,0);
560 for(;!prev_groups.empty();prev_groups.pop_front())
562 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
563 ui_manager->insert_action_group(prev_groups.front(),1);
568 class Preferences : public synfigapp::Settings
571 virtual bool get_value(const synfig::String& key, synfig::String& value)const
575 value=strprintf("%f %f %f %f",
576 App::gamma.get_gamma_r(),
577 App::gamma.get_gamma_g(),
578 App::gamma.get_gamma_b(),
579 App::gamma.get_black_level()
583 if(key=="time_format")
585 value=strprintf("%i",App::get_time_format());
588 if(key=="file_history.size")
590 value=strprintf("%i",App::get_max_recent_files());
593 if(key=="use_colorspace_gamma")
595 value=strprintf("%i",(int)App::use_colorspace_gamma);
598 if(key=="distance_system")
600 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
603 if(key=="auto_recover_backup_interval")
605 value=strprintf("%i",App::auto_recover->get_timeout());
609 return synfigapp::Settings::get_value(key,value);
612 virtual bool set_value(const synfig::String& key,const synfig::String& value)
618 strscanf(value,"%f %f %f %f",
625 App::gamma.set_all(r,g,b,blk);
629 if(key=="time_format")
631 int i(atoi(value.c_str()));
632 App::set_time_format(static_cast<synfig::Time::Format>(i));
635 if(key=="auto_recover_backup_interval")
637 int i(atoi(value.c_str()));
638 App::auto_recover->set_timeout(i);
641 if(key=="file_history.size")
643 int i(atoi(value.c_str()));
644 App::set_max_recent_files(i);
647 if(key=="use_colorspace_gamma")
649 int i(atoi(value.c_str()));
650 App::use_colorspace_gamma=i;
653 if(key=="distance_system")
655 App::distance_system=Distance::ident_system(value);;
659 return synfigapp::Settings::set_value(key,value);
662 virtual KeyList get_key_list()const
664 KeyList ret(synfigapp::Settings::get_key_list());
665 ret.push_back("gamma");
666 ret.push_back("time_format");
667 ret.push_back("distance_system");
668 ret.push_back("file_history.size");
669 ret.push_back("use_colorspace_gamma");
670 ret.push_back("auto_recover_backup_interval");
675 static ::Preferences _preferences;
680 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
682 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
684 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
686 menus_action_group->add( Gtk::Action::create("menu-file", "_File") );
687 menus_action_group->add( Gtk::Action::create("menu-edit", "_Edit") );
688 menus_action_group->add( Gtk::Action::create("menu-view", "_View") );
689 menus_action_group->add( Gtk::Action::create("menu-canvas", "_Canvas") );
690 menus_action_group->add( Gtk::Action::create("menu-layer", "_Layer") );
691 menus_action_group->add( Gtk::Action::create("menu-duck-mask", "Show/Hide Ducks") );
692 menus_action_group->add( Gtk::Action::create("menu-preview-quality", "Preview Quality") );
693 menus_action_group->add( Gtk::Action::create("menu-layer-new", "New Layer") );
694 menus_action_group->add( Gtk::Action::create("menu-keyframe", "Keyframe") );
695 menus_action_group->add( Gtk::Action::create("menu-group", "Group") );
696 menus_action_group->add( Gtk::Action::create("menu-state", "State") );
697 menus_action_group->add( Gtk::Action::create("menu-toolbox", "Toolbox") );
699 // Add the synfigapp actions...
700 synfigapp::Action::Book::iterator iter;
701 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
703 actions_action_group->add(Gtk::Action::create(
704 "action-"+iter->second.name,
705 get_action_stock_id(iter->second),
706 iter->second.local_name,iter->second.local_name
710 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
711 #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); }
712 #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); }
714 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
715 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
716 DEFINE_ACTION("open", Gtk::Stock::OPEN);
717 DEFINE_ACTION("save", Gtk::Stock::SAVE);
718 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
719 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
720 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
721 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
722 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
723 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
724 DEFINE_ACTION("import", _("Import"));
725 DEFINE_ACTION("render", _("Render"));
726 DEFINE_ACTION("preview", _("Preview"));
727 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
728 DEFINE_ACTION("sound", _("Sound File"));
729 DEFINE_ACTION("options", _("Options"));
730 DEFINE_ACTION("close", _("Close"));
733 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
734 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
735 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
736 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
737 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
738 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
739 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
740 DEFINE_ACTION("properties", _("Properties"));
742 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
743 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
744 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
745 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
746 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
747 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
748 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
749 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
750 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
751 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
752 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
753 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
754 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
755 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
756 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
757 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
758 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
759 DEFINE_ACTION("play", _("Play"));
760 // DEFINE_ACTION("pause", _("Pause"));
761 DEFINE_ACTION("stop", _("Stop"));
762 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
763 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
764 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
765 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
766 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
767 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
768 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
769 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
770 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
771 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
772 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
773 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
774 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
775 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
776 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
777 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
778 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
779 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
780 DEFINE_ACTION("seek-end", _("Seek to End"));
782 DEFINE_ACTION("action-group_add", _("Add group"));
784 DEFINE_ACTION("canvas-new", _("New Canvas"));
786 DEFINE_ACTION("amount-inc", _("Increase Amount"));
787 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
792 // Set up synfigapp actions
794 synfigapp::Action::Book::iterator iter;
796 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
798 Gtk::StockID stock_id;
800 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
802 //Gtk::Image* image(manage(new Gtk::Image()));
803 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
804 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
805 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
806 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
807 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
808 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
809 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
810 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
811 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
812 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
814 actions_action_group->add(Gtk::Action::create(
815 "action-"+iter->second.name,
817 iter->second.local_name,iter->second.local_name
825 Glib::ustring ui_info =
827 " <popup name='menu-toolbox' action='menu-toolbox'>"
828 " <menu action='menu-file'>"
831 " <popup name='menu-main' action='menu-main'>"
832 " <menu action='menu-file'>"
833 " <menuitem action='save' />"
834 " <menuitem action='save-as' />"
835 " <menuitem action='revert' />"
836 " <separator name='bleh01'/>"
837 " <menuitem action='cvs-add' />"
838 " <menuitem action='cvs-update' />"
839 " <menuitem action='cvs-commit' />"
840 " <menuitem action='cvs-revert' />"
841 " <separator name='bleh02'/>"
842 " <menuitem action='import' />"
843 " <separator name='bleh03'/>"
844 " <menuitem action='render' />"
845 " <menuitem action='preview' />"
846 " <menuitem action='sound' />"
847 " <separator name='bleh04'/>"
848 " <menuitem action='options' />"
849 " <menuitem action='close' />"
851 " <menu action='menu-edit'>"
852 " <menuitem action='undo'/>"
853 " <menuitem action='redo'/>"
854 " <separator name='bleh05'/>"
855 " <menuitem action='cut'/>"
856 " <menuitem action='copy'/>"
857 " <menuitem action='paste'/>"
858 " <separator name='bleh06'/>"
859 " <menuitem action='select-all-ducks'/>"
860 " <menuitem action='unselect-all-layers'/>"
861 " <separator name='bleh07'/>"
862 " <menuitem action='properties'/>"
864 " <menu action='menu-view'>"
865 " <menu action='menu-duck-mask'>"
866 " <menuitem action='mask-position-ducks' />"
867 " <menuitem action='mask-vertex-ducks' />"
868 " <menuitem action='mask-tangent-ducks' />"
869 " <menuitem action='mask-radius-ducks' />"
870 " <menuitem action='mask-width-ducks' />"
871 " <menuitem action='mask-angle-ducks' />"
873 " <menu action='menu-preview-quality'>"
874 " <menuitem action='quality-00' />"
875 " <menuitem action='quality-01' />"
876 " <menuitem action='quality-02' />"
877 " <menuitem action='quality-03' />"
878 " <menuitem action='quality-04' />"
879 " <menuitem action='quality-05' />"
880 " <menuitem action='quality-06' />"
881 " <menuitem action='quality-07' />"
882 " <menuitem action='quality-08' />"
883 " <menuitem action='quality-09' />"
884 " <menuitem action='quality-10' />"
886 " <separator name='bleh08'/>"
887 " <menuitem action='play'/>"
888 //" <menuitem action='pause'/>"
889 " <menuitem action='stop'/>"
890 " <menuitem action='dialog-flipbook'/>"
891 " <separator name='bleh09'/>"
892 " <menuitem action='toggle-grid-show'/>"
893 " <menuitem action='toggle-grid-snap'/>"
894 " <menuitem action='toggle-guide-show'/>"
895 " <menuitem action='toggle-low-res'/>"
896 " <menuitem action='toggle-onion-skin'/>"
897 " <separator name='bleh10'/>"
898 " <menuitem action='canvas-zoom-in'/>"
899 " <menuitem action='canvas-zoom-out'/>"
900 " <menuitem action='canvas-zoom-fit'/>"
901 " <menuitem action='canvas-zoom-100'/>"
902 " <separator name='bleh11'/>"
903 " <menuitem action='time-zoom-in'/>"
904 " <menuitem action='time-zoom-out'/>"
905 " <separator name='bleh12'/>"
906 " <menuitem action='jump-next-keyframe'/>"
907 " <menuitem action='jump-prev-keyframe'/>"
908 " <menuitem action='seek-next-frame'/>"
909 " <menuitem action='seek-prev-frame'/>"
910 " <menuitem action='seek-next-second'/>"
911 " <menuitem action='seek-prev-second'/>"
912 " <menuitem action='seek-begin'/>"
913 " <menuitem action='seek-end'/>"
915 " <menu action='menu-canvas'>"
916 " <menuitem action='canvas-new'/>"
918 " <menu name='menu-state' action='menu-state'>"
920 " <menu action='menu-group'>"
921 " <menuitem action='action-group_add'/>"
923 " <menu action='menu-layer'>"
924 //" <menuitem action='cut'/>"
925 //" <menuitem action='copy'/>"
926 //" <menuitem action='paste'/>"
927 //" <separator name='bleh06'/>"
928 " <menu action='menu-layer-new'></menu>"
929 " <menuitem action='amount-inc'/>"
930 " <menuitem action='amount-dec'/>"
932 " <menu action='menu-keyframe'>"
933 " <menuitem action='keyframe-properties'/>"
940 " <menubar name='MenuBar'>"
941 " <menu action='MenuFile'>"
942 " <menuitem action='New'/>"
943 " <menuitem action='Open'/>"
945 " <menuitem action='Quit'/>"
947 " <menu action='MenuEdit'>"
948 " <menuitem action='Cut'/>"
949 " <menuitem action='Copy'/>"
950 " <menuitem action='Paste'/>"
953 " <toolbar name='ToolBar'>"
954 " <toolitem action='Open'/>"
955 " <toolitem action='Quit'/>"
961 actions_action_group->set_sensitive(false);
962 App::ui_manager()->set_add_tearoffs(true);
963 App::ui_manager()->insert_action_group(menus_action_group,1);
964 App::ui_manager()->insert_action_group(actions_action_group,1);
965 App::ui_manager()->add_ui_from_string(ui_info);
967 //App::ui_manager()->get_accel_group()->unlock();
969 catch(const Glib::Error& ex)
971 synfig::error("building menus and toolbars failed: " + ex.what());
974 // Add default keyboard accelerators
975 #define ACCEL(path,accel) \
977 Gtk::AccelKey accel_key(accel,path); \
978 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
981 #define ACCEL2(accel) \
983 Gtk::AccelKey accel_key(accel); \
984 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
987 ACCEL("<Actions>//select-all-ducks","<Control>a");
988 ACCEL("<Actions>//unselect-all-layers","<Control>d");
989 ACCEL("<Actions>//render","F9");
990 ACCEL("<Actions>//preview","F11");
991 ACCEL("<Actions>//properties","F8");
992 ACCEL("<Actions>//options","F12");
993 ACCEL("<Actions>//import","<control>i");
994 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
995 ACCEL("<Actions>//toggle-grid-show","<Control>g");
996 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
997 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
998 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
999 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1000 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1001 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1002 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1003 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1005 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1006 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1008 ACCEL("<Actions>//quality-01","<Control>1");
1009 ACCEL("<Actions>//quality-02","<Control>2");
1010 ACCEL("<Actions>//quality-03","<Control>3");
1011 ACCEL("<Actions>//quality-04","<Control>4");
1012 ACCEL("<Actions>//quality-05","<Control>5");
1013 ACCEL("<Actions>//quality-06","<Control>6");
1014 ACCEL("<Actions>//quality-07","<Control>7");
1015 ACCEL("<Actions>//quality-08","<Control>8");
1016 ACCEL("<Actions>//quality-09","<Control>9");
1017 ACCEL("<Actions>//quality-10","<Control>0");
1018 ACCEL("<Actions>//undo","<Control>z");
1019 ACCEL("<Actions>//redo","<Control>r");
1020 ACCEL("<Actions>//action-layer_remove","Delete");
1022 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1023 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1024 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1025 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1026 ACCEL("<Actions>//time-zoom-in","+");
1027 ACCEL("<Actions>//time-zoom-out","_");
1029 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1030 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1032 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1033 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1034 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1035 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1036 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1037 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1038 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1039 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1040 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1041 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1042 ACCEL2(Gtk::AccelKey('o',Gdk::CONTROL_MASK,"<Actions>//toggle-onion-skin"));
1043 ACCEL("<Actions>//play", "<Control>p");
1044 ACCEL("<Actions>//seek-begin","Home");
1045 ACCEL("<Actions>//seek-end","End");
1047 ACCEL("<Actions>//state-normal", "<Mod1>a");
1048 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1049 ACCEL("<Actions>//state-scale", "<Mod1>d");
1050 ACCEL("<Actions>//state-rotate", "<Mod1>s");
1052 ACCEL("<Actions>//state-bline", "<Mod1>b");
1053 ACCEL("<Actions>//state-circle", "<Mod1>c");
1054 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1055 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1057 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1058 ACCEL("<Actions>//state-fill", "<Mod1>f");
1059 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1060 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1062 ACCEL("<Actions>//state-draw", "<Mod1>w");
1063 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1064 ACCEL("<Actions>//state-width", "<Mod1>t");
1065 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1067 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1073 #define mkdir(x,y) mkdir(x)
1076 /* === M E T H O D S ======================================================= */
1078 App::App(int *argc, char ***argv):
1079 Gtk::Main(argc,argv),
1080 IconControler(etl::dirname((*argv)[0]))
1082 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1085 serial_=check_license(app_base_path_);
1088 ui_interface_=new GlobalUIInterface();
1092 Glib::thread_init();
1094 distance_system=Distance::SYSTEM_UNITS;
1096 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1099 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1103 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1111 if(!SYNFIG_CHECK_VERSION())
1113 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1114 dialog_error_blocking("Synfig Studio",
1115 "This copy of Synfig Studio was compiled against a\n"
1116 "different version of libsynfig than what is currently\n"
1117 "installed. Synfig Studio will now abort. Try downloading\n"
1118 "the latest version from the Synfig website at\n"
1119 "http://www.synfig.com/ "
1124 catch(synfig::SoftwareExpired)
1126 cerr<<"FATAL: Software Expired"<<endl;
1127 dialog_error_blocking("Synfig Studio",
1128 "This copy of Synfig Studio has expired.\n"
1129 "Please erase this copy, or download and\n"
1130 "install the latest copy from the Synfig\n"
1131 "website at http://www.synfig.com/ ."
1135 Glib::set_application_name(_("Synfig Studio"));
1138 about_window.set_can_self_destruct(false);
1139 about_window.show();
1141 shutdown_in_progress=false;
1142 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1143 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1145 // Initialize the Synfig library
1146 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1149 get_ui_interface()->error("Failed to initialize synfig!");
1153 // add the preferences to the settings
1154 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1158 studio_init_cb.task("Init UI Manager...");
1159 App::ui_manager_=studio::UIManager::create();
1162 studio_init_cb.task("Init Dock Manager...");
1163 dock_manager=new studio::DockManager();
1165 studio_init_cb.task("Init State Manager...");
1166 state_manager=new StateManager();
1168 studio_init_cb.task("Init Toolbox...");
1169 toolbox=new studio::Toolbox();
1171 studio_init_cb.task("Init Tool Options...");
1172 dialog_tool_options=new studio::Dialog_ToolOptions();
1173 dock_manager->register_dockable(*dialog_tool_options);
1175 studio_init_cb.task("Init History...");
1176 dock_history=new studio::Dock_History();
1177 dock_manager->register_dockable(*dock_history);
1179 studio_init_cb.task("Init Canvases...");
1180 dock_canvases=new studio::Dock_Canvases();
1181 dock_manager->register_dockable(*dock_canvases);
1183 studio_init_cb.task("Init Keyframes...");
1184 dock_keyframes=new studio::Dock_Keyframes();
1185 dock_manager->register_dockable(*dock_keyframes);
1187 studio_init_cb.task("Init Layers...");
1188 dock_layers=new studio::Dock_Layers();
1189 dock_manager->register_dockable(*dock_layers);
1191 studio_init_cb.task("Init Params...");
1192 dock_params=new studio::Dock_Params();
1193 dock_manager->register_dockable(*dock_params);
1195 studio_init_cb.task("Init MetaData...");
1196 dock_meta_data=new studio::Dock_MetaData();
1197 dock_manager->register_dockable(*dock_meta_data);
1199 studio_init_cb.task("Init Children...");
1200 dock_children=new studio::Dock_Children();
1201 dock_manager->register_dockable(*dock_children);
1203 studio_init_cb.task("Init Info...");
1204 dock_info = new studio::Dock_Info();
1205 dock_manager->register_dockable(*dock_info);
1207 studio_init_cb.task("Init Navigator...");
1208 dock_navigator = new studio::Dock_Navigator();
1209 dock_manager->register_dockable(*dock_navigator);
1211 studio_init_cb.task("Init Timetrack...");
1212 dock_timetrack = new studio::Dock_Timetrack();
1213 dock_manager->register_dockable(*dock_timetrack);
1215 studio_init_cb.task("Init Curve Editor...");
1216 dock_curves = new studio::Dock_Curves();
1217 dock_manager->register_dockable(*dock_curves);
1219 studio_init_cb.task("Init Layer Groups...");
1220 dock_layer_groups = new studio::Dock_LayerGroups();
1221 dock_manager->register_dockable(*dock_layer_groups);
1224 studio_init_cb.task("Init Color Dialog...");
1225 dialog_color=new studio::Dialog_Color();
1227 studio_init_cb.task("Init Gradient Dialog...");
1228 dialog_gradient=new studio::Dialog_Gradient();
1230 studio_init_cb.task("Init DeviceTracker...");
1231 device_tracker=new studio::DeviceTracker();
1233 studio_init_cb.task("Init Tools...");
1234 state_manager->add_state(&state_normal);
1235 state_manager->add_state(&state_smooth_move);
1236 state_manager->add_state(&state_scale);
1237 state_manager->add_state(&state_rotate);
1239 state_manager->add_state(&state_bline);
1242 state_manager->add_state(&state_circle);
1243 state_manager->add_state(&state_rectangle);
1245 state_manager->add_state(&state_gradient);
1246 state_manager->add_state(&state_eyedrop);
1247 state_manager->add_state(&state_fill);
1249 state_manager->add_state(&state_zoom);
1251 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1252 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1253 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1255 // Enabled for now. Let's see whether they're good enough yet.
1256 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1257 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1259 // Disabled by default - it doesn't work properly?
1260 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1262 studio_init_cb.task("Init ModPalette...");
1263 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1265 studio_init_cb.task("Init ModMirror...");
1266 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1269 studio_init_cb.task("Init Setup Dialog...");
1270 dialog_setup=new studio::Dialog_Setup();
1272 studio_init_cb.task("Init Input Dialog...");
1273 dialog_input=new Gtk::InputDialog();
1274 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1275 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1277 studio_init_cb.task("Init auto recovery...");
1278 auto_recover=new AutoRecover();
1280 studio_init_cb.amount_complete(9250,10000);
1281 studio_init_cb.task("Loading Settings...");
1283 studio_init_cb.task("Checking auto-recover...");
1285 studio_init_cb.amount_complete(9900,10000);
1287 if(auto_recover->recovery_needed())
1289 about_window.hide();
1291 get_ui_interface()->yes_no(
1293 "Synfig Studio seems to have crashed\n"
1294 "before you could save all your files.\n"
1295 "Would you like to re-open those files\n"
1296 "and recover your unsaved changes?"
1297 )==synfigapp::UIInterface::RESPONSE_YES
1300 if(!auto_recover->recover())
1302 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1305 get_ui_interface()->error(
1306 _("Synfig Studio has attempted to recover\n"
1307 "from a previous crash. The files that it has\n"
1308 "recovered are NOT YET SAVED. It would be a good\n"
1309 "idea to review them and save them now.")
1312 about_window.show();
1315 // Look for any files given on the command line,
1316 // and load them if found.
1317 for(;*argc>=1;(*argc)--)
1318 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1320 studio_init_cb.task("Loading files...");
1321 about_window.hide();
1322 open((*argv)[*argc]);
1323 about_window.show();
1326 studio_init_cb.task("Done.");
1327 studio_init_cb.amount_complete(10000,10000);
1333 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1337 StateManager* App::get_state_manager() { return state_manager; }
1341 shutdown_in_progress=true;
1345 synfigapp::Main::settings().remove_domain("pref");
1347 selected_instance=0;
1349 // Unload all of the modules
1350 for(;!module_list_.empty();module_list_.pop_back());
1352 delete state_manager;
1356 delete auto_recover;
1360 // studio::App::iteration(false);
1364 // studio::App::iteration(false);
1366 // studio::App::iteration(false);
1368 delete dialog_setup;
1370 delete dialog_gradient;
1372 delete dialog_color;
1374 delete dialog_input;
1376 delete dock_manager;
1378 instance_list.clear();
1380 // studio::App::iteration(false);
1384 App::get_user_app_directory()
1386 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1390 App::get_config_file(const synfig::String& file)
1392 return Glib::build_filename(get_user_app_directory(),file);
1396 App::add_recent_file(const std::string &file_name)
1398 std::string filename(file_name);
1400 assert(!filename.empty());
1402 if(filename.empty())
1405 // Toss out any "hidden" files
1406 if(basename(filename)[0]=='.')
1409 // If we aren't an absolute path, turn outselves into one
1410 if(!is_absolute_path(filename))
1411 filename=absolute_path(filename);
1413 list<string>::iterator iter;
1414 // Check to see if the file is already on the list.
1415 // If it is, then remove it from the list
1416 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1419 recent_files.erase(iter);
1424 // Push the filename to the front of the list
1425 recent_files.push_front(filename);
1427 // Clean out the files at the end of the list.
1428 while(recent_files.size()>(unsigned)get_max_recent_files())
1429 recent_files.pop_back();
1431 signal_recent_files_changed_();
1436 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1439 App::get_time_format()
1441 return _App_time_format;
1445 App::set_time_format(synfig::Time::Format x)
1452 App::save_settings()
1457 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1458 setlocale(LC_NUMERIC, "C");
1460 std::string filename=get_config_file("accelrc");
1461 Gtk::AccelMap::save(filename);
1464 std::string filename=get_config_file("recentfiles");
1466 std::ofstream file(filename.c_str());
1470 synfig::warning("Unable to save %s",filename.c_str());
1474 list<string>::reverse_iterator iter;
1476 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1480 std::string filename=get_config_file("settings");
1481 synfigapp::Main::settings().save_to_file(filename);
1482 setlocale(LC_NUMERIC,old_locale);
1486 synfig::warning("Caught exception when attempting to save settings.");
1491 App::load_settings()
1496 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1497 setlocale(LC_NUMERIC, "C");
1499 std::string filename=get_config_file("accelrc");
1500 Gtk::AccelMap::load(filename);
1503 std::string filename=get_config_file("recentfiles");
1505 std::ifstream file(filename.c_str());
1509 std::string recent_file;
1510 getline(file,recent_file);
1511 if(!recent_file.empty())
1512 add_recent_file(recent_file);
1515 std::string filename=get_config_file("settings");
1516 if(!synfigapp::Main::settings().load_from_file(filename))
1518 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1519 //if(!synfigapp::Main::settings().load_from_file(filename))
1521 gamma.set_gamma(1.0/2.2);
1522 reset_initial_window_configuration();
1525 setlocale(LC_NUMERIC,old_locale);
1529 synfig::warning("Caught exception when attempting to load settings.");
1534 App::reset_initial_window_configuration()
1536 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1537 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1538 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1539 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1540 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1541 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1542 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1543 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1544 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1545 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1546 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1547 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1548 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1552 App::shutdown_request(GdkEventAny*)
1556 //return !shutdown_in_progress;
1562 if(shutdown_in_progress)return;
1565 get_ui_interface()->task("Quit Request");
1568 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1572 std::list<etl::handle<Instance> >::iterator iter;
1573 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1575 if(!(*iter)->safe_close())
1579 if((*iter)->synfigapp::Instance::get_action_count())
1581 handle<synfigapp::UIInterface> uim;
1582 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1584 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1585 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1587 case synfigapp::UIInterface::RESPONSE_NO:
1589 case synfigapp::UIInterface::RESPONSE_YES:
1592 case synfigapp::UIInterface::RESPONSE_CANCEL:
1601 if((*iter)->synfigapp::Instance::is_modified())
1603 handle<synfigapp::UIInterface> uim;
1604 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1606 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() );
1607 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1609 case synfigapp::UIInterface::RESPONSE_NO:
1611 case synfigapp::UIInterface::RESPONSE_YES:
1612 (*iter)->dialog_cvs_commit();
1614 case synfigapp::UIInterface::RESPONSE_CANCEL:
1623 // This next line causes things to crash for some reason
1627 shutdown_in_progress=true;
1629 instance_list.clear();
1631 while(studio::App::events_pending())studio::App::iteration(false);
1634 auto_recover->normal_shutdown();
1636 get_ui_interface()->task("Quit Request sent");
1642 dialog_setup->refresh();
1643 dialog_setup->show();
1646 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1647 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1650 //#define USE_WIN32_FILE_DIALOGS 1
1653 #ifdef USE_WIN32_FILE_DIALOGS
1654 static OPENFILENAME ofn={};
1658 #include <gdk/gdkwin32.h>
1662 App::dialog_open_file(const std::string &title, std::string &filename)
1664 #ifdef USE_WIN32_FILE_DIALOGS
1665 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1667 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1668 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1669 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1671 ofn.lStructSize=sizeof(OPENFILENAME);
1672 ofn.hwndOwner = hWnd;
1673 ofn.hInstance = hInstance;
1674 ofn.lpstrFilter = szFilter;
1675 // ofn.lpstrCustomFilter=NULL;
1676 // ofn.nMaxCustFilter=0;
1677 // ofn.nFilterIndex=0;
1678 // ofn.lpstrFile=NULL;
1679 ofn.nMaxFile=MAX_PATH;
1680 // ofn.lpstrFileTitle=NULL;
1681 // ofn.lpstrInitialDir=NULL;
1682 // ofn.lpstrTitle=NULL;
1683 ofn.Flags=OFN_HIDEREADONLY;
1684 // ofn.nFileOffset=0;
1685 // ofn.nFileExtension=0;
1686 ofn.lpstrDefExt=TEXT("sif");
1687 // ofn.lCustData = 0l;
1689 // ofn.lpTemplateName=NULL;
1691 CHAR szFilename[MAX_PATH];
1693 strcpy(szFilename,filename.c_str());
1694 strcpy(szTitle,title.c_str());
1696 ofn.lpstrFile=szFilename;
1697 ofn.lpstrFileTitle=szTitle;
1699 if(GetOpenFileName(&ofn))
1701 filename=szFilename;
1707 synfig::String prev_path;
1708 if(!_preferences.get_value("curr_path",prev_path))
1710 prev_path = absolute_path(prev_path);
1712 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1713 dialog->set_current_folder(prev_path);
1714 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1715 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1716 if(!filename.empty())
1717 if (is_absolute_path(filename))
1718 dialog->set_filename(filename);
1720 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1721 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1722 filename=dialog->get_filename();
1734 GtkWidget *fileselection;
1735 fileselection = gtk_file_selection_new(title.c_str());
1738 if(basename(filename)==filename)
1740 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1743 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1745 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1747 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1748 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1750 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1751 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1753 gtk_widget_show(fileselection);
1761 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1762 _preferences.set_value("curr_path",dirname(filename));
1766 gtk_widget_destroy(fileselection);
1769 gtk_widget_destroy(fileselection);
1776 App::dialog_save_file(const std::string &title, std::string &filename)
1778 #if USE_WIN32_FILE_DIALOGS
1779 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1781 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1782 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1783 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1785 ofn.lStructSize=sizeof(OPENFILENAME);
1786 ofn.hwndOwner = hWnd;
1787 ofn.hInstance = hInstance;
1788 ofn.lpstrFilter = szFilter;
1789 // ofn.lpstrCustomFilter=NULL;
1790 // ofn.nMaxCustFilter=0;
1791 // ofn.nFilterIndex=0;
1792 // ofn.lpstrFile=NULL;
1793 ofn.nMaxFile=MAX_PATH;
1794 // ofn.lpstrFileTitle=NULL;
1795 // ofn.lpstrInitialDir=NULL;
1796 // ofn.lpstrTitle=NULL;
1797 ofn.Flags=OFN_OVERWRITEPROMPT;
1798 // ofn.nFileOffset=0;
1799 // ofn.nFileExtension=0;
1800 ofn.lpstrDefExt=TEXT("sif");
1801 // ofn.lCustData = 0l;
1803 // ofn.lpTemplateName=NULL;
1805 CHAR szFilename[MAX_PATH];
1807 strcpy(szFilename,filename.c_str());
1808 strcpy(szTitle,title.c_str());
1810 ofn.lpstrFile=szFilename;
1811 ofn.lpstrFileTitle=szTitle;
1813 if(GetSaveFileName(&ofn))
1815 filename=szFilename;
1816 _preferences.set_value("curr_path",dirname(filename));
1821 synfig::String prev_path;
1822 if(!_preferences.get_value("curr_path",prev_path))
1824 prev_path = absolute_path(prev_path);
1826 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1827 dialog->set_current_folder(prev_path);
1828 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1829 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1830 if(!filename.empty())
1832 std::string full_path;
1833 if (is_absolute_path(filename))
1834 full_path = filename;
1836 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1837 // select the file if it exists
1838 dialog->set_filename(full_path);
1840 // if the file doesn't exist, put its name into the filename box
1842 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1843 dialog->set_current_name(basename(filename));
1845 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1846 filename=dialog->get_filename();
1848 _preferences.set_value("curr_path",dirname(filename));
1853 // return dialog_open_file(title, filename);
1858 App::dialog_error_blocking(const std::string &title, const std::string &message)
1860 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1861 dialog.set_title(title);
1867 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1869 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1870 dialog.set_title(title);
1876 App::dialog_yes_no(const std::string &title, const std::string &message)
1881 true // use_separator
1883 Gtk::Label label(message);
1886 dialog.get_vbox()->pack_start(label);
1887 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1888 dialog.add_button(Gtk::StockID("gtk-no"),0);
1890 return dialog.run();
1894 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1899 true // use_separator
1901 Gtk::Label label(message);
1904 dialog.get_vbox()->pack_start(label);
1905 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1906 dialog.add_button(Gtk::StockID("gtk-no"),0);
1907 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1909 return dialog.run();
1913 App::dialog_not_implemented()
1915 Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1916 dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
1921 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1926 true // use_separator
1928 Gtk::Label label(message);
1930 dialog.get_vbox()->pack_start(label);
1933 entry.set_text(text);
1935 entry.set_activates_default(true);
1936 dialog.get_vbox()->pack_start(entry);
1938 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1939 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1940 dialog.set_default_response(Gtk::RESPONSE_OK);
1941 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1944 if(dialog.run()!=Gtk::RESPONSE_OK)
1947 text=entry.get_text();
1956 App::open(std::string filename)
1958 return open_as(filename,filename);
1961 // this is called from autorecover.cpp:
1962 // App::open_as(get_shadow_file_name(filename),filename)
1963 // other than that, 'filename' and 'as' are the same
1965 App::open_as(std::string filename,std::string as)
1968 char long_name[1024];
1969 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1975 OneMoment one_moment;
1977 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1978 if(canvas && get_instance(canvas))
1980 get_instance(canvas)->find_canvas_view(canvas)->present();
1981 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1984 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1986 add_recent_file(as);
1988 handle<Instance> instance(Instance::create(canvas));
1991 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1995 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)")))
1996 instance->dialog_cvs_update();
2000 dialog_error_blocking(_("Error"), x);
2005 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2009 _preferences.set_value("curr_path",dirname(as));
2018 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2019 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2021 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2023 canvas->rend_desc().set_frame_rate(24.0);
2024 canvas->rend_desc().set_time_start(0.0);
2025 canvas->rend_desc().set_time_end(00.0);
2026 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2027 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2028 canvas->rend_desc().set_tl(Vector(-4,2.25));
2029 canvas->rend_desc().set_br(Vector(4,-2.25));
2030 canvas->rend_desc().set_w(480);
2031 canvas->rend_desc().set_h(270);
2032 canvas->rend_desc().set_antialias(1);
2033 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2034 canvas->set_file_name(file_name);
2036 Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2042 string filename="*.sif";
2044 while(dialog_open_file("Open", filename))
2046 // If the filename still has wildcards, then we should
2047 // continue looking for the file we want
2048 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2054 get_ui_interface()->error(_("Unable to open file"));
2059 App::set_selected_instance(etl::loose_handle<Instance> instance)
2061 /* if(get_selected_instance()==instance)
2063 selected_instance=instance;
2064 signal_instance_selected()(instance);
2070 selected_instance=instance;
2071 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2075 instance->focus(instance->get_canvas());
2078 set_selected_canvas_view(0);
2080 signal_instance_selected()(instance);
2084 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2086 selected_canvas_view=canvas_view;
2087 signal_canvas_view_focus()(selected_canvas_view);
2090 selected_instance=canvas_view->get_instance();
2091 signal_instance_selected()(canvas_view->get_instance());
2094 if(get_selected_canvas_view()==canvas_view)
2096 signal_canvas_view_focus()(selected_canvas_view);
2097 signal_instance_selected()(canvas_view->get_instance());
2100 selected_canvas_view=canvas_view;
2101 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2102 set_selected_instance(canvas_view->get_instance());
2103 signal_canvas_view_focus()(selected_canvas_view);
2107 etl::loose_handle<Instance>
2108 App::get_instance(Canvas::Handle canvas)
2110 if(!canvas) return 0;
2111 canvas=canvas->get_root();
2113 std::list<etl::handle<Instance> >::iterator iter;
2114 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2116 if((*iter)->get_canvas()==canvas)
2125 (new class About())->show();
2131 if(selected_instance)
2132 selected_instance->undo();
2138 if(selected_instance)
2139 selected_instance->redo();
2143 studio::App::get_base_path()
2145 return app_base_path_;