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)
1540 #ifdef USE_WIN32_FILE_DIALOGS
1541 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1543 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1544 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1545 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1547 ofn.lStructSize=sizeof(OPENFILENAME);
1548 ofn.hwndOwner = hWnd;
1549 ofn.hInstance = hInstance;
1550 ofn.lpstrFilter = szFilter;
1551 // ofn.lpstrCustomFilter=NULL;
1552 // ofn.nMaxCustFilter=0;
1553 // ofn.nFilterIndex=0;
1554 // ofn.lpstrFile=NULL;
1555 ofn.nMaxFile=MAX_PATH;
1556 // ofn.lpstrFileTitle=NULL;
1557 // ofn.lpstrInitialDir=NULL;
1558 // ofn.lpstrTitle=NULL;
1559 ofn.Flags=OFN_HIDEREADONLY;
1560 // ofn.nFileOffset=0;
1561 // ofn.nFileExtension=0;
1562 ofn.lpstrDefExt=TEXT("sif");
1563 // ofn.lCustData = 0l;
1565 // ofn.lpTemplateName=NULL;
1567 CHAR szFilename[MAX_PATH];
1569 strcpy(szFilename,filename.c_str());
1570 strcpy(szTitle,title.c_str());
1572 ofn.lpstrFile=szFilename;
1573 ofn.lpstrFileTitle=szTitle;
1575 if(GetOpenFileName(&ofn))
1577 filename=szFilename;
1583 synfig::String prev_path;
1584 if(!_preferences.get_value("curr_path",prev_path))
1586 prev_path = absolute_path(prev_path);
1588 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
1589 dialog->set_current_folder(prev_path);
1590 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1591 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1592 if(!filename.empty())
1593 if (is_absolute_path(filename))
1594 dialog->set_filename(filename);
1596 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1597 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1598 filename=dialog->get_filename();
1610 GtkWidget *fileselection;
1611 fileselection = gtk_file_selection_new(title.c_str());
1614 if(basename(filename)==filename)
1616 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1619 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1621 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1623 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1624 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1626 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1627 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1629 gtk_widget_show(fileselection);
1637 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1638 _preferences.set_value("curr_path",dirname(filename));
1642 gtk_widget_destroy(fileselection);
1645 gtk_widget_destroy(fileselection);
1652 App::dialog_save_file(const std::string &title, std::string &filename)
1654 #if USE_WIN32_FILE_DIALOGS
1655 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1657 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1658 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1659 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1661 ofn.lStructSize=sizeof(OPENFILENAME);
1662 ofn.hwndOwner = hWnd;
1663 ofn.hInstance = hInstance;
1664 ofn.lpstrFilter = szFilter;
1665 // ofn.lpstrCustomFilter=NULL;
1666 // ofn.nMaxCustFilter=0;
1667 // ofn.nFilterIndex=0;
1668 // ofn.lpstrFile=NULL;
1669 ofn.nMaxFile=MAX_PATH;
1670 // ofn.lpstrFileTitle=NULL;
1671 // ofn.lpstrInitialDir=NULL;
1672 // ofn.lpstrTitle=NULL;
1673 ofn.Flags=OFN_OVERWRITEPROMPT;
1674 // ofn.nFileOffset=0;
1675 // ofn.nFileExtension=0;
1676 ofn.lpstrDefExt=TEXT("sif");
1677 // ofn.lCustData = 0l;
1679 // ofn.lpTemplateName=NULL;
1681 CHAR szFilename[MAX_PATH];
1683 strcpy(szFilename,filename.c_str());
1684 strcpy(szTitle,title.c_str());
1686 ofn.lpstrFile=szFilename;
1687 ofn.lpstrFileTitle=szTitle;
1689 if(GetSaveFileName(&ofn))
1691 filename=szFilename;
1692 _preferences.set_value("curr_path",dirname(filename));
1697 synfig::String prev_path;
1698 if(!_preferences.get_value("curr_path",prev_path))
1700 prev_path = absolute_path(prev_path);
1702 Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
1703 dialog->set_current_folder(prev_path);
1704 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1705 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1706 if(!filename.empty())
1708 std::string full_path;
1709 if (is_absolute_path(filename))
1710 full_path = filename;
1712 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1713 // select the file if it exists
1714 dialog->set_filename(full_path);
1716 // if the file doesn't exist, put its name into the filename box
1718 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1719 dialog->set_current_name(basename(filename));
1721 if(dialog->run()==GTK_RESPONSE_ACCEPT) {
1722 filename=dialog->get_filename();
1724 _preferences.set_value("curr_path",dirname(filename));
1729 // return dialog_open_file(title, filename);
1734 App::dialog_error_blocking(const std::string &title, const std::string &message)
1736 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1737 dialog.set_title(title);
1743 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1745 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1746 dialog.set_title(title);
1752 App::dialog_yes_no(const std::string &title, const std::string &message)
1757 true // use_separator
1759 Gtk::Label label(message);
1762 dialog.get_vbox()->pack_start(label);
1763 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1764 dialog.add_button(Gtk::StockID("gtk-no"),0);
1766 return dialog.run();
1770 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1775 true // use_separator
1777 Gtk::Label label(message);
1780 dialog.get_vbox()->pack_start(label);
1781 dialog.add_button(Gtk::StockID("gtk-yes"),1);
1782 dialog.add_button(Gtk::StockID("gtk-no"),0);
1783 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1785 return dialog.run();
1789 App::dialog_not_implemented()
1791 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1792 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1797 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1802 true // use_separator
1804 Gtk::Label label(message);
1806 dialog.get_vbox()->pack_start(label);
1809 entry.set_text(text);
1811 entry.set_activates_default(true);
1812 dialog.get_vbox()->pack_start(entry);
1814 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1815 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1816 dialog.set_default_response(Gtk::RESPONSE_OK);
1817 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1820 if(dialog.run()!=Gtk::RESPONSE_OK)
1823 text=entry.get_text();
1832 App::open(std::string filename)
1834 return open_as(filename,filename);
1837 // this is called from autorecover.cpp:
1838 // App::open_as(get_shadow_file_name(filename),filename)
1839 // other than that, 'filename' and 'as' are the same
1841 App::open_as(std::string filename,std::string as)
1844 char long_name[1024];
1845 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1851 OneMoment one_moment;
1853 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1854 if(canvas && get_instance(canvas))
1856 get_instance(canvas)->find_canvas_view(canvas)->present();
1857 throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1860 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1862 add_recent_file(as);
1864 handle<Instance> instance(Instance::create(canvas));
1867 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1871 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)")))
1872 instance->dialog_cvs_update();
1876 dialog_error_blocking(_("Error"), x);
1881 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1885 _preferences.set_value("curr_path",dirname(as));
1894 handle<synfig::Canvas> canvas=synfig::Canvas::create();
1895 canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1897 String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1899 canvas->rend_desc().set_frame_rate(24.0);
1900 canvas->rend_desc().set_time_start(0.0);
1901 canvas->rend_desc().set_time_end(00.0);
1902 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1903 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1904 canvas->rend_desc().set_tl(Vector(-4,2.25));
1905 canvas->rend_desc().set_br(Vector(4,-2.25));
1906 canvas->rend_desc().set_w(480);
1907 canvas->rend_desc().set_h(270);
1908 canvas->rend_desc().set_antialias(1);
1909 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
1910 canvas->set_file_name(file_name);
1912 handle<Instance> instance = Instance::create(canvas);
1914 if (!getenv("SYNFIG_DISABLE_NEW_CANVAS_EDIT_PROPERTIES"))
1915 instance->find_canvas_view(canvas)->canvas_properties.present();
1921 string filename="*.sif";
1923 while(dialog_open_file("Open", filename))
1925 // If the filename still has wildcards, then we should
1926 // continue looking for the file we want
1927 if(find(filename.begin(),filename.end(),'*')!=filename.end())
1933 get_ui_interface()->error(_("Unable to open file"));
1938 App::set_selected_instance(etl::loose_handle<Instance> instance)
1940 /* if(get_selected_instance()==instance)
1942 selected_instance=instance;
1943 signal_instance_selected()(instance);
1949 selected_instance=instance;
1950 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
1954 instance->focus(instance->get_canvas());
1957 set_selected_canvas_view(0);
1959 signal_instance_selected()(instance);
1963 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
1965 selected_canvas_view=canvas_view;
1966 signal_canvas_view_focus()(selected_canvas_view);
1969 selected_instance=canvas_view->get_instance();
1970 signal_instance_selected()(canvas_view->get_instance());
1973 if(get_selected_canvas_view()==canvas_view)
1975 signal_canvas_view_focus()(selected_canvas_view);
1976 signal_instance_selected()(canvas_view->get_instance());
1979 selected_canvas_view=canvas_view;
1980 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
1981 set_selected_instance(canvas_view->get_instance());
1982 signal_canvas_view_focus()(selected_canvas_view);
1986 etl::loose_handle<Instance>
1987 App::get_instance(etl::handle<synfig::Canvas> canvas)
1989 if(!canvas) return 0;
1990 canvas=canvas->get_root();
1992 std::list<etl::handle<Instance> >::iterator iter;
1993 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
1995 if((*iter)->get_canvas()==canvas)
2004 (new class About())->show();
2010 if(selected_instance)
2011 selected_instance->undo();
2017 if(selected_instance)
2018 selected_instance->redo();
2022 studio::App::get_base_path()
2024 return app_base_path_;