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);
1260 // Disabled by default - it doesn't work properly?
1261 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1263 studio_init_cb.task(_("Init ModPalette..."));
1264 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1266 studio_init_cb.task(_("Init Setup Dialog..."));
1267 dialog_setup=new studio::Dialog_Setup();
1269 studio_init_cb.task(_("Init Input Dialog..."));
1270 dialog_input=new Gtk::InputDialog();
1271 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1272 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1274 studio_init_cb.task(_("Init auto recovery..."));
1275 auto_recover=new AutoRecover();
1277 studio_init_cb.amount_complete(9250,10000);
1278 studio_init_cb.task(_("Loading Settings..."));
1280 studio_init_cb.task(_("Checking auto-recover..."));
1282 studio_init_cb.amount_complete(9900,10000);
1284 bool opened_any = false;
1285 if(auto_recover->recovery_needed())
1287 splash_screen.hide();
1288 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1289 _("Synfig Studio seems to have crashed\n"
1290 "before you could save all your files.\n"
1291 "Would you like to re-open those files\n"
1292 "and recover your unsaved changes?")) ==
1293 synfigapp::UIInterface::RESPONSE_YES)
1295 int number_recovered;
1296 if(!auto_recover->recover(number_recovered))
1297 if (number_recovered)
1298 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1300 get_ui_interface()->error(_("Unable to recover from previous crash"));
1302 get_ui_interface()->error(
1303 _("Synfig Studio has attempted to recover\n"
1304 "from a previous crash. The files that it has\n"
1305 "recovered are NOT YET SAVED. It would be a good\n"
1306 "idea to review them and save them now."));
1308 if (number_recovered)
1311 splash_screen.show();
1314 // Look for any files given on the command line,
1315 // and load them if found.
1316 for(;*argc>=1;(*argc)--)
1317 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1319 studio_init_cb.task(_("Loading files..."));
1320 splash_screen.hide();
1321 open((*argv)[*argc]);
1323 splash_screen.show();
1326 // if no file was specified to be opened, create a new document to help new users get started more easily
1327 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1330 studio_init_cb.task(_("Done."));
1331 studio_init_cb.amount_complete(10000,10000);
1337 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1341 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1345 StateManager* App::get_state_manager() { return state_manager; }
1349 shutdown_in_progress=true;
1353 synfigapp::Main::settings().remove_domain("pref");
1355 selected_instance=0;
1357 // Unload all of the modules
1358 for(;!module_list_.empty();module_list_.pop_back())
1361 delete state_manager;
1365 delete auto_recover;
1371 // studio::App::iteration(false);
1375 // studio::App::iteration(false);
1377 // studio::App::iteration(false);
1379 delete dialog_setup;
1381 delete dialog_gradient;
1383 delete dialog_color;
1385 delete dialog_input;
1387 delete dock_manager;
1389 instance_list.clear();
1391 // studio::App::iteration(false);
1395 App::get_user_app_directory()
1397 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1399 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1401 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1406 App::get_config_file(const synfig::String& file)
1408 return Glib::build_filename(get_user_app_directory(),file);
1411 #define SCALE_FACTOR (1280)
1412 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1414 App::set_recent_file_window_size(etl::handle<Instance> instance)
1416 int screen_w(Gdk::screen_width());
1417 int screen_h(Gdk::screen_height());
1419 const std::string &canvas_window_size = *recent_files_window_size.begin();
1421 if(canvas_window_size.empty())
1424 synfig::String::size_type current=0;
1425 bool seen_root(false), shown_non_root(false);
1427 while(current != synfig::String::npos)
1429 // find end of first field (canvas) or return
1430 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1431 if(separator == synfig::String::npos) break;
1434 synfig::Canvas::Handle canvas;
1436 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1438 catch(Exception::IDNotFound) {
1439 // can't find the canvas; skip to the next canvas or return
1440 separator = canvas_window_size.find_first_of('\t', current);
1441 if(separator == synfig::String::npos) return;
1442 current = separator+1;
1446 if (canvas->is_root())
1449 shown_non_root = true;
1451 // check that we have the tab character the ends this canvas' data or return
1452 current = separator+1;
1453 separator = canvas_window_size.find_first_of('\t', current);
1454 if(separator == synfig::String::npos) return;
1457 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1459 current = separator+1;
1463 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1464 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1465 x=x*screen_w/SCALE_FACTOR;
1466 y=y*screen_h/SCALE_FACTOR;
1467 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1468 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1469 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1470 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1472 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1473 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1475 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1476 canvasview->move(x,y);
1477 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1478 canvasview->present();
1480 current = separator+1;
1483 if (shown_non_root && !seen_root)
1484 instance->find_canvas_view(instance->get_canvas())->hide();
1488 App::add_recent_file(const etl::handle<Instance> instance)
1490 int screen_w(Gdk::screen_width());
1491 int screen_h(Gdk::screen_height());
1493 std::string canvas_window_size;
1495 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1496 Instance::CanvasViewList::const_iterator iter;
1498 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1500 if( !((*iter)->is_visible()) )
1503 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1504 int x_pos, y_pos, x_size, y_size;
1505 (*iter)->get_position(x_pos,y_pos);
1506 (*iter)->get_size(x_size,y_size);
1508 canvas_window_size += strprintf("%s %d %d %d %d\t",
1509 canvas->get_relative_id(canvas->get_root()).c_str(),
1510 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1511 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1514 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1519 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1521 std::string filename(file_name);
1523 assert(!filename.empty());
1525 if(filename.empty())
1528 // Toss out any "hidden" files
1529 if(basename(filename)[0]=='.')
1532 // If we aren't an absolute path, turn ourselves into one
1533 if(!is_absolute_path(filename))
1534 filename=absolute_path(filename);
1536 std::string old_window_size;
1538 list<string>::iterator iter;
1539 list<string>::iterator iter_wsize;
1540 // Check to see if the file is already on the list.
1541 // If it is, then remove it from the list
1542 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1545 recent_files.erase(iter);
1546 old_window_size = *iter_wsize;
1547 recent_files_window_size.erase(iter_wsize);
1552 // Push the filename to the front of the list
1553 recent_files.push_front(filename);
1554 if(window_size.empty())
1555 recent_files_window_size.push_front(old_window_size);
1557 recent_files_window_size.push_front(window_size);
1559 // Clean out the files at the end of the list.
1560 while(recent_files.size()>(unsigned)get_max_recent_files())
1562 recent_files.pop_back();
1563 recent_files_window_size.pop_back();
1566 signal_recent_files_changed_();
1571 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1574 App::get_time_format()
1576 return _App_time_format;
1580 App::set_time_format(synfig::Time::Format x)
1587 App::save_settings()
1592 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1593 setlocale(LC_NUMERIC, "C");
1595 std::string filename=get_config_file("accelrc");
1596 Gtk::AccelMap::save(filename);
1599 std::string filename=get_config_file("recentfiles");
1601 std::ofstream file(filename.c_str());
1605 synfig::warning("Unable to save %s",filename.c_str());
1609 list<string>::reverse_iterator iter;
1611 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1615 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1617 std::ofstream file(filename.c_str());
1621 synfig::warning("Unable to save %s",filename.c_str());
1625 list<string>::reverse_iterator iter;
1627 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1631 std::string filename=get_config_file("settings");
1632 synfigapp::Main::settings().save_to_file(filename);
1633 setlocale(LC_NUMERIC,old_locale);
1637 synfig::warning("Caught exception when attempting to save settings.");
1642 App::load_settings()
1647 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1648 setlocale(LC_NUMERIC, "C");
1650 std::string filename=get_config_file("accelrc");
1651 Gtk::AccelMap::load(filename);
1654 bool window_size_broken = false;
1656 std::string filename=get_config_file("recentfiles");
1657 std::string filename_window_size=filename+std::string("_window_size");
1659 std::ifstream file(filename.c_str());
1660 std::ifstream file_window_size(filename_window_size.c_str());
1662 if(!file_window_size)
1663 window_size_broken = true;
1667 std::string recent_file;
1668 std::string recent_file_window_size;
1669 getline(file,recent_file);
1670 if(!window_size_broken)
1671 getline(file_window_size,recent_file_window_size);
1672 if(!recent_file.empty())
1674 if(!window_size_broken && !file_window_size)
1675 window_size_broken = true;
1676 if (std::ifstream(recent_file.c_str()))
1678 if(!window_size_broken)
1679 add_recent_file(recent_file,recent_file_window_size);
1681 add_recent_file(recent_file);
1685 if(!window_size_broken && file_window_size)
1686 window_size_broken = true;
1688 if(window_size_broken)
1690 recent_files_window_size.clear();
1691 recent_files_window_size.resize(recent_files.size());
1694 std::string filename=get_config_file("settings");
1695 if(!synfigapp::Main::settings().load_from_file(filename))
1697 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1698 //if(!synfigapp::Main::settings().load_from_file(filename))
1700 gamma.set_gamma(1.0/2.2);
1701 reset_initial_window_configuration();
1704 setlocale(LC_NUMERIC,old_locale);
1708 synfig::warning("Caught exception when attempting to load settings.");
1713 App::reset_initial_window_configuration()
1715 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1716 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1717 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1718 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1719 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1720 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1721 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1722 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1723 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1724 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1725 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1726 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1727 #ifdef SINGLE_THREADED
1728 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1730 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1731 synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
1732 synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
1733 synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
1734 synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
1735 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1739 App::shutdown_request(GdkEventAny*)
1743 //return !shutdown_in_progress;
1749 if(shutdown_in_progress)return;
1752 get_ui_interface()->task(_("Quit Request"));
1755 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1759 std::list<etl::handle<Instance> >::iterator iter;
1760 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1762 if(!(*iter)->safe_close())
1766 if((*iter)->synfigapp::Instance::get_action_count())
1768 handle<synfigapp::UIInterface> uim;
1769 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1771 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1772 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1774 case synfigapp::UIInterface::RESPONSE_NO:
1776 case synfigapp::UIInterface::RESPONSE_YES:
1779 case synfigapp::UIInterface::RESPONSE_CANCEL:
1788 if((*iter)->synfigapp::Instance::is_modified())
1790 handle<synfigapp::UIInterface> uim;
1791 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1793 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() );
1794 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1796 case synfigapp::UIInterface::RESPONSE_NO:
1798 case synfigapp::UIInterface::RESPONSE_YES:
1799 (*iter)->dialog_cvs_commit();
1801 case synfigapp::UIInterface::RESPONSE_CANCEL:
1810 // This next line causes things to crash for some reason
1814 shutdown_in_progress=true;
1816 instance_list.clear();
1818 while(studio::App::events_pending())studio::App::iteration(false);
1821 auto_recover->normal_shutdown();
1823 get_ui_interface()->task(_("Quit Request sent"));
1829 dialog_setup->refresh();
1830 dialog_setup->show();
1833 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1834 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1837 //#define USE_WIN32_FILE_DIALOGS 1
1840 #ifdef USE_WIN32_FILE_DIALOGS
1841 static OPENFILENAME ofn={};
1845 #include <gdk/gdkwin32.h>
1849 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1851 // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1853 #ifdef USE_WIN32_FILE_DIALOGS
1854 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1856 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1857 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1858 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1860 ofn.lStructSize=sizeof(OPENFILENAME);
1861 ofn.hwndOwner = hWnd;
1862 ofn.hInstance = hInstance;
1863 ofn.lpstrFilter = szFilter;
1864 // ofn.lpstrCustomFilter=NULL;
1865 // ofn.nMaxCustFilter=0;
1866 // ofn.nFilterIndex=0;
1867 // ofn.lpstrFile=NULL;
1868 ofn.nMaxFile=MAX_PATH;
1869 // ofn.lpstrFileTitle=NULL;
1870 // ofn.lpstrInitialDir=NULL;
1871 // ofn.lpstrTitle=NULL;
1872 ofn.Flags=OFN_HIDEREADONLY;
1873 // ofn.nFileOffset=0;
1874 // ofn.nFileExtension=0;
1875 ofn.lpstrDefExt=TEXT("sif");
1876 // ofn.lCustData = 0l;
1878 // ofn.lpTemplateName=NULL;
1880 CHAR szFilename[MAX_PATH];
1882 strcpy(szFilename,filename.c_str());
1883 strcpy(szTitle,title.c_str());
1885 ofn.lpstrFile=szFilename;
1886 ofn.lpstrFileTitle=szTitle;
1888 if(GetOpenFileName(&ofn))
1890 filename=szFilename;
1896 synfig::String prev_path;
1898 if(!_preferences.get_value(preference, prev_path))
1901 prev_path = absolute_path(prev_path);
1903 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1905 dialog->set_current_folder(prev_path);
1906 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1907 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1909 if (filename.empty())
1910 dialog->set_filename(prev_path);
1911 else if (is_absolute_path(filename))
1912 dialog->set_filename(filename);
1914 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1916 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1917 filename = dialog->get_filename();
1918 // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1919 _preferences.set_value(preference, dirname(filename));
1933 GtkWidget *fileselection;
1934 fileselection = gtk_file_selection_new(title.c_str());
1937 if(basename(filename)==filename)
1939 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1942 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1944 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1946 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1947 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1949 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1950 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1952 gtk_widget_show(fileselection);
1960 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1961 _preferences.set_value(preference,dirname(filename));
1965 gtk_widget_destroy(fileselection);
1968 gtk_widget_destroy(fileselection);
1975 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1977 // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1979 #if USE_WIN32_FILE_DIALOGS
1980 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1982 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1983 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1984 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1986 ofn.lStructSize=sizeof(OPENFILENAME);
1987 ofn.hwndOwner = hWnd;
1988 ofn.hInstance = hInstance;
1989 ofn.lpstrFilter = szFilter;
1990 // ofn.lpstrCustomFilter=NULL;
1991 // ofn.nMaxCustFilter=0;
1992 // ofn.nFilterIndex=0;
1993 // ofn.lpstrFile=NULL;
1994 ofn.nMaxFile=MAX_PATH;
1995 // ofn.lpstrFileTitle=NULL;
1996 // ofn.lpstrInitialDir=NULL;
1997 // ofn.lpstrTitle=NULL;
1998 ofn.Flags=OFN_OVERWRITEPROMPT;
1999 // ofn.nFileOffset=0;
2000 // ofn.nFileExtension=0;
2001 ofn.lpstrDefExt=TEXT("sif");
2002 // ofn.lCustData = 0l;
2004 // ofn.lpTemplateName=NULL;
2006 CHAR szFilename[MAX_PATH];
2008 strcpy(szFilename,filename.c_str());
2009 strcpy(szTitle,title.c_str());
2011 ofn.lpstrFile=szFilename;
2012 ofn.lpstrFileTitle=szTitle;
2014 if(GetSaveFileName(&ofn))
2016 filename=szFilename;
2017 _preferences.set_value(preference,dirname(filename));
2022 synfig::String prev_path;
2024 if(!_preferences.get_value(preference, prev_path))
2027 prev_path = absolute_path(prev_path);
2029 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
2031 dialog->set_current_folder(prev_path);
2032 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2033 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2035 Widget_Enum *file_type_enum = 0;
2036 if (preference == ANIMATION_DIR_PREFERENCE)
2038 file_type_enum = manage(new Widget_Enum());
2039 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
2040 .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current")))
2041 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08")
2042 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
2043 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
2044 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
2046 Gtk::HBox *hbox = manage(new Gtk::HBox);
2047 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
2048 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
2051 dialog->set_extra_widget(*hbox);
2054 if (filename.empty())
2055 dialog->set_filename(prev_path);
2058 std::string full_path;
2059 if (is_absolute_path(filename))
2060 full_path = filename;
2062 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
2064 // select the file if it exists
2065 dialog->set_filename(full_path);
2067 // if the file doesn't exist, put its name into the filename box
2069 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
2070 dialog->set_current_name(basename(filename));
2073 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2074 if (preference == ANIMATION_DIR_PREFERENCE)
2075 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2076 filename = dialog->get_filename();
2077 // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2078 _preferences.set_value(preference, dirname(filename));
2089 App::dialog_error_blocking(const std::string &title, const std::string &message)
2091 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2092 dialog.set_title(title);
2098 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2100 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2101 dialog.set_title(title);
2107 App::dialog_yes_no(const std::string &title, const std::string &message)
2112 true // use_separator
2114 Gtk::Label label(message);
2117 dialog.get_vbox()->pack_start(label);
2118 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2119 dialog.add_button(Gtk::StockID("gtk-no"),0);
2121 return dialog.run();
2125 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2130 true // use_separator
2132 Gtk::Label label(message);
2135 dialog.get_vbox()->pack_start(label);
2136 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2137 dialog.add_button(Gtk::StockID("gtk-no"),0);
2138 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2140 return dialog.run();
2144 App::dialog_not_implemented()
2146 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2147 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2152 try_open_url(const std::string &url)
2155 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2157 std::vector<std::string> command_line;
2158 std::vector<std::string> browsers;
2159 browsers.reserve(23);
2161 // Browser wrapper scripts
2162 #ifdef USE_OPEN_FOR_URLS
2163 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2165 browsers.push_back("xdg-open"); // XDG wrapper
2166 browsers.push_back("sensible-browser"); // Debian wrapper
2167 browsers.push_back("gnome-open"); // GNOME wrapper
2168 browsers.push_back("kfmclient"); // KDE wrapper
2169 browsers.push_back("exo-open"); // XFCE wrapper
2171 // Alternatives system
2172 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2173 browsers.push_back("x-www-browser"); // Debian GUI alternative
2175 // Individual browsers
2176 browsers.push_back("firefox");
2177 browsers.push_back("epiphany-browser");
2178 browsers.push_back("epiphany");
2179 browsers.push_back("konqueror");
2180 browsers.push_back("iceweasel");
2181 browsers.push_back("mozilla");
2182 browsers.push_back("netscape");
2183 browsers.push_back("icecat");
2184 browsers.push_back("galeon");
2185 browsers.push_back("midori");
2186 browsers.push_back("safari");
2187 browsers.push_back("opera");
2188 browsers.push_back("amaya");
2189 browsers.push_back("netsurf");
2190 browsers.push_back("dillo");
2192 // Try the user-specified browser first
2193 command_line.push_back(App::browser_command);
2194 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2195 command_line.push_back(url);
2197 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2198 catch( Glib::SpawnError& exception ){
2200 while ( !browsers.empty() )
2202 // Skip the browser if we already tried it
2203 if( browsers[0] == App::browser_command )
2206 // Construct the command line
2207 command_line.clear();
2208 command_line.push_back(browsers[0]);
2209 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2210 command_line.push_back(url);
2212 // Remove the browser from the list
2213 browsers.erase(browsers.begin());
2215 // Try to spawn the browser
2216 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2217 // Failed, move on to the next one
2218 catch(Glib::SpawnError& exception){ continue; }
2219 return true; // No exception means we succeeded!
2230 if (!try_open_url("http://synfig.org/Documentation"))
2232 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2233 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2234 dialog.set_title(_("Help"));
2240 App::open_url(const std::string &url)
2242 if(!try_open_url(url))
2244 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2245 dialog.set_secondary_text(url);
2246 dialog.set_title(_("No browser found"));
2252 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2257 true); // use_separator
2259 Gtk::Label label(message);
2261 dialog.get_vbox()->pack_start(label);
2264 entry.set_text(text);
2266 entry.set_activates_default(true);
2268 dialog.get_vbox()->pack_start(entry);
2270 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2271 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2272 dialog.set_default_response(Gtk::RESPONSE_OK);
2274 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2277 if(dialog.run()!=Gtk::RESPONSE_OK)
2280 text=entry.get_text();
2286 App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text)
2291 true); // use_separator
2293 Gtk::Label label(message);
2295 dialog.get_vbox()->pack_start(label);
2297 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
2298 text_buffer->set_text(text);
2299 Gtk::TextView text_view(text_buffer);
2302 dialog.get_vbox()->pack_start(text_view);
2304 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2305 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2306 dialog.set_default_response(Gtk::RESPONSE_OK);
2308 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2311 if(dialog.run()!=Gtk::RESPONSE_OK)
2314 text=text_buffer->get_text();
2320 App::open(std::string filename)
2322 return open_as(filename,filename);
2325 // this is called from autorecover.cpp:
2326 // App::open_as(get_shadow_file_name(filename),filename)
2327 // other than that, 'filename' and 'as' are the same
2329 App::open_as(std::string filename,std::string as)
2332 char long_name[1024];
2333 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2334 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2335 // don't use it if that's the case
2336 if (long_name[0] != '\0')
2342 OneMoment one_moment;
2344 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2345 if(canvas && get_instance(canvas))
2347 get_instance(canvas)->find_canvas_view(canvas)->present();
2348 info("%s is already open", filename.c_str());
2349 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2354 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2356 if (as.find(custom_filename_prefix.c_str()) != 0)
2357 add_recent_file(as);
2359 handle<Instance> instance(Instance::create(canvas));
2362 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2364 set_recent_file_window_size(instance);
2368 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)")))
2369 instance->dialog_cvs_update();
2374 dialog_error_blocking(_("Error"), x);
2379 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2390 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2392 String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1));
2393 canvas->set_name(file_name);
2394 file_name += ".sifz";
2396 canvas->rend_desc().set_frame_rate(24.0);
2397 canvas->rend_desc().set_time_start(0.0);
2398 canvas->rend_desc().set_time_end(5.0);
2399 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2400 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2401 // The top left and botton right positions are expressed in units
2402 // Original convention is that 1 unit = 60 pixels
2403 canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0));
2404 canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0));
2405 canvas->rend_desc().set_w(preferred_x_size);
2406 canvas->rend_desc().set_h(preferred_y_size);
2407 canvas->rend_desc().set_antialias(1);
2408 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2409 canvas->set_file_name(file_name);
2411 handle<Instance> instance = Instance::create(canvas);
2413 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2414 instance->find_canvas_view(canvas)->canvas_properties.present();
2418 App::dialog_open(string filename)
2420 if (filename.empty())
2423 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2425 // If the filename still has wildcards, then we should
2426 // continue looking for the file we want
2427 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2433 get_ui_interface()->error(_("Unable to open file"));
2438 App::set_selected_instance(etl::loose_handle<Instance> instance)
2440 /* if(get_selected_instance()==instance)
2442 selected_instance=instance;
2443 signal_instance_selected()(instance);
2449 selected_instance=instance;
2450 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2454 instance->focus(instance->get_canvas());
2457 set_selected_canvas_view(0);
2459 signal_instance_selected()(instance);
2463 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2465 selected_canvas_view=canvas_view;
2466 signal_canvas_view_focus()(selected_canvas_view);
2469 selected_instance=canvas_view->get_instance();
2470 signal_instance_selected()(canvas_view->get_instance());
2473 if(get_selected_canvas_view()==canvas_view)
2475 signal_canvas_view_focus()(selected_canvas_view);
2476 signal_instance_selected()(canvas_view->get_instance());
2479 selected_canvas_view=canvas_view;
2480 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2481 set_selected_instance(canvas_view->get_instance());
2482 signal_canvas_view_focus()(selected_canvas_view);
2486 etl::loose_handle<Instance>
2487 App::get_instance(etl::handle<synfig::Canvas> canvas)
2489 if(!canvas) return 0;
2490 canvas=canvas->get_root();
2492 std::list<etl::handle<Instance> >::iterator iter;
2493 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2495 if((*iter)->get_canvas()==canvas)
2511 if(selected_instance)
2512 selected_instance->undo();
2518 if(selected_instance)
2519 selected_instance->redo();
2523 studio::App::get_base_path()
2525 return app_base_path_;