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
12 ** This package is free software; you can redistribute it and/or
13 ** modify it under the terms of the GNU General Public License as
14 ** published by the Free Software Foundation; either version 2 of
15 ** the License, or (at your option) any later version.
17 ** This package is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ** General Public License for more details.
23 /* ========================================================================= */
25 /* === H E A D E R S ======================================================= */
44 #ifdef HAVE_SYS_ERRNO_H
45 #include <sys/errno.h>
47 #include <gtkmm/fileselection.h>
48 #include <gtkmm/dialog.h>
49 #include <gtkmm/messagedialog.h>
50 #include <gtkmm/label.h>
51 #include <gtkmm/stock.h>
52 #include <gtkmm/stockitem.h>
53 #include <gtkmm/iconsource.h>
54 #include <gtkmm/inputdialog.h>
55 #include <gtkmm/accelmap.h>
56 #include <gtkmm/uimanager.h>
57 #include <gtkmm/textview.h>
61 #include <gdkmm/general.h>
63 #include <synfig/loadcanvas.h>
64 #include <synfig/savecanvas.h>
70 #include "canvasview.h"
71 #include "dialog_setup.h"
72 #include "dialog_gradient.h"
73 #include "dialog_color.h"
76 #include "onemoment.h"
78 #include "dockmanager.h"
80 #include "state_eyedrop.h"
81 #include "state_normal.h"
82 #include "state_draw.h"
83 #include "state_fill.h"
84 #include "state_bline.h"
85 #include "state_polygon.h"
86 #include "state_sketch.h"
87 #include "state_gradient.h"
88 #include "state_circle.h"
89 #include "state_rectangle.h"
90 #include "state_smoothmove.h"
91 #include "state_scale.h"
92 #include "state_star.h"
93 #include "state_text.h"
94 #include "state_width.h"
95 #include "state_rotate.h"
96 #include "state_zoom.h"
98 #include "devicetracker.h"
99 #include "dialog_tooloptions.h"
100 #include "widget_enum.h"
102 #include "autorecover.h"
104 #include <synfigapp/settings.h>
105 #include "dock_history.h"
106 #include "dock_canvases.h"
107 #include "dock_keyframes.h"
108 #include "dock_layers.h"
109 #include "dock_params.h"
110 #include "dock_metadata.h"
111 #include "dock_children.h"
112 #include "dock_info.h"
113 #include "dock_navigator.h"
114 #include "dock_layergroups.h"
115 #include "dock_timetrack.h"
116 #include "dock_curves.h"
118 #include "mod_palette/mod_palette.h"
119 #include "mod_mirror/mod_mirror.h"
121 #include <sys/stat.h>
127 #include "statemanager.h"
133 #include <gtkmm/accelmap.h>
134 #include <gtkmm/filechooser.h>
135 #include <gtkmm/filechooserdialog.h>
141 /* === U S I N G =========================================================== */
145 using namespace synfig;
146 using namespace studio;
148 /* === M A C R O S ========================================================= */
150 #ifndef SYNFIG_USER_APP_DIR
152 #define SYNFIG_USER_APP_DIR "Library/Synfig"
153 #elif defined(_WIN32)
154 #define SYNFIG_USER_APP_DIR "Synfig"
156 #define SYNFIG_USER_APP_DIR ".synfig"
161 #define DPM2DPI(x) (float(x)/39.3700787402f)
162 #define DPI2DPM(x) (float(x)*39.3700787402f)
168 # define IMAGE_DIR "share\\pixmaps"
173 # define IMAGE_DIR "/usr/local/share/pixmaps"
177 # define IMAGE_EXT "tif"
180 #include <synfigapp/main.h>
182 /* === S I G N A L S ======================================================= */
184 static sigc::signal<void> signal_present_all_;
186 App::signal_present_all() { return signal_present_all_; }
188 static sigc::signal<void> signal_recent_files_changed_;
190 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
192 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
193 sigc::signal<void,etl::loose_handle<CanvasView> >&
194 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
196 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
197 sigc::signal<void,etl::handle<Instance> >&
198 App::signal_instance_selected() { return signal_instance_selected_; }
200 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
201 sigc::signal<void,etl::handle<Instance> >&
202 App::signal_instance_created() { return signal_instance_created_; }
204 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
205 sigc::signal<void,etl::handle<Instance> >&
206 App::signal_instance_deleted() { return signal_instance_deleted_; }
208 /* === G L O B A L S ======================================================= */
210 static std::list<std::string> recent_files;
211 const std::list<std::string>& App::get_recent_files() { return recent_files; }
213 static std::list<std::string> recent_files_window_size;
215 int App::Busy::count;
216 bool App::shutdown_in_progress;
218 synfig::Gamma App::gamma;
220 Glib::RefPtr<studio::UIManager> App::ui_manager_;
222 synfig::Distance::System App::distance_system;
224 studio::Dialog_Setup* App::dialog_setup;
226 etl::handle< studio::ModPalette > mod_palette_;
227 //studio::Dialog_Palette* App::dialog_palette;
229 std::list<etl::handle<Instance> > App::instance_list;
231 static etl::handle<synfigapp::UIInterface> ui_interface_;
232 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
234 etl::handle<Instance> App::selected_instance;
235 etl::handle<CanvasView> App::selected_canvas_view;
237 studio::About *studio::App::about=NULL;
239 studio::Toolbox *studio::App::toolbox=NULL;
241 studio::AutoRecover *studio::App::auto_recover=NULL;
243 studio::IPC *ipc=NULL;
245 studio::DockManager* studio::App::dock_manager=0;
247 studio::DeviceTracker* studio::App::device_tracker=0;
249 studio::Dialog_Gradient* studio::App::dialog_gradient;
251 studio::Dialog_Color* studio::App::dialog_color;
253 Gtk::InputDialog* studio::App::dialog_input;
255 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
257 studio::Dock_History* dock_history;
258 studio::Dock_Canvases* dock_canvases;
259 studio::Dock_Keyframes* dock_keyframes;
260 studio::Dock_Layers* dock_layers;
261 studio::Dock_Params* dock_params;
262 studio::Dock_MetaData* dock_meta_data;
263 studio::Dock_Children* dock_children;
264 studio::Dock_Info* dock_info;
265 studio::Dock_LayerGroups* dock_layer_groups;
266 studio::Dock_Navigator* dock_navigator;
267 studio::Dock_Timetrack* dock_timetrack;
268 studio::Dock_Curves* dock_curves;
270 std::list< etl::handle< studio::Module > > module_list_;
272 bool studio::App::use_colorspace_gamma=true;
273 #ifdef SINGLE_THREADED
274 bool studio::App::single_threaded=false;
276 bool studio::App::restrict_radius_ducks=false;
277 String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
278 int studio::App::preferred_x_size=480;
279 int studio::App::preferred_y_size=270;
280 String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE);
281 #ifdef USE_OPEN_FOR_URLS
282 String studio::App::browser_command("open"); // MacOS only
284 String studio::App::browser_command("xdg-open"); // Linux XDG standard
287 static int max_recent_files_=25;
288 int studio::App::get_max_recent_files() { return max_recent_files_; }
289 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
291 static synfig::String app_base_path_;
296 really_delete_widget(Gtk::Widget *widget)
298 // synfig::info("really delete %p", (void*)widget);
303 // nasty workaround - when we've finished with a popup menu, we want to delete it
304 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
305 // so schedule the real delete to happen in 50ms, giving the action a chance to run
307 delete_widget(Gtk::Widget *widget)
309 // synfig::info("delete %p", (void*)widget);
310 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
313 }; // END of namespace studio
314 studio::StateManager* state_manager;
319 class GlobalUIInterface : public synfigapp::UIInterface
323 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
328 true // use_separator
330 Gtk::Label label(message);
333 dialog.get_vbox()->pack_start(label);
334 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
335 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
337 dialog.set_default_response(dflt);
339 return (Response)dialog.run();
341 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
346 true // use_separator
348 Gtk::Label label(message);
351 dialog.get_vbox()->pack_start(label);
352 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
353 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
354 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
356 dialog.set_default_response(dflt);
358 return (Response)dialog.run();
360 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
365 true // use_separator
367 Gtk::Label label(message);
370 dialog.get_vbox()->pack_start(label);
371 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
372 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
374 dialog.set_default_response(dflt);
376 return (Response)dialog.run();
380 task(const std::string &task)
382 std::cerr<<task<<std::endl;
383 while(studio::App::events_pending())studio::App::iteration(false);
388 error(const std::string &err)
390 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
397 warning(const std::string &err)
399 std::cerr<<"warning: "<<err<<std::endl;
400 while(studio::App::events_pending())studio::App::iteration(false);
405 amount_complete(int /*current*/, int /*total*/)
407 while(studio::App::events_pending())studio::App::iteration(false);
412 /* === P R O C E D U R E S ================================================= */
416 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
418 action_group_list.push_back(action_group);
419 Gtk::UIManager::insert_action_group(action_group, pos);
423 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
425 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
426 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
427 if(*iter==action_group)
429 action_group_list.erase(iter);
430 Gtk::UIManager::remove_action_group(action_group);
433 synfig::error("Unable to find action group");
437 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
439 ui_manager->insert_action_group(group,0);
441 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
442 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
444 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
446 if(*iter && (*iter)->get_name()!="menus")
448 synfig::info("Removing action group "+(*iter)->get_name());
449 ui_manager->remove_action_group(*iter);
452 ui_manager->insert_action_group(group,0);
454 for(;!prev_groups.empty();prev_groups.pop_front())
456 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
457 ui_manager->insert_action_group(prev_groups.front(),1);
461 class Preferences : public synfigapp::Settings
464 virtual bool get_value(const synfig::String& key, synfig::String& value)const
468 value=strprintf("%f %f %f %f",
469 App::gamma.get_gamma_r(),
470 App::gamma.get_gamma_g(),
471 App::gamma.get_gamma_b(),
472 App::gamma.get_black_level()
476 if(key=="time_format")
478 value=strprintf("%i",App::get_time_format());
481 if(key=="file_history.size")
483 value=strprintf("%i",App::get_max_recent_files());
486 if(key=="use_colorspace_gamma")
488 value=strprintf("%i",(int)App::use_colorspace_gamma);
491 if(key=="distance_system")
493 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
496 #ifdef SINGLE_THREADED
497 if(key=="single_threaded")
499 value=strprintf("%i",(int)App::single_threaded);
503 if(key=="auto_recover_backup_interval")
505 value=strprintf("%i",App::auto_recover->get_timeout());
508 if(key=="restrict_radius_ducks")
510 value=strprintf("%i",(int)App::restrict_radius_ducks);
513 if(key=="browser_command")
515 value=App::browser_command;
518 if(key=="custom_filename_prefix")
520 value=App::custom_filename_prefix;
523 if(key=="preferred_x_size")
525 value=strprintf("%i",App::preferred_x_size);
528 if(key=="preferred_y_size")
530 value=strprintf("%i",App::preferred_y_size);
533 if(key=="predefined_size")
535 value=strprintf("%s",App::predefined_size.c_str());
539 return synfigapp::Settings::get_value(key,value);
542 virtual bool set_value(const synfig::String& key,const synfig::String& value)
548 strscanf(value,"%f %f %f %f",
555 App::gamma.set_all(r,g,b,blk);
559 if(key=="time_format")
561 int i(atoi(value.c_str()));
562 App::set_time_format(static_cast<synfig::Time::Format>(i));
565 if(key=="auto_recover_backup_interval")
567 int i(atoi(value.c_str()));
568 App::auto_recover->set_timeout(i);
571 if(key=="file_history.size")
573 int i(atoi(value.c_str()));
574 App::set_max_recent_files(i);
577 if(key=="use_colorspace_gamma")
579 int i(atoi(value.c_str()));
580 App::use_colorspace_gamma=i;
583 if(key=="distance_system")
585 App::distance_system=Distance::ident_system(value);;
588 #ifdef SINGLE_THREADED
589 if(key=="single_threaded")
591 int i(atoi(value.c_str()));
592 App::single_threaded=i;
596 if(key=="restrict_radius_ducks")
598 int i(atoi(value.c_str()));
599 App::restrict_radius_ducks=i;
602 if(key=="browser_command")
604 App::browser_command=value;
607 if(key=="custom_filename_prefix")
609 App::custom_filename_prefix=value;
612 if(key=="preferred_x_size")
614 int i(atoi(value.c_str()));
615 App::preferred_x_size=i;
618 if(key=="preferred_y_size")
620 int i(atoi(value.c_str()));
621 App::preferred_y_size=i;
624 if(key=="predefined_size")
626 App::predefined_size=value;
629 return synfigapp::Settings::set_value(key,value);
632 virtual KeyList get_key_list()const
634 KeyList ret(synfigapp::Settings::get_key_list());
635 ret.push_back("gamma");
636 ret.push_back("time_format");
637 ret.push_back("distance_system");
638 ret.push_back("file_history.size");
639 ret.push_back("use_colorspace_gamma");
640 #ifdef SINGLE_THREADED
641 ret.push_back("single_threaded");
643 ret.push_back("auto_recover_backup_interval");
644 ret.push_back("restrict_radius_ducks");
645 ret.push_back("browser_command");
646 ret.push_back("custom_filename_prefix");
647 ret.push_back("preferred_x_size");
648 ret.push_back("preferred_y_size");
649 ret.push_back("predefined_size");
654 static ::Preferences _preferences;
659 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
661 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
663 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
665 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
666 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
667 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
668 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
669 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
670 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
671 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
672 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
673 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
674 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
675 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
676 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
677 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
679 // Add the synfigapp actions...
680 synfigapp::Action::Book::iterator iter;
681 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
683 actions_action_group->add(Gtk::Action::create(
684 "action-"+iter->second.name,
685 get_action_stock_id(iter->second),
686 iter->second.local_name,iter->second.local_name
690 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
691 #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); }
692 #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); }
694 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
695 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
696 DEFINE_ACTION("new", Gtk::Stock::NEW);
697 DEFINE_ACTION("open", Gtk::Stock::OPEN);
698 DEFINE_ACTION("save", Gtk::Stock::SAVE);
699 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
700 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
701 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
702 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
703 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
704 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
705 DEFINE_ACTION("import", _("Import"));
706 DEFINE_ACTION("render", _("Render"));
707 DEFINE_ACTION("preview", _("Preview"));
708 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
709 DEFINE_ACTION("sound", _("Sound File"));
710 DEFINE_ACTION("options", _("Options"));
711 DEFINE_ACTION("close", _("Close View"));
712 DEFINE_ACTION("close-document", _("Close Document"));
713 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
716 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
717 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
718 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
719 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
720 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
721 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
722 DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks"));
723 DEFINE_ACTION("select-all-layers", _("Select All Layers"));
724 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
725 DEFINE_ACTION("properties", _("Properties"));
727 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
728 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
729 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
730 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
731 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
732 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
733 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
734 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
735 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
736 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
737 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
738 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
739 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
740 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
741 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
742 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
743 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
744 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
745 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
746 DEFINE_ACTION("play", _("Play"));
747 // DEFINE_ACTION("pause", _("Pause"));
748 DEFINE_ACTION("stop", _("Stop"));
749 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
750 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
751 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
752 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
753 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
754 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
755 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
756 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
757 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
758 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
759 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
760 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
761 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
762 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
763 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
764 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
765 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
766 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
767 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
768 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
769 DEFINE_ACTION("seek-end", _("Seek to End"));
771 DEFINE_ACTION("action-group_add", _("Add group"));
773 DEFINE_ACTION("canvas-new", _("New Canvas"));
775 DEFINE_ACTION("amount-inc", _("Increase Amount"));
776 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
781 // Set up synfigapp actions
783 synfigapp::Action::Book::iterator iter;
785 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
787 Gtk::StockID stock_id;
789 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
791 //Gtk::Image* image(manage(new Gtk::Image()));
792 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
793 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
794 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
795 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
796 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
797 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
798 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
799 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
800 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
801 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
803 actions_action_group->add(Gtk::Action::create(
804 "action-"+iter->second.name,
806 iter->second.local_name,iter->second.local_name
814 Glib::ustring ui_info =
816 " <popup name='menu-toolbox' action='menu-toolbox'>"
817 " <menu action='menu-file'>"
820 " <popup name='menu-main' action='menu-main'>"
821 " <menu action='menu-file'>"
822 " <menuitem action='new' />"
823 " <menuitem action='open' />"
824 " <menuitem action='save' />"
825 " <menuitem action='save-as' />"
826 " <menuitem action='revert' />"
827 " <separator name='bleh01'/>"
828 " <menuitem action='cvs-add' />"
829 " <menuitem action='cvs-update' />"
830 " <menuitem action='cvs-commit' />"
831 " <menuitem action='cvs-revert' />"
832 " <separator name='bleh02'/>"
833 " <menuitem action='import' />"
834 " <separator name='bleh03'/>"
835 " <menuitem action='render' />"
836 " <menuitem action='preview' />"
837 " <menuitem action='sound' />"
838 " <separator name='bleh04'/>"
839 " <menuitem action='options' />"
840 " <menuitem action='close' />"
841 " <menuitem action='close-document' />"
842 " <menuitem action='quit' />"
844 " <menu action='menu-edit'>"
845 " <menuitem action='undo'/>"
846 " <menuitem action='redo'/>"
847 " <separator name='bleh05'/>"
848 " <menuitem action='cut'/>"
849 " <menuitem action='copy'/>"
850 " <menuitem action='paste'/>"
851 " <separator name='bleh06'/>"
852 " <menuitem action='select-all-layers'/>"
853 " <menuitem action='unselect-all-layers'/>"
854 " <menuitem action='select-all-ducks'/>"
855 " <menuitem action='unselect-all-ducks'/>"
856 " <separator name='bleh07'/>"
857 " <menuitem action='properties'/>"
859 " <menu action='menu-view'>"
860 " <menu action='menu-duck-mask'>"
861 " <menuitem action='mask-position-ducks' />"
862 " <menuitem action='mask-vertex-ducks' />"
863 " <menuitem action='mask-tangent-ducks' />"
864 " <menuitem action='mask-radius-ducks' />"
865 " <menuitem action='mask-width-ducks' />"
866 " <menuitem action='mask-angle-ducks' />"
868 " <menu action='menu-preview-quality'>"
869 " <menuitem action='quality-00' />"
870 " <menuitem action='quality-01' />"
871 " <menuitem action='quality-02' />"
872 " <menuitem action='quality-03' />"
873 " <menuitem action='quality-04' />"
874 " <menuitem action='quality-05' />"
875 " <menuitem action='quality-06' />"
876 " <menuitem action='quality-07' />"
877 " <menuitem action='quality-08' />"
878 " <menuitem action='quality-09' />"
879 " <menuitem action='quality-10' />"
881 " <menu action='menu-lowres-pixel'>"
882 " <menuitem action='decrease-low-res-pixel-size'/>"
883 " <menuitem action='increase-low-res-pixel-size'/>"
884 " <separator name='pixel-size-separator'/>"
887 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
888 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
892 " <separator name='bleh08'/>"
893 " <menuitem action='play'/>"
894 //" <menuitem action='pause'/>"
895 " <menuitem action='stop'/>"
896 " <menuitem action='dialog-flipbook'/>"
897 " <separator name='bleh09'/>"
898 " <menuitem action='toggle-grid-show'/>"
899 " <menuitem action='toggle-grid-snap'/>"
900 " <menuitem action='toggle-guide-show'/>"
901 " <menuitem action='toggle-low-res'/>"
902 " <menuitem action='toggle-onion-skin'/>"
903 " <separator name='bleh10'/>"
904 " <menuitem action='canvas-zoom-in'/>"
905 " <menuitem action='canvas-zoom-out'/>"
906 " <menuitem action='canvas-zoom-fit'/>"
907 " <menuitem action='canvas-zoom-100'/>"
908 " <separator name='bleh11'/>"
909 " <menuitem action='time-zoom-in'/>"
910 " <menuitem action='time-zoom-out'/>"
911 " <separator name='bleh12'/>"
912 " <menuitem action='jump-next-keyframe'/>"
913 " <menuitem action='jump-prev-keyframe'/>"
914 " <menuitem action='seek-next-frame'/>"
915 " <menuitem action='seek-prev-frame'/>"
916 " <menuitem action='seek-next-second'/>"
917 " <menuitem action='seek-prev-second'/>"
918 " <menuitem action='seek-begin'/>"
919 " <menuitem action='seek-end'/>"
921 " <menu action='menu-canvas'>"
922 " <menuitem action='canvas-new'/>"
924 " <menu name='menu-state' action='menu-state'>"
926 " <menu action='menu-group'>"
927 " <menuitem action='action-group_add'/>"
929 " <menu action='menu-layer'>"
930 //" <menuitem action='cut'/>"
931 //" <menuitem action='copy'/>"
932 //" <menuitem action='paste'/>"
933 //" <separator name='bleh06'/>"
934 " <menu action='menu-layer-new'></menu>"
935 " <menuitem action='amount-inc'/>"
936 " <menuitem action='amount-dec'/>"
938 " <menu action='menu-keyframe'>"
939 " <menuitem action='keyframe-properties'/>"
946 " <menubar name='MenuBar'>"
947 " <menu action='MenuFile'>"
948 " <menuitem action='New'/>"
949 " <menuitem action='Open'/>"
951 " <menuitem action='Quit'/>"
953 " <menu action='MenuEdit'>"
954 " <menuitem action='Cut'/>"
955 " <menuitem action='Copy'/>"
956 " <menuitem action='Paste'/>"
959 " <toolbar name='ToolBar'>"
960 " <toolitem action='Open'/>"
961 " <toolitem action='Quit'/>"
967 actions_action_group->set_sensitive(false);
968 App::ui_manager()->set_add_tearoffs(true);
969 App::ui_manager()->insert_action_group(menus_action_group,1);
970 App::ui_manager()->insert_action_group(actions_action_group,1);
971 App::ui_manager()->add_ui_from_string(ui_info);
973 //App::ui_manager()->get_accel_group()->unlock();
975 catch(const Glib::Error& ex)
977 synfig::error("building menus and toolbars failed: " + ex.what());
980 // Add default keyboard accelerators
981 #define ACCEL(path,accel) \
983 Gtk::AccelKey accel_key(accel,path); \
984 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
987 #define ACCEL2(accel) \
989 Gtk::AccelKey accel_key(accel); \
990 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
993 ACCEL("<Actions>//select-all-ducks","<Control>a");
994 ACCEL("<Actions>//unselect-all-ducks","<Control>d");
995 ACCEL("<Actions>//select-all-layers","<Control><Shift>a");
996 ACCEL("<Actions>//unselect-all-layers","<Control><Shift>d");
997 ACCEL("<Actions>//render","F9");
998 ACCEL("<Actions>//preview","F11");
999 ACCEL("<Actions>//properties","F8");
1000 ACCEL("<Actions>//options","F12");
1001 ACCEL("<Actions>//import","<control>i");
1002 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
1003 ACCEL("<Actions>//toggle-grid-show","<Control>g");
1004 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
1005 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
1006 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
1007 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
1008 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
1009 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
1010 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
1011 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
1013 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
1014 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
1016 ACCEL("<Actions>//quality-01","<Control>1");
1017 ACCEL("<Actions>//quality-02","<Control>2");
1018 ACCEL("<Actions>//quality-03","<Control>3");
1019 ACCEL("<Actions>//quality-04","<Control>4");
1020 ACCEL("<Actions>//quality-05","<Control>5");
1021 ACCEL("<Actions>//quality-06","<Control>6");
1022 ACCEL("<Actions>//quality-07","<Control>7");
1023 ACCEL("<Actions>//quality-08","<Control>8");
1024 ACCEL("<Actions>//quality-09","<Control>9");
1025 ACCEL("<Actions>//quality-10","<Control>0");
1026 ACCEL("<Actions>//undo","<Control>z");
1027 ACCEL("<Actions>//redo","<Control>r");
1028 ACCEL("<Actions>//action-layer_remove","Delete");
1030 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
1031 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
1032 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
1033 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
1034 ACCEL("<Actions>//time-zoom-in","+");
1035 ACCEL("<Actions>//time-zoom-out","_");
1037 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
1038 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
1040 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
1041 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
1043 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
1044 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
1045 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
1046 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
1047 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
1048 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
1049 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
1050 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
1051 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
1052 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
1053 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
1054 ACCEL("<Actions>//play", "<Control>p");
1055 ACCEL("<Actions>//seek-begin","Home");
1056 ACCEL("<Actions>//seek-end","End");
1058 ACCEL("<Actions>//state-normal", "<Mod1>a");
1059 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1060 ACCEL("<Actions>//state-scale", "<Mod1>s");
1061 ACCEL("<Actions>//state-rotate", "<Mod1>t");
1062 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1064 ACCEL("<Actions>//state-circle", "<Mod1>c");
1065 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1066 ACCEL("<Actions>//state-star", "<Mod1>q");
1067 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1068 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1070 ACCEL("<Actions>//state-bline", "<Mod1>b");
1071 ACCEL("<Actions>//state-text", "<Mod1>x");
1072 ACCEL("<Actions>//state-fill", "<Mod1>f");
1073 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1074 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1076 ACCEL("<Actions>//state-draw", "<Mod1>d");
1077 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1078 ACCEL("<Actions>//state-width", "<Mod1>w");
1080 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1086 #define mkdir(x,y) mkdir(x)
1089 /* === M E T H O D S ======================================================= */
1091 App::App(int *argc, char ***argv):
1092 Gtk::Main(argc,argv),
1093 IconController(etl::dirname((*argv)[0]))
1095 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1098 ui_interface_=new GlobalUIInterface();
1102 // don't call thread_init() if threads are already initialized
1103 // on some machines bonobo_init() initialized threads before we get here
1104 if (!g_thread_supported())
1105 Glib::thread_init();
1107 distance_system=Distance::SYSTEM_UNITS;
1109 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1112 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1116 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1122 if(!SYNFIG_CHECK_VERSION())
1124 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1125 dialog_error_blocking("Synfig Studio",
1126 "This copy of Synfig Studio was compiled against a\n"
1127 "different version of libsynfig than what is currently\n"
1128 "installed. Synfig Studio will now abort. Try downloading\n"
1129 "the latest version from the Synfig website at\n"
1130 "http://synfig.org/Download"
1134 Glib::set_application_name(_("Synfig Studio"));
1136 Splash splash_screen;
1137 splash_screen.show();
1139 shutdown_in_progress=false;
1140 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1141 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1143 // Initialize the Synfig library
1144 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1147 get_ui_interface()->error(_("Failed to initialize synfig!"));
1151 // add the preferences to the settings
1152 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1156 studio_init_cb.task(_("Init UI Manager..."));
1157 App::ui_manager_=studio::UIManager::create();
1160 studio_init_cb.task(_("Init Dock Manager..."));
1161 dock_manager=new studio::DockManager();
1163 studio_init_cb.task(_("Init State Manager..."));
1164 state_manager=new StateManager();
1166 studio_init_cb.task(_("Init Toolbox..."));
1167 toolbox=new studio::Toolbox();
1169 studio_init_cb.task(_("Init About Dialog..."));
1170 about=new studio::About();
1172 studio_init_cb.task(_("Init Tool Options..."));
1173 dialog_tool_options=new studio::Dialog_ToolOptions();
1174 dock_manager->register_dockable(*dialog_tool_options);
1176 studio_init_cb.task(_("Init History..."));
1177 dock_history=new studio::Dock_History();
1178 dock_manager->register_dockable(*dock_history);
1180 studio_init_cb.task(_("Init Canvases..."));
1181 dock_canvases=new studio::Dock_Canvases();
1182 dock_manager->register_dockable(*dock_canvases);
1184 studio_init_cb.task(_("Init Keyframes..."));
1185 dock_keyframes=new studio::Dock_Keyframes();
1186 dock_manager->register_dockable(*dock_keyframes);
1188 studio_init_cb.task(_("Init Layers..."));
1189 dock_layers=new studio::Dock_Layers();
1190 dock_manager->register_dockable(*dock_layers);
1192 studio_init_cb.task(_("Init Params..."));
1193 dock_params=new studio::Dock_Params();
1194 dock_manager->register_dockable(*dock_params);
1196 studio_init_cb.task(_("Init MetaData..."));
1197 dock_meta_data=new studio::Dock_MetaData();
1198 dock_manager->register_dockable(*dock_meta_data);
1200 studio_init_cb.task(_("Init Children..."));
1201 dock_children=new studio::Dock_Children();
1202 dock_manager->register_dockable(*dock_children);
1204 studio_init_cb.task(_("Init Info..."));
1205 dock_info = new studio::Dock_Info();
1206 dock_manager->register_dockable(*dock_info);
1208 studio_init_cb.task(_("Init Navigator..."));
1209 dock_navigator = new studio::Dock_Navigator();
1210 dock_manager->register_dockable(*dock_navigator);
1212 studio_init_cb.task(_("Init Timetrack..."));
1213 dock_timetrack = new studio::Dock_Timetrack();
1214 dock_manager->register_dockable(*dock_timetrack);
1216 studio_init_cb.task(_("Init Curve Editor..."));
1217 dock_curves = new studio::Dock_Curves();
1218 dock_manager->register_dockable(*dock_curves);
1220 studio_init_cb.task(_("Init Layer Groups..."));
1221 dock_layer_groups = new studio::Dock_LayerGroups();
1222 dock_manager->register_dockable(*dock_layer_groups);
1225 studio_init_cb.task(_("Init Color Dialog..."));
1226 dialog_color=new studio::Dialog_Color();
1228 studio_init_cb.task(_("Init Gradient Dialog..."));
1229 dialog_gradient=new studio::Dialog_Gradient();
1231 studio_init_cb.task(_("Init DeviceTracker..."));
1232 device_tracker=new studio::DeviceTracker();
1234 studio_init_cb.task(_("Init Tools..."));
1237 state_manager->add_state(&state_normal);
1238 state_manager->add_state(&state_smooth_move);
1239 state_manager->add_state(&state_scale);
1240 state_manager->add_state(&state_rotate);
1241 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1244 state_manager->add_state(&state_circle);
1245 state_manager->add_state(&state_rectangle);
1246 state_manager->add_state(&state_star);
1247 state_manager->add_state(&state_gradient);
1248 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1251 state_manager->add_state(&state_bline);
1252 state_manager->add_state(&state_text);
1253 state_manager->add_state(&state_fill);
1254 state_manager->add_state(&state_eyedrop);
1255 state_manager->add_state(&state_zoom);
1257 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1258 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1259 if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
1261 studio_init_cb.task(_("Init ModPalette..."));
1262 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1264 studio_init_cb.task(_("Init Setup Dialog..."));
1265 dialog_setup=new studio::Dialog_Setup();
1267 studio_init_cb.task(_("Init Input Dialog..."));
1268 dialog_input=new Gtk::InputDialog();
1269 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1270 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1272 studio_init_cb.task(_("Init auto recovery..."));
1273 auto_recover=new AutoRecover();
1275 studio_init_cb.amount_complete(9250,10000);
1276 studio_init_cb.task(_("Loading Settings..."));
1278 studio_init_cb.task(_("Checking auto-recover..."));
1280 studio_init_cb.amount_complete(9900,10000);
1282 bool opened_any = false;
1283 if(auto_recover->recovery_needed())
1285 splash_screen.hide();
1286 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1287 _("Synfig Studio seems to have crashed\n"
1288 "before you could save all your files.\n"
1289 "Would you like to re-open those files\n"
1290 "and recover your unsaved changes?")) ==
1291 synfigapp::UIInterface::RESPONSE_YES)
1293 int number_recovered;
1294 if(!auto_recover->recover(number_recovered))
1295 if (number_recovered)
1296 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1298 get_ui_interface()->error(_("Unable to recover from previous crash"));
1300 get_ui_interface()->error(
1301 _("Synfig Studio has attempted to recover\n"
1302 "from a previous crash. The files that it has\n"
1303 "recovered are NOT YET SAVED. It would be a good\n"
1304 "idea to review them and save them now."));
1306 if (number_recovered)
1309 splash_screen.show();
1312 // Look for any files given on the command line,
1313 // and load them if found.
1314 for(;*argc>=1;(*argc)--)
1315 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1317 studio_init_cb.task(_("Loading files..."));
1318 splash_screen.hide();
1319 open((*argv)[*argc]);
1321 splash_screen.show();
1324 // if no file was specified to be opened, create a new document to help new users get started more easily
1325 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1328 studio_init_cb.task(_("Done."));
1329 studio_init_cb.amount_complete(10000,10000);
1335 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1339 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1343 StateManager* App::get_state_manager() { return state_manager; }
1347 shutdown_in_progress=true;
1351 synfigapp::Main::settings().remove_domain("pref");
1353 selected_instance=0;
1355 // Unload all of the modules
1356 for(;!module_list_.empty();module_list_.pop_back())
1359 delete state_manager;
1363 delete auto_recover;
1369 // studio::App::iteration(false);
1373 // studio::App::iteration(false);
1375 // studio::App::iteration(false);
1377 delete dialog_setup;
1379 delete dialog_gradient;
1381 delete dialog_color;
1383 delete dialog_input;
1385 delete dock_manager;
1387 instance_list.clear();
1389 // studio::App::iteration(false);
1393 App::get_user_app_directory()
1395 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1397 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1399 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1404 App::get_config_file(const synfig::String& file)
1406 return Glib::build_filename(get_user_app_directory(),file);
1409 #define SCALE_FACTOR (1280)
1410 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1412 App::set_recent_file_window_size(etl::handle<Instance> instance)
1414 int screen_w(Gdk::screen_width());
1415 int screen_h(Gdk::screen_height());
1417 const std::string &canvas_window_size = *recent_files_window_size.begin();
1419 if(canvas_window_size.empty())
1422 synfig::String::size_type current=0;
1423 bool seen_root(false), shown_non_root(false);
1425 while(current != synfig::String::npos)
1427 // find end of first field (canvas) or return
1428 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1429 if(separator == synfig::String::npos) break;
1432 synfig::Canvas::Handle canvas;
1434 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1436 catch(Exception::IDNotFound) {
1437 // can't find the canvas; skip to the next canvas or return
1438 separator = canvas_window_size.find_first_of('\t', current);
1439 if(separator == synfig::String::npos) return;
1440 current = separator+1;
1444 if (canvas->is_root())
1447 shown_non_root = true;
1449 // check that we have the tab character the ends this canvas' data or return
1450 current = separator+1;
1451 separator = canvas_window_size.find_first_of('\t', current);
1452 if(separator == synfig::String::npos) return;
1455 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1457 current = separator+1;
1461 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1462 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1463 x=x*screen_w/SCALE_FACTOR;
1464 y=y*screen_h/SCALE_FACTOR;
1465 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1466 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1467 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1468 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1470 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1471 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1473 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1474 canvasview->move(x,y);
1475 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1476 canvasview->present();
1478 current = separator+1;
1481 if (shown_non_root && !seen_root)
1482 instance->find_canvas_view(instance->get_canvas())->hide();
1486 App::add_recent_file(const etl::handle<Instance> instance)
1488 int screen_w(Gdk::screen_width());
1489 int screen_h(Gdk::screen_height());
1491 std::string canvas_window_size;
1493 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1494 Instance::CanvasViewList::const_iterator iter;
1496 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1498 if( !((*iter)->is_visible()) )
1501 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1502 int x_pos, y_pos, x_size, y_size;
1503 (*iter)->get_position(x_pos,y_pos);
1504 (*iter)->get_size(x_size,y_size);
1506 canvas_window_size += strprintf("%s %d %d %d %d\t",
1507 canvas->get_relative_id(canvas->get_root()).c_str(),
1508 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1509 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1512 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1517 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1519 std::string filename(file_name);
1521 assert(!filename.empty());
1523 if(filename.empty())
1526 // Toss out any "hidden" files
1527 if(basename(filename)[0]=='.')
1530 // If we aren't an absolute path, turn ourselves into one
1531 if(!is_absolute_path(filename))
1532 filename=absolute_path(filename);
1534 std::string old_window_size;
1536 list<string>::iterator iter;
1537 list<string>::iterator iter_wsize;
1538 // Check to see if the file is already on the list.
1539 // If it is, then remove it from the list
1540 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1543 recent_files.erase(iter);
1544 old_window_size = *iter_wsize;
1545 recent_files_window_size.erase(iter_wsize);
1550 // Push the filename to the front of the list
1551 recent_files.push_front(filename);
1552 if(window_size.empty())
1553 recent_files_window_size.push_front(old_window_size);
1555 recent_files_window_size.push_front(window_size);
1557 // Clean out the files at the end of the list.
1558 while(recent_files.size()>(unsigned)get_max_recent_files())
1560 recent_files.pop_back();
1561 recent_files_window_size.pop_back();
1564 signal_recent_files_changed_();
1569 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1572 App::get_time_format()
1574 return _App_time_format;
1578 App::set_time_format(synfig::Time::Format x)
1585 App::save_settings()
1590 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1591 setlocale(LC_NUMERIC, "C");
1593 std::string filename=get_config_file("accelrc");
1594 Gtk::AccelMap::save(filename);
1597 std::string filename=get_config_file("recentfiles");
1599 std::ofstream file(filename.c_str());
1603 synfig::warning("Unable to save %s",filename.c_str());
1607 list<string>::reverse_iterator iter;
1609 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1613 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1615 std::ofstream file(filename.c_str());
1619 synfig::warning("Unable to save %s",filename.c_str());
1623 list<string>::reverse_iterator iter;
1625 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1629 std::string filename=get_config_file("settings");
1630 synfigapp::Main::settings().save_to_file(filename);
1631 setlocale(LC_NUMERIC,old_locale);
1635 synfig::warning("Caught exception when attempting to save settings.");
1640 App::load_settings()
1645 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1646 setlocale(LC_NUMERIC, "C");
1648 std::string filename=get_config_file("accelrc");
1649 Gtk::AccelMap::load(filename);
1652 bool window_size_broken = false;
1654 std::string filename=get_config_file("recentfiles");
1655 std::string filename_window_size=filename+std::string("_window_size");
1657 std::ifstream file(filename.c_str());
1658 std::ifstream file_window_size(filename_window_size.c_str());
1660 if(!file_window_size)
1661 window_size_broken = true;
1665 std::string recent_file;
1666 std::string recent_file_window_size;
1667 getline(file,recent_file);
1668 if(!window_size_broken)
1669 getline(file_window_size,recent_file_window_size);
1670 if(!recent_file.empty())
1672 if(!window_size_broken && !file_window_size)
1673 window_size_broken = true;
1674 if (std::ifstream(recent_file.c_str()))
1676 if(!window_size_broken)
1677 add_recent_file(recent_file,recent_file_window_size);
1679 add_recent_file(recent_file);
1683 if(!window_size_broken && file_window_size)
1684 window_size_broken = true;
1686 if(window_size_broken)
1688 recent_files_window_size.clear();
1689 recent_files_window_size.resize(recent_files.size());
1692 std::string filename=get_config_file("settings");
1693 if(!synfigapp::Main::settings().load_from_file(filename))
1695 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1696 //if(!synfigapp::Main::settings().load_from_file(filename))
1698 gamma.set_gamma(1.0/2.2);
1699 reset_initial_window_configuration();
1702 setlocale(LC_NUMERIC,old_locale);
1706 synfig::warning("Caught exception when attempting to load settings.");
1711 App::reset_initial_window_configuration()
1713 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1714 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1715 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1716 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1717 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1718 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1719 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1720 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1721 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1722 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1723 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1724 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1725 #ifdef SINGLE_THREADED
1726 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1728 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1729 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1730 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1731 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1732 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1733 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1737 App::shutdown_request(GdkEventAny*)
1741 //return !shutdown_in_progress;
1747 if(shutdown_in_progress)return;
1750 get_ui_interface()->task(_("Quit Request"));
1753 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1757 std::list<etl::handle<Instance> >::iterator iter;
1758 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1760 if(!(*iter)->safe_close())
1764 if((*iter)->synfigapp::Instance::get_action_count())
1766 handle<synfigapp::UIInterface> uim;
1767 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1769 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1770 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1772 case synfigapp::UIInterface::RESPONSE_NO:
1774 case synfigapp::UIInterface::RESPONSE_YES:
1777 case synfigapp::UIInterface::RESPONSE_CANCEL:
1786 if((*iter)->synfigapp::Instance::is_modified())
1788 handle<synfigapp::UIInterface> uim;
1789 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1791 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() );
1792 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1794 case synfigapp::UIInterface::RESPONSE_NO:
1796 case synfigapp::UIInterface::RESPONSE_YES:
1797 (*iter)->dialog_cvs_commit();
1799 case synfigapp::UIInterface::RESPONSE_CANCEL:
1808 // This next line causes things to crash for some reason
1812 shutdown_in_progress=true;
1814 instance_list.clear();
1816 while(studio::App::events_pending())studio::App::iteration(false);
1819 auto_recover->normal_shutdown();
1821 get_ui_interface()->task(_("Quit Request sent"));
1827 dialog_setup->refresh();
1828 dialog_setup->show();
1831 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1832 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1835 //#define USE_WIN32_FILE_DIALOGS 1
1838 #ifdef USE_WIN32_FILE_DIALOGS
1839 static OPENFILENAME ofn={};
1843 #include <gdk/gdkwin32.h>
1847 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1849 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1851 #ifdef USE_WIN32_FILE_DIALOGS
1852 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1854 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1855 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1856 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1858 ofn.lStructSize=sizeof(OPENFILENAME);
1859 ofn.hwndOwner = hWnd;
1860 ofn.hInstance = hInstance;
1861 ofn.lpstrFilter = szFilter;
1862 // ofn.lpstrCustomFilter=NULL;
1863 // ofn.nMaxCustFilter=0;
1864 // ofn.nFilterIndex=0;
1865 // ofn.lpstrFile=NULL;
1866 ofn.nMaxFile=MAX_PATH;
1867 // ofn.lpstrFileTitle=NULL;
1868 // ofn.lpstrInitialDir=NULL;
1869 // ofn.lpstrTitle=NULL;
1870 ofn.Flags=OFN_HIDEREADONLY;
1871 // ofn.nFileOffset=0;
1872 // ofn.nFileExtension=0;
1873 ofn.lpstrDefExt=TEXT("sif");
1874 // ofn.lCustData = 0l;
1876 // ofn.lpTemplateName=NULL;
1878 CHAR szFilename[MAX_PATH];
1880 strcpy(szFilename,filename.c_str());
1881 strcpy(szTitle,title.c_str());
1883 ofn.lpstrFile=szFilename;
1884 ofn.lpstrFileTitle=szTitle;
1886 if(GetOpenFileName(&ofn))
1888 filename=szFilename;
1894 synfig::String prev_path;
1896 if(!_preferences.get_value(preference, prev_path))
1899 prev_path = absolute_path(prev_path);
1901 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1903 dialog->set_current_folder(prev_path);
1904 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1905 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1907 if (filename.empty())
1908 dialog->set_filename(prev_path);
1909 else if (is_absolute_path(filename))
1910 dialog->set_filename(filename);
1912 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1914 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1915 filename = dialog->get_filename();
1916 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1917 _preferences.set_value(preference, dirname(filename));
1931 GtkWidget *fileselection;
1932 fileselection = gtk_file_selection_new(title.c_str());
1935 if(basename(filename)==filename)
1937 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1940 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1942 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1944 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1945 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1947 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1948 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1950 gtk_widget_show(fileselection);
1958 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1959 _preferences.set_value(preference,dirname(filename));
1963 gtk_widget_destroy(fileselection);
1966 gtk_widget_destroy(fileselection);
1973 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1975 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1977 #if USE_WIN32_FILE_DIALOGS
1978 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1980 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1981 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1982 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1984 ofn.lStructSize=sizeof(OPENFILENAME);
1985 ofn.hwndOwner = hWnd;
1986 ofn.hInstance = hInstance;
1987 ofn.lpstrFilter = szFilter;
1988 // ofn.lpstrCustomFilter=NULL;
1989 // ofn.nMaxCustFilter=0;
1990 // ofn.nFilterIndex=0;
1991 // ofn.lpstrFile=NULL;
1992 ofn.nMaxFile=MAX_PATH;
1993 // ofn.lpstrFileTitle=NULL;
1994 // ofn.lpstrInitialDir=NULL;
1995 // ofn.lpstrTitle=NULL;
1996 ofn.Flags=OFN_OVERWRITEPROMPT;
1997 // ofn.nFileOffset=0;
1998 // ofn.nFileExtension=0;
1999 ofn.lpstrDefExt=TEXT("sif");
2000 // ofn.lCustData = 0l;
2002 // ofn.lpTemplateName=NULL;
2004 CHAR szFilename[MAX_PATH];
2006 strcpy(szFilename,filename.c_str());
2007 strcpy(szTitle,title.c_str());
2009 ofn.lpstrFile=szFilename;
2010 ofn.lpstrFileTitle=szTitle;
2012 if(GetSaveFileName(&ofn))
2014 filename=szFilename;
2015 _preferences.set_value(preference,dirname(filename));
2020 synfig::String prev_path;
2022 if(!_preferences.get_value(preference, prev_path))
2025 prev_path = absolute_path(prev_path);
2027 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2029 dialog->set_current_folder(prev_path);
2030 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2031 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2033 Widget_Enum *file_type_enum = 0;
2034 if (preference == ANIMATION_DIR_PREFERENCE)
2036 file_type_enum = manage(new Widget_Enum());
2037 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2038 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2039 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2040 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2041 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2042 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2044 Gtk::HBox *hbox = manage(new Gtk::HBox);
2045 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2046 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2049 dialog->set_extra_widget(*hbox);
2052 if (filename.empty())
2053 dialog->set_filename(prev_path);
2056 std::string full_path;
2057 if (is_absolute_path(filename))
2058 full_path = filename;
2060 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2062 // select the file if it exists
2063 dialog->set_filename(full_path);
2065 // if the file doesn't exist, put its name into the filename box
2067 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2068 dialog->set_current_name(basename(filename));
2071 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2072 if (preference == ANIMATION_DIR_PREFERENCE)
2073 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2074 filename = dialog->get_filename();
2075 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2076 _preferences.set_value(preference, dirname(filename));
2087 App::dialog_error_blocking(const std::string &title, const std::string &message)
2089 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2090 dialog.set_title(title);
2096 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2098 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2099 dialog.set_title(title);
2105 App::dialog_yes_no(const std::string &title, const std::string &message)
2110 true // use_separator
2112 Gtk::Label label(message);
2115 dialog.get_vbox()->pack_start(label);
2116 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2117 dialog.add_button(Gtk::StockID("gtk-no"),0);
2119 return dialog.run();
2123 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2128 true // use_separator
2130 Gtk::Label label(message);
2133 dialog.get_vbox()->pack_start(label);
2134 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2135 dialog.add_button(Gtk::StockID("gtk-no"),0);
2136 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2138 return dialog.run();
2142 App::dialog_not_implemented()
2144 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2145 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2150 try_open_url(const std::string &url)
2153 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2155 std::vector<std::string> command_line;
2156 std::vector<std::string> browsers;
2157 browsers.reserve(23);
2159 // Browser wrapper scripts
2160 #ifdef USE_OPEN_FOR_URLS
2161 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2163 browsers.push_back("xdg-open"); // XDG wrapper
2164 browsers.push_back("sensible-browser"); // Debian wrapper
2165 browsers.push_back("gnome-open"); // GNOME wrapper
2166 browsers.push_back("kfmclient"); // KDE wrapper
2167 browsers.push_back("exo-open"); // XFCE wrapper
2169 // Alternatives system
2170 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2171 browsers.push_back("x-www-browser"); // Debian GUI alternative
2173 // Individual browsers
2174 browsers.push_back("firefox");
2175 browsers.push_back("epiphany-browser");
2176 browsers.push_back("epiphany");
2177 browsers.push_back("konqueror");
2178 browsers.push_back("iceweasel");
2179 browsers.push_back("mozilla");
2180 browsers.push_back("netscape");
2181 browsers.push_back("icecat");
2182 browsers.push_back("galeon");
2183 browsers.push_back("midori");
2184 browsers.push_back("safari");
2185 browsers.push_back("opera");
2186 browsers.push_back("amaya");
2187 browsers.push_back("netsurf");
2188 browsers.push_back("dillo");
2190 // Try the user-specified browser first
2191 command_line.push_back(App::browser_command);
2192 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2193 command_line.push_back(url);
2195 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2196 catch( Glib::SpawnError& exception ){
2198 while ( !browsers.empty() )
2200 // Skip the browser if we already tried it
2201 if( browsers[0] == App::browser_command )
2204 // Construct the command line
2205 command_line.clear();
2206 command_line.push_back(browsers[0]);
2207 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2208 command_line.push_back(url);
2210 // Remove the browser from the list
2211 browsers.erase(browsers.begin());
2213 // Try to spawn the browser
2214 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2215 // Failed, move on to the next one
2216 catch(Glib::SpawnError& exception){ continue; }
2217 return true; // No exception means we succeeded!
2228 if (!try_open_url("http://synfig.org/Documentation"))
2230 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2231 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2232 dialog.set_title(_("Help"));
2238 App::open_url(const std::string &url)
2240 if(!try_open_url(url))
2242 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2243 dialog.set_secondary_text(url);
2244 dialog.set_title(_("No browser found"));
2250 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2255 true); // use_separator
2257 Gtk::Label label(message);
2259 dialog.get_vbox()->pack_start(label);
2262 entry.set_text(text);
2264 entry.set_activates_default(true);
2266 dialog.get_vbox()->pack_start(entry);
2268 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2269 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2270 dialog.set_default_response(Gtk::RESPONSE_OK);
2272 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2275 if(dialog.run()!=Gtk::RESPONSE_OK)
2278 text=entry.get_text();
2284 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2289 true); // use_separator
2291 Gtk::Label label(message);
2293 dialog.get_vbox()->pack_start(label);
2295 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2296 text_buffer->set_text(text);
2297 Gtk::TextView text_view(text_buffer);
2300 dialog.get_vbox()->pack_start(text_view);
2302 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2303 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2304 dialog.set_default_response(Gtk::RESPONSE_OK);
2306 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2309 if(dialog.run()!=Gtk::RESPONSE_OK)
2312 text=text_buffer->get_text();
2318 App::open(std::string filename)
2320 return open_as(filename,filename);
2323 // this is called from autorecover.cpp:
2324 // App::open_as(get_shadow_file_name(filename),filename)
2325 // other than that, 'filename' and 'as' are the same
2327 App::open_as(std::string filename,std::string as)
2330 char long_name[1024];
2331 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2332 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2333 // don't use it if that's the case
2334 if (long_name[0] != '\0')
2340 OneMoment one_moment;
2342 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2343 if(canvas && get_instance(canvas))
2345 get_instance(canvas)->find_canvas_view(canvas)->present();
2346 info("%s is already open", filename.c_str());
2347 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2352 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2354 if (as.find(custom_filename_prefix.c_str()) != 0)
2355 add_recent_file(as);
2357 handle<Instance> instance(Instance::create(canvas));
2360 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2362 set_recent_file_window_size(instance);
2366 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)")))
2367 instance->dialog_cvs_update();
2372 dialog_error_blocking(_("Error"), x);
2377 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2388 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2390 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2391 canvas->set_name(file_name);
2392 file_name += ".sifz";
2394 canvas->rend_desc().set_frame_rate(24.0);
2395 canvas->rend_desc().set_time_start(0.0);
2396 canvas->rend_desc().set_time_end(5.0);
2397 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2398 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2399 // The top left and botton right positions are expressed in units
2400 // Original convention is that 1 unit = 60 pixels
2401 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2402 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2403 canvas->rend_desc().set_w(preferred_x_size);
2404 canvas->rend_desc().set_h(preferred_y_size);
2405 canvas->rend_desc().set_antialias(1);
2406 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2407 canvas->set_file_name(file_name);
2409 handle<Instance> instance = Instance::create(canvas);
2411 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2412 instance->find_canvas_view(canvas)->canvas_properties.present();
2416 App::dialog_open(string filename)
2418 if (filename.empty())
2421 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2423 // If the filename still has wildcards, then we should
2424 // continue looking for the file we want
2425 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2431 get_ui_interface()->error(_("Unable to open file"));
2436 App::set_selected_instance(etl::loose_handle<Instance> instance)
2438 /* if(get_selected_instance()==instance)
2440 selected_instance=instance;
2441 signal_instance_selected()(instance);
2447 selected_instance=instance;
2448 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2452 instance->focus(instance->get_canvas());
2455 set_selected_canvas_view(0);
2457 signal_instance_selected()(instance);
2461 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2463 selected_canvas_view=canvas_view;
2464 signal_canvas_view_focus()(selected_canvas_view);
2467 selected_instance=canvas_view->get_instance();
2468 signal_instance_selected()(canvas_view->get_instance());
2471 if(get_selected_canvas_view()==canvas_view)
2473 signal_canvas_view_focus()(selected_canvas_view);
2474 signal_instance_selected()(canvas_view->get_instance());
2477 selected_canvas_view=canvas_view;
2478 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2479 set_selected_instance(canvas_view->get_instance());
2480 signal_canvas_view_focus()(selected_canvas_view);
2484 etl::loose_handle<Instance>
2485 App::get_instance(etl::handle<synfig::Canvas> canvas)
2487 if(!canvas) return 0;
2488 canvas=canvas->get_root();
2490 std::list<etl::handle<Instance> >::iterator iter;
2491 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2493 if((*iter)->get_canvas()==canvas)
2509 if(selected_instance)
2510 selected_instance->undo();
2516 if(selected_instance)
2517 selected_instance->redo();
2521 studio::App::get_base_path()
2523 return app_base_path_;