1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2008 Gerald Young
11 ** Copyright (c) 2008 Carlos López
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
24 /* ========================================================================= */
26 /* === H E A D E R S ======================================================= */
45 #ifdef HAVE_SYS_ERRNO_H
46 #include <sys/errno.h>
48 #include <gtkmm/fileselection.h>
49 #include <gtkmm/dialog.h>
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/label.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/stockitem.h>
54 #include <gtkmm/iconsource.h>
55 #include <gtkmm/inputdialog.h>
56 #include <gtkmm/accelmap.h>
57 #include <gtkmm/uimanager.h>
58 #include <gtkmm/textview.h>
62 #include <gdkmm/general.h>
64 #include <synfig/loadcanvas.h>
65 #include <synfig/savecanvas.h>
71 #include "canvasview.h"
72 #include "dialog_setup.h"
73 #include "dialog_gradient.h"
74 #include "dialog_color.h"
77 #include "onemoment.h"
79 #include "dockmanager.h"
81 #include "state_eyedrop.h"
82 #include "state_normal.h"
83 #include "state_draw.h"
84 #include "state_fill.h"
85 #include "state_bline.h"
86 #include "state_polygon.h"
87 #include "state_sketch.h"
88 #include "state_gradient.h"
89 #include "state_circle.h"
90 #include "state_rectangle.h"
91 #include "state_smoothmove.h"
92 #include "state_scale.h"
93 #include "state_star.h"
94 #include "state_text.h"
95 #include "state_width.h"
96 #include "state_rotate.h"
97 #include "state_zoom.h"
99 #include "devicetracker.h"
100 #include "dialog_tooloptions.h"
101 #include "widget_enum.h"
103 #include "autorecover.h"
105 #include <synfigapp/settings.h>
106 #include "dock_history.h"
107 #include "dock_canvases.h"
108 #include "dock_keyframes.h"
109 #include "dock_layers.h"
110 #include "dock_params.h"
111 #include "dock_metadata.h"
112 #include "dock_children.h"
113 #include "dock_info.h"
114 #include "dock_navigator.h"
115 #include "dock_layergroups.h"
116 #include "dock_timetrack.h"
117 #include "dock_curves.h"
119 #include "mod_palette/mod_palette.h"
120 #include "mod_mirror/mod_mirror.h"
122 #include <sys/stat.h>
128 #include "statemanager.h"
134 #include <gtkmm/accelmap.h>
135 #include <gtkmm/filechooser.h>
136 #include <gtkmm/filechooserdialog.h>
142 /* === U S I N G =========================================================== */
146 using namespace synfig;
147 using namespace studio;
149 /* === M A C R O S ========================================================= */
151 #ifndef SYNFIG_USER_APP_DIR
153 #define SYNFIG_USER_APP_DIR "Library/Synfig"
154 #elif defined(_WIN32)
155 #define SYNFIG_USER_APP_DIR "Synfig"
157 #define SYNFIG_USER_APP_DIR ".synfig"
162 #define DPM2DPI(x) (float(x)/39.3700787402f)
163 #define DPI2DPM(x) (float(x)*39.3700787402f)
169 # define IMAGE_DIR "share\\pixmaps"
174 # define IMAGE_DIR "/usr/local/share/pixmaps"
178 # define IMAGE_EXT "tif"
181 #include <synfigapp/main.h>
183 /* === S I G N A L S ======================================================= */
185 static sigc::signal<void> signal_present_all_;
187 App::signal_present_all() { return signal_present_all_; }
189 static sigc::signal<void> signal_recent_files_changed_;
191 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
193 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
194 sigc::signal<void,etl::loose_handle<CanvasView> >&
195 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_selected() { return signal_instance_selected_; }
201 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
202 sigc::signal<void,etl::handle<Instance> >&
203 App::signal_instance_created() { return signal_instance_created_; }
205 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
206 sigc::signal<void,etl::handle<Instance> >&
207 App::signal_instance_deleted() { return signal_instance_deleted_; }
209 /* === G L O B A L S ======================================================= */
211 static std::list<std::string> recent_files;
212 const std::list<std::string>& App::get_recent_files() { return recent_files; }
214 static std::list<std::string> recent_files_window_size;
216 int App::Busy::count;
217 bool App::shutdown_in_progress;
219 synfig::Gamma App::gamma;
221 Glib::RefPtr<studio::UIManager> App::ui_manager_;
223 synfig::Distance::System App::distance_system;
225 studio::Dialog_Setup* App::dialog_setup;
227 etl::handle< studio::ModPalette > mod_palette_;
228 //studio::Dialog_Palette* App::dialog_palette;
230 std::list<etl::handle<Instance> > App::instance_list;
232 static etl::handle<synfigapp::UIInterface> ui_interface_;
233 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
235 etl::handle<Instance> App::selected_instance;
236 etl::handle<CanvasView> App::selected_canvas_view;
238 studio::About *studio::App::about=NULL;
240 studio::Toolbox *studio::App::toolbox=NULL;
242 studio::AutoRecover *studio::App::auto_recover=NULL;
244 studio::IPC *ipc=NULL;
246 studio::DockManager* studio::App::dock_manager=0;
248 studio::DeviceTracker* studio::App::device_tracker=0;
250 studio::Dialog_Gradient* studio::App::dialog_gradient;
252 studio::Dialog_Color* studio::App::dialog_color;
254 Gtk::InputDialog* studio::App::dialog_input;
256 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
258 studio::Dock_History* dock_history;
259 studio::Dock_Canvases* dock_canvases;
260 studio::Dock_Keyframes* dock_keyframes;
261 studio::Dock_Layers* dock_layers;
262 studio::Dock_Params* dock_params;
263 studio::Dock_MetaData* dock_meta_data;
264 studio::Dock_Children* dock_children;
265 studio::Dock_Info* dock_info;
266 studio::Dock_LayerGroups* dock_layer_groups;
267 studio::Dock_Navigator* dock_navigator;
268 studio::Dock_Timetrack* dock_timetrack;
269 studio::Dock_Curves* dock_curves;
271 std::list< etl::handle< studio::Module > > module_list_;
273 bool studio::App::use_colorspace_gamma=true;
274 #ifdef SINGLE_THREADED
275 bool studio::App::single_threaded=false;
277 bool studio::App::restrict_radius_ducks=false;
278 bool studio::App::resize_imported_images=false;
279 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
280 int studio::App::preferred_x_size=480;
281 int studio::App::preferred_y_size=270;
282 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
283 #ifdef USE_OPEN_FOR_URLS
284 String studio::App::browser_command("open"); // MacOS only
286 String studio::App::browser_command("xdg-open"); // Linux XDG standard
289 static int max_recent_files_=25;
290 int studio::App::get_max_recent_files() { return max_recent_files_; }
291 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
293 static synfig::String app_base_path_;
298 really_delete_widget(Gtk::Widget *widget)
300 // synfig::info("really delete %p", (void*)widget);
305 // nasty workaround - when we've finished with a popup menu, we want to delete it
306 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
307 // so schedule the real delete to happen in 50ms, giving the action a chance to run
309 delete_widget(Gtk::Widget *widget)
311 // synfig::info("delete %p", (void*)widget);
312 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
315 }; // END of namespace studio
316 studio::StateManager* state_manager;
321 class GlobalUIInterface : public synfigapp::UIInterface
325 virtual Response confirmation(const std::string &title,
326 const std::string &primaryText,
327 const std::string &secondaryText,
328 const std::string &confirmPhrase,
329 const std::string &cancelPhrase,
330 Response defaultResponse)
332 Gtk::MessageDialog dialog(
333 primaryText, // Message
335 Gtk::MESSAGE_WARNING, // Type
336 Gtk::BUTTONS_NONE, // Buttons
341 dialog.set_title(title);
342 if (! secondaryText.empty())
343 dialog.set_secondary_text(secondaryText);
345 dialog.add_button(cancelPhrase, RESPONSE_CANCEL);
346 dialog.add_button(confirmPhrase, RESPONSE_OK);
347 dialog.set_default_response(defaultResponse);
350 return (Response) dialog.run();
353 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
358 true // use_separator
360 Gtk::Label label(message);
363 dialog.get_vbox()->pack_start(label);
364 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
365 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
367 dialog.set_default_response(dflt);
369 return (Response)dialog.run();
371 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
376 true // use_separator
378 Gtk::Label label(message);
381 dialog.get_vbox()->pack_start(label);
382 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
383 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
384 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
386 dialog.set_default_response(dflt);
388 return (Response)dialog.run();
390 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
395 true // use_separator
397 Gtk::Label label(message);
400 dialog.get_vbox()->pack_start(label);
401 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
402 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
404 dialog.set_default_response(dflt);
406 return (Response)dialog.run();
410 task(const std::string &task)
412 std::cerr<<task<<std::endl;
413 while(studio::App::events_pending())studio::App::iteration(false);
418 error(const std::string &err)
420 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
427 warning(const std::string &err)
429 std::cerr<<"warning: "<<err<<std::endl;
430 while(studio::App::events_pending())studio::App::iteration(false);
435 amount_complete(int /*current*/, int /*total*/)
437 while(studio::App::events_pending())studio::App::iteration(false);
442 /* === P R O C E D U R E S ================================================= */
446 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
448 action_group_list.push_back(action_group);
449 Gtk::UIManager::insert_action_group(action_group, pos);
453 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
455 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
456 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
457 if(*iter==action_group)
459 action_group_list.erase(iter);
460 Gtk::UIManager::remove_action_group(action_group);
463 synfig::error("Unable to find action group");
467 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
469 ui_manager->insert_action_group(group,0);
471 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
472 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
474 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
476 if(*iter && (*iter)->get_name()!="menus")
478 synfig::info("Removing action group "+(*iter)->get_name());
479 ui_manager->remove_action_group(*iter);
482 ui_manager->insert_action_group(group,0);
484 for(;!prev_groups.empty();prev_groups.pop_front())
486 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
487 ui_manager->insert_action_group(prev_groups.front(),1);
491 class Preferences : public synfigapp::Settings
494 virtual bool get_value(const synfig::String& key, synfig::String& value)const
498 value=strprintf("%f %f %f %f",
499 App::gamma.get_gamma_r(),
500 App::gamma.get_gamma_g(),
501 App::gamma.get_gamma_b(),
502 App::gamma.get_black_level()
506 if(key=="time_format")
508 value=strprintf("%i",App::get_time_format());
511 if(key=="file_history.size")
513 value=strprintf("%i",App::get_max_recent_files());
516 if(key=="use_colorspace_gamma")
518 value=strprintf("%i",(int)App::use_colorspace_gamma);
521 if(key=="distance_system")
523 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
526 #ifdef SINGLE_THREADED
527 if(key=="single_threaded")
529 value=strprintf("%i",(int)App::single_threaded);
533 if(key=="auto_recover_backup_interval")
535 value=strprintf("%i",App::auto_recover->get_timeout());
538 if(key=="restrict_radius_ducks")
540 value=strprintf("%i",(int)App::restrict_radius_ducks);
543 if(key=="resize_imported_images")
545 value=strprintf("%i",(int)App::resize_imported_images);
548 if(key=="browser_command")
550 value=App::browser_command;
553 if(key=="custom_filename_prefix")
555 value=App::custom_filename_prefix;
558 if(key=="preferred_x_size")
560 value=strprintf("%i",App::preferred_x_size);
563 if(key=="preferred_y_size")
565 value=strprintf("%i",App::preferred_y_size);
568 if(key=="predefined_size")
570 value=strprintf("%s",App::predefined_size.c_str());
574 return synfigapp::Settings::get_value(key,value);
577 virtual bool set_value(const synfig::String& key,const synfig::String& value)
583 strscanf(value,"%f %f %f %f",
590 App::gamma.set_all(r,g,b,blk);
594 if(key=="time_format")
596 int i(atoi(value.c_str()));
597 App::set_time_format(static_cast<synfig::Time::Format>(i));
600 if(key=="auto_recover_backup_interval")
602 int i(atoi(value.c_str()));
603 App::auto_recover->set_timeout(i);
606 if(key=="file_history.size")
608 int i(atoi(value.c_str()));
609 App::set_max_recent_files(i);
612 if(key=="use_colorspace_gamma")
614 int i(atoi(value.c_str()));
615 App::use_colorspace_gamma=i;
618 if(key=="distance_system")
620 App::distance_system=Distance::ident_system(value);;
623 #ifdef SINGLE_THREADED
624 if(key=="single_threaded")
626 int i(atoi(value.c_str()));
627 App::single_threaded=i;
631 if(key=="restrict_radius_ducks")
633 int i(atoi(value.c_str()));
634 App::restrict_radius_ducks=i;
637 if(key=="resize_imported_images")
639 int i(atoi(value.c_str()));
640 App::resize_imported_images=i;
643 if(key=="browser_command")
645 App::browser_command=value;
648 if(key=="custom_filename_prefix")
650 App::custom_filename_prefix=value;
653 if(key=="preferred_x_size")
655 int i(atoi(value.c_str()));
656 App::preferred_x_size=i;
659 if(key=="preferred_y_size")
661 int i(atoi(value.c_str()));
662 App::preferred_y_size=i;
665 if(key=="predefined_size")
667 App::predefined_size=value;
670 return synfigapp::Settings::set_value(key,value);
673 virtual KeyList get_key_list()const
675 KeyList ret(synfigapp::Settings::get_key_list());
676 ret.push_back("gamma");
677 ret.push_back("time_format");
678 ret.push_back("distance_system");
679 ret.push_back("file_history.size");
680 ret.push_back("use_colorspace_gamma");
681 #ifdef SINGLE_THREADED
682 ret.push_back("single_threaded");
684 ret.push_back("auto_recover_backup_interval");
685 ret.push_back("restrict_radius_ducks");
686 ret.push_back("resize_imported_images");
687 ret.push_back("browser_command");
688 ret.push_back("custom_filename_prefix");
689 ret.push_back("preferred_x_size");
690 ret.push_back("preferred_y_size");
691 ret.push_back("predefined_size");
696 static ::Preferences _preferences;
701 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
703 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
705 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
707 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
708 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
709 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
710 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
711 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
712 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
713 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
714 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
715 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
716 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
717 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
718 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
719 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
721 // Add the synfigapp actions...
722 synfigapp::Action::Book::iterator iter;
723 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
725 actions_action_group->add(Gtk::Action::create(
726 "action-"+iter->second.name,
727 get_action_stock_id(iter->second),
728 iter->second.local_name,iter->second.local_name
732 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
733 #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); }
734 #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); }
736 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
737 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
738 DEFINE_ACTION("new", Gtk::Stock::NEW);
739 DEFINE_ACTION("open", Gtk::Stock::OPEN);
740 DEFINE_ACTION("save", Gtk::Stock::SAVE);
741 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
742 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
743 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
744 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
745 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
746 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
747 DEFINE_ACTION("import", _("Import"));
748 DEFINE_ACTION("render", _("Render"));
749 DEFINE_ACTION("preview", _("Preview"));
750 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
751 DEFINE_ACTION("sound", _("Sound File"));
752 DEFINE_ACTION("options", _("Options"));
753 DEFINE_ACTION("close", _("Close View"));
754 DEFINE_ACTION("close-document", _("Close Document"));
755 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
758 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
759 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
760 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
761 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
762 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
763 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
764 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
765 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
766 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
767 DEFINE_ACTION("properties", _("Properties"));
769 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
770 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
771 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
772 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
773 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
774 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
775 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
776 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
777 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
778 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
779 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
780 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
781 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
782 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
783 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
784 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
785 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
786 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
787 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
788 DEFINE_ACTION("play", _("Play"));
789 // DEFINE_ACTION("pause", _("Pause"));
790 DEFINE_ACTION("stop", _("Stop"));
791 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
792 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
793 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
794 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
795 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
796 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
797 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
798 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
799 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
800 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
801 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
802 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
803 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
804 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
805 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
806 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
807 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
808 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
809 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
810 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
811 DEFINE_ACTION("seek-end", _("Seek to End"));
813 DEFINE_ACTION("action-group_add", _("Add group"));
815 DEFINE_ACTION("canvas-new", _("New Canvas"));
817 DEFINE_ACTION("amount-inc", _("Increase Amount"));
818 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
823 // Set up synfigapp actions
825 synfigapp::Action::Book::iterator iter;
827 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
829 Gtk::StockID stock_id;
831 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
833 //Gtk::Image* image(manage(new Gtk::Image()));
834 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
835 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
836 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
837 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
838 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
839 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
840 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
841 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
842 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
843 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
845 actions_action_group->add(Gtk::Action::create(
846 "action-"+iter->second.name,
848 iter->second.local_name,iter->second.local_name
856 Glib::ustring ui_info =
858 " <popup name='menu-toolbox' action='menu-toolbox'>"
859 " <menu action='menu-file'>"
862 " <popup name='menu-main' action='menu-main'>"
863 " <menu action='menu-file'>"
864 " <menuitem action='new' />"
865 " <menuitem action='open' />"
866 " <menuitem action='save' />"
867 " <menuitem action='save-as' />"
868 " <menuitem action='revert' />"
869 " <separator name='bleh01'/>"
870 " <menuitem action='cvs-add' />"
871 " <menuitem action='cvs-update' />"
872 " <menuitem action='cvs-commit' />"
873 " <menuitem action='cvs-revert' />"
874 " <separator name='bleh02'/>"
875 " <menuitem action='import' />"
876 " <separator name='bleh03'/>"
877 " <menuitem action='render' />"
878 " <menuitem action='preview' />"
879 " <menuitem action='sound' />"
880 " <separator name='bleh04'/>"
881 " <menuitem action='options' />"
882 " <menuitem action='close' />"
883 " <menuitem action='close-document' />"
884 " <menuitem action='quit' />"
886 " <menu action='menu-edit'>"
887 " <menuitem action='undo'/>"
888 " <menuitem action='redo'/>"
889 " <separator name='bleh05'/>"
890 " <menuitem action='cut'/>"
891 " <menuitem action='copy'/>"
892 " <menuitem action='paste'/>"
893 " <separator name='bleh06'/>"
894 " <menuitem action='select-all-layers'/>"
895 " <menuitem action='unselect-all-layers'/>"
896 " <menuitem action='select-all-ducks'/>"
897 " <menuitem action='unselect-all-ducks'/>"
898 " <separator name='bleh07'/>"
899 " <menuitem action='properties'/>"
901 " <menu action='menu-view'>"
902 " <menu action='menu-duck-mask'>"
903 " <menuitem action='mask-position-ducks' />"
904 " <menuitem action='mask-vertex-ducks' />"
905 " <menuitem action='mask-tangent-ducks' />"
906 " <menuitem action='mask-radius-ducks' />"
907 " <menuitem action='mask-width-ducks' />"
908 " <menuitem action='mask-angle-ducks' />"
910 " <menu action='menu-preview-quality'>"
911 " <menuitem action='quality-00' />"
912 " <menuitem action='quality-01' />"
913 " <menuitem action='quality-02' />"
914 " <menuitem action='quality-03' />"
915 " <menuitem action='quality-04' />"
916 " <menuitem action='quality-05' />"
917 " <menuitem action='quality-06' />"
918 " <menuitem action='quality-07' />"
919 " <menuitem action='quality-08' />"
920 " <menuitem action='quality-09' />"
921 " <menuitem action='quality-10' />"
923 " <menu action='menu-lowres-pixel'>"
924 " <menuitem action='decrease-low-res-pixel-size'/>"
925 " <menuitem action='increase-low-res-pixel-size'/>"
926 " <separator name='pixel-size-separator'/>"
929 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
930 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
934 " <separator name='bleh08'/>"
935 " <menuitem action='play'/>"
936 //" <menuitem action='pause'/>"
937 " <menuitem action='stop'/>"
938 " <menuitem action='dialog-flipbook'/>"
939 " <separator name='bleh09'/>"
940 " <menuitem action='toggle-grid-show'/>"
941 " <menuitem action='toggle-grid-snap'/>"
942 " <menuitem action='toggle-guide-show'/>"
943 " <menuitem action='toggle-low-res'/>"
944 " <menuitem action='toggle-onion-skin'/>"
945 " <separator name='bleh10'/>"
946 " <menuitem action='canvas-zoom-in'/>"
947 " <menuitem action='canvas-zoom-out'/>"
948 " <menuitem action='canvas-zoom-fit'/>"
949 " <menuitem action='canvas-zoom-100'/>"
950 " <separator name='bleh11'/>"
951 " <menuitem action='time-zoom-in'/>"
952 " <menuitem action='time-zoom-out'/>"
953 " <separator name='bleh12'/>"
954 " <menuitem action='jump-next-keyframe'/>"
955 " <menuitem action='jump-prev-keyframe'/>"
956 " <menuitem action='seek-next-frame'/>"
957 " <menuitem action='seek-prev-frame'/>"
958 " <menuitem action='seek-next-second'/>"
959 " <menuitem action='seek-prev-second'/>"
960 " <menuitem action='seek-begin'/>"
961 " <menuitem action='seek-end'/>"
963 " <menu action='menu-canvas'>"
964 " <menuitem action='canvas-new'/>"
966 " <menu name='menu-state' action='menu-state'>"
968 " <menu action='menu-group'>"
969 " <menuitem action='action-group_add'/>"
971 " <menu action='menu-layer'>"
972 //" <menuitem action='cut'/>"
973 //" <menuitem action='copy'/>"
974 //" <menuitem action='paste'/>"
975 //" <separator name='bleh06'/>"
976 " <menu action='menu-layer-new'></menu>"
977 " <menuitem action='amount-inc'/>"
978 " <menuitem action='amount-dec'/>"
980 " <menu action='menu-keyframe'>"
981 " <menuitem action='keyframe-properties'/>"
988 " <menubar name='MenuBar'>"
989 " <menu action='MenuFile'>"
990 " <menuitem action='New'/>"
991 " <menuitem action='Open'/>"
993 " <menuitem action='Quit'/>"
995 " <menu action='MenuEdit'>"
996 " <menuitem action='Cut'/>"
997 " <menuitem action='Copy'/>"
998 " <menuitem action='Paste'/>"
1001 " <toolbar name='ToolBar'>"
1002 " <toolitem action='Open'/>"
1003 " <toolitem action='Quit'/>"
1009 actions_action_group->set_sensitive(false);
1010 App::ui_manager()->set_add_tearoffs(true);
1011 App::ui_manager()->insert_action_group(menus_action_group,1);
1012 App::ui_manager()->insert_action_group(actions_action_group,1);
1013 App::ui_manager()->add_ui_from_string(ui_info);
1015 //App::ui_manager()->get_accel_group()->unlock();
1017 catch(const Glib::Error& ex)
1019 synfig::error("building menus and toolbars failed: " + ex.what());
1022 // Add default keyboard accelerators
1023 #define ACCEL(accel,path) \
1025 Gtk::AccelKey accel_key(accel,path); \
1026 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1029 #define ACCEL2(accel) \
1031 Gtk::AccelKey accel_key(accel); \
1032 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
1036 ACCEL("<Mod1>a", "<Actions>//state-normal" );
1037 ACCEL("<Mod1>v", "<Actions>//state-smooth_move" );
1038 ACCEL("<Mod1>s", "<Actions>//state-scale" );
1039 ACCEL("<Mod1>t", "<Actions>//state-rotate" );
1040 ACCEL("<Mod1>m", "<Actions>//state-mirror" );
1041 ACCEL("<Mod1>c", "<Actions>//state-circle" );
1042 ACCEL("<Mod1>r", "<Actions>//state-rectangle" );
1043 ACCEL("<Mod1>q", "<Actions>//state-star" );
1044 ACCEL("<Mod1>g", "<Actions>//state-gradient" );
1045 ACCEL("<Mod1>p", "<Actions>//state-polygon" );
1046 ACCEL("<Mod1>b", "<Actions>//state-bline" );
1047 ACCEL("<Mod1>x", "<Actions>//state-text" );
1048 ACCEL("<Mod1>f", "<Actions>//state-fill" );
1049 ACCEL("<Mod1>e", "<Actions>//state-eyedrop" );
1050 ACCEL("<Mod1>z", "<Actions>//state-zoom" );
1051 ACCEL("<Mod1>d", "<Actions>//state-draw" );
1052 ACCEL("<Mod1>k", "<Actions>//state-sketch" );
1053 ACCEL("<Mod1>w", "<Actions>//state-width" );
1056 ACCEL("<Control>a", "<Actions>//select-all-ducks" );
1057 ACCEL("<Control>d", "<Actions>//unselect-all-ducks" );
1058 ACCEL("<Control><Shift>a", "<Actions>//select-all-layers" );
1059 ACCEL("<Control><Shift>d", "<Actions>//unselect-all-layers" );
1060 ACCEL("F9", "<Actions>//render" );
1061 ACCEL("F11", "<Actions>//preview" );
1062 ACCEL("F8", "<Actions>//properties" );
1063 ACCEL("F12", "<Actions>//options" );
1064 ACCEL("<control>i", "<Actions>//import" );
1065 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0), "<Actions>//stop" ));
1066 ACCEL("<Control>g", "<Actions>//toggle-grid-show" );
1067 ACCEL("<Control>l", "<Actions>//toggle-grid-snap" );
1068 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "<Actions>//toggle-low-res" ));
1069 ACCEL("<Mod1>1", "<Actions>//mask-position-ducks" );
1070 ACCEL("<Mod1>2", "<Actions>//mask-vertex-ducks" );
1071 ACCEL("<Mod1>3", "<Actions>//mask-tangent-ducks" );
1072 ACCEL("<Mod1>4", "<Actions>//mask-radius-ducks" );
1073 ACCEL("<Mod1>5", "<Actions>//mask-width-ducks" );
1074 ACCEL("<Mod1>6", "<Actions>//mask-angle-ducks" );
1075 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "<Actions>//action-LayerRaise" ));
1076 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "<Actions>//action-LayerLower" ));
1077 ACCEL("<Control>1", "<Actions>//quality-01" );
1078 ACCEL("<Control>2", "<Actions>//quality-02" );
1079 ACCEL("<Control>3", "<Actions>//quality-03" );
1080 ACCEL("<Control>4", "<Actions>//quality-04" );
1081 ACCEL("<Control>5", "<Actions>//quality-05" );
1082 ACCEL("<Control>6", "<Actions>//quality-06" );
1083 ACCEL("<Control>7", "<Actions>//quality-07" );
1084 ACCEL("<Control>8", "<Actions>//quality-08" );
1085 ACCEL("<Control>9", "<Actions>//quality-09" );
1086 ACCEL("<Control>0", "<Actions>//quality-10" );
1087 ACCEL("<Control>z", "<Actions>//undo" );
1088 ACCEL("<Control>r", "<Actions>//redo" );
1089 ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "<Actions>//action-LayerRemove" ));
1090 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "<Actions>//decrease-low-res-pixel-size" ));
1091 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "<Actions>//increase-low-res-pixel-size" ));
1092 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>//amount-dec" ));
1093 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "<Actions>//amount-inc" ));
1094 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "<Actions>//jump-next-keyframe" ));
1095 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "<Actions>//jump-prev-keyframe" ));
1096 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "<Actions>//canvas-zoom-in" ));
1097 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "<Actions>//canvas-zoom-out" ));
1098 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "<Actions>//time-zoom-in" ));
1099 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "<Actions>//time-zoom-out" ));
1100 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "<Actions>//seek-next-frame" ));
1101 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "<Actions>//seek-prev-frame" ));
1102 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "<Actions>//seek-next-second" ));
1103 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "<Actions>//seek-prev-second" ));
1104 ACCEL("<Mod1>o", "<Actions>//toggle-onion-skin" );
1105 ACCEL("<Control><Shift>z", "<Actions>//canvas-zoom-fit" );
1106 ACCEL("<Control>p", "<Actions>//play" );
1107 ACCEL("Home", "<Actions>//seek-begin" );
1108 ACCEL("End", "<Actions>//seek-end" );
1114 #define mkdir(x,y) mkdir(x)
1117 /* === M E T H O D S ======================================================= */
1119 App::App(int *argc, char ***argv):
1120 Gtk::Main(argc,argv),
1121 IconController(etl::dirname((*argv)[0]))
1123 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1126 ui_interface_=new GlobalUIInterface();
1130 // don't call thread_init() if threads are already initialized
1131 // on some machines bonobo_init() initialized threads before we get here
1132 if (!g_thread_supported())
1133 Glib::thread_init();
1135 distance_system=Distance::SYSTEM_UNITS;
1137 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1140 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1144 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1150 if(!SYNFIG_CHECK_VERSION())
1152 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1153 dialog_error_blocking("Synfig Studio",
1154 "This copy of Synfig Studio was compiled against a\n"
1155 "different version of libsynfig than what is currently\n"
1156 "installed. Synfig Studio will now abort. Try downloading\n"
1157 "the latest version from the Synfig website at\n"
1158 "http://synfig.org/Download"
1162 Glib::set_application_name(_("Synfig Studio"));
1164 Splash splash_screen;
1165 splash_screen.show();
1167 shutdown_in_progress=false;
1168 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1169 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1171 // Initialize the Synfig library
1172 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1173 catch(std::runtime_error x)
1175 get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what()));
1180 get_ui_interface()->error(_("Failed to initialize synfig!"));
1184 // add the preferences to the settings
1185 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1189 studio_init_cb.task(_("Init UI Manager..."));
1190 App::ui_manager_=studio::UIManager::create();
1193 studio_init_cb.task(_("Init Dock Manager..."));
1194 dock_manager=new studio::DockManager();
1196 studio_init_cb.task(_("Init State Manager..."));
1197 state_manager=new StateManager();
1199 studio_init_cb.task(_("Init Toolbox..."));
1200 toolbox=new studio::Toolbox();
1202 studio_init_cb.task(_("Init About Dialog..."));
1203 about=new studio::About();
1205 studio_init_cb.task(_("Init Tool Options..."));
1206 dialog_tool_options=new studio::Dialog_ToolOptions();
1207 dock_manager->register_dockable(*dialog_tool_options);
1209 studio_init_cb.task(_("Init History..."));
1210 dock_history=new studio::Dock_History();
1211 dock_manager->register_dockable(*dock_history);
1213 studio_init_cb.task(_("Init Canvases..."));
1214 dock_canvases=new studio::Dock_Canvases();
1215 dock_manager->register_dockable(*dock_canvases);
1217 studio_init_cb.task(_("Init Keyframes..."));
1218 dock_keyframes=new studio::Dock_Keyframes();
1219 dock_manager->register_dockable(*dock_keyframes);
1221 studio_init_cb.task(_("Init Layers..."));
1222 dock_layers=new studio::Dock_Layers();
1223 dock_manager->register_dockable(*dock_layers);
1225 studio_init_cb.task(_("Init Params..."));
1226 dock_params=new studio::Dock_Params();
1227 dock_manager->register_dockable(*dock_params);
1229 studio_init_cb.task(_("Init MetaData..."));
1230 dock_meta_data=new studio::Dock_MetaData();
1231 dock_manager->register_dockable(*dock_meta_data);
1233 studio_init_cb.task(_("Init Children..."));
1234 dock_children=new studio::Dock_Children();
1235 dock_manager->register_dockable(*dock_children);
1237 studio_init_cb.task(_("Init Info..."));
1238 dock_info = new studio::Dock_Info();
1239 dock_manager->register_dockable(*dock_info);
1241 studio_init_cb.task(_("Init Navigator..."));
1242 dock_navigator = new studio::Dock_Navigator();
1243 dock_manager->register_dockable(*dock_navigator);
1245 studio_init_cb.task(_("Init Timetrack..."));
1246 dock_timetrack = new studio::Dock_Timetrack();
1247 dock_manager->register_dockable(*dock_timetrack);
1249 studio_init_cb.task(_("Init Curve Editor..."));
1250 dock_curves = new studio::Dock_Curves();
1251 dock_manager->register_dockable(*dock_curves);
1253 studio_init_cb.task(_("Init Layer Groups..."));
1254 dock_layer_groups = new studio::Dock_LayerGroups();
1255 dock_manager->register_dockable(*dock_layer_groups);
1258 studio_init_cb.task(_("Init Color Dialog..."));
1259 dialog_color=new studio::Dialog_Color();
1261 studio_init_cb.task(_("Init Gradient Dialog..."));
1262 dialog_gradient=new studio::Dialog_Gradient();
1264 studio_init_cb.task(_("Init DeviceTracker..."));
1265 device_tracker=new studio::DeviceTracker();
1267 studio_init_cb.task(_("Init Tools..."));
1270 state_manager->add_state(&state_normal);
1271 state_manager->add_state(&state_smooth_move);
1272 state_manager->add_state(&state_scale);
1273 state_manager->add_state(&state_rotate);
1274 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1277 state_manager->add_state(&state_circle);
1278 state_manager->add_state(&state_rectangle);
1279 state_manager->add_state(&state_star);
1280 state_manager->add_state(&state_gradient);
1281 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1284 state_manager->add_state(&state_bline);
1285 state_manager->add_state(&state_text);
1286 state_manager->add_state(&state_fill);
1287 state_manager->add_state(&state_eyedrop);
1288 state_manager->add_state(&state_zoom);
1290 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1291 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1292 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1294 studio_init_cb.task(_("Init ModPalette..."));
1295 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1297 studio_init_cb.task(_("Init Setup Dialog..."));
1298 dialog_setup=new studio::Dialog_Setup();
1300 studio_init_cb.task(_("Init Input Dialog..."));
1301 dialog_input=new Gtk::InputDialog();
1302 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1303 dialog_input->get_save_button()->signal_clicked().connect( sigc::mem_fun( *device_tracker, &DeviceTracker::save_preferences) );
1305 studio_init_cb.task(_("Init auto recovery..."));
1306 auto_recover=new AutoRecover();
1308 studio_init_cb.amount_complete(9250,10000);
1309 studio_init_cb.task(_("Loading Settings..."));
1311 device_tracker->load_preferences();
1313 studio_init_cb.task(_("Checking auto-recover..."));
1315 studio_init_cb.amount_complete(9900,10000);
1317 bool opened_any = false;
1318 if(auto_recover->recovery_needed())
1320 splash_screen.hide();
1321 if (get_ui_interface()->confirmation("Crash Recovery",
1322 _("Auto recovery file found"),
1323 _("Synfig Studio seems to have crashed\n"
1324 "before you could save all your files.\n"
1325 "Recover unsaved changes?"),
1326 _("Recover"), _("Ignore"))
1327 == synfigapp::UIInterface::RESPONSE_OK)
1329 int number_recovered;
1330 if(!auto_recover->recover(number_recovered))
1331 if (number_recovered)
1332 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1334 get_ui_interface()->error(_("Unable to recover from previous crash"));
1336 get_ui_interface()->error(
1337 _("Synfig Studio has attempted to recover\n"
1338 "from a previous crash. The files that it has\n"
1339 "recovered are NOT YET SAVED. It would be a good\n"
1340 "idea to review them and save them now."));
1342 if (number_recovered)
1345 splash_screen.show();
1348 // Look for any files given on the command line,
1349 // and load them if found.
1350 for(;*argc>=1;(*argc)--)
1351 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1353 studio_init_cb.task(_("Loading files..."));
1354 splash_screen.hide();
1355 open((*argv)[*argc]);
1357 splash_screen.show();
1360 // if no file was specified to be opened, create a new document to help new users get started more easily
1361 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1364 studio_init_cb.task(_("Done."));
1365 studio_init_cb.amount_complete(10000,10000);
1371 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1375 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1379 StateManager* App::get_state_manager() { return state_manager; }
1383 shutdown_in_progress=true;
1387 synfigapp::Main::settings().remove_domain("pref");
1389 selected_instance=0;
1391 // Unload all of the modules
1392 for(;!module_list_.empty();module_list_.pop_back())
1395 delete state_manager;
1399 delete auto_recover;
1405 // studio::App::iteration(false);
1409 // studio::App::iteration(false);
1411 // studio::App::iteration(false);
1413 delete dialog_setup;
1415 delete dialog_gradient;
1417 delete dialog_color;
1419 delete dialog_input;
1421 delete dock_manager;
1423 instance_list.clear();
1425 // studio::App::iteration(false);
1429 App::get_user_app_directory()
1431 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1433 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1435 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1440 App::get_config_file(const synfig::String& file)
1442 return Glib::build_filename(get_user_app_directory(),file);
1445 #define SCALE_FACTOR (1280)
1446 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1448 App::set_recent_file_window_size(etl::handle<Instance> instance)
1450 int screen_w(Gdk::screen_width());
1451 int screen_h(Gdk::screen_height());
1453 const std::string &canvas_window_size = *recent_files_window_size.begin();
1455 if(canvas_window_size.empty())
1458 synfig::String::size_type current=0;
1459 bool seen_root(false), shown_non_root(false);
1461 while(current != synfig::String::npos)
1463 // find end of first field (canvas) or return
1464 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1465 if(separator == synfig::String::npos) break;
1468 synfig::Canvas::Handle canvas;
1471 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings);
1473 catch(Exception::IDNotFound) {
1474 // can't find the canvas; skip to the next canvas or return
1475 separator = canvas_window_size.find_first_of('\t', current);
1476 if(separator == synfig::String::npos) return;
1477 current = separator+1;
1481 if (canvas->is_root())
1484 shown_non_root = true;
1486 // check that we have the tab character the ends this canvas' data or return
1487 current = separator+1;
1488 separator = canvas_window_size.find_first_of('\t', current);
1489 if(separator == synfig::String::npos) return;
1492 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1494 current = separator+1;
1498 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1499 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1500 x=x*screen_w/SCALE_FACTOR;
1501 y=y*screen_h/SCALE_FACTOR;
1502 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1503 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1504 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1505 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1507 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1508 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1510 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1511 canvasview->move(x,y);
1512 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1513 canvasview->present();
1515 current = separator+1;
1518 if (shown_non_root && !seen_root)
1519 instance->find_canvas_view(instance->get_canvas())->hide();
1523 App::add_recent_file(const etl::handle<Instance> instance)
1525 int screen_w(Gdk::screen_width());
1526 int screen_h(Gdk::screen_height());
1528 std::string canvas_window_size;
1530 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1531 Instance::CanvasViewList::const_iterator iter;
1533 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1535 if( !((*iter)->is_visible()) )
1538 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1539 int x_pos, y_pos, x_size, y_size;
1540 (*iter)->get_position(x_pos,y_pos);
1541 (*iter)->get_size(x_size,y_size);
1543 canvas_window_size += strprintf("%s %d %d %d %d\t",
1544 canvas->get_relative_id(canvas->get_root()).c_str(),
1545 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1546 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1549 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1554 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1556 std::string filename(file_name);
1558 assert(!filename.empty());
1560 if(filename.empty())
1563 // Toss out any "hidden" files
1564 if(basename(filename)[0]=='.')
1567 // If we aren't an absolute path, turn ourselves into one
1568 if(!is_absolute_path(filename))
1569 filename=absolute_path(filename);
1571 std::string old_window_size;
1573 list<string>::iterator iter;
1574 list<string>::iterator iter_wsize;
1575 // Check to see if the file is already on the list.
1576 // If it is, then remove it from the list
1577 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1580 recent_files.erase(iter);
1581 old_window_size = *iter_wsize;
1582 recent_files_window_size.erase(iter_wsize);
1587 // Push the filename to the front of the list
1588 recent_files.push_front(filename);
1589 if(window_size.empty())
1590 recent_files_window_size.push_front(old_window_size);
1592 recent_files_window_size.push_front(window_size);
1594 // Clean out the files at the end of the list.
1595 while(recent_files.size()>(unsigned)get_max_recent_files())
1597 recent_files.pop_back();
1598 recent_files_window_size.pop_back();
1601 signal_recent_files_changed_();
1606 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1609 App::get_time_format()
1611 return _App_time_format;
1615 App::set_time_format(synfig::Time::Format x)
1622 App::save_settings()
1627 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1628 setlocale(LC_NUMERIC, "C");
1630 std::string filename=get_config_file("accelrc");
1631 Gtk::AccelMap::save(filename);
1634 std::string filename=get_config_file("recentfiles");
1636 std::ofstream file(filename.c_str());
1640 synfig::warning("Unable to save %s",filename.c_str());
1644 list<string>::reverse_iterator iter;
1646 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1650 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1652 std::ofstream file(filename.c_str());
1656 synfig::warning("Unable to save %s",filename.c_str());
1660 list<string>::reverse_iterator iter;
1662 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1666 std::string filename=get_config_file("settings");
1667 synfigapp::Main::settings().save_to_file(filename);
1668 setlocale(LC_NUMERIC,old_locale);
1672 synfig::warning("Caught exception when attempting to save settings.");
1677 App::load_settings()
1682 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1683 setlocale(LC_NUMERIC, "C");
1685 std::string filename=get_config_file("accelrc");
1686 Gtk::AccelMap::load(filename);
1689 bool window_size_broken = false;
1691 std::string filename=get_config_file("recentfiles");
1692 std::string filename_window_size=filename+std::string("_window_size");
1694 std::ifstream file(filename.c_str());
1695 std::ifstream file_window_size(filename_window_size.c_str());
1697 if(!file_window_size)
1698 window_size_broken = true;
1702 std::string recent_file;
1703 std::string recent_file_window_size;
1704 getline(file,recent_file);
1705 if(!window_size_broken)
1706 getline(file_window_size,recent_file_window_size);
1707 if(!recent_file.empty())
1709 if(!window_size_broken && !file_window_size)
1710 window_size_broken = true;
1711 if (std::ifstream(recent_file.c_str()))
1713 if(!window_size_broken)
1714 add_recent_file(recent_file,recent_file_window_size);
1716 add_recent_file(recent_file);
1720 if(!window_size_broken && file_window_size)
1721 window_size_broken = true;
1723 if(window_size_broken)
1725 recent_files_window_size.clear();
1726 recent_files_window_size.resize(recent_files.size());
1729 std::string filename=get_config_file("settings");
1730 if(!synfigapp::Main::settings().load_from_file(filename))
1732 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1733 //if(!synfigapp::Main::settings().load_from_file(filename))
1735 gamma.set_gamma(1.0/2.2);
1736 reset_initial_window_configuration();
1739 setlocale(LC_NUMERIC,old_locale);
1743 synfig::warning("Caught exception when attempting to load settings.");
1748 App::reset_initial_window_configuration()
1750 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1751 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1752 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1753 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1754 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1755 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1756 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1757 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1758 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1759 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1760 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1761 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1762 #ifdef SINGLE_THREADED
1763 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1765 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1766 synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
1767 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1768 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1769 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1770 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1771 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1775 App::shutdown_request(GdkEventAny*)
1779 //return !shutdown_in_progress;
1785 if(shutdown_in_progress)return;
1788 get_ui_interface()->task(_("Quit Request"));
1791 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1795 std::list<etl::handle<Instance> >::iterator iter;
1796 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1798 if(!(*iter)->safe_close())
1802 if((*iter)->synfigapp::Instance::get_action_count())
1804 handle<synfigapp::UIInterface> uim;
1805 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1807 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1808 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1810 case synfigapp::UIInterface::RESPONSE_NO:
1812 case synfigapp::UIInterface::RESPONSE_YES:
1815 case synfigapp::UIInterface::RESPONSE_CANCEL:
1824 if((*iter)->synfigapp::Instance::is_modified())
1826 handle<synfigapp::UIInterface> uim;
1827 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1829 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() );
1830 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1832 case synfigapp::UIInterface::RESPONSE_NO:
1834 case synfigapp::UIInterface::RESPONSE_YES:
1835 (*iter)->dialog_cvs_commit();
1837 case synfigapp::UIInterface::RESPONSE_CANCEL:
1846 // This next line causes things to crash for some reason
1850 shutdown_in_progress=true;
1852 instance_list.clear();
1854 while(studio::App::events_pending())studio::App::iteration(false);
1857 auto_recover->normal_shutdown();
1859 get_ui_interface()->task(_("Quit Request sent"));
1865 dialog_setup->refresh();
1866 dialog_setup->show();
1869 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1870 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1873 //#define USE_WIN32_FILE_DIALOGS 1
1876 #ifdef USE_WIN32_FILE_DIALOGS
1877 static OPENFILENAME ofn={};
1881 #include <gdk/gdkwin32.h>
1885 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1887 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1889 #ifdef USE_WIN32_FILE_DIALOGS
1890 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1892 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1893 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1894 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1896 ofn.lStructSize=sizeof(OPENFILENAME);
1897 ofn.hwndOwner = hWnd;
1898 ofn.hInstance = hInstance;
1899 ofn.lpstrFilter = szFilter;
1900 // ofn.lpstrCustomFilter=NULL;
1901 // ofn.nMaxCustFilter=0;
1902 // ofn.nFilterIndex=0;
1903 // ofn.lpstrFile=NULL;
1904 ofn.nMaxFile=MAX_PATH;
1905 // ofn.lpstrFileTitle=NULL;
1906 // ofn.lpstrInitialDir=NULL;
1907 // ofn.lpstrTitle=NULL;
1908 ofn.Flags=OFN_HIDEREADONLY;
1909 // ofn.nFileOffset=0;
1910 // ofn.nFileExtension=0;
1911 ofn.lpstrDefExt=TEXT("sif");
1912 // ofn.lCustData = 0l;
1914 // ofn.lpTemplateName=NULL;
1916 CHAR szFilename[MAX_PATH];
1918 strcpy(szFilename,filename.c_str());
1919 strcpy(szTitle,title.c_str());
1921 ofn.lpstrFile=szFilename;
1922 ofn.lpstrFileTitle=szTitle;
1924 if(GetOpenFileName(&ofn))
1926 filename=szFilename;
1932 synfig::String prev_path;
1934 if(!_preferences.get_value(preference, prev_path))
1937 prev_path = absolute_path(prev_path);
1939 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1941 dialog->set_current_folder(prev_path);
1942 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1943 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1945 if (filename.empty())
1946 dialog->set_filename(prev_path);
1947 else if (is_absolute_path(filename))
1948 dialog->set_filename(filename);
1950 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1952 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1953 filename = dialog->get_filename();
1954 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1955 _preferences.set_value(preference, dirname(filename));
1969 GtkWidget *fileselection;
1970 fileselection = gtk_file_selection_new(title.c_str());
1973 if(basename(filename)==filename)
1975 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1978 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1980 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1982 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1983 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1985 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1986 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1988 gtk_widget_show(fileselection);
1996 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1997 _preferences.set_value(preference,dirname(filename));
2001 gtk_widget_destroy(fileselection);
2004 gtk_widget_destroy(fileselection);
2011 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
2013 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
2015 #if USE_WIN32_FILE_DIALOGS
2016 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
2018 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
2019 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
2020 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
2022 ofn.lStructSize=sizeof(OPENFILENAME);
2023 ofn.hwndOwner = hWnd;
2024 ofn.hInstance = hInstance;
2025 ofn.lpstrFilter = szFilter;
2026 // ofn.lpstrCustomFilter=NULL;
2027 // ofn.nMaxCustFilter=0;
2028 // ofn.nFilterIndex=0;
2029 // ofn.lpstrFile=NULL;
2030 ofn.nMaxFile=MAX_PATH;
2031 // ofn.lpstrFileTitle=NULL;
2032 // ofn.lpstrInitialDir=NULL;
2033 // ofn.lpstrTitle=NULL;
2034 ofn.Flags=OFN_OVERWRITEPROMPT;
2035 // ofn.nFileOffset=0;
2036 // ofn.nFileExtension=0;
2037 ofn.lpstrDefExt=TEXT("sif");
2038 // ofn.lCustData = 0l;
2040 // ofn.lpTemplateName=NULL;
2042 CHAR szFilename[MAX_PATH];
2044 strcpy(szFilename,filename.c_str());
2045 strcpy(szTitle,title.c_str());
2047 ofn.lpstrFile=szFilename;
2048 ofn.lpstrFileTitle=szTitle;
2050 if(GetSaveFileName(&ofn))
2052 filename=szFilename;
2053 _preferences.set_value(preference,dirname(filename));
2058 synfig::String prev_path;
2060 if(!_preferences.get_value(preference, prev_path))
2063 prev_path = absolute_path(prev_path);
2065 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2067 dialog->set_current_folder(prev_path);
2068 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2069 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2071 Widget_Enum *file_type_enum = 0;
2072 if (preference == ANIMATION_DIR_PREFERENCE)
2074 file_type_enum = manage(new Widget_Enum());
2075 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2076 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2077 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2078 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2079 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2080 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2082 Gtk::HBox *hbox = manage(new Gtk::HBox);
2083 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2084 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2087 dialog->set_extra_widget(*hbox);
2090 if (filename.empty())
2091 dialog->set_filename(prev_path);
2094 std::string full_path;
2095 if (is_absolute_path(filename))
2096 full_path = filename;
2098 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2100 // select the file if it exists
2101 dialog->set_filename(full_path);
2103 // if the file doesn't exist, put its name into the filename box
2105 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2106 dialog->set_current_name(basename(filename));
2109 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2110 if (preference == ANIMATION_DIR_PREFERENCE)
2111 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2112 filename = dialog->get_filename();
2113 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2114 _preferences.set_value(preference, dirname(filename));
2125 App::dialog_error_blocking(const std::string &title, const std::string &message)
2127 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2128 dialog.set_title(title);
2134 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2136 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2137 dialog.set_title(title);
2143 App::dialog_yes_no(const std::string &title, const std::string &message)
2148 true // use_separator
2150 Gtk::Label label(message);
2153 dialog.get_vbox()->pack_start(label);
2154 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2155 dialog.add_button(Gtk::StockID("gtk-no"),0);
2157 return dialog.run();
2161 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2166 true // use_separator
2168 Gtk::Label label(message);
2171 dialog.get_vbox()->pack_start(label);
2172 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2173 dialog.add_button(Gtk::StockID("gtk-no"),0);
2174 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2176 return dialog.run();
2180 App::dialog_not_implemented()
2182 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2183 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2188 try_open_url(const std::string &url)
2191 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2193 std::vector<std::string> command_line;
2194 std::vector<std::string> browsers;
2195 browsers.reserve(23);
2197 // Browser wrapper scripts
2198 #ifdef USE_OPEN_FOR_URLS
2199 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2201 browsers.push_back("xdg-open"); // XDG wrapper
2202 browsers.push_back("sensible-browser"); // Debian wrapper
2203 browsers.push_back("gnome-open"); // GNOME wrapper
2204 browsers.push_back("kfmclient"); // KDE wrapper
2205 browsers.push_back("exo-open"); // XFCE wrapper
2207 // Alternatives system
2208 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2209 browsers.push_back("x-www-browser"); // Debian GUI alternative
2211 // Individual browsers
2212 browsers.push_back("firefox");
2213 browsers.push_back("epiphany-browser");
2214 browsers.push_back("epiphany");
2215 browsers.push_back("konqueror");
2216 browsers.push_back("iceweasel");
2217 browsers.push_back("mozilla");
2218 browsers.push_back("netscape");
2219 browsers.push_back("icecat");
2220 browsers.push_back("galeon");
2221 browsers.push_back("midori");
2222 browsers.push_back("safari");
2223 browsers.push_back("opera");
2224 browsers.push_back("amaya");
2225 browsers.push_back("netsurf");
2226 browsers.push_back("dillo");
2228 // Try the user-specified browser first
2229 command_line.push_back(App::browser_command);
2230 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2231 command_line.push_back(url);
2233 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2234 catch( Glib::SpawnError& exception ){
2236 while ( !browsers.empty() )
2238 // Skip the browser if we already tried it
2239 if( browsers[0] == App::browser_command )
2242 // Construct the command line
2243 command_line.clear();
2244 command_line.push_back(browsers[0]);
2245 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2246 command_line.push_back(url);
2248 // Remove the browser from the list
2249 browsers.erase(browsers.begin());
2251 // Try to spawn the browser
2252 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2253 // Failed, move on to the next one
2254 catch(Glib::SpawnError& exception){ continue; }
2255 return true; // No exception means we succeeded!
2266 if (!try_open_url("http://synfig.org/Documentation"))
2268 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2269 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2270 dialog.set_title(_("Help"));
2276 App::open_url(const std::string &url)
2278 if(!try_open_url(url))
2280 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2281 dialog.set_secondary_text(url);
2282 dialog.set_title(_("No browser found"));
2288 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2293 true); // use_separator
2295 Gtk::Label label(message);
2297 dialog.get_vbox()->pack_start(label);
2300 entry.set_text(text);
2302 entry.set_activates_default(true);
2304 dialog.get_vbox()->pack_start(entry);
2306 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2307 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2308 dialog.set_default_response(Gtk::RESPONSE_OK);
2310 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2313 if(dialog.run()!=Gtk::RESPONSE_OK)
2316 text=entry.get_text();
2322 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2327 true); // use_separator
2329 Gtk::Label label(message);
2331 dialog.get_vbox()->pack_start(label);
2333 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2334 text_buffer->set_text(text);
2335 Gtk::TextView text_view(text_buffer);
2338 dialog.get_vbox()->pack_start(text_view);
2340 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2341 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2342 dialog.set_default_response(Gtk::RESPONSE_OK);
2344 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2347 if(dialog.run()!=Gtk::RESPONSE_OK)
2350 text=text_buffer->get_text();
2356 App::open(std::string filename)
2358 return open_as(filename,filename);
2361 // this is called from autorecover.cpp:
2362 // App::open_as(get_shadow_file_name(filename),filename)
2363 // other than that, 'filename' and 'as' are the same
2365 App::open_as(std::string filename,std::string as)
2368 char long_name[1024];
2369 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2370 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2371 // don't use it if that's the case
2372 if (long_name[0] != '\0')
2378 OneMoment one_moment;
2379 String errors, warnings;
2381 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors,warnings));
2382 if(canvas && get_instance(canvas))
2384 get_instance(canvas)->find_canvas_view(canvas)->present();
2385 info("%s is already open", filename.c_str());
2386 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2391 throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
2394 dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str()));
2396 if (as.find(custom_filename_prefix.c_str()) != 0)
2397 add_recent_file(as);
2399 handle<Instance> instance(Instance::create(canvas));
2402 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2404 set_recent_file_window_size(instance);
2408 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)")))
2409 instance->dialog_cvs_update();
2414 dialog_error_blocking(_("Error"), x);
2417 catch(runtime_error x)
2419 dialog_error_blocking(_("Error"), x.what());
2424 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2435 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2437 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2438 canvas->set_name(file_name);
2439 file_name += ".sifz";
2441 canvas->rend_desc().set_frame_rate(24.0);
2442 canvas->rend_desc().set_time_start(0.0);
2443 canvas->rend_desc().set_time_end(5.0);
2444 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2445 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2446 // The top left and botton right positions are expressed in units
2447 // Original convention is that 1 unit = 60 pixels
2448 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2449 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2450 canvas->rend_desc().set_w(preferred_x_size);
2451 canvas->rend_desc().set_h(preferred_y_size);
2452 canvas->rend_desc().set_antialias(1);
2453 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2454 canvas->set_file_name(file_name);
2456 handle<Instance> instance = Instance::create(canvas);
2458 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2459 instance->find_canvas_view(canvas)->canvas_properties.present();
2463 App::dialog_open(string filename)
2465 if (filename.empty())
2468 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2470 // If the filename still has wildcards, then we should
2471 // continue looking for the file we want
2472 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2478 get_ui_interface()->error(_("Unable to open file"));
2483 App::set_selected_instance(etl::loose_handle<Instance> instance)
2485 /* if(get_selected_instance()==instance)
2487 selected_instance=instance;
2488 signal_instance_selected()(instance);
2494 selected_instance=instance;
2495 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2499 instance->focus(instance->get_canvas());
2502 set_selected_canvas_view(0);
2504 signal_instance_selected()(instance);
2508 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2510 selected_canvas_view=canvas_view;
2511 signal_canvas_view_focus()(selected_canvas_view);
2514 selected_instance=canvas_view->get_instance();
2515 signal_instance_selected()(canvas_view->get_instance());
2518 if(get_selected_canvas_view()==canvas_view)
2520 signal_canvas_view_focus()(selected_canvas_view);
2521 signal_instance_selected()(canvas_view->get_instance());
2524 selected_canvas_view=canvas_view;
2525 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2526 set_selected_instance(canvas_view->get_instance());
2527 signal_canvas_view_focus()(selected_canvas_view);
2531 etl::loose_handle<Instance>
2532 App::get_instance(etl::handle<synfig::Canvas> canvas)
2534 if(!canvas) return 0;
2535 canvas=canvas->get_root();
2537 std::list<etl::handle<Instance> >::iterator iter;
2538 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2540 if((*iter)->get_canvas()==canvas)
2556 if(selected_instance)
2557 selected_instance->undo();
2563 if(selected_instance)
2564 selected_instance->redo();
2568 studio::App::get_base_path()
2570 return app_base_path_;