1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
40 #include <gtkmm/fileselection.h>
41 #include <gtkmm/dialog.h>
42 #include <gtkmm/messagedialog.h>
43 #include <gtkmm/label.h>
44 #include <gtkmm/stock.h>
45 #include <gtkmm/stockitem.h>
46 #include <gtkmm/iconsource.h>
47 #include <gtkmm/inputdialog.h>
48 #include <gtkmm/accelmap.h>
49 #include <gtkmm/uimanager.h>
53 #include <synfig/loadcanvas.h>
58 #include "canvasview.h"
59 #include "dialog_setup.h"
60 #include "dialog_gradient.h"
61 #include "dialog_color.h"
64 #include "onemoment.h"
66 #include "dockmanager.h"
68 #include "state_eyedrop.h"
69 #include "state_normal.h"
70 #include "state_draw.h"
71 #include "state_fill.h"
72 #include "state_bline.h"
73 #include "state_polygon.h"
74 #include "state_sketch.h"
75 #include "state_gradient.h"
76 #include "state_circle.h"
77 #include "state_rectangle.h"
78 #include "state_smoothmove.h"
79 #include "state_scale.h"
80 #include "state_width.h"
81 #include "state_rotate.h"
82 #include "state_zoom.h"
84 #include "devicetracker.h"
85 #include "dialog_tooloptions.h"
87 #include "autorecover.h"
89 #include <synfigapp/settings.h>
90 #include "dock_history.h"
91 #include "dock_canvases.h"
92 #include "dock_keyframes.h"
93 #include "dock_layers.h"
94 #include "dock_params.h"
95 #include "dock_metadata.h"
96 #include "dock_children.h"
97 #include "dock_info.h"
98 #include "dock_navigator.h"
99 #include "dock_layergroups.h"
100 #include "dock_timetrack.h"
101 #include "dock_curves.h"
103 #include "mod_palette/mod_palette.h"
104 #include "mod_mirror/mod_mirror.h"
106 #include <sys/stat.h>
112 #include "statemanager.h"
119 #define _WIN32_WINNT 0x0500
122 #include <gtkmm/accelmap.h>
123 #include <gtkmm/filechooser.h>
124 #include <gtkmm/filechooserdialog.h>
130 /* === U S I N G =========================================================== */
134 using namespace synfig;
135 using namespace studio;
137 /* === M A C R O S ========================================================= */
139 #ifndef SYNFIG_USER_APP_DIR
141 #define SYNFIG_USER_APP_DIR "Library/Synfig"
142 #elif defined(_WIN32)
143 #define SYNFIG_USER_APP_DIR "Synfig"
145 #define SYNFIG_USER_APP_DIR ".synfig"
150 #define DPM2DPI(x) (float(x)/39.3700787402f)
151 #define DPI2DPM(x) (float(x)*39.3700787402f)
157 # define IMAGE_DIR "share\\pixmaps"
162 # define IMAGE_DIR "/usr/local/share/pixmaps"
166 # define IMAGE_EXT "tif"
169 #include <synfigapp/main.h>
171 /* === S I G N A L S ======================================================= */
173 static sigc::signal<void> signal_present_all_;
175 App::signal_present_all() { return signal_present_all_; }
177 static sigc::signal<void> signal_recent_files_changed_;
179 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
181 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
182 sigc::signal<void,etl::loose_handle<CanvasView> >&
183 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
185 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
186 sigc::signal<void,etl::handle<Instance> >&
187 App::signal_instance_selected() { return signal_instance_selected_; }
189 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
190 sigc::signal<void,etl::handle<Instance> >&
191 App::signal_instance_created() { return signal_instance_created_; }
193 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
194 sigc::signal<void,etl::handle<Instance> >&
195 App::signal_instance_deleted() { return signal_instance_deleted_; }
197 /* === G L O B A L S ======================================================= */
199 static std::list<std::string> recent_files;
200 const std::list<std::string>& App::get_recent_files() { return recent_files; }
202 int App::Busy::count;
203 bool App::shutdown_in_progress;
205 synfig::Gamma App::gamma;
207 Glib::RefPtr<studio::UIManager> App::ui_manager_;
209 synfig::Distance::System App::distance_system;
211 studio::Dialog_Setup* App::dialog_setup;
213 etl::handle< studio::ModPalette > mod_palette_;
214 //studio::Dialog_Palette* App::dialog_palette;
216 std::list<etl::handle<Instance> > App::instance_list;
218 static etl::handle<synfigapp::UIInterface> ui_interface_;
219 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
221 etl::handle<Instance> App::selected_instance;
222 etl::handle<CanvasView> App::selected_canvas_view;
224 studio::Toolbox *studio::App::toolbox=NULL;
226 studio::AutoRecover *studio::App::auto_recover=NULL;
228 studio::IPC *ipc=NULL;
230 studio::DockManager* studio::App::dock_manager=0;
232 studio::DeviceTracker* studio::App::device_tracker=0;
234 studio::Dialog_Gradient* studio::App::dialog_gradient;
236 studio::Dialog_Color* studio::App::dialog_color;
238 Gtk::InputDialog* studio::App::dialog_input;
240 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
242 studio::Dock_History* dock_history;
243 studio::Dock_Canvases* dock_canvases;
244 studio::Dock_Keyframes* dock_keyframes;
245 studio::Dock_Layers* dock_layers;
246 studio::Dock_Params* dock_params;
247 studio::Dock_MetaData* dock_meta_data;
248 studio::Dock_Children* dock_children;
249 studio::Dock_Info* dock_info;
250 studio::Dock_LayerGroups* dock_layer_groups;
251 studio::Dock_Navigator* dock_navigator;
252 studio::Dock_Timetrack* dock_timetrack;
253 studio::Dock_Curves* dock_curves;
255 std::list< etl::handle< studio::Module > > module_list_;
257 bool studio::App::use_colorspace_gamma=true;
258 bool studio::App::single_threaded=false;
260 static int max_recent_files_=25;
261 int studio::App::get_max_recent_files() { return max_recent_files_; }
262 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
264 static synfig::String app_base_path_;
269 really_delete_widget(Gtk::Widget *widget)
271 // synfig::info("really delete %p", (void*)widget);
276 // nasty workaround - when we've finished with a popup menu, we want to delete it
277 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
278 // so schedule the real delete to happen in 50ms, giving the action a chance to run
280 delete_widget(Gtk::Widget *widget)
282 // synfig::info("delete %p", (void*)widget);
283 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
286 }; // END of namespace studio
287 studio::StateManager* state_manager;
292 class GlobalUIInterface : public synfigapp::UIInterface
296 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
301 true // use_separator
303 Gtk::Label label(message);
306 dialog.get_vbox()->pack_start(label);
307 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
308 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
310 dialog.set_default_response(dflt);
312 return (Response)dialog.run();
314 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
319 true // use_separator
321 Gtk::Label label(message);
324 dialog.get_vbox()->pack_start(label);
325 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
326 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
327 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
329 dialog.set_default_response(dflt);
331 return (Response)dialog.run();
333 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
338 true // use_separator
340 Gtk::Label label(message);
343 dialog.get_vbox()->pack_start(label);
344 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
345 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
347 dialog.set_default_response(dflt);
349 return (Response)dialog.run();
353 task(const std::string &task)
355 std::cerr<<task<<std::endl;
356 while(studio::App::events_pending())studio::App::iteration(false);
361 error(const std::string &err)
363 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
370 warning(const std::string &err)
372 std::cerr<<"warning: "<<err<<std::endl;
373 while(studio::App::events_pending())studio::App::iteration(false);
378 amount_complete(int /*current*/, int /*total*/)
380 while(studio::App::events_pending())studio::App::iteration(false);
385 /* === P R O C E D U R E S ================================================= */
389 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
391 action_group_list.push_back(action_group);
392 Gtk::UIManager::insert_action_group(action_group, pos);
396 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
398 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
399 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
400 if(*iter==action_group)
402 action_group_list.erase(iter);
403 Gtk::UIManager::remove_action_group(action_group);
406 synfig::error("Unable to find action group");
410 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
412 ui_manager->insert_action_group(group,0);
414 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
415 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
417 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
419 if(*iter && (*iter)->get_name()!="menus")
421 synfig::info("Removing action group "+(*iter)->get_name());
422 ui_manager->remove_action_group(*iter);
425 ui_manager->insert_action_group(group,0);
427 for(;!prev_groups.empty();prev_groups.pop_front())
429 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
430 ui_manager->insert_action_group(prev_groups.front(),1);
434 class Preferences : public synfigapp::Settings
437 virtual bool get_value(const synfig::String& key, synfig::String& value)const
441 value=strprintf("%f %f %f %f",
442 App::gamma.get_gamma_r(),
443 App::gamma.get_gamma_g(),
444 App::gamma.get_gamma_b(),
445 App::gamma.get_black_level()
449 if(key=="time_format")
451 value=strprintf("%i",App::get_time_format());
454 if(key=="file_history.size")
456 value=strprintf("%i",App::get_max_recent_files());
459 if(key=="use_colorspace_gamma")
461 value=strprintf("%i",(int)App::use_colorspace_gamma);
464 if(key=="distance_system")
466 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
469 if(key=="single_threaded")
471 value=strprintf("%i",(int)App::single_threaded);
474 if(key=="auto_recover_backup_interval")
476 value=strprintf("%i",App::auto_recover->get_timeout());
480 return synfigapp::Settings::get_value(key,value);
483 virtual bool set_value(const synfig::String& key,const synfig::String& value)
489 strscanf(value,"%f %f %f %f",
496 App::gamma.set_all(r,g,b,blk);
500 if(key=="time_format")
502 int i(atoi(value.c_str()));
503 App::set_time_format(static_cast<synfig::Time::Format>(i));
506 if(key=="auto_recover_backup_interval")
508 int i(atoi(value.c_str()));
509 App::auto_recover->set_timeout(i);
512 if(key=="file_history.size")
514 int i(atoi(value.c_str()));
515 App::set_max_recent_files(i);
518 if(key=="use_colorspace_gamma")
520 int i(atoi(value.c_str()));
521 App::use_colorspace_gamma=i;
524 if(key=="distance_system")
526 App::distance_system=Distance::ident_system(value);;
529 if(key=="single_threaded")
531 int i(atoi(value.c_str()));
532 App::single_threaded=i;
536 return synfigapp::Settings::set_value(key,value);
539 virtual KeyList get_key_list()const
541 KeyList ret(synfigapp::Settings::get_key_list());
542 ret.push_back("gamma");
543 ret.push_back("time_format");
544 ret.push_back("distance_system");
545 ret.push_back("file_history.size");
546 ret.push_back("use_colorspace_gamma");
547 ret.push_back("single_threaded");
548 ret.push_back("auto_recover_backup_interval");
553 static ::Preferences _preferences;
558 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
560 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
562 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
564 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
565 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
566 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
567 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
568 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
569 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
570 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
571 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
572 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
573 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
574 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
575 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
577 // Add the synfigapp actions...
578 synfigapp::Action::Book::iterator iter;
579 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
581 actions_action_group->add(Gtk::Action::create(
582 "action-"+iter->second.name,
583 get_action_stock_id(iter->second),
584 iter->second.local_name,iter->second.local_name
588 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
589 #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); }
590 #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); }
592 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
593 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
594 DEFINE_ACTION("new", Gtk::Stock::NEW);
595 DEFINE_ACTION("open", Gtk::Stock::OPEN);
596 DEFINE_ACTION("save", Gtk::Stock::SAVE);
597 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
598 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
599 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
600 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
601 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
602 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
603 DEFINE_ACTION("import", _("Import"));
604 DEFINE_ACTION("render", _("Render"));
605 DEFINE_ACTION("preview", _("Preview"));
606 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
607 DEFINE_ACTION("sound", _("Sound File"));
608 DEFINE_ACTION("options", _("Options"));
609 DEFINE_ACTION("close", _("Close View"));
610 DEFINE_ACTION("close-document", _("Close Document"));
611 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
614 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
615 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
616 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
617 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
618 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
619 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
620 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
621 DEFINE_ACTION("properties", _("Properties"));
623 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
624 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
625 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
626 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
627 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
628 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
629 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
630 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
631 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
632 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
633 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
634 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
635 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
636 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
637 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
638 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
639 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
640 DEFINE_ACTION("play", _("Play"));
641 // DEFINE_ACTION("pause", _("Pause"));
642 DEFINE_ACTION("stop", _("Stop"));
643 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
644 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
645 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
646 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
647 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
648 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
649 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
650 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
651 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
652 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
653 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
654 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
655 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
656 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
657 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
658 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
659 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
660 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
661 DEFINE_ACTION("seek-end", _("Seek to End"));
663 DEFINE_ACTION("action-group_add", _("Add group"));
665 DEFINE_ACTION("canvas-new", _("New Canvas"));
667 DEFINE_ACTION("amount-inc", _("Increase Amount"));
668 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
673 // Set up synfigapp actions
675 synfigapp::Action::Book::iterator iter;
677 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
679 Gtk::StockID stock_id;
681 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
683 //Gtk::Image* image(manage(new Gtk::Image()));
684 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
685 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
686 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
687 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
688 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
689 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
690 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
691 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
692 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
693 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
695 actions_action_group->add(Gtk::Action::create(
696 "action-"+iter->second.name,
698 iter->second.local_name,iter->second.local_name
706 Glib::ustring ui_info =
708 " <popup name='menu-toolbox' action='menu-toolbox'>"
709 " <menu action='menu-file'>"
712 " <popup name='menu-main' action='menu-main'>"
713 " <menu action='menu-file'>"
714 " <menuitem action='new' />"
715 " <menuitem action='open' />"
716 " <menuitem action='save' />"
717 " <menuitem action='save-as' />"
718 " <menuitem action='revert' />"
719 " <separator name='bleh01'/>"
720 " <menuitem action='cvs-add' />"
721 " <menuitem action='cvs-update' />"
722 " <menuitem action='cvs-commit' />"
723 " <menuitem action='cvs-revert' />"
724 " <separator name='bleh02'/>"
725 " <menuitem action='import' />"
726 " <separator name='bleh03'/>"
727 " <menuitem action='render' />"
728 " <menuitem action='preview' />"
729 " <menuitem action='sound' />"
730 " <separator name='bleh04'/>"
731 " <menuitem action='options' />"
732 " <menuitem action='close' />"
733 " <menuitem action='close-document' />"
734 " <menuitem action='quit' />"
736 " <menu action='menu-edit'>"
737 " <menuitem action='undo'/>"
738 " <menuitem action='redo'/>"
739 " <separator name='bleh05'/>"
740 " <menuitem action='cut'/>"
741 " <menuitem action='copy'/>"
742 " <menuitem action='paste'/>"
743 " <separator name='bleh06'/>"
744 " <menuitem action='select-all-ducks'/>"
745 " <menuitem action='unselect-all-layers'/>"
746 " <separator name='bleh07'/>"
747 " <menuitem action='properties'/>"
749 " <menu action='menu-view'>"
750 " <menu action='menu-duck-mask'>"
751 " <menuitem action='mask-position-ducks' />"
752 " <menuitem action='mask-vertex-ducks' />"
753 " <menuitem action='mask-tangent-ducks' />"
754 " <menuitem action='mask-radius-ducks' />"
755 " <menuitem action='mask-width-ducks' />"
756 " <menuitem action='mask-angle-ducks' />"
758 " <menu action='menu-preview-quality'>"
759 " <menuitem action='quality-00' />"
760 " <menuitem action='quality-01' />"
761 " <menuitem action='quality-02' />"
762 " <menuitem action='quality-03' />"
763 " <menuitem action='quality-04' />"
764 " <menuitem action='quality-05' />"
765 " <menuitem action='quality-06' />"
766 " <menuitem action='quality-07' />"
767 " <menuitem action='quality-08' />"
768 " <menuitem action='quality-09' />"
769 " <menuitem action='quality-10' />"
771 " <separator name='bleh08'/>"
772 " <menuitem action='play'/>"
773 //" <menuitem action='pause'/>"
774 " <menuitem action='stop'/>"
775 " <menuitem action='dialog-flipbook'/>"
776 " <separator name='bleh09'/>"
777 " <menuitem action='toggle-grid-show'/>"
778 " <menuitem action='toggle-grid-snap'/>"
779 " <menuitem action='toggle-guide-show'/>"
780 " <menuitem action='toggle-low-res'/>"
781 " <menuitem action='toggle-onion-skin'/>"
782 " <separator name='bleh10'/>"
783 " <menuitem action='canvas-zoom-in'/>"
784 " <menuitem action='canvas-zoom-out'/>"
785 " <menuitem action='canvas-zoom-fit'/>"
786 " <menuitem action='canvas-zoom-100'/>"
787 " <separator name='bleh11'/>"
788 " <menuitem action='time-zoom-in'/>"
789 " <menuitem action='time-zoom-out'/>"
790 " <separator name='bleh12'/>"
791 " <menuitem action='jump-next-keyframe'/>"
792 " <menuitem action='jump-prev-keyframe'/>"
793 " <menuitem action='seek-next-frame'/>"
794 " <menuitem action='seek-prev-frame'/>"
795 " <menuitem action='seek-next-second'/>"
796 " <menuitem action='seek-prev-second'/>"
797 " <menuitem action='seek-begin'/>"
798 " <menuitem action='seek-end'/>"
800 " <menu action='menu-canvas'>"
801 " <menuitem action='canvas-new'/>"
803 " <menu name='menu-state' action='menu-state'>"
805 " <menu action='menu-group'>"
806 " <menuitem action='action-group_add'/>"
808 " <menu action='menu-layer'>"
809 //" <menuitem action='cut'/>"
810 //" <menuitem action='copy'/>"
811 //" <menuitem action='paste'/>"
812 //" <separator name='bleh06'/>"
813 " <menu action='menu-layer-new'></menu>"
814 " <menuitem action='amount-inc'/>"
815 " <menuitem action='amount-dec'/>"
817 " <menu action='menu-keyframe'>"
818 " <menuitem action='keyframe-properties'/>"
825 " <menubar name='MenuBar'>"
826 " <menu action='MenuFile'>"
827 " <menuitem action='New'/>"
828 " <menuitem action='Open'/>"
830 " <menuitem action='Quit'/>"
832 " <menu action='MenuEdit'>"
833 " <menuitem action='Cut'/>"
834 " <menuitem action='Copy'/>"
835 " <menuitem action='Paste'/>"
838 " <toolbar name='ToolBar'>"
839 " <toolitem action='Open'/>"
840 " <toolitem action='Quit'/>"
846 actions_action_group->set_sensitive(false);
847 App::ui_manager()->set_add_tearoffs(true);
848 App::ui_manager()->insert_action_group(menus_action_group,1);
849 App::ui_manager()->insert_action_group(actions_action_group,1);
850 App::ui_manager()->add_ui_from_string(ui_info);
852 //App::ui_manager()->get_accel_group()->unlock();
854 catch(const Glib::Error& ex)
856 synfig::error("building menus and toolbars failed: " + ex.what());
859 // Add default keyboard accelerators
860 #define ACCEL(path,accel) \
862 Gtk::AccelKey accel_key(accel,path); \
863 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
866 #define ACCEL2(accel) \
868 Gtk::AccelKey accel_key(accel); \
869 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
872 ACCEL("<Actions>//select-all-ducks","<Control>a");
873 ACCEL("<Actions>//unselect-all-layers","<Control>d");
874 ACCEL("<Actions>//render","F9");
875 ACCEL("<Actions>//preview","F11");
876 ACCEL("<Actions>//properties","F8");
877 ACCEL("<Actions>//options","F12");
878 ACCEL("<Actions>//import","<control>i");
879 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
880 ACCEL("<Actions>//toggle-grid-show","<Control>g");
881 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
882 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
883 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
884 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
885 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
886 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
887 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
888 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
890 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
891 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
893 ACCEL("<Actions>//quality-01","<Control>1");
894 ACCEL("<Actions>//quality-02","<Control>2");
895 ACCEL("<Actions>//quality-03","<Control>3");
896 ACCEL("<Actions>//quality-04","<Control>4");
897 ACCEL("<Actions>//quality-05","<Control>5");
898 ACCEL("<Actions>//quality-06","<Control>6");
899 ACCEL("<Actions>//quality-07","<Control>7");
900 ACCEL("<Actions>//quality-08","<Control>8");
901 ACCEL("<Actions>//quality-09","<Control>9");
902 ACCEL("<Actions>//quality-10","<Control>0");
903 ACCEL("<Actions>//undo","<Control>z");
904 ACCEL("<Actions>//redo","<Control>r");
905 ACCEL("<Actions>//action-layer_remove","Delete");
907 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
908 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
909 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
910 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
911 ACCEL("<Actions>//time-zoom-in","+");
912 ACCEL("<Actions>//time-zoom-out","_");
914 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
915 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
917 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
918 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
919 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
920 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
921 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
922 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
923 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
924 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
925 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
926 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
927 ACCEL2(Gtk::AccelKey('o',Gdk::CONTROL_MASK,"<Actions>//toggle-onion-skin"));
928 ACCEL("<Actions>//play", "<Control>p");
929 ACCEL("<Actions>//seek-begin","Home");
930 ACCEL("<Actions>//seek-end","End");
932 ACCEL("<Actions>//state-normal", "<Mod1>a");
933 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
934 ACCEL("<Actions>//state-scale", "<Mod1>d");
935 ACCEL("<Actions>//state-rotate", "<Mod1>s");
937 ACCEL("<Actions>//state-bline", "<Mod1>b");
938 ACCEL("<Actions>//state-circle", "<Mod1>c");
939 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
940 ACCEL("<Actions>//state-gradient", "<Mod1>g");
942 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
943 ACCEL("<Actions>//state-fill", "<Mod1>f");
944 ACCEL("<Actions>//state-zoom", "<Mod1>z");
945 ACCEL("<Actions>//state-polygon", "<Mod1>p");
947 ACCEL("<Actions>//state-draw", "<Mod1>w");
948 ACCEL("<Actions>//state-sketch", "<Mod1>k");
949 ACCEL("<Actions>//state-width", "<Mod1>t");
950 ACCEL("<Actions>//state-mirror", "<Mod1>m");
952 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
958 #define mkdir(x,y) mkdir(x)
961 /* === M E T H O D S ======================================================= */
963 App::App(int *argc, char ***argv):
964 Gtk::Main(argc,argv),
965 IconController(etl::dirname((*argv)[0]))
967 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
970 ui_interface_=new GlobalUIInterface();
974 // don't call thread_init() if threads are already initialized
975 // on some machines bonobo_init() initialized threads before we get here
976 if (!g_thread_supported())
979 distance_system=Distance::SYSTEM_UNITS;
981 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
984 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
988 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
994 if(!SYNFIG_CHECK_VERSION())
996 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
997 dialog_error_blocking("Synfig Studio",
998 "This copy of Synfig Studio was compiled against a\n"
999 "different version of libsynfig than what is currently\n"
1000 "installed. Synfig Studio will now abort. Try downloading\n"
1001 "the latest version from the Synfig website at\n"
1002 "http://synfig.org/Download"
1006 Glib::set_application_name(_("Synfig Studio"));
1009 about_window.set_can_self_destruct(false);
1010 about_window.show();
1012 shutdown_in_progress=false;
1013 SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
1014 SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
1016 // Initialize the Synfig library
1017 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1020 get_ui_interface()->error(_("Failed to initialize synfig!"));
1024 // add the preferences to the settings
1025 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1029 studio_init_cb.task(_("Init UI Manager..."));
1030 App::ui_manager_=studio::UIManager::create();
1033 studio_init_cb.task(_("Init Dock Manager..."));
1034 dock_manager=new studio::DockManager();
1036 studio_init_cb.task(_("Init State Manager..."));
1037 state_manager=new StateManager();
1039 studio_init_cb.task(_("Init Toolbox..."));
1040 toolbox=new studio::Toolbox();
1042 studio_init_cb.task(_("Init Tool Options..."));
1043 dialog_tool_options=new studio::Dialog_ToolOptions();
1044 dock_manager->register_dockable(*dialog_tool_options);
1046 studio_init_cb.task(_("Init History..."));
1047 dock_history=new studio::Dock_History();
1048 dock_manager->register_dockable(*dock_history);
1050 studio_init_cb.task(_("Init Canvases..."));
1051 dock_canvases=new studio::Dock_Canvases();
1052 dock_manager->register_dockable(*dock_canvases);
1054 studio_init_cb.task(_("Init Keyframes..."));
1055 dock_keyframes=new studio::Dock_Keyframes();
1056 dock_manager->register_dockable(*dock_keyframes);
1058 studio_init_cb.task(_("Init Layers..."));
1059 dock_layers=new studio::Dock_Layers();
1060 dock_manager->register_dockable(*dock_layers);
1062 studio_init_cb.task(_("Init Params..."));
1063 dock_params=new studio::Dock_Params();
1064 dock_manager->register_dockable(*dock_params);
1066 studio_init_cb.task(_("Init MetaData..."));
1067 dock_meta_data=new studio::Dock_MetaData();
1068 dock_manager->register_dockable(*dock_meta_data);
1070 studio_init_cb.task(_("Init Children..."));
1071 dock_children=new studio::Dock_Children();
1072 dock_manager->register_dockable(*dock_children);
1074 studio_init_cb.task(_("Init Info..."));
1075 dock_info = new studio::Dock_Info();
1076 dock_manager->register_dockable(*dock_info);
1078 studio_init_cb.task(_("Init Navigator..."));
1079 dock_navigator = new studio::Dock_Navigator();
1080 dock_manager->register_dockable(*dock_navigator);
1082 studio_init_cb.task(_("Init Timetrack..."));
1083 dock_timetrack = new studio::Dock_Timetrack();
1084 dock_manager->register_dockable(*dock_timetrack);
1086 studio_init_cb.task(_("Init Curve Editor..."));
1087 dock_curves = new studio::Dock_Curves();
1088 dock_manager->register_dockable(*dock_curves);
1090 studio_init_cb.task(_("Init Layer Groups..."));
1091 dock_layer_groups = new studio::Dock_LayerGroups();
1092 dock_manager->register_dockable(*dock_layer_groups);
1095 studio_init_cb.task(_("Init Color Dialog..."));
1096 dialog_color=new studio::Dialog_Color();
1098 studio_init_cb.task(_("Init Gradient Dialog..."));
1099 dialog_gradient=new studio::Dialog_Gradient();
1101 studio_init_cb.task(_("Init DeviceTracker..."));
1102 device_tracker=new studio::DeviceTracker();
1104 studio_init_cb.task(_("Init Tools..."));
1105 state_manager->add_state(&state_normal);
1106 state_manager->add_state(&state_smooth_move);
1107 state_manager->add_state(&state_scale);
1108 state_manager->add_state(&state_rotate);
1110 state_manager->add_state(&state_bline);
1113 state_manager->add_state(&state_circle);
1114 state_manager->add_state(&state_rectangle);
1116 state_manager->add_state(&state_gradient);
1117 state_manager->add_state(&state_eyedrop);
1118 state_manager->add_state(&state_fill);
1120 state_manager->add_state(&state_zoom);
1122 // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
1123 // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
1124 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
1126 // Enabled for now. Let's see whether they're good enough yet.
1127 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
1128 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1130 // Disabled by default - it doesn't work properly?
1131 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1133 studio_init_cb.task(_("Init ModPalette..."));
1134 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1136 studio_init_cb.task(_("Init ModMirror..."));
1137 module_list_.push_back(new ModMirror()); module_list_.back()->start();
1140 studio_init_cb.task(_("Init Setup Dialog..."));
1141 dialog_setup=new studio::Dialog_Setup();
1143 studio_init_cb.task(_("Init Input Dialog..."));
1144 dialog_input=new Gtk::InputDialog();
1145 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1146 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1148 studio_init_cb.task(_("Init auto recovery..."));
1149 auto_recover=new AutoRecover();
1151 studio_init_cb.amount_complete(9250,10000);
1152 studio_init_cb.task(_("Loading Settings..."));
1154 studio_init_cb.task(_("Checking auto-recover..."));
1156 studio_init_cb.amount_complete(9900,10000);
1158 if(auto_recover->recovery_needed())
1160 about_window.hide();
1162 get_ui_interface()->yes_no(
1164 _("Synfig Studio seems to have crashed\n"
1165 "before you could save all your files.\n"
1166 "Would you like to re-open those files\n"
1167 "and recover your unsaved changes?")
1168 )==synfigapp::UIInterface::RESPONSE_YES
1171 if(!auto_recover->recover())
1173 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1176 get_ui_interface()->error(
1177 _("Synfig Studio has attempted to recover\n"
1178 "from a previous crash. The files that it has\n"
1179 "recovered are NOT YET SAVED. It would be a good\n"
1180 "idea to review them and save them now.")
1183 about_window.show();
1186 // Look for any files given on the command line,
1187 // and load them if found.
1188 for(;*argc>=1;(*argc)--)
1189 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1191 studio_init_cb.task(_("Loading files..."));
1192 about_window.hide();
1193 open((*argv)[*argc]);
1194 about_window.show();
1197 studio_init_cb.task(_("Done."));
1198 studio_init_cb.amount_complete(10000,10000);
1204 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1208 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1212 StateManager* App::get_state_manager() { return state_manager; }
1216 shutdown_in_progress=true;
1220 synfigapp::Main::settings().remove_domain("pref");
1222 selected_instance=0;
1224 // Unload all of the modules
1225 for(;!module_list_.empty();module_list_.pop_back());
1227 delete state_manager;
1231 delete auto_recover;
1235 // studio::App::iteration(false);
1239 // studio::App::iteration(false);
1241 // studio::App::iteration(false);
1243 delete dialog_setup;
1245 delete dialog_gradient;
1247 delete dialog_color;
1249 delete dialog_input;
1251 delete dock_manager;
1253 instance_list.clear();
1255 // studio::App::iteration(false);
1259 App::get_user_app_directory()
1261 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1265 App::get_config_file(const synfig::String& file)
1267 return Glib::build_filename(get_user_app_directory(),file);
1271 App::add_recent_file(const std::string &file_name)
1273 std::string filename(file_name);
1275 assert(!filename.empty());
1277 if(filename.empty())
1280 // Toss out any "hidden" files
1281 if(basename(filename)[0]=='.')
1284 // If we aren't an absolute path, turn ourselves into one
1285 if(!is_absolute_path(filename))
1286 filename=absolute_path(filename);
1288 list<string>::iterator iter;
1289 // Check to see if the file is already on the list.
1290 // If it is, then remove it from the list
1291 for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1294 recent_files.erase(iter);
1299 // Push the filename to the front of the list
1300 recent_files.push_front(filename);
1302 // Clean out the files at the end of the list.
1303 while(recent_files.size()>(unsigned)get_max_recent_files())
1304 recent_files.pop_back();
1306 signal_recent_files_changed_();
1311 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1314 App::get_time_format()
1316 return _App_time_format;
1320 App::set_time_format(synfig::Time::Format x)
1327 App::save_settings()
1332 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1333 setlocale(LC_NUMERIC, "C");
1335 std::string filename=get_config_file("accelrc");
1336 Gtk::AccelMap::save(filename);
1339 std::string filename=get_config_file("recentfiles");
1341 std::ofstream file(filename.c_str());
1345 synfig::warning("Unable to save %s",filename.c_str());
1349 list<string>::reverse_iterator iter;
1351 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1355 std::string filename=get_config_file("settings");
1356 synfigapp::Main::settings().save_to_file(filename);
1357 setlocale(LC_NUMERIC,old_locale);
1361 synfig::warning("Caught exception when attempting to save settings.");
1366 App::load_settings()
1371 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1372 setlocale(LC_NUMERIC, "C");
1374 std::string filename=get_config_file("accelrc");
1375 Gtk::AccelMap::load(filename);
1378 std::string filename=get_config_file("recentfiles");
1380 std::ifstream file(filename.c_str());
1384 std::string recent_file;
1385 getline(file,recent_file);
1386 if(!recent_file.empty())
1387 add_recent_file(recent_file);
1390 std::string filename=get_config_file("settings");
1391 if(!synfigapp::Main::settings().load_from_file(filename))
1393 //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1394 //if(!synfigapp::Main::settings().load_from_file(filename))
1396 gamma.set_gamma(1.0/2.2);
1397 reset_initial_window_configuration();
1400 setlocale(LC_NUMERIC,old_locale);
1404 synfig::warning("Caught exception when attempting to load settings.");
1409 App::reset_initial_window_configuration()
1411 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1412 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1413 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1414 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1415 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1416 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1417 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1418 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1419 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1420 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1421 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1422 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1423 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1424 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1428 App::shutdown_request(GdkEventAny*)
1432 //return !shutdown_in_progress;
1438 if(shutdown_in_progress)return;
1441 get_ui_interface()->task(_("Quit Request"));
1444 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1448 std::list<etl::handle<Instance> >::iterator iter;
1449 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1451 if(!(*iter)->safe_close())
1455 if((*iter)->synfigapp::Instance::get_action_count())
1457 handle<synfigapp::UIInterface> uim;
1458 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1460 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1461 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1463 case synfigapp::UIInterface::RESPONSE_NO:
1465 case synfigapp::UIInterface::RESPONSE_YES:
1468 case synfigapp::UIInterface::RESPONSE_CANCEL:
1477 if((*iter)->synfigapp::Instance::is_modified())
1479 handle<synfigapp::UIInterface> uim;
1480 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1482 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() );
1483 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1485 case synfigapp::UIInterface::RESPONSE_NO:
1487 case synfigapp::UIInterface::RESPONSE_YES:
1488 (*iter)->dialog_cvs_commit();
1490 case synfigapp::UIInterface::RESPONSE_CANCEL:
1499 // This next line causes things to crash for some reason
1503 shutdown_in_progress=true;
1505 instance_list.clear();
1507 while(studio::App::events_pending())studio::App::iteration(false);
1510 auto_recover->normal_shutdown();
1512 get_ui_interface()->task(_("Quit Request sent"));
1518 dialog_setup->refresh();
1519 dialog_setup->show();
1522 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1523 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1526 //#define USE_WIN32_FILE_DIALOGS 1
1529 #ifdef USE_WIN32_FILE_DIALOGS
1530 static OPENFILENAME ofn={};
1534 #include <gdk/gdkwin32.h>
1538 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1540 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1542 #ifdef USE_WIN32_FILE_DIALOGS
1543 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1545 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1546 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1547 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1549 ofn.lStructSize=sizeof(OPENFILENAME);
1550 ofn.hwndOwner = hWnd;
1551 ofn.hInstance = hInstance;
1552 ofn.lpstrFilter = szFilter;
1553 // ofn.lpstrCustomFilter=NULL;
1554 // ofn.nMaxCustFilter=0;
1555 // ofn.nFilterIndex=0;
1556 // ofn.lpstrFile=NULL;
1557 ofn.nMaxFile=MAX_PATH;
1558 // ofn.lpstrFileTitle=NULL;
1559 // ofn.lpstrInitialDir=NULL;
1560 // ofn.lpstrTitle=NULL;
1561 ofn.Flags=OFN_HIDEREADONLY;
1562 // ofn.nFileOffset=0;
1563 // ofn.nFileExtension=0;
1564 ofn.lpstrDefExt=TEXT("sif");
1565 // ofn.lCustData = 0l;
1567 // ofn.lpTemplateName=NULL;
1569 CHAR szFilename[MAX_PATH];
1571 strcpy(szFilename,filename.c_str());
1572 strcpy(szTitle,title.c_str());
1574 ofn.lpstrFile=szFilename;
1575 ofn.lpstrFileTitle=szTitle;
1577 if(GetOpenFileName(&ofn))
1579 filename=szFilename;
1585 synfig::String prev_path;
1587 if(!_preferences.get_value(preference, prev_path))
1590 prev_path = absolute_path(prev_path);
1592 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1594 dialog->set_current_folder(prev_path);
1595 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1596 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1598 if (filename.empty())
1599 dialog->set_filename(prev_path);
1600 else if (is_absolute_path(filename))
1601 dialog->set_filename(filename);
1603 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1605 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1606 filename = dialog->get_filename();
1607 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1608 _preferences.set_value(preference, dirname(filename));
1622 GtkWidget *fileselection;
1623 fileselection = gtk_file_selection_new(title.c_str());
1626 if(basename(filename)==filename)
1628 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1631 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1633 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1635 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1636 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1638 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1639 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1641 gtk_widget_show(fileselection);
1649 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1650 _preferences.set_value(preference,dirname(filename));
1654 gtk_widget_destroy(fileselection);
1657 gtk_widget_destroy(fileselection);
1664 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1666 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1668 #if USE_WIN32_FILE_DIALOGS
1669 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1671 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1672 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1673 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1675 ofn.lStructSize=sizeof(OPENFILENAME);
1676 ofn.hwndOwner = hWnd;
1677 ofn.hInstance = hInstance;
1678 ofn.lpstrFilter = szFilter;
1679 // ofn.lpstrCustomFilter=NULL;
1680 // ofn.nMaxCustFilter=0;
1681 // ofn.nFilterIndex=0;
1682 // ofn.lpstrFile=NULL;
1683 ofn.nMaxFile=MAX_PATH;
1684 // ofn.lpstrFileTitle=NULL;
1685 // ofn.lpstrInitialDir=NULL;
1686 // ofn.lpstrTitle=NULL;
1687 ofn.Flags=OFN_OVERWRITEPROMPT;
1688 // ofn.nFileOffset=0;
1689 // ofn.nFileExtension=0;
1690 ofn.lpstrDefExt=TEXT("sif");
1691 // ofn.lCustData = 0l;
1693 // ofn.lpTemplateName=NULL;
1695 CHAR szFilename[MAX_PATH];
1697 strcpy(szFilename,filename.c_str());
1698 strcpy(szTitle,title.c_str());
1700 ofn.lpstrFile=szFilename;
1701 ofn.lpstrFileTitle=szTitle;
1703 if(GetSaveFileName(&ofn))
1705 filename=szFilename;
1706 _preferences.set_value(preference,dirname(filename));
1711 synfig::String prev_path;
1713 if(!_preferences.get_value(preference, prev_path))
1716 prev_path = absolute_path(prev_path);
1718 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1720 dialog->set_current_folder(prev_path);
1721 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1722 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1724 if (filename.empty())
1725 dialog->set_filename(prev_path);
1728 std::string full_path;
1729 if (is_absolute_path(filename))
1730 full_path = filename;
1732 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1734 // select the file if it exists
1735 dialog->set_filename(full_path);
1737 // if the file doesn't exist, put its name into the filename box
1739 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1740 dialog->set_current_name(basename(filename));
1743 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1744 filename = dialog->get_filename();
1745 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1746 _preferences.set_value(preference, dirname(filename));
1757 App::dialog_error_blocking(const std::string &title, const std::string &message)
1759 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1760 dialog.set_title(title);
1766 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1768 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1769 dialog.set_title(title);
1775 App::dialog_yes_no(const std::string &title, const std::string &message)
1780 true // use_separator
1782 Gtk::Label label(message);
1785 dialog.get_vbox()->pack_start(label);
1786 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1787 dialog.add_button(Gtk::StockID("gtk-no"),0);
1789 return dialog.run();
1793 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1798 true // use_separator
1800 Gtk::Label label(message);
1803 dialog.get_vbox()->pack_start(label);
1804 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1805 dialog.add_button(Gtk::StockID("gtk-no"),0);
1806 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1808 return dialog.run();
1812 App::dialog_not_implemented()
1814 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1815 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1820 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1825 true // use_separator
1827 Gtk::Label label(message);
1829 dialog.get_vbox()->pack_start(label);
1832 entry.set_text(text);
1834 entry.set_activates_default(true);
1835 dialog.get_vbox()->pack_start(entry);
1837 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1838 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1839 dialog.set_default_response(Gtk::RESPONSE_OK);
1840 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1843 if(dialog.run()!=Gtk::RESPONSE_OK)
1846 text=entry.get_text();
1855 App::open(std::string filename)
1857 return open_as(filename,filename);
1860 // this is called from autorecover.cpp:
1861 // App::open_as(get_shadow_file_name(filename),filename)
1862 // other than that, 'filename' and 'as' are the same
1864 App::open_as(std::string filename,std::string as)
1867 char long_name[1024];
1868 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1874 OneMoment one_moment;
1876 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1877 if(canvas && get_instance(canvas))
1879 get_instance(canvas)->find_canvas_view(canvas)->present();
1880 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1883 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1885 add_recent_file(as);
1887 handle<Instance> instance(Instance::create(canvas));
1890 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1894 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)")))
1895 instance->dialog_cvs_update();
1899 dialog_error_blocking(_("Error"), x);
1904 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1915 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1916 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1918 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1920 canvas->rend_desc().set_frame_rate(24.0);
1921 canvas->rend_desc().set_time_start(0.0);
1922 canvas->rend_desc().set_time_end(00.0);
1923 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1924 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1925 canvas->rend_desc().set_tl(Vector(-4,2.25));
1926 canvas->rend_desc().set_br(Vector(4,-2.25));
1927 canvas->rend_desc().set_w(480);
1928 canvas->rend_desc().set_h(270);
1929 canvas->rend_desc().set_antialias(1);
1930 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1931 canvas->set_file_name(file_name);
1933 handle<Instance> instance = Instance::create(canvas);
1935 if (!getenv("SYNFIG_DISABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1936 instance->find_canvas_view(canvas)->canvas_properties.present();
1942 string filename="*.sif";
1944 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
1946 // If the filename still has wildcards, then we should
1947 // continue looking for the file we want
1948 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1954 get_ui_interface()->error(_("Unable to open file"));
1959 App::set_selected_instance(etl::loose_handle<Instance> instance)
1961 /* if(get_selected_instance()==instance)
1963 selected_instance=instance;
1964 signal_instance_selected()(instance);
1970 selected_instance=instance;
1971 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
1975 instance->focus(instance->get_canvas());
1978 set_selected_canvas_view(0);
1980 signal_instance_selected()(instance);
1984 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
1986 selected_canvas_view=canvas_view;
1987 signal_canvas_view_focus()(selected_canvas_view);
1990 selected_instance=canvas_view->get_instance();
1991 signal_instance_selected()(canvas_view->get_instance());
1994 if(get_selected_canvas_view()==canvas_view)
1996 signal_canvas_view_focus()(selected_canvas_view);
1997 signal_instance_selected()(canvas_view->get_instance());
2000 selected_canvas_view=canvas_view;
2001 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2002 set_selected_instance(canvas_view->get_instance());
2003 signal_canvas_view_focus()(selected_canvas_view);
2007 etl::loose_handle<Instance>
2008 App::get_instance(etl::handle<synfig::Canvas> canvas)
2010 if(!canvas) return 0;
2011 canvas=canvas->get_root();
2013 std::list<etl::handle<Instance> >::iterator iter;
2014 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2016 if((*iter)->get_canvas()==canvas)
2025 (new class About())->show();
2031 if(selected_instance)
2032 selected_instance->undo();
2038 if(selected_instance)
2039 selected_instance->redo();
2043 studio::App::get_base_path()
2045 return app_base_path_;