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>
60 #include <gdkmm/general.h>
62 #include <synfig/loadcanvas.h>
63 #include <synfig/savecanvas.h>
69 #include "canvasview.h"
70 #include "dialog_setup.h"
71 #include "dialog_gradient.h"
72 #include "dialog_color.h"
75 #include "onemoment.h"
77 #include "dockmanager.h"
79 #include "state_eyedrop.h"
80 #include "state_normal.h"
81 #include "state_draw.h"
82 #include "state_fill.h"
83 #include "state_bline.h"
84 #include "state_polygon.h"
85 #include "state_sketch.h"
86 #include "state_gradient.h"
87 #include "state_circle.h"
88 #include "state_rectangle.h"
89 #include "state_smoothmove.h"
90 #include "state_scale.h"
91 #include "state_width.h"
92 #include "state_rotate.h"
93 #include "state_zoom.h"
95 #include "devicetracker.h"
96 #include "dialog_tooloptions.h"
97 #include "widget_enum.h"
99 #include "autorecover.h"
101 #include <synfigapp/settings.h>
102 #include "dock_history.h"
103 #include "dock_canvases.h"
104 #include "dock_keyframes.h"
105 #include "dock_layers.h"
106 #include "dock_params.h"
107 #include "dock_metadata.h"
108 #include "dock_children.h"
109 #include "dock_info.h"
110 #include "dock_navigator.h"
111 #include "dock_layergroups.h"
112 #include "dock_timetrack.h"
113 #include "dock_curves.h"
115 #include "mod_palette/mod_palette.h"
116 #include "mod_mirror/mod_mirror.h"
118 #include <sys/stat.h>
124 #include "statemanager.h"
130 #include <gtkmm/accelmap.h>
131 #include <gtkmm/filechooser.h>
132 #include <gtkmm/filechooserdialog.h>
138 /* === U S I N G =========================================================== */
142 using namespace synfig;
143 using namespace studio;
145 /* === M A C R O S ========================================================= */
147 #ifndef SYNFIG_USER_APP_DIR
149 #define SYNFIG_USER_APP_DIR "Library/Synfig"
150 #elif defined(_WIN32)
151 #define SYNFIG_USER_APP_DIR "Synfig"
153 #define SYNFIG_USER_APP_DIR ".synfig"
158 #define DPM2DPI(x) (float(x)/39.3700787402f)
159 #define DPI2DPM(x) (float(x)*39.3700787402f)
165 # define IMAGE_DIR "share\\pixmaps"
170 # define IMAGE_DIR "/usr/local/share/pixmaps"
174 # define IMAGE_EXT "tif"
177 #include <synfigapp/main.h>
179 /* === S I G N A L S ======================================================= */
181 static sigc::signal<void> signal_present_all_;
183 App::signal_present_all() { return signal_present_all_; }
185 static sigc::signal<void> signal_recent_files_changed_;
187 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
189 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
190 sigc::signal<void,etl::loose_handle<CanvasView> >&
191 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
193 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
194 sigc::signal<void,etl::handle<Instance> >&
195 App::signal_instance_selected() { return signal_instance_selected_; }
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_created() { return signal_instance_created_; }
201 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
202 sigc::signal<void,etl::handle<Instance> >&
203 App::signal_instance_deleted() { return signal_instance_deleted_; }
205 /* === G L O B A L S ======================================================= */
207 static std::list<std::string> recent_files;
208 const std::list<std::string>& App::get_recent_files() { return recent_files; }
210 static std::list<std::string> recent_files_window_size;
212 int App::Busy::count;
213 bool App::shutdown_in_progress;
215 synfig::Gamma App::gamma;
217 Glib::RefPtr<studio::UIManager> App::ui_manager_;
219 synfig::Distance::System App::distance_system;
221 studio::Dialog_Setup* App::dialog_setup;
223 etl::handle< studio::ModPalette > mod_palette_;
224 //studio::Dialog_Palette* App::dialog_palette;
226 std::list<etl::handle<Instance> > App::instance_list;
228 static etl::handle<synfigapp::UIInterface> ui_interface_;
229 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
231 etl::handle<Instance> App::selected_instance;
232 etl::handle<CanvasView> App::selected_canvas_view;
234 studio::About *studio::App::about=NULL;
236 studio::Toolbox *studio::App::toolbox=NULL;
238 studio::AutoRecover *studio::App::auto_recover=NULL;
240 studio::IPC *ipc=NULL;
242 studio::DockManager* studio::App::dock_manager=0;
244 studio::DeviceTracker* studio::App::device_tracker=0;
246 studio::Dialog_Gradient* studio::App::dialog_gradient;
248 studio::Dialog_Color* studio::App::dialog_color;
250 Gtk::InputDialog* studio::App::dialog_input;
252 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
254 studio::Dock_History* dock_history;
255 studio::Dock_Canvases* dock_canvases;
256 studio::Dock_Keyframes* dock_keyframes;
257 studio::Dock_Layers* dock_layers;
258 studio::Dock_Params* dock_params;
259 studio::Dock_MetaData* dock_meta_data;
260 studio::Dock_Children* dock_children;
261 studio::Dock_Info* dock_info;
262 studio::Dock_LayerGroups* dock_layer_groups;
263 studio::Dock_Navigator* dock_navigator;
264 studio::Dock_Timetrack* dock_timetrack;
265 studio::Dock_Curves* dock_curves;
267 std::list< etl::handle< studio::Module > > module_list_;
269 bool studio::App::use_colorspace_gamma=true;
270 #ifdef SINGLE_THREADED
271 bool studio::App::single_threaded=false;
273 bool studio::App::restrict_radius_ducks=false;
274 #ifdef USE_OPEN_FOR_URLS
275 String studio::App::browser_command("open"); // MacOS only
277 String studio::App::browser_command("xdg-open"); // Linux XDG standard
280 static int max_recent_files_=25;
281 int studio::App::get_max_recent_files() { return max_recent_files_; }
282 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
284 static synfig::String app_base_path_;
289 really_delete_widget(Gtk::Widget *widget)
291 // synfig::info("really delete %p", (void*)widget);
296 // nasty workaround - when we've finished with a popup menu, we want to delete it
297 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
298 // so schedule the real delete to happen in 50ms, giving the action a chance to run
300 delete_widget(Gtk::Widget *widget)
302 // synfig::info("delete %p", (void*)widget);
303 Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
306 }; // END of namespace studio
307 studio::StateManager* state_manager;
312 class GlobalUIInterface : public synfigapp::UIInterface
316 virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
321 true // use_separator
323 Gtk::Label label(message);
326 dialog.get_vbox()->pack_start(label);
327 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
328 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
330 dialog.set_default_response(dflt);
332 return (Response)dialog.run();
334 virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
339 true // use_separator
341 Gtk::Label label(message);
344 dialog.get_vbox()->pack_start(label);
345 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
346 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
347 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
349 dialog.set_default_response(dflt);
351 return (Response)dialog.run();
353 virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
358 true // use_separator
360 Gtk::Label label(message);
363 dialog.get_vbox()->pack_start(label);
364 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
365 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
367 dialog.set_default_response(dflt);
369 return (Response)dialog.run();
373 task(const std::string &task)
375 std::cerr<<task<<std::endl;
376 while(studio::App::events_pending())studio::App::iteration(false);
381 error(const std::string &err)
383 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
390 warning(const std::string &err)
392 std::cerr<<"warning: "<<err<<std::endl;
393 while(studio::App::events_pending())studio::App::iteration(false);
398 amount_complete(int /*current*/, int /*total*/)
400 while(studio::App::events_pending())studio::App::iteration(false);
405 /* === P R O C E D U R E S ================================================= */
409 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
411 action_group_list.push_back(action_group);
412 Gtk::UIManager::insert_action_group(action_group, pos);
416 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
418 std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
419 for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
420 if(*iter==action_group)
422 action_group_list.erase(iter);
423 Gtk::UIManager::remove_action_group(action_group);
426 synfig::error("Unable to find action group");
430 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
432 ui_manager->insert_action_group(group,0);
434 std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
435 std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
437 for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
439 if(*iter && (*iter)->get_name()!="menus")
441 synfig::info("Removing action group "+(*iter)->get_name());
442 ui_manager->remove_action_group(*iter);
445 ui_manager->insert_action_group(group,0);
447 for(;!prev_groups.empty();prev_groups.pop_front())
449 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
450 ui_manager->insert_action_group(prev_groups.front(),1);
454 class Preferences : public synfigapp::Settings
457 virtual bool get_value(const synfig::String& key, synfig::String& value)const
461 value=strprintf("%f %f %f %f",
462 App::gamma.get_gamma_r(),
463 App::gamma.get_gamma_g(),
464 App::gamma.get_gamma_b(),
465 App::gamma.get_black_level()
469 if(key=="time_format")
471 value=strprintf("%i",App::get_time_format());
474 if(key=="file_history.size")
476 value=strprintf("%i",App::get_max_recent_files());
479 if(key=="use_colorspace_gamma")
481 value=strprintf("%i",(int)App::use_colorspace_gamma);
484 if(key=="distance_system")
486 value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
489 #ifdef SINGLE_THREADED
490 if(key=="single_threaded")
492 value=strprintf("%i",(int)App::single_threaded);
496 if(key=="auto_recover_backup_interval")
498 value=strprintf("%i",App::auto_recover->get_timeout());
501 if(key=="restrict_radius_ducks")
503 value=strprintf("%i",(int)App::restrict_radius_ducks);
506 if(key=="browser_command")
508 value=App::browser_command;
512 return synfigapp::Settings::get_value(key,value);
515 virtual bool set_value(const synfig::String& key,const synfig::String& value)
521 strscanf(value,"%f %f %f %f",
528 App::gamma.set_all(r,g,b,blk);
532 if(key=="time_format")
534 int i(atoi(value.c_str()));
535 App::set_time_format(static_cast<synfig::Time::Format>(i));
538 if(key=="auto_recover_backup_interval")
540 int i(atoi(value.c_str()));
541 App::auto_recover->set_timeout(i);
544 if(key=="file_history.size")
546 int i(atoi(value.c_str()));
547 App::set_max_recent_files(i);
550 if(key=="use_colorspace_gamma")
552 int i(atoi(value.c_str()));
553 App::use_colorspace_gamma=i;
556 if(key=="distance_system")
558 App::distance_system=Distance::ident_system(value);;
561 #ifdef SINGLE_THREADED
562 if(key=="single_threaded")
564 int i(atoi(value.c_str()));
565 App::single_threaded=i;
569 if(key=="restrict_radius_ducks")
571 int i(atoi(value.c_str()));
572 App::restrict_radius_ducks=i;
575 if(key=="browser_command")
577 App::browser_command=value;
581 return synfigapp::Settings::set_value(key,value);
584 virtual KeyList get_key_list()const
586 KeyList ret(synfigapp::Settings::get_key_list());
587 ret.push_back("gamma");
588 ret.push_back("time_format");
589 ret.push_back("distance_system");
590 ret.push_back("file_history.size");
591 ret.push_back("use_colorspace_gamma");
592 #ifdef SINGLE_THREADED
593 ret.push_back("single_threaded");
595 ret.push_back("auto_recover_backup_interval");
596 ret.push_back("restrict_radius_ducks");
597 ret.push_back("browser_command");
602 static ::Preferences _preferences;
607 Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
609 Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
611 Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
613 menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
614 menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
615 menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
616 menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
617 menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
618 menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
619 menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
620 menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
621 menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
622 menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
623 menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
624 menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
625 menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
627 // Add the synfigapp actions...
628 synfigapp::Action::Book::iterator iter;
629 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
631 actions_action_group->add(Gtk::Action::create(
632 "action-"+iter->second.name,
633 get_action_stock_id(iter->second),
634 iter->second.local_name,iter->second.local_name
638 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
639 #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); }
640 #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); }
642 DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
643 DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
644 DEFINE_ACTION("new", Gtk::Stock::NEW);
645 DEFINE_ACTION("open", Gtk::Stock::OPEN);
646 DEFINE_ACTION("save", Gtk::Stock::SAVE);
647 DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
648 DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
649 DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
650 DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
651 DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
652 DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
653 DEFINE_ACTION("import", _("Import"));
654 DEFINE_ACTION("render", _("Render"));
655 DEFINE_ACTION("preview", _("Preview"));
656 DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
657 DEFINE_ACTION("sound", _("Sound File"));
658 DEFINE_ACTION("options", _("Options"));
659 DEFINE_ACTION("close", _("Close View"));
660 DEFINE_ACTION("close-document", _("Close Document"));
661 DEFINE_ACTION("quit", Gtk::Stock::QUIT);
664 DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
665 DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
666 DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
667 DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
668 DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
669 DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
670 DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
671 DEFINE_ACTION("properties", _("Properties"));
673 DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
674 DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
675 DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
676 DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
677 DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
678 DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
679 DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
680 DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
681 DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
682 DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
683 DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
684 DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
685 DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
686 DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
687 DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
688 DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
689 DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
690 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
691 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
692 DEFINE_ACTION("play", _("Play"));
693 // DEFINE_ACTION("pause", _("Pause"));
694 DEFINE_ACTION("stop", _("Stop"));
695 DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
696 DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
697 DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
698 DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
699 DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
700 DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
701 DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
702 DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
703 DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
704 DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
705 DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
706 DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
707 DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
708 DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
709 DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
710 DEFINE_ACTION("seek-next-frame", _("Next Frame"));
711 DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
712 DEFINE_ACTION("seek-next-second", _("Seek Forward"));
713 DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
714 DEFINE_ACTION("seek-begin", _("Seek to Begin"));
715 DEFINE_ACTION("seek-end", _("Seek to End"));
717 DEFINE_ACTION("action-group_add", _("Add group"));
719 DEFINE_ACTION("canvas-new", _("New Canvas"));
721 DEFINE_ACTION("amount-inc", _("Increase Amount"));
722 DEFINE_ACTION("amount-dec", _("Decrease Amount"));
727 // Set up synfigapp actions
729 synfigapp::Action::Book::iterator iter;
731 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
733 Gtk::StockID stock_id;
735 if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
737 //Gtk::Image* image(manage(new Gtk::Image()));
738 if(iter->second.task=="raise") stock_id=Gtk::Stock::GO_UP;
739 else if(iter->second.task=="lower") stock_id=Gtk::Stock::GO_DOWN;
740 else if(iter->second.task=="move_top") stock_id=Gtk::Stock::GOTO_TOP;
741 else if(iter->second.task=="move_bottom") stock_id=Gtk::Stock::GOTO_BOTTOM;
742 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
743 else if(iter->second.task=="set_on") stock_id=Gtk::Stock::YES;
744 else if(iter->second.task=="set_off") stock_id=Gtk::Stock::NO;
745 //else if(iter->second.task=="duplicate") stock_id=Gtk::Stock::COPY;
746 else if(iter->second.task=="remove") stock_id=Gtk::Stock::DELETE;
747 else stock_id=Gtk::StockID("synfig-"+iter->second.task);
749 actions_action_group->add(Gtk::Action::create(
750 "action-"+iter->second.name,
752 iter->second.local_name,iter->second.local_name
760 Glib::ustring ui_info =
762 " <popup name='menu-toolbox' action='menu-toolbox'>"
763 " <menu action='menu-file'>"
766 " <popup name='menu-main' action='menu-main'>"
767 " <menu action='menu-file'>"
768 " <menuitem action='new' />"
769 " <menuitem action='open' />"
770 " <menuitem action='save' />"
771 " <menuitem action='save-as' />"
772 " <menuitem action='revert' />"
773 " <separator name='bleh01'/>"
774 " <menuitem action='cvs-add' />"
775 " <menuitem action='cvs-update' />"
776 " <menuitem action='cvs-commit' />"
777 " <menuitem action='cvs-revert' />"
778 " <separator name='bleh02'/>"
779 " <menuitem action='import' />"
780 " <separator name='bleh03'/>"
781 " <menuitem action='render' />"
782 " <menuitem action='preview' />"
783 " <menuitem action='sound' />"
784 " <separator name='bleh04'/>"
785 " <menuitem action='options' />"
786 " <menuitem action='close' />"
787 " <menuitem action='close-document' />"
788 " <menuitem action='quit' />"
790 " <menu action='menu-edit'>"
791 " <menuitem action='undo'/>"
792 " <menuitem action='redo'/>"
793 " <separator name='bleh05'/>"
794 " <menuitem action='cut'/>"
795 " <menuitem action='copy'/>"
796 " <menuitem action='paste'/>"
797 " <separator name='bleh06'/>"
798 " <menuitem action='select-all-ducks'/>"
799 " <menuitem action='unselect-all-layers'/>"
800 " <separator name='bleh07'/>"
801 " <menuitem action='properties'/>"
803 " <menu action='menu-view'>"
804 " <menu action='menu-duck-mask'>"
805 " <menuitem action='mask-position-ducks' />"
806 " <menuitem action='mask-vertex-ducks' />"
807 " <menuitem action='mask-tangent-ducks' />"
808 " <menuitem action='mask-radius-ducks' />"
809 " <menuitem action='mask-width-ducks' />"
810 " <menuitem action='mask-angle-ducks' />"
812 " <menu action='menu-preview-quality'>"
813 " <menuitem action='quality-00' />"
814 " <menuitem action='quality-01' />"
815 " <menuitem action='quality-02' />"
816 " <menuitem action='quality-03' />"
817 " <menuitem action='quality-04' />"
818 " <menuitem action='quality-05' />"
819 " <menuitem action='quality-06' />"
820 " <menuitem action='quality-07' />"
821 " <menuitem action='quality-08' />"
822 " <menuitem action='quality-09' />"
823 " <menuitem action='quality-10' />"
825 " <menu action='menu-lowres-pixel'>"
826 " <menuitem action='decrease-low-res-pixel-size'/>"
827 " <menuitem action='increase-low-res-pixel-size'/>"
828 " <separator name='pixel-size-separator'/>"
831 for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
832 ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
836 " <separator name='bleh08'/>"
837 " <menuitem action='play'/>"
838 //" <menuitem action='pause'/>"
839 " <menuitem action='stop'/>"
840 " <menuitem action='dialog-flipbook'/>"
841 " <separator name='bleh09'/>"
842 " <menuitem action='toggle-grid-show'/>"
843 " <menuitem action='toggle-grid-snap'/>"
844 " <menuitem action='toggle-guide-show'/>"
845 " <menuitem action='toggle-low-res'/>"
846 " <menuitem action='toggle-onion-skin'/>"
847 " <separator name='bleh10'/>"
848 " <menuitem action='canvas-zoom-in'/>"
849 " <menuitem action='canvas-zoom-out'/>"
850 " <menuitem action='canvas-zoom-fit'/>"
851 " <menuitem action='canvas-zoom-100'/>"
852 " <separator name='bleh11'/>"
853 " <menuitem action='time-zoom-in'/>"
854 " <menuitem action='time-zoom-out'/>"
855 " <separator name='bleh12'/>"
856 " <menuitem action='jump-next-keyframe'/>"
857 " <menuitem action='jump-prev-keyframe'/>"
858 " <menuitem action='seek-next-frame'/>"
859 " <menuitem action='seek-prev-frame'/>"
860 " <menuitem action='seek-next-second'/>"
861 " <menuitem action='seek-prev-second'/>"
862 " <menuitem action='seek-begin'/>"
863 " <menuitem action='seek-end'/>"
865 " <menu action='menu-canvas'>"
866 " <menuitem action='canvas-new'/>"
868 " <menu name='menu-state' action='menu-state'>"
870 " <menu action='menu-group'>"
871 " <menuitem action='action-group_add'/>"
873 " <menu action='menu-layer'>"
874 //" <menuitem action='cut'/>"
875 //" <menuitem action='copy'/>"
876 //" <menuitem action='paste'/>"
877 //" <separator name='bleh06'/>"
878 " <menu action='menu-layer-new'></menu>"
879 " <menuitem action='amount-inc'/>"
880 " <menuitem action='amount-dec'/>"
882 " <menu action='menu-keyframe'>"
883 " <menuitem action='keyframe-properties'/>"
890 " <menubar name='MenuBar'>"
891 " <menu action='MenuFile'>"
892 " <menuitem action='New'/>"
893 " <menuitem action='Open'/>"
895 " <menuitem action='Quit'/>"
897 " <menu action='MenuEdit'>"
898 " <menuitem action='Cut'/>"
899 " <menuitem action='Copy'/>"
900 " <menuitem action='Paste'/>"
903 " <toolbar name='ToolBar'>"
904 " <toolitem action='Open'/>"
905 " <toolitem action='Quit'/>"
911 actions_action_group->set_sensitive(false);
912 App::ui_manager()->set_add_tearoffs(true);
913 App::ui_manager()->insert_action_group(menus_action_group,1);
914 App::ui_manager()->insert_action_group(actions_action_group,1);
915 App::ui_manager()->add_ui_from_string(ui_info);
917 //App::ui_manager()->get_accel_group()->unlock();
919 catch(const Glib::Error& ex)
921 synfig::error("building menus and toolbars failed: " + ex.what());
924 // Add default keyboard accelerators
925 #define ACCEL(path,accel) \
927 Gtk::AccelKey accel_key(accel,path); \
928 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
931 #define ACCEL2(accel) \
933 Gtk::AccelKey accel_key(accel); \
934 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \
937 ACCEL("<Actions>//select-all-ducks","<Control>a");
938 ACCEL("<Actions>//unselect-all-layers","<Control>d");
939 ACCEL("<Actions>//render","F9");
940 ACCEL("<Actions>//preview","F11");
941 ACCEL("<Actions>//properties","F8");
942 ACCEL("<Actions>//options","F12");
943 ACCEL("<Actions>//import","<control>i");
944 ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
945 ACCEL("<Actions>//toggle-grid-show","<Control>g");
946 ACCEL("<Actions>//toggle-grid-snap","<Control>l");
947 ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
948 ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
949 ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
950 ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
951 ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
952 ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
953 ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
955 ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
956 ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
958 ACCEL("<Actions>//quality-01","<Control>1");
959 ACCEL("<Actions>//quality-02","<Control>2");
960 ACCEL("<Actions>//quality-03","<Control>3");
961 ACCEL("<Actions>//quality-04","<Control>4");
962 ACCEL("<Actions>//quality-05","<Control>5");
963 ACCEL("<Actions>//quality-06","<Control>6");
964 ACCEL("<Actions>//quality-07","<Control>7");
965 ACCEL("<Actions>//quality-08","<Control>8");
966 ACCEL("<Actions>//quality-09","<Control>9");
967 ACCEL("<Actions>//quality-10","<Control>0");
968 ACCEL("<Actions>//undo","<Control>z");
969 ACCEL("<Actions>//redo","<Control>r");
970 ACCEL("<Actions>//action-layer_remove","Delete");
972 /* ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
973 ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
974 ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
975 ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
976 ACCEL("<Actions>//time-zoom-in","+");
977 ACCEL("<Actions>//time-zoom-out","_");
979 ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
980 ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
982 ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
983 ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
985 ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
986 ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
987 ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
988 ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
989 ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
990 ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
991 ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
992 ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
993 ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
994 ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
995 ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
996 ACCEL("<Actions>//play", "<Control>p");
997 ACCEL("<Actions>//seek-begin","Home");
998 ACCEL("<Actions>//seek-end","End");
1000 ACCEL("<Actions>//state-normal", "<Mod1>a");
1001 ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
1002 ACCEL("<Actions>//state-scale", "<Mod1>d");
1003 ACCEL("<Actions>//state-rotate", "<Mod1>s");
1005 ACCEL("<Actions>//state-bline", "<Mod1>b");
1006 ACCEL("<Actions>//state-circle", "<Mod1>c");
1007 ACCEL("<Actions>//state-rectangle", "<Mod1>r");
1008 ACCEL("<Actions>//state-gradient", "<Mod1>g");
1010 ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
1011 ACCEL("<Actions>//state-fill", "<Mod1>f");
1012 ACCEL("<Actions>//state-zoom", "<Mod1>z");
1013 ACCEL("<Actions>//state-polygon", "<Mod1>p");
1015 ACCEL("<Actions>//state-draw", "<Mod1>w");
1016 ACCEL("<Actions>//state-sketch", "<Mod1>k");
1017 ACCEL("<Actions>//state-width", "<Mod1>t");
1018 ACCEL("<Actions>//state-mirror", "<Mod1>m");
1020 ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
1026 #define mkdir(x,y) mkdir(x)
1029 /* === M E T H O D S ======================================================= */
1031 App::App(int *argc, char ***argv):
1032 Gtk::Main(argc,argv),
1033 IconController(etl::dirname((*argv)[0]))
1035 app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1038 ui_interface_=new GlobalUIInterface();
1042 // don't call thread_init() if threads are already initialized
1043 // on some machines bonobo_init() initialized threads before we get here
1044 if (!g_thread_supported())
1045 Glib::thread_init();
1047 distance_system=Distance::SYSTEM_UNITS;
1049 if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1052 synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1056 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1062 if(!SYNFIG_CHECK_VERSION())
1064 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1065 dialog_error_blocking("Synfig Studio",
1066 "This copy of Synfig Studio was compiled against a\n"
1067 "different version of libsynfig than what is currently\n"
1068 "installed. Synfig Studio will now abort. Try downloading\n"
1069 "the latest version from the Synfig website at\n"
1070 "http://synfig.org/Download"
1074 Glib::set_application_name(_("Synfig Studio"));
1076 Splash splash_screen;
1077 splash_screen.show();
1079 shutdown_in_progress=false;
1080 SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1081 SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1083 // Initialize the Synfig library
1084 try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1087 get_ui_interface()->error(_("Failed to initialize synfig!"));
1091 // add the preferences to the settings
1092 synfigapp::Main::settings().add_domain(&_preferences,"pref");
1096 studio_init_cb.task(_("Init UI Manager..."));
1097 App::ui_manager_=studio::UIManager::create();
1100 studio_init_cb.task(_("Init Dock Manager..."));
1101 dock_manager=new studio::DockManager();
1103 studio_init_cb.task(_("Init State Manager..."));
1104 state_manager=new StateManager();
1106 studio_init_cb.task(_("Init Toolbox..."));
1107 toolbox=new studio::Toolbox();
1109 studio_init_cb.task(_("Init About Dialog..."));
1110 about=new studio::About();
1112 studio_init_cb.task(_("Init Tool Options..."));
1113 dialog_tool_options=new studio::Dialog_ToolOptions();
1114 dock_manager->register_dockable(*dialog_tool_options);
1116 studio_init_cb.task(_("Init History..."));
1117 dock_history=new studio::Dock_History();
1118 dock_manager->register_dockable(*dock_history);
1120 studio_init_cb.task(_("Init Canvases..."));
1121 dock_canvases=new studio::Dock_Canvases();
1122 dock_manager->register_dockable(*dock_canvases);
1124 studio_init_cb.task(_("Init Keyframes..."));
1125 dock_keyframes=new studio::Dock_Keyframes();
1126 dock_manager->register_dockable(*dock_keyframes);
1128 studio_init_cb.task(_("Init Layers..."));
1129 dock_layers=new studio::Dock_Layers();
1130 dock_manager->register_dockable(*dock_layers);
1132 studio_init_cb.task(_("Init Params..."));
1133 dock_params=new studio::Dock_Params();
1134 dock_manager->register_dockable(*dock_params);
1136 studio_init_cb.task(_("Init MetaData..."));
1137 dock_meta_data=new studio::Dock_MetaData();
1138 dock_manager->register_dockable(*dock_meta_data);
1140 studio_init_cb.task(_("Init Children..."));
1141 dock_children=new studio::Dock_Children();
1142 dock_manager->register_dockable(*dock_children);
1144 studio_init_cb.task(_("Init Info..."));
1145 dock_info = new studio::Dock_Info();
1146 dock_manager->register_dockable(*dock_info);
1148 studio_init_cb.task(_("Init Navigator..."));
1149 dock_navigator = new studio::Dock_Navigator();
1150 dock_manager->register_dockable(*dock_navigator);
1152 studio_init_cb.task(_("Init Timetrack..."));
1153 dock_timetrack = new studio::Dock_Timetrack();
1154 dock_manager->register_dockable(*dock_timetrack);
1156 studio_init_cb.task(_("Init Curve Editor..."));
1157 dock_curves = new studio::Dock_Curves();
1158 dock_manager->register_dockable(*dock_curves);
1160 studio_init_cb.task(_("Init Layer Groups..."));
1161 dock_layer_groups = new studio::Dock_LayerGroups();
1162 dock_manager->register_dockable(*dock_layer_groups);
1165 studio_init_cb.task(_("Init Color Dialog..."));
1166 dialog_color=new studio::Dialog_Color();
1168 studio_init_cb.task(_("Init Gradient Dialog..."));
1169 dialog_gradient=new studio::Dialog_Gradient();
1171 studio_init_cb.task(_("Init DeviceTracker..."));
1172 device_tracker=new studio::DeviceTracker();
1174 studio_init_cb.task(_("Init Tools..."));
1177 state_manager->add_state(&state_normal);
1178 state_manager->add_state(&state_smooth_move);
1179 state_manager->add_state(&state_scale);
1180 state_manager->add_state(&state_rotate);
1181 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1184 state_manager->add_state(&state_bline);
1185 state_manager->add_state(&state_circle);
1186 state_manager->add_state(&state_rectangle);
1187 state_manager->add_state(&state_gradient);
1188 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1191 if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet.
1192 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1193 state_manager->add_state(&state_fill);
1194 state_manager->add_state(&state_eyedrop);
1195 state_manager->add_state(&state_zoom);
1197 // Disabled by default - it doesn't work properly?
1198 if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
1200 studio_init_cb.task(_("Init ModPalette..."));
1201 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1203 studio_init_cb.task(_("Init Setup Dialog..."));
1204 dialog_setup=new studio::Dialog_Setup();
1206 studio_init_cb.task(_("Init Input Dialog..."));
1207 dialog_input=new Gtk::InputDialog();
1208 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1209 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1211 studio_init_cb.task(_("Init auto recovery..."));
1212 auto_recover=new AutoRecover();
1214 studio_init_cb.amount_complete(9250,10000);
1215 studio_init_cb.task(_("Loading Settings..."));
1217 studio_init_cb.task(_("Checking auto-recover..."));
1219 studio_init_cb.amount_complete(9900,10000);
1221 bool opened_any = false;
1222 if(auto_recover->recovery_needed())
1224 splash_screen.hide();
1225 if (get_ui_interface()->yes_no(_("Auto Recovery"),
1226 _("Synfig Studio seems to have crashed\n"
1227 "before you could save all your files.\n"
1228 "Would you like to re-open those files\n"
1229 "and recover your unsaved changes?")) ==
1230 synfigapp::UIInterface::RESPONSE_YES)
1232 int number_recovered;
1233 if(!auto_recover->recover(number_recovered))
1234 if (number_recovered)
1235 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1237 get_ui_interface()->error(_("Unable to recover from previous crash"));
1239 get_ui_interface()->error(
1240 _("Synfig Studio has attempted to recover\n"
1241 "from a previous crash. The files that it has\n"
1242 "recovered are NOT YET SAVED. It would be a good\n"
1243 "idea to review them and save them now."));
1245 if (number_recovered)
1248 splash_screen.show();
1251 // Look for any files given on the command line,
1252 // and load them if found.
1253 for(;*argc>=1;(*argc)--)
1254 if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1256 studio_init_cb.task(_("Loading files..."));
1257 splash_screen.hide();
1258 open((*argv)[*argc]);
1260 splash_screen.show();
1263 // if no file was specified to be opened, create a new document to help new users get started more easily
1264 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1267 studio_init_cb.task(_("Done."));
1268 studio_init_cb.amount_complete(10000,10000);
1274 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1278 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1282 StateManager* App::get_state_manager() { return state_manager; }
1286 shutdown_in_progress=true;
1290 synfigapp::Main::settings().remove_domain("pref");
1292 selected_instance=0;
1294 // Unload all of the modules
1295 for(;!module_list_.empty();module_list_.pop_back())
1298 delete state_manager;
1302 delete auto_recover;
1308 // studio::App::iteration(false);
1312 // studio::App::iteration(false);
1314 // studio::App::iteration(false);
1316 delete dialog_setup;
1318 delete dialog_gradient;
1320 delete dialog_color;
1322 delete dialog_input;
1324 delete dock_manager;
1326 instance_list.clear();
1328 // studio::App::iteration(false);
1332 App::get_user_app_directory()
1334 //! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445)
1336 return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR));
1338 return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1343 App::get_config_file(const synfig::String& file)
1345 return Glib::build_filename(get_user_app_directory(),file);
1348 #define SCALE_FACTOR (1280)
1349 //! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size
1351 App::set_recent_file_window_size(etl::handle<Instance> instance)
1353 int screen_w(Gdk::screen_width());
1354 int screen_h(Gdk::screen_height());
1356 const std::string &canvas_window_size = *recent_files_window_size.begin();
1358 if(canvas_window_size.empty())
1361 synfig::String::size_type current=0;
1362 bool seen_root(false), shown_non_root(false);
1364 while(current != synfig::String::npos)
1366 // find end of first field (canvas) or return
1367 synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current);
1368 if(separator == synfig::String::npos) break;
1371 synfig::Canvas::Handle canvas;
1373 canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
1375 catch(Exception::IDNotFound) {
1376 // can't find the canvas; skip to the next canvas or return
1377 separator = canvas_window_size.find_first_of('\t', current);
1378 if(separator == synfig::String::npos) return;
1379 current = separator+1;
1383 if (canvas->is_root())
1386 shown_non_root = true;
1388 // check that we have the tab character the ends this canvas' data or return
1389 current = separator+1;
1390 separator = canvas_window_size.find_first_of('\t', current);
1391 if(separator == synfig::String::npos) return;
1394 if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h))
1396 current = separator+1;
1400 if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0;
1401 if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0;
1402 x=x*screen_w/SCALE_FACTOR;
1403 y=y*screen_h/SCALE_FACTOR;
1404 if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"))
1405 x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET"));
1406 if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"))
1407 y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET"));
1409 if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
1410 if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
1412 CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
1413 canvasview->move(x,y);
1414 canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR);
1415 canvasview->present();
1417 current = separator+1;
1420 if (shown_non_root && !seen_root)
1421 instance->find_canvas_view(instance->get_canvas())->hide();
1425 App::add_recent_file(const etl::handle<Instance> instance)
1427 int screen_w(Gdk::screen_width());
1428 int screen_h(Gdk::screen_height());
1430 std::string canvas_window_size;
1432 const Instance::CanvasViewList& cview_list = instance->canvas_view_list();
1433 Instance::CanvasViewList::const_iterator iter;
1435 for(iter=cview_list.begin();iter!=cview_list.end();iter++)
1437 if( !((*iter)->is_visible()) )
1440 etl::handle<synfig::Canvas> canvas = (*iter)->get_canvas();
1441 int x_pos, y_pos, x_size, y_size;
1442 (*iter)->get_position(x_pos,y_pos);
1443 (*iter)->get_size(x_size,y_size);
1445 canvas_window_size += strprintf("%s %d %d %d %d\t",
1446 canvas->get_relative_id(canvas->get_root()).c_str(),
1447 x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h,
1448 x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h);
1451 add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size);
1456 App::add_recent_file(const std::string &file_name, const std::string &window_size)
1458 std::string filename(file_name);
1460 assert(!filename.empty());
1462 if(filename.empty())
1465 // Toss out any "hidden" files
1466 if(basename(filename)[0]=='.')
1469 // If we aren't an absolute path, turn ourselves into one
1470 if(!is_absolute_path(filename))
1471 filename=absolute_path(filename);
1473 std::string old_window_size;
1475 list<string>::iterator iter;
1476 list<string>::iterator iter_wsize;
1477 // Check to see if the file is already on the list.
1478 // If it is, then remove it from the list
1479 for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++)
1482 recent_files.erase(iter);
1483 old_window_size = *iter_wsize;
1484 recent_files_window_size.erase(iter_wsize);
1489 // Push the filename to the front of the list
1490 recent_files.push_front(filename);
1491 if(window_size.empty())
1492 recent_files_window_size.push_front(old_window_size);
1494 recent_files_window_size.push_front(window_size);
1496 // Clean out the files at the end of the list.
1497 while(recent_files.size()>(unsigned)get_max_recent_files())
1499 recent_files.pop_back();
1500 recent_files_window_size.pop_back();
1503 signal_recent_files_changed_();
1508 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1511 App::get_time_format()
1513 return _App_time_format;
1517 App::set_time_format(synfig::Time::Format x)
1524 App::save_settings()
1529 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1530 setlocale(LC_NUMERIC, "C");
1532 std::string filename=get_config_file("accelrc");
1533 Gtk::AccelMap::save(filename);
1536 std::string filename=get_config_file("recentfiles");
1538 std::ofstream file(filename.c_str());
1542 synfig::warning("Unable to save %s",filename.c_str());
1546 list<string>::reverse_iterator iter;
1548 for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1552 std::string filename=get_config_file("recentfiles")+std::string("_window_size");
1554 std::ofstream file(filename.c_str());
1558 synfig::warning("Unable to save %s",filename.c_str());
1562 list<string>::reverse_iterator iter;
1564 for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
1568 std::string filename=get_config_file("settings");
1569 synfigapp::Main::settings().save_to_file(filename);
1570 setlocale(LC_NUMERIC,old_locale);
1574 synfig::warning("Caught exception when attempting to save settings.");
1579 App::load_settings()
1584 old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1585 setlocale(LC_NUMERIC, "C");
1587 std::string filename=get_config_file("accelrc");
1588 Gtk::AccelMap::load(filename);
1591 bool window_size_broken = false;
1593 std::string filename=get_config_file("recentfiles");
1594 std::string filename_window_size=filename+std::string("_window_size");
1596 std::ifstream file(filename.c_str());
1597 std::ifstream file_window_size(filename_window_size.c_str());
1599 if(!file_window_size)
1600 window_size_broken = true;
1604 std::string recent_file;
1605 std::string recent_file_window_size;
1606 getline(file,recent_file);
1607 if(!window_size_broken)
1608 getline(file_window_size,recent_file_window_size);
1609 if(!recent_file.empty())
1611 if(!window_size_broken && !file_window_size)
1612 window_size_broken = true;
1613 if(!window_size_broken)
1614 add_recent_file(recent_file,recent_file_window_size);
1616 add_recent_file(recent_file);
1619 if(!window_size_broken && file_window_size)
1620 window_size_broken = true;
1622 if(window_size_broken)
1624 recent_files_window_size.clear();
1625 recent_files_window_size.resize(recent_files.size());
1628 std::string filename=get_config_file("settings");
1629 if(!synfigapp::Main::settings().load_from_file(filename))
1631 //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
1632 //if(!synfigapp::Main::settings().load_from_file(filename))
1634 gamma.set_gamma(1.0/2.2);
1635 reset_initial_window_configuration();
1638 setlocale(LC_NUMERIC,old_locale);
1642 synfig::warning("Caught exception when attempting to load settings.");
1647 App::reset_initial_window_configuration()
1649 synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1650 synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1651 synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1652 synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1653 synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1654 synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1655 synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1656 synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1657 synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1658 synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1659 synfigapp::Main::settings().set_value("pref.distance_system","pt");
1660 synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1661 #ifdef SINGLE_THREADED
1662 synfigapp::Main::settings().set_value("pref.single_threaded","0");
1664 synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1665 synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1669 App::shutdown_request(GdkEventAny*)
1673 //return !shutdown_in_progress;
1679 if(shutdown_in_progress)return;
1682 get_ui_interface()->task(_("Quit Request"));
1685 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1689 std::list<etl::handle<Instance> >::iterator iter;
1690 for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1692 if(!(*iter)->safe_close())
1696 if((*iter)->synfigapp::Instance::get_action_count())
1698 handle<synfigapp::UIInterface> uim;
1699 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1701 string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1702 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1704 case synfigapp::UIInterface::RESPONSE_NO:
1706 case synfigapp::UIInterface::RESPONSE_YES:
1709 case synfigapp::UIInterface::RESPONSE_CANCEL:
1718 if((*iter)->synfigapp::Instance::is_modified())
1720 handle<synfigapp::UIInterface> uim;
1721 uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1723 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() );
1724 switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1726 case synfigapp::UIInterface::RESPONSE_NO:
1728 case synfigapp::UIInterface::RESPONSE_YES:
1729 (*iter)->dialog_cvs_commit();
1731 case synfigapp::UIInterface::RESPONSE_CANCEL:
1740 // This next line causes things to crash for some reason
1744 shutdown_in_progress=true;
1746 instance_list.clear();
1748 while(studio::App::events_pending())studio::App::iteration(false);
1751 auto_recover->normal_shutdown();
1753 get_ui_interface()->task(_("Quit Request sent"));
1759 dialog_setup->refresh();
1760 dialog_setup->show();
1763 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1764 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1767 //#define USE_WIN32_FILE_DIALOGS 1
1770 #ifdef USE_WIN32_FILE_DIALOGS
1771 static OPENFILENAME ofn={};
1775 #include <gdk/gdkwin32.h>
1779 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1781 info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1783 #ifdef USE_WIN32_FILE_DIALOGS
1784 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1786 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1787 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1788 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1790 ofn.lStructSize=sizeof(OPENFILENAME);
1791 ofn.hwndOwner = hWnd;
1792 ofn.hInstance = hInstance;
1793 ofn.lpstrFilter = szFilter;
1794 // ofn.lpstrCustomFilter=NULL;
1795 // ofn.nMaxCustFilter=0;
1796 // ofn.nFilterIndex=0;
1797 // ofn.lpstrFile=NULL;
1798 ofn.nMaxFile=MAX_PATH;
1799 // ofn.lpstrFileTitle=NULL;
1800 // ofn.lpstrInitialDir=NULL;
1801 // ofn.lpstrTitle=NULL;
1802 ofn.Flags=OFN_HIDEREADONLY;
1803 // ofn.nFileOffset=0;
1804 // ofn.nFileExtension=0;
1805 ofn.lpstrDefExt=TEXT("sif");
1806 // ofn.lCustData = 0l;
1808 // ofn.lpTemplateName=NULL;
1810 CHAR szFilename[MAX_PATH];
1812 strcpy(szFilename,filename.c_str());
1813 strcpy(szTitle,title.c_str());
1815 ofn.lpstrFile=szFilename;
1816 ofn.lpstrFileTitle=szTitle;
1818 if(GetOpenFileName(&ofn))
1820 filename=szFilename;
1826 synfig::String prev_path;
1828 if(!_preferences.get_value(preference, prev_path))
1831 prev_path = absolute_path(prev_path);
1833 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1835 dialog->set_current_folder(prev_path);
1836 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1837 dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1839 if (filename.empty())
1840 dialog->set_filename(prev_path);
1841 else if (is_absolute_path(filename))
1842 dialog->set_filename(filename);
1844 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1846 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1847 filename = dialog->get_filename();
1848 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1849 _preferences.set_value(preference, dirname(filename));
1863 GtkWidget *fileselection;
1864 fileselection = gtk_file_selection_new(title.c_str());
1867 if(basename(filename)==filename)
1869 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1872 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1874 gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1876 ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1877 cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1879 gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1880 gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1882 gtk_widget_show(fileselection);
1890 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1891 _preferences.set_value(preference,dirname(filename));
1895 gtk_widget_destroy(fileselection);
1898 gtk_widget_destroy(fileselection);
1905 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1907 info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1909 #if USE_WIN32_FILE_DIALOGS
1910 static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1912 GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1913 HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1914 HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1916 ofn.lStructSize=sizeof(OPENFILENAME);
1917 ofn.hwndOwner = hWnd;
1918 ofn.hInstance = hInstance;
1919 ofn.lpstrFilter = szFilter;
1920 // ofn.lpstrCustomFilter=NULL;
1921 // ofn.nMaxCustFilter=0;
1922 // ofn.nFilterIndex=0;
1923 // ofn.lpstrFile=NULL;
1924 ofn.nMaxFile=MAX_PATH;
1925 // ofn.lpstrFileTitle=NULL;
1926 // ofn.lpstrInitialDir=NULL;
1927 // ofn.lpstrTitle=NULL;
1928 ofn.Flags=OFN_OVERWRITEPROMPT;
1929 // ofn.nFileOffset=0;
1930 // ofn.nFileExtension=0;
1931 ofn.lpstrDefExt=TEXT("sif");
1932 // ofn.lCustData = 0l;
1934 // ofn.lpTemplateName=NULL;
1936 CHAR szFilename[MAX_PATH];
1938 strcpy(szFilename,filename.c_str());
1939 strcpy(szTitle,title.c_str());
1941 ofn.lpstrFile=szFilename;
1942 ofn.lpstrFileTitle=szTitle;
1944 if(GetSaveFileName(&ofn))
1946 filename=szFilename;
1947 _preferences.set_value(preference,dirname(filename));
1952 synfig::String prev_path;
1954 if(!_preferences.get_value(preference, prev_path))
1957 prev_path = absolute_path(prev_path);
1959 Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1961 dialog->set_current_folder(prev_path);
1962 dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1963 dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1965 Widget_Enum *file_type_enum = 0;
1966 if (preference == ANIMATION_DIR_PREFERENCE)
1968 file_type_enum = manage(new Widget_Enum());
1969 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1970 .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", strprintf("0.61.08 (%s)", _("current")))
1971 .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1972 .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1973 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1975 Gtk::HBox *hbox = manage(new Gtk::HBox);
1976 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1977 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1980 dialog->set_extra_widget(*hbox);
1983 if (filename.empty())
1984 dialog->set_filename(prev_path);
1987 std::string full_path;
1988 if (is_absolute_path(filename))
1989 full_path = filename;
1991 full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1993 // select the file if it exists
1994 dialog->set_filename(full_path);
1996 // if the file doesn't exist, put its name into the filename box
1998 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1999 dialog->set_current_name(basename(filename));
2002 if(dialog->run() == GTK_RESPONSE_ACCEPT) {
2003 if (preference == ANIMATION_DIR_PREFERENCE)
2004 set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
2005 filename = dialog->get_filename();
2006 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
2007 _preferences.set_value(preference, dirname(filename));
2018 App::dialog_error_blocking(const std::string &title, const std::string &message)
2020 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2021 dialog.set_title(title);
2027 App::dialog_warning_blocking(const std::string &title, const std::string &message)
2029 Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
2030 dialog.set_title(title);
2036 App::dialog_yes_no(const std::string &title, const std::string &message)
2041 true // use_separator
2043 Gtk::Label label(message);
2046 dialog.get_vbox()->pack_start(label);
2047 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2048 dialog.add_button(Gtk::StockID("gtk-no"),0);
2050 return dialog.run();
2054 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
2059 true // use_separator
2061 Gtk::Label label(message);
2064 dialog.get_vbox()->pack_start(label);
2065 dialog.add_button(Gtk::StockID("gtk-yes"),1);
2066 dialog.add_button(Gtk::StockID("gtk-no"),0);
2067 dialog.add_button(Gtk::StockID("gtk-cancel"),2);
2069 return dialog.run();
2073 App::dialog_not_implemented()
2075 Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2076 dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
2081 try_open_url(const std::string &url)
2084 return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW);
2086 std::vector<std::string> command_line;
2087 std::vector<std::string> browsers;
2088 browsers.reserve(23);
2090 // Browser wrapper scripts
2091 #ifdef USE_OPEN_FOR_URLS
2092 browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console
2094 browsers.push_back("xdg-open"); // XDG wrapper
2095 browsers.push_back("sensible-browser"); // Debian wrapper
2096 browsers.push_back("gnome-open"); // GNOME wrapper
2097 browsers.push_back("kfmclient"); // KDE wrapper
2098 browsers.push_back("exo-open"); // XFCE wrapper
2100 // Alternatives system
2101 browsers.push_back("gnome-www-browser"); // Debian GNOME alternative
2102 browsers.push_back("x-www-browser"); // Debian GUI alternative
2104 // Individual browsers
2105 browsers.push_back("firefox");
2106 browsers.push_back("epiphany-browser");
2107 browsers.push_back("epiphany");
2108 browsers.push_back("konqueror");
2109 browsers.push_back("iceweasel");
2110 browsers.push_back("mozilla");
2111 browsers.push_back("netscape");
2112 browsers.push_back("icecat");
2113 browsers.push_back("galeon");
2114 browsers.push_back("midori");
2115 browsers.push_back("safari");
2116 browsers.push_back("opera");
2117 browsers.push_back("amaya");
2118 browsers.push_back("netsurf");
2119 browsers.push_back("dillo");
2121 // Try the user-specified browser first
2122 command_line.push_back(App::browser_command);
2123 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2124 command_line.push_back(url);
2126 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; }
2127 catch( Glib::SpawnError& exception ){
2129 while ( !browsers.empty() )
2131 // Skip the browser if we already tried it
2132 if( browsers[0] == App::browser_command )
2135 // Construct the command line
2136 command_line.clear();
2137 command_line.push_back(browsers[0]);
2138 if( command_line[0] == "kfmclient" ) command_line.push_back("openURL");
2139 command_line.push_back(url);
2141 // Remove the browser from the list
2142 browsers.erase(browsers.begin());
2144 // Try to spawn the browser
2145 try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); }
2146 // Failed, move on to the next one
2147 catch(Glib::SpawnError& exception){ continue; }
2148 return true; // No exception means we succeeded!
2159 if (!try_open_url("http://synfig.org/Documentation"))
2161 Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true);
2162 dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation"));
2163 dialog.set_title(_("Help"));
2169 App::open_url(const std::string &url)
2171 if(!try_open_url(url))
2173 Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
2174 dialog.set_secondary_text(url);
2175 dialog.set_title(_("No browser found"));
2181 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
2186 true // use_separator
2188 Gtk::Label label(message);
2190 dialog.get_vbox()->pack_start(label);
2193 entry.set_text(text);
2195 entry.set_activates_default(true);
2196 dialog.get_vbox()->pack_start(entry);
2198 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
2199 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
2200 dialog.set_default_response(Gtk::RESPONSE_OK);
2201 entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
2204 if(dialog.run()!=Gtk::RESPONSE_OK)
2207 text=entry.get_text();
2216 App::open(std::string filename)
2218 return open_as(filename,filename);
2221 // this is called from autorecover.cpp:
2222 // App::open_as(get_shadow_file_name(filename),filename)
2223 // other than that, 'filename' and 'as' are the same
2225 App::open_as(std::string filename,std::string as)
2228 char long_name[1024];
2229 if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
2230 // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty
2231 // don't use it if that's the case
2232 if (long_name[0] != '\0')
2238 OneMoment one_moment;
2240 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
2241 if(canvas && get_instance(canvas))
2243 get_instance(canvas)->find_canvas_view(canvas)->present();
2244 info("%s is already open", filename.c_str());
2245 // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
2250 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
2252 if (as.find(DEFAULT_FILENAME_PREFIX) != 0)
2253 add_recent_file(as);
2255 handle<Instance> instance(Instance::create(canvas));
2258 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
2260 set_recent_file_window_size(instance);
2264 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)")))
2265 instance->dialog_cvs_update();
2270 dialog_error_blocking(_("Error"), x);
2275 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
2286 handle<synfig::Canvas> canvas=synfig::Canvas::create();
2288 String file_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
2289 canvas->set_name(file_name);
2290 file_name += ".sifz";
2292 canvas->rend_desc().set_frame_rate(24.0);
2293 canvas->rend_desc().set_time_start(0.0);
2294 canvas->rend_desc().set_time_end(5.0);
2295 canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
2296 canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
2297 canvas->rend_desc().set_tl(Vector(-4,2.25));
2298 canvas->rend_desc().set_br(Vector(4,-2.25));
2299 canvas->rend_desc().set_w(480);
2300 canvas->rend_desc().set_h(270);
2301 canvas->rend_desc().set_antialias(1);
2302 canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2303 canvas->set_file_name(file_name);
2305 handle<Instance> instance = Instance::create(canvas);
2307 if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2308 instance->find_canvas_view(canvas)->canvas_properties.present();
2312 App::dialog_open(string filename)
2314 if (filename.empty())
2317 while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2319 // If the filename still has wildcards, then we should
2320 // continue looking for the file we want
2321 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2327 get_ui_interface()->error(_("Unable to open file"));
2332 App::set_selected_instance(etl::loose_handle<Instance> instance)
2334 /* if(get_selected_instance()==instance)
2336 selected_instance=instance;
2337 signal_instance_selected()(instance);
2343 selected_instance=instance;
2344 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2348 instance->focus(instance->get_canvas());
2351 set_selected_canvas_view(0);
2353 signal_instance_selected()(instance);
2357 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2359 selected_canvas_view=canvas_view;
2360 signal_canvas_view_focus()(selected_canvas_view);
2363 selected_instance=canvas_view->get_instance();
2364 signal_instance_selected()(canvas_view->get_instance());
2367 if(get_selected_canvas_view()==canvas_view)
2369 signal_canvas_view_focus()(selected_canvas_view);
2370 signal_instance_selected()(canvas_view->get_instance());
2373 selected_canvas_view=canvas_view;
2374 if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2375 set_selected_instance(canvas_view->get_instance());
2376 signal_canvas_view_focus()(selected_canvas_view);
2380 etl::loose_handle<Instance>
2381 App::get_instance(etl::handle<synfig::Canvas> canvas)
2383 if(!canvas) return 0;
2384 canvas=canvas->get_root();
2386 std::list<etl::handle<Instance> >::iterator iter;
2387 for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2389 if((*iter)->get_canvas()==canvas)
2405 if(selected_instance)
2406 selected_instance->undo();
2412 if(selected_instance)
2413 selected_instance->redo();
2417 studio::App::get_base_path()
2419 return app_base_path_;