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>//seek-begin","Home");
1044 ACCEL("<Actions>//seek-end","End");
1046 ACCEL("<Actions>//state-normal", "<Mod1>a");
1047 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1048 ACCEL("<Actions>//state-scale", "<Mod1>d");
1049 ACCEL("<Actions>//state-rotate", "<Mod1>s");
1051 ACCEL("<Actions>//state-bline", "<Mod1>b");
1052 ACCEL("<Actions>//state-circle", "<Mod1>c");
1053 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1054 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1056 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1057 ACCEL("<Actions>//state-fill", "<Mod1>f");
1058 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1059 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1061 ACCEL("<Actions>//state-draw", "<Mod1>w");
1062 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1063 ACCEL("<Actions>//state-width", "<Mod1>t");
1064 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1066 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1072 #define mkdir(x,y) mkdir(x)
1075 /* === M E T H O D S ======================================================= */
1077 App::App(int *argc, char ***argv):
1078 Gtk::Main(argc,argv),
1079 IconControler(etl::dirname((*argv)[0]))
1081 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1084 serial_=check_license(app_base_path_);
1087 ui_interface_=new GlobalUIInterface();
1091 Glib::thread_init();
1093 distance_system=Distance::SYSTEM_UNITS;
1095 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1098 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1102 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1110 if(!SYNFIG_CHECK_VERSION())
1112 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1113 dialog_error_blocking("Synfig Studio",
1114 "This copy of Synfig Studio was compiled against a\n"
1115 "different version of libsynfig than what is currently\n"
1116 "installed. Synfig Studio will now abort. Try downloading\n"
1117 "the latest version from the Synfig website at\n"
1118 "http://www.synfig.com/ "
1123 catch(synfig::SoftwareExpired)
1125 cerr<<"FATAL: Software Expired"<<endl;
1126 dialog_error_blocking("Synfig Studio",
1127 "This copy of Synfig Studio has expired.\n"
1128 "Please erase this copy, or download and\n"
1129 "install the latest copy from the Synfig\n"
1130 "website at http://www.synfig.com/ ."
1134 Glib::set_application_name(_("Synfig Studio"));
1137 about_window.set_can_self_destruct(false);
1138 about_window.show();
1140 shutdown_in_progress=false;
1141 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1142 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1144 // Initialize the Synfig library
1145 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1148 get_ui_interface()->error("Failed to initialize synfig!");
1152 // add the preferences to the settings
1153 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1157 studio_init_cb.task("Init UI Manager...");
1158 App::ui_manager_=studio::UIManager::create();
1161 studio_init_cb.task("Init Dock Manager...");
1162 dock_manager=new studio::DockManager();
1164 studio_init_cb.task("Init State Manager...");
1165 state_manager=new StateManager();
1167 studio_init_cb.task("Init Toolbox...");
1168 toolbox=new studio::Toolbox();
1170 studio_init_cb.task("Init Tool Options...");
1171 dialog_tool_options=new studio::Dialog_ToolOptions();
1172 dock_manager->register_dockable(*dialog_tool_options);
1174 studio_init_cb.task("Init History...");
1175 dock_history=new studio::Dock_History();
1176 dock_manager->register_dockable(*dock_history);
1178 studio_init_cb.task("Init Canvases...");
1179 dock_canvases=new studio::Dock_Canvases();
1180 dock_manager->register_dockable(*dock_canvases);
1182 studio_init_cb.task("Init Keyframes...");
1183 dock_keyframes=new studio::Dock_Keyframes();
1184 dock_manager->register_dockable(*dock_keyframes);
1186 studio_init_cb.task("Init Layers...");
1187 dock_layers=new studio::Dock_Layers();
1188 dock_manager->register_dockable(*dock_layers);
1190 studio_init_cb.task("Init Params...");
1191 dock_params=new studio::Dock_Params();
1192 dock_manager->register_dockable(*dock_params);
1194 studio_init_cb.task("Init MetaData...");
1195 dock_meta_data=new studio::Dock_MetaData();
1196 dock_manager->register_dockable(*dock_meta_data);
1198 studio_init_cb.task("Init Children...");
1199 dock_children=new studio::Dock_Children();
1200 dock_manager->register_dockable(*dock_children);
1202 studio_init_cb.task("Init Info...");
1203 dock_info = new studio::Dock_Info();
1204 dock_manager->register_dockable(*dock_info);
1206 studio_init_cb.task("Init Navigator...");
1207 dock_navigator = new studio::Dock_Navigator();
1208 dock_manager->register_dockable(*dock_navigator);
1210 studio_init_cb.task("Init Timetrack...");
1211 dock_timetrack = new studio::Dock_Timetrack();
1212 dock_manager->register_dockable(*dock_timetrack);
1214 studio_init_cb.task("Init Curve Editor...");
1215 dock_curves = new studio::Dock_Curves();
1216 dock_manager->register_dockable(*dock_curves);
1218 studio_init_cb.task("Init Layer Groups...");
1219 dock_layer_groups = new studio::Dock_LayerGroups();
1220 dock_manager->register_dockable(*dock_layer_groups);
1223 studio_init_cb.task("Init Color Dialog...");
1224 dialog_color=new studio::Dialog_Color();
1226 studio_init_cb.task("Init Gradient Dialog...");
1227 dialog_gradient=new studio::Dialog_Gradient();
1229 studio_init_cb.task("Init DeviceTracker...");
1230 device_tracker=new studio::DeviceTracker();
1232 studio_init_cb.task("Init Tools...");
1233 state_manager->add_state(&state_normal);
1234 state_manager->add_state(&state_smooth_move);
1235 state_manager->add_state(&state_scale);
1236 state_manager->add_state(&state_rotate);
1238 state_manager->add_state(&state_bline);
1241 state_manager->add_state(&state_circle);
1242 state_manager->add_state(&state_rectangle);
1244 state_manager->add_state(&state_gradient);
1245 state_manager->add_state(&state_eyedrop);
1246 state_manager->add_state(&state_fill);
1248 state_manager->add_state(&state_zoom);
1250 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1251 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1252 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1254 // Enabled for now. Let's see whether they're good enough yet.
1255 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1256 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1258 // Disabled by default - it doesn't work properly?
1259 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1261 studio_init_cb.task("Init ModPalette...");
1262 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1264 studio_init_cb.task("Init ModMirror...");
1265 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1268 studio_init_cb.task("Init Setup Dialog...");
1269 dialog_setup=new studio::Dialog_Setup();
1271 studio_init_cb.task("Init Input Dialog...");
1272 dialog_input=new Gtk::InputDialog();
1273 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1274 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1276 studio_init_cb.task("Init auto recovery...");
1277 auto_recover=new AutoRecover();
1279 studio_init_cb.amount_complete(9250,10000);
1280 studio_init_cb.task("Loading Settings...");
1282 studio_init_cb.task("Checking auto-recover...");
1284 studio_init_cb.amount_complete(9900,10000);
1286 if(auto_recover->recovery_needed())
1288 about_window.hide();
1290 get_ui_interface()->yes_no(
1292 "Synfig Studio seems to have crashed\n"
1293 "before you could save all your files.\n"
1294 "Would you like to re-open those files\n"
1295 "and recover your unsaved changes?"
1296 )==synfigapp::UIInterface::RESPONSE_YES
1299 if(!auto_recover->recover())
1301 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1304 get_ui_interface()->error(
1305 _("Synfig Studio has attempted to recover\n"
1306 "from a previous crash. The files that it has\n"
1307 "recovered are NOT YET SAVED. It would be a good\n"
1308 "idea to review them and save them now.")
1311 about_window.show();
1314 // Look for any files given on the command line,
1315 // and load them if found.
1316 for(;*argc>=1;(*argc)--)
1317 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1319 studio_init_cb.task("Loading files...");
1320 about_window.hide();
1321 open((*argv)[*argc]);
1322 about_window.show();
1325 studio_init_cb.task("Done.");
1326 studio_init_cb.amount_complete(10000,10000);
1332 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1336 StateManager* App::get_state_manager() { return state_manager; }
1340 shutdown_in_progress=true;
1344 synfigapp::Main::settings().remove_domain("pref");
1346 selected_instance=0;
1348 // Unload all of the modules
1349 for(;!module_list_.empty();module_list_.pop_back());
1351 delete state_manager;
1355 delete auto_recover;
1359 // studio::App::iteration(false);
1363 // studio::App::iteration(false);
1365 // studio::App::iteration(false);
1367 delete dialog_setup;
1369 delete dialog_gradient;
1371 delete dialog_color;
1373 delete dialog_input;
1375 delete dock_manager;
1377 instance_list.clear();
1379 // studio::App::iteration(false);
1383 App::get_user_app_directory()
1385 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1389 App::get_config_file(const synfig::String& file)
1391 return Glib::build_filename(get_user_app_directory(),file);
1395 App::add_recent_file(const std::string &file_name)
1397 std::string filename(file_name);
1399 assert(!filename.empty());
1401 if(filename.empty())
1404 // Toss out any "hidden" files
1405 if(basename(filename)[0]=='.')
1408 // If we aren't an absolute path, turn outselves into one
1409 if(!is_absolute_path(filename))
1410 filename=absolute_path(filename);
1412 list<string>::iterator iter;
1413 // Check to see if the file is already on the list.
1414 // If it is, then remove it from the list
1415 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1418 recent_files.erase(iter);
1423 // Push the filename to the front of the list
1424 recent_files.push_front(filename);
1426 // Clean out the files at the end of the list.
1427 while(recent_files.size()>(unsigned)get_max_recent_files())
1428 recent_files.pop_back();
1430 signal_recent_files_changed_();
1435 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1438 App::get_time_format()
1440 return _App_time_format;
1444 App::set_time_format(synfig::Time::Format x)
1451 App::save_settings()
1456 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1457 setlocale(LC_NUMERIC, "C");
1459 std::string filename=get_config_file("accelrc");
1460 Gtk::AccelMap::save(filename);
1463 std::string filename=get_config_file("recentfiles");
1465 std::ofstream file(filename.c_str());
1469 synfig::warning("Unable to save %s",filename.c_str());
1473 list<string>::reverse_iterator iter;
1475 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1479 std::string filename=get_config_file("settings");
1480 synfigapp::Main::settings().save_to_file(filename);
1481 setlocale(LC_NUMERIC,old_locale);
1485 synfig::warning("Caught exception when attempting to save settings.");
1490 App::load_settings()
1495 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1496 setlocale(LC_NUMERIC, "C");
1498 std::string filename=get_config_file("accelrc");
1499 Gtk::AccelMap::load(filename);
1502 std::string filename=get_config_file("recentfiles");
1504 std::ifstream file(filename.c_str());
1508 std::string recent_file;
1509 getline(file,recent_file);
1510 if(!recent_file.empty())
1511 add_recent_file(recent_file);
1514 std::string filename=get_config_file("settings");
1515 if(!synfigapp::Main::settings().load_from_file(filename))
1517 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1518 //if(!synfigapp::Main::settings().load_from_file(filename))
1520 gamma.set_gamma(1.0/2.2);
1521 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1522 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1523 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1524 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1525 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1526 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1527 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1528 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1529 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1530 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1531 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1532 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1533 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1536 setlocale(LC_NUMERIC,old_locale);
1540 synfig::warning("Caught exception when attempting to load settings.");
1545 App::shutdown_request(GdkEventAny*)
1549 //return !shutdown_in_progress;
1555 if(shutdown_in_progress)return;
1558 get_ui_interface()->task("Quit Request");
1561 dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
1565 std::list<etl::handle<Instance> >::iterator iter;
1566 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1568 if(!(*iter)->safe_close())
1572 if((*iter)->synfigapp::Instance::get_action_count())
1574 handle<synfigapp::UIInterface> uim;
1575 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1577 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1578 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1580 case synfigapp::UIInterface::RESPONSE_NO:
1582 case synfigapp::UIInterface::RESPONSE_YES:
1585 case synfigapp::UIInterface::RESPONSE_CANCEL:
1594 if((*iter)->synfigapp::Instance::is_modified())
1596 handle<synfigapp::UIInterface> uim;
1597 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1599 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() );
1600 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1602 case synfigapp::UIInterface::RESPONSE_NO:
1604 case synfigapp::UIInterface::RESPONSE_YES:
1605 (*iter)->dialog_cvs_commit();
1607 case synfigapp::UIInterface::RESPONSE_CANCEL:
1616 // This next line causes things to crash for some reason
1620 shutdown_in_progress=true;
1622 instance_list.clear();
1624 while(studio::App::events_pending())studio::App::iteration(false);
1627 auto_recover->normal_shutdown();
1629 get_ui_interface()->task("Quit Request sent");
1635 dialog_setup->refresh();
1636 dialog_setup->show();
1639 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1640 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1643 //#define USE_WIN32_FILE_DIALOGS 1
1646 #ifdef USE_WIN32_FILE_DIALOGS
1647 static OPENFILENAME ofn={};
1651 #include <gdk/gdkwin32.h>
1655 App::dialog_open_file(const std::string &title, std::string &filename)
1657 #ifdef USE_WIN32_FILE_DIALOGS
1658 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1660 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1661 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1662 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1664 ofn.lStructSize=sizeof(OPENFILENAME);
1665 ofn.hwndOwner = hWnd;
1666 ofn.hInstance = hInstance;
1667 ofn.lpstrFilter = szFilter;
1668 // ofn.lpstrCustomFilter=NULL;
1669 // ofn.nMaxCustFilter=0;
1670 // ofn.nFilterIndex=0;
1671 // ofn.lpstrFile=NULL;
1672 ofn.nMaxFile=MAX_PATH;
1673 // ofn.lpstrFileTitle=NULL;
1674 // ofn.lpstrInitialDir=NULL;
1675 // ofn.lpstrTitle=NULL;
1676 ofn.Flags=OFN_HIDEREADONLY;
1677 // ofn.nFileOffset=0;
1678 // ofn.nFileExtension=0;
1679 ofn.lpstrDefExt=TEXT("sif");
1680 // ofn.lCustData = 0l;
1682 // ofn.lpTemplateName=NULL;
1684 CHAR szFilename[MAX_PATH];
1686 strcpy(szFilename,filename.c_str());
1687 strcpy(szTitle,title.c_str());
1689 ofn.lpstrFile=szFilename;
1690 ofn.lpstrFileTitle=szTitle;
1692 if(GetOpenFileName(&ofn))
1694 filename=szFilename;
1700 synfig::String prev_path;
1701 if(!_preferences.get_value("curr_path",prev_path))
1704 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1705 dialog->set_current_folder(prev_path);
1706 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1707 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1708 if(!filename.empty())
1709 dialog->set_filename(filename);
1710 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1711 filename=dialog->get_filename();
1723 GtkWidget *fileselection;
1724 fileselection = gtk_file_selection_new(title.c_str());
1727 if(basename(filename)==filename)
1729 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPERATOR).c_str());
1732 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1734 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1736 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1737 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1739 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1740 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1742 gtk_widget_show(fileselection);
1750 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1751 _preferences.set_value("curr_path",dirname(filename));
1755 gtk_widget_destroy(fileselection);
1758 gtk_widget_destroy(fileselection);
1765 App::dialog_save_file(const std::string &title, std::string &filename)
1767 #ifdef USE_WIN32_FILE_DIALOGS
1768 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1770 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1771 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1772 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1774 ofn.lStructSize=sizeof(OPENFILENAME);
1775 ofn.hwndOwner = hWnd;
1776 ofn.hInstance = hInstance;
1777 ofn.lpstrFilter = szFilter;
1778 // ofn.lpstrCustomFilter=NULL;
1779 // ofn.nMaxCustFilter=0;
1780 // ofn.nFilterIndex=0;
1781 // ofn.lpstrFile=NULL;
1782 ofn.nMaxFile=MAX_PATH;
1783 // ofn.lpstrFileTitle=NULL;
1784 // ofn.lpstrInitialDir=NULL;
1785 // ofn.lpstrTitle=NULL;
1786 ofn.Flags=OFN_OVERWRITEPROMPT;
1787 // ofn.nFileOffset=0;
1788 // ofn.nFileExtension=0;
1789 ofn.lpstrDefExt=TEXT("sif");
1790 // ofn.lCustData = 0l;
1792 // ofn.lpTemplateName=NULL;
1794 CHAR szFilename[MAX_PATH];
1796 strcpy(szFilename,filename.c_str());
1797 strcpy(szTitle,title.c_str());
1799 ofn.lpstrFile=szFilename;
1800 ofn.lpstrFileTitle=szTitle;
1802 if(GetSaveFileName(&ofn))
1804 filename=szFilename;
1809 synfig::String prev_path;
1810 if(!_preferences.get_value("curr_path",prev_path))
1813 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1814 dialog->set_current_folder(prev_path);
1815 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1816 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1817 if(!filename.empty())
1818 dialog->set_filename(filename);
1819 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1820 filename=dialog->get_filename();
1826 // return dialog_open_file(title, filename);
1831 App::dialog_saveas_file(const std::string &title, std::string &filename)
1833 #if USE_WIN32_FILE_DIALOGS
1834 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1836 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1837 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1838 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1840 ofn.lStructSize=sizeof(OPENFILENAME);
1841 ofn.hwndOwner = hWnd;
1842 ofn.hInstance = hInstance;
1843 ofn.lpstrFilter = szFilter;
1844 // ofn.lpstrCustomFilter=NULL;
1845 // ofn.nMaxCustFilter=0;
1846 // ofn.nFilterIndex=0;
1847 // ofn.lpstrFile=NULL;
1848 ofn.nMaxFile=MAX_PATH;
1849 // ofn.lpstrFileTitle=NULL;
1850 // ofn.lpstrInitialDir=NULL;
1851 // ofn.lpstrTitle=NULL;
1852 ofn.Flags=OFN_OVERWRITEPROMPT;
1853 // ofn.nFileOffset=0;
1854 // ofn.nFileExtension=0;
1855 ofn.lpstrDefExt=TEXT("sif");
1856 // ofn.lCustData = 0l;
1858 // ofn.lpTemplateName=NULL;
1860 CHAR szFilename[MAX_PATH];
1862 strcpy(szFilename,filename.c_str());
1863 strcpy(szTitle,title.c_str());
1865 ofn.lpstrFile=szFilename;
1866 ofn.lpstrFileTitle=szTitle;
1868 if(GetSaveFileName(&ofn))
1870 filename=szFilename;
1875 synfig::String prev_path;
1876 if(!_preferences.get_value("curr_path",prev_path))
1879 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1880 dialog->set_current_folder(prev_path);
1881 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1882 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1883 if(!filename.empty())
1884 dialog->set_filename(filename);
1885 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1886 filename=dialog->get_filename();
1892 // return dialog_open_file(title, filename);
1897 App::dialog_error_blocking(const std::string &title, const std::string &message)
1899 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1900 dialog.set_title(title);
1906 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1908 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1909 dialog.set_title(title);
1915 App::dialog_yes_no(const std::string &title, const std::string &message)
1920 true // use_separator
1922 Gtk::Label label(message);
1925 dialog.get_vbox()->pack_start(label);
1926 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1927 dialog.add_button(Gtk::StockID("gtk-no"),0);
1929 return dialog.run();
1933 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1938 true // use_separator
1940 Gtk::Label label(message);
1943 dialog.get_vbox()->pack_start(label);
1944 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1945 dialog.add_button(Gtk::StockID("gtk-no"),0);
1946 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1948 return dialog.run();
1952 App::dialog_not_implemented()
1954 Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1955 dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
1960 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1965 true // use_separator
1967 Gtk::Label label(message);
1969 dialog.get_vbox()->pack_start(label);
1972 entry.set_text(text);
1974 entry.set_activates_default(true);
1975 dialog.get_vbox()->pack_start(entry);
1977 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1978 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1979 dialog.set_default_response(Gtk::RESPONSE_OK);
1980 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1983 if(dialog.run()!=Gtk::RESPONSE_OK)
1986 text=entry.get_text();
1995 App::open(std::string filename)
1997 return open_as(filename,filename);
2001 App::open_as(std::string filename,std::string as)
2004 char long_name[1024];
2005 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2011 OneMoment one_moment;
2013 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2014 if(canvas && get_instance(canvas))
2016 get_instance(canvas)->find_canvas_view(canvas)->present();
2017 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2020 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2022 add_recent_file(as);
2024 handle<Instance> instance(Instance::create(canvas));
2027 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2031 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)")))
2032 instance->dialog_cvs_update();
2036 dialog_error_blocking(_("Error"), x);
2041 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2045 _preferences.set_value("curr_path",dirname(as));
2054 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2055 canvas->set_name(strprintf("Untitled%d",Instance::get_count()));
2057 String file_name(strprintf("untitled%d.sif",Instance::get_count()));
2059 canvas->rend_desc().set_frame_rate(24.0);
2060 canvas->rend_desc().set_time_start(0.0);
2061 canvas->rend_desc().set_time_end(00.0);
2062 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2063 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2064 canvas->rend_desc().set_tl(Vector(-4,2.25));
2065 canvas->rend_desc().set_br(Vector(4,-2.25));
2066 canvas->rend_desc().set_w(480);
2067 canvas->rend_desc().set_h(270);
2068 canvas->rend_desc().set_antialias(1);
2069 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2070 canvas->set_file_name(file_name);
2072 Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
2078 string filename="*.sif";
2080 while(dialog_open_file("Open", filename))
2082 // If the filename still has wildcards, then we should
2083 // continue looking for the file we want
2084 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2090 get_ui_interface()->error(_("Unable to open file"));
2095 App::set_selected_instance(etl::loose_handle<Instance> instance)
2097 /* if(get_selected_instance()==instance)
2099 selected_instance=instance;
2100 signal_instance_selected()(instance);
2106 selected_instance=instance;
2107 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2111 instance->focus(instance->get_canvas());
2114 set_selected_canvas_view(0);
2116 signal_instance_selected()(instance);
2120 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2122 selected_canvas_view=canvas_view;
2123 signal_canvas_view_focus()(selected_canvas_view);
2126 selected_instance=canvas_view->get_instance();
2127 signal_instance_selected()(canvas_view->get_instance());
2130 if(get_selected_canvas_view()==canvas_view)
2132 signal_canvas_view_focus()(selected_canvas_view);
2133 signal_instance_selected()(canvas_view->get_instance());
2136 selected_canvas_view=canvas_view;
2137 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2138 set_selected_instance(canvas_view->get_instance());
2139 signal_canvas_view_focus()(selected_canvas_view);
2143 etl::loose_handle<Instance>
2144 App::get_instance(Canvas::Handle canvas)
2146 if(!canvas) return 0;
2147 canvas=canvas->get_root();
2149 std::list<etl::handle<Instance> >::iterator iter;
2150 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2152 if((*iter)->get_canvas()==canvas)
2161 (new class About())->show();
2167 if(selected_instance)
2168 selected_instance->undo();
2174 if(selected_instance)
2175 selected_instance->redo();
2179 studio::App::get_base_path()
2181 return app_base_path_;