X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-studio%2Ftrunk%2Fsrc%2Fgtkmm%2Fapp.cpp;h=ee4459b5e5f2e773e72b9d316c3aa6135b17594a;hb=4ba22fb51d97f1ecce04dcc5e40569a4354c1bae;hp=1025f07969e2fe94c924735c56a7522c619967a9;hpb=012576f2d8a088ec178f2b01bc70430d8a216ef4;p=synfig.git diff --git a/synfig-studio/trunk/src/gtkmm/app.cpp b/synfig-studio/trunk/src/gtkmm/app.cpp index 1025f07..ee4459b 100644 --- a/synfig-studio/trunk/src/gtkmm/app.cpp +++ b/synfig-studio/trunk/src/gtkmm/app.cpp @@ -6,7 +6,9 @@ ** ** \legal ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007 Chris Moore +** Copyright (c) 2007, 2008 Chris Moore +** Copyright (c) 2008 Gerald Young +** Copyright (c) 2008 Carlos López ** ** This package is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License as @@ -30,6 +32,11 @@ # include #endif +#ifdef WIN32 +#define WINVER 0x0500 +#include +#endif + #include #include #include @@ -48,9 +55,12 @@ #include #include #include +#include #include +#include + #include #include @@ -80,6 +90,8 @@ #include "state_rectangle.h" #include "state_smoothmove.h" #include "state_scale.h" +#include "state_star.h" +#include "state_text.h" #include "state_width.h" #include "state_rotate.h" #include "state_zoom.h" @@ -119,10 +131,6 @@ #include #endif -#ifdef WIN32 -#define _WIN32_WINNT 0x0500 -#include -#endif #include #include #include @@ -203,6 +211,8 @@ App::signal_instance_deleted() { return signal_instance_deleted_; } static std::list recent_files; const std::list& App::get_recent_files() { return recent_files; } +static std::list recent_files_window_size; + int App::Busy::count; bool App::shutdown_in_progress; @@ -261,7 +271,20 @@ studio::Dock_Curves* dock_curves; std::list< etl::handle< studio::Module > > module_list_; bool studio::App::use_colorspace_gamma=true; +#ifdef SINGLE_THREADED bool studio::App::single_threaded=false; +#endif +bool studio::App::restrict_radius_ducks=false; +bool studio::App::resize_imported_images=false; +String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX); +int studio::App::preferred_x_size=480; +int studio::App::preferred_y_size=270; +String studio::App::predefined_size(DEFAULT_PREDEFINED_SIZE); +#ifdef USE_OPEN_FOR_URLS +String studio::App::browser_command("open"); // MacOS only +#else +String studio::App::browser_command("xdg-open"); // Linux XDG standard +#endif static int max_recent_files_=25; int studio::App::get_max_recent_files() { return max_recent_files_; } @@ -472,16 +495,53 @@ public: value=strprintf("%s",Distance::system_name(App::distance_system).c_str()); return true; } +#ifdef SINGLE_THREADED if(key=="single_threaded") { value=strprintf("%i",(int)App::single_threaded); return true; } +#endif if(key=="auto_recover_backup_interval") { value=strprintf("%i",App::auto_recover->get_timeout()); return true; } + if(key=="restrict_radius_ducks") + { + value=strprintf("%i",(int)App::restrict_radius_ducks); + return true; + } + if(key=="resize_imported_images") + { + value=strprintf("%i",(int)App::resize_imported_images); + return true; + } + if(key=="browser_command") + { + value=App::browser_command; + return true; + } + if(key=="custom_filename_prefix") + { + value=App::custom_filename_prefix; + return true; + } + if(key=="preferred_x_size") + { + value=strprintf("%i",App::preferred_x_size); + return true; + } + if(key=="preferred_y_size") + { + value=strprintf("%i",App::preferred_y_size); + return true; + } + if(key=="predefined_size") + { + value=strprintf("%s",App::predefined_size.c_str()); + return true; + } return synfigapp::Settings::get_value(key,value); } @@ -532,13 +592,53 @@ public: App::distance_system=Distance::ident_system(value);; return true; } +#ifdef SINGLE_THREADED if(key=="single_threaded") { int i(atoi(value.c_str())); App::single_threaded=i; return true; } - +#endif + if(key=="restrict_radius_ducks") + { + int i(atoi(value.c_str())); + App::restrict_radius_ducks=i; + return true; + } + if(key=="resize_imported_images") + { + int i(atoi(value.c_str())); + App::resize_imported_images=i; + return true; + } + if(key=="browser_command") + { + App::browser_command=value; + return true; + } + if(key=="custom_filename_prefix") + { + App::custom_filename_prefix=value; + return true; + } + if(key=="preferred_x_size") + { + int i(atoi(value.c_str())); + App::preferred_x_size=i; + return true; + } + if(key=="preferred_y_size") + { + int i(atoi(value.c_str())); + App::preferred_y_size=i; + return true; + } + if(key=="predefined_size") + { + App::predefined_size=value; + return true; + } return synfigapp::Settings::set_value(key,value); } @@ -550,8 +650,17 @@ public: ret.push_back("distance_system"); ret.push_back("file_history.size"); ret.push_back("use_colorspace_gamma"); +#ifdef SINGLE_THREADED ret.push_back("single_threaded"); +#endif ret.push_back("auto_recover_backup_interval"); + ret.push_back("restrict_radius_ducks"); + ret.push_back("resize_imported_images"); + ret.push_back("browser_command"); + ret.push_back("custom_filename_prefix"); + ret.push_back("preferred_x_size"); + ret.push_back("preferred_y_size"); + ret.push_back("predefined_size"); return ret; } }; @@ -624,6 +733,8 @@ init_ui_manager() DEFINE_ACTION("copy", Gtk::StockID("gtk-copy")); DEFINE_ACTION("paste", Gtk::StockID("gtk-paste")); DEFINE_ACTION("select-all-ducks", _("Select All Ducks")); + DEFINE_ACTION("unselect-all-ducks", _("Unselect All Ducks")); + DEFINE_ACTION("select-all-layers", _("Select All Layers")); DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers")); DEFINE_ACTION("properties", _("Properties")); @@ -752,8 +863,10 @@ init_ui_manager() " " " " " " -" " +" " " " +" " +" " " " " " " " @@ -879,7 +992,7 @@ init_ui_manager() } // Add default keyboard accelerators -#define ACCEL(path,accel) \ +#define ACCEL(accel,path) \ { \ Gtk::AccelKey accel_key(accel,path); \ Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \ @@ -891,90 +1004,80 @@ init_ui_manager() Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod()); \ } - ACCEL("//select-all-ducks","a"); - ACCEL("//unselect-all-layers","d"); - ACCEL("//render","F9"); - ACCEL("//preview","F11"); - ACCEL("//properties","F8"); - ACCEL("//options","F12"); - ACCEL("//import","i"); - ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast(0),"//stop")); - ACCEL("//toggle-grid-show","g"); - ACCEL("//toggle-grid-snap","l"); - ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"//toggle-low-res")); - ACCEL("//mask-position-ducks", "1"); - ACCEL("//mask-vertex-ducks", "2"); - ACCEL("//mask-tangent-ducks", "3"); - ACCEL("//mask-radius-ducks", "4"); - ACCEL("//mask-width-ducks", "5"); - ACCEL("//mask-angle-ducks", "6"); - - ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"//action-layer_raise")); - ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"//action-layer_lower")); - - ACCEL("//quality-01","1"); - ACCEL("//quality-02","2"); - ACCEL("//quality-03","3"); - ACCEL("//quality-04","4"); - ACCEL("//quality-05","5"); - ACCEL("//quality-06","6"); - ACCEL("//quality-07","7"); - ACCEL("//quality-08","8"); - ACCEL("//quality-09","9"); - ACCEL("//quality-10","0"); - ACCEL("//undo","z"); - ACCEL("//redo","r"); - ACCEL("//action-layer_remove","Delete"); - -/* ACCEL2(Gtk::AccelKey(']',static_cast(0),"//jump-next-keyframe")); - ACCEL2(Gtk::AccelKey('[',static_cast(0),"//jump-prev-keyframe")); - ACCEL2(Gtk::AccelKey('=',static_cast(0),"//canvas-zoom-in")); - ACCEL2(Gtk::AccelKey('-',static_cast(0),"//canvas-zoom-out")); - ACCEL("//time-zoom-in","+"); - ACCEL("//time-zoom-out","_"); -*/ - ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"//decrease-low-res-pixel-size")); - ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"//increase-low-res-pixel-size")); - - ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"//amount-dec")); - ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"//amount-inc")); - - ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"//jump-next-keyframe")); - ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"//jump-prev-keyframe")); - ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"//canvas-zoom-in")); - ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"//canvas-zoom-out")); - ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"//time-zoom-in")); - ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"//time-zoom-out")); - ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"//seek-next-frame")); - ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"//seek-prev-frame")); - ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"//seek-next-second")); - ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"//seek-prev-second")); - ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"//toggle-onion-skin")); - ACCEL("//play", "p"); - ACCEL("//seek-begin","Home"); - ACCEL("//seek-end","End"); - - ACCEL("//state-normal", "a"); - ACCEL("//state-smooth_move", "v"); - ACCEL("//state-scale", "d"); - ACCEL("//state-rotate", "s"); - - ACCEL("//state-bline", "b"); - ACCEL("//state-circle", "c"); - ACCEL("//state-rectangle", "r"); - ACCEL("//state-gradient", "g"); - - ACCEL("//state-eyedrop", "e"); - ACCEL("//state-fill", "f"); - ACCEL("//state-zoom", "z"); - ACCEL("//state-polygon", "p"); - - ACCEL("//state-draw", "w"); - ACCEL("//state-sketch", "k"); - ACCEL("//state-width", "t"); - ACCEL("//state-mirror", "m"); - - ACCEL("//canvas-zoom-fit","z"); + // the toolbox + ACCEL("a", "//state-normal" ); + ACCEL("v", "//state-smooth_move" ); + ACCEL("s", "//state-scale" ); + ACCEL("t", "//state-rotate" ); + ACCEL("m", "//state-mirror" ); + ACCEL("c", "//state-circle" ); + ACCEL("r", "//state-rectangle" ); + ACCEL("q", "//state-star" ); + ACCEL("g", "//state-gradient" ); + ACCEL("p", "//state-polygon" ); + ACCEL("b", "//state-bline" ); + ACCEL("x", "//state-text" ); + ACCEL("f", "//state-fill" ); + ACCEL("e", "//state-eyedrop" ); + ACCEL("z", "//state-zoom" ); + ACCEL("d", "//state-draw" ); + ACCEL("k", "//state-sketch" ); + ACCEL("w", "//state-width" ); + + // everything else + ACCEL("a", "//select-all-ducks" ); + ACCEL("d", "//unselect-all-ducks" ); + ACCEL("a", "//select-all-layers" ); + ACCEL("d", "//unselect-all-layers" ); + ACCEL("F9", "//render" ); + ACCEL("F11", "//preview" ); + ACCEL("F8", "//properties" ); + ACCEL("F12", "//options" ); + ACCEL("i", "//import" ); + ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast(0), "//stop" )); + ACCEL("g", "//toggle-grid-show" ); + ACCEL("l", "//toggle-grid-snap" ); + ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK, "//toggle-low-res" )); + ACCEL("1", "//mask-position-ducks" ); + ACCEL("2", "//mask-vertex-ducks" ); + ACCEL("3", "//mask-tangent-ducks" ); + ACCEL("4", "//mask-radius-ducks" ); + ACCEL("5", "//mask-width-ducks" ); + ACCEL("6", "//mask-angle-ducks" ); + ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK, "//action-LayerRaise" )); + ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK, "//action-LayerLower" )); + ACCEL("1", "//quality-01" ); + ACCEL("2", "//quality-02" ); + ACCEL("3", "//quality-03" ); + ACCEL("4", "//quality-04" ); + ACCEL("5", "//quality-05" ); + ACCEL("6", "//quality-06" ); + ACCEL("7", "//quality-07" ); + ACCEL("8", "//quality-08" ); + ACCEL("9", "//quality-09" ); + ACCEL("0", "//quality-10" ); + ACCEL("z", "//undo" ); + ACCEL("r", "//redo" ); + ACCEL2(Gtk::AccelKey(GDK_Delete,Gdk::CONTROL_MASK, "//action-LayerRemove" )); + ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK, "//decrease-low-res-pixel-size" )); + ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK, "//increase-low-res-pixel-size" )); + ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "//amount-dec" )); + ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK, "//amount-inc" )); + ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK, "//jump-next-keyframe" )); + ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK, "//jump-prev-keyframe" )); + ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK, "//canvas-zoom-in" )); + ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK, "//canvas-zoom-out" )); + ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK, "//time-zoom-in" )); + ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK, "//time-zoom-out" )); + ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK, "//seek-next-frame" )); + ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK, "//seek-prev-frame" )); + ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK, "//seek-next-second" )); + ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK, "//seek-prev-second" )); + ACCEL("o", "//toggle-onion-skin" ); + ACCEL("z", "//canvas-zoom-fit" ); + ACCEL("p", "//play" ); + ACCEL("Home", "//seek-begin" ); + ACCEL("End", "//seek-end" ); #undef ACCEL } @@ -1031,7 +1134,6 @@ App::App(int *argc, char ***argv): Glib::set_application_name(_("Synfig Studio")); Splash splash_screen; - splash_screen.set_can_self_destruct(false); splash_screen.show(); shutdown_in_progress=false; @@ -1040,6 +1142,11 @@ App::App(int *argc, char ***argv): // Initialize the Synfig library try { synfigapp_main=etl::smart_ptr(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); } + catch(std::runtime_error x) + { + get_ui_interface()->error(strprintf("%s\n\n%s", _("Failed to initialize synfig!"), x.what())); + throw; + } catch(...) { get_ui_interface()->error(_("Failed to initialize synfig!")); @@ -1139,21 +1246,22 @@ App::App(int *argc, char ***argv): studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start(); /* row 2 */ - state_manager->add_state(&state_bline); state_manager->add_state(&state_circle); state_manager->add_state(&state_rectangle); + state_manager->add_state(&state_star); state_manager->add_state(&state_gradient); if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks /* row 3 */ - if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet. - if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch); + state_manager->add_state(&state_bline); + state_manager->add_state(&state_text); state_manager->add_state(&state_fill); state_manager->add_state(&state_eyedrop); state_manager->add_state(&state_zoom); - // Disabled by default - it doesn't work properly? - if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width); + if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw); // Enabled for now. Let's see whether they're good enough yet. + if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch); + if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09 studio_init_cb.task(_("Init ModPalette...")); module_list_.push_back(new ModPalette()); module_list_.back()->start(); @@ -1260,7 +1368,7 @@ App::~App() delete auto_recover; delete about; - + toolbox->hide(); // studio::App::iteration(false); @@ -1289,7 +1397,12 @@ App::~App() String App::get_user_app_directory() { +//! \todo do we need locale_from_utf8() on non-Windows boxes too? (bug #1837445) +#ifdef WIN32 + return Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR)); +#else return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR); +#endif } synfig::String @@ -1298,8 +1411,116 @@ App::get_config_file(const synfig::String& file) return Glib::build_filename(get_user_app_directory(),file); } +#define SCALE_FACTOR (1280) +//! set the \a instance's canvas(es) position and size to be those specified in the first entry of recent_files_window_size void -App::add_recent_file(const std::string &file_name) +App::set_recent_file_window_size(etl::handle instance) +{ + int screen_w(Gdk::screen_width()); + int screen_h(Gdk::screen_height()); + + const std::string &canvas_window_size = *recent_files_window_size.begin(); + + if(canvas_window_size.empty()) + return; + + synfig::String::size_type current=0; + bool seen_root(false), shown_non_root(false); + + while(current != synfig::String::npos) + { + // find end of first field (canvas) or return + synfig::String::size_type separator = canvas_window_size.find_first_of(' ', current); + if(separator == synfig::String::npos) break; + + // find the canvas + synfig::Canvas::Handle canvas; + try { + String warnings; + canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current), warnings); + } + catch(Exception::IDNotFound) { + // can't find the canvas; skip to the next canvas or return + separator = canvas_window_size.find_first_of('\t', current); + if(separator == synfig::String::npos) return; + current = separator+1; + continue; + } + + if (canvas->is_root()) + seen_root = true; + else + shown_non_root = true; + + // check that we have the tab character the ends this canvas' data or return + current = separator+1; + separator = canvas_window_size.find_first_of('\t', current); + if(separator == synfig::String::npos) return; + + int x,y,w,h; + if(!strscanf(String(canvas_window_size, current, separator-current),"%d %d %d %d",&x, &y, &w, &h)) + { + current = separator+1; + continue; + } + + if (x > SCALE_FACTOR) x = SCALE_FACTOR - 150; if (x < 0) x = 0; + if (y > SCALE_FACTOR) y = SCALE_FACTOR - 150; if (y < 0) y = 0; + x=x*screen_w/SCALE_FACTOR; + y=y*screen_h/SCALE_FACTOR; + if(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET")) + x += atoi(getenv("SYNFIG_WINDOW_POSITION_X_OFFSET")); + if(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET")) + y += atoi(getenv("SYNFIG_WINDOW_POSITION_Y_OFFSET")); + + if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0; + if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0; + + CanvasView::Handle canvasview = instance->find_canvas_view(canvas); + canvasview->move(x,y); + canvasview->resize(w*screen_w/SCALE_FACTOR,h*screen_h/SCALE_FACTOR); + canvasview->present(); + + current = separator+1; + } + + if (shown_non_root && !seen_root) + instance->find_canvas_view(instance->get_canvas())->hide(); +} + +void +App::add_recent_file(const etl::handle instance) +{ + int screen_w(Gdk::screen_width()); + int screen_h(Gdk::screen_height()); + + std::string canvas_window_size; + + const Instance::CanvasViewList& cview_list = instance->canvas_view_list(); + Instance::CanvasViewList::const_iterator iter; + + for(iter=cview_list.begin();iter!=cview_list.end();iter++) + { + if( !((*iter)->is_visible()) ) + continue; + + etl::handle canvas = (*iter)->get_canvas(); + int x_pos, y_pos, x_size, y_size; + (*iter)->get_position(x_pos,y_pos); + (*iter)->get_size(x_size,y_size); + + canvas_window_size += strprintf("%s %d %d %d %d\t", + canvas->get_relative_id(canvas->get_root()).c_str(), + x_pos*SCALE_FACTOR/screen_w, y_pos*SCALE_FACTOR/screen_h, + x_size*SCALE_FACTOR/screen_w, y_size*SCALE_FACTOR/screen_h); + } + + add_recent_file(absolute_path(instance->get_file_name()), canvas_window_size); +} +#undef SCALE_FACTOR + +void +App::add_recent_file(const std::string &file_name, const std::string &window_size) { std::string filename(file_name); @@ -1316,23 +1537,35 @@ App::add_recent_file(const std::string &file_name) if(!is_absolute_path(filename)) filename=absolute_path(filename); + std::string old_window_size; + list::iterator iter; + list::iterator iter_wsize; // Check to see if the file is already on the list. // If it is, then remove it from the list - for(iter=recent_files.begin();iter!=recent_files.end();iter++) + for(iter=recent_files.begin(), iter_wsize=recent_files_window_size.begin();iter!=recent_files.end();iter++, iter_wsize++) if(*iter==filename) { recent_files.erase(iter); + old_window_size = *iter_wsize; + recent_files_window_size.erase(iter_wsize); break; } // Push the filename to the front of the list recent_files.push_front(filename); + if(window_size.empty()) + recent_files_window_size.push_front(old_window_size); + else + recent_files_window_size.push_front(window_size); // Clean out the files at the end of the list. while(recent_files.size()>(unsigned)get_max_recent_files()) + { recent_files.pop_back(); + recent_files_window_size.pop_back(); + } signal_recent_files_changed_(); @@ -1382,7 +1615,23 @@ App::save_settings() for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++) file<<*iter<::reverse_iterator iter; + + for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++) + file<<*iter<run() == GTK_RESPONSE_ACCEPT) { filename = dialog->get_filename(); - info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str()); + // info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str()); _preferences.set_value(preference, dirname(filename)); delete dialog; return true; @@ -1694,7 +1979,7 @@ App::dialog_open_file(const std::string &title, std::string &filename, std::stri bool App::dialog_save_file(const std::string &title, std::string &filename, std::string preference) { - info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str()); + // info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str()); #if USE_WIN32_FILE_DIALOGS static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ; @@ -1752,14 +2037,16 @@ App::dialog_save_file(const std::string &title, std::string &filename, std::stri dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); - Widget_Enum *file_type_enum; + Widget_Enum *file_type_enum = 0; if (preference == ANIMATION_DIR_PREFERENCE) { file_type_enum = manage(new Widget_Enum()); file_type_enum->set_param_desc(ParamDesc().set_hint("enum") - .add_enum_value(synfig::FILE_VERSION_0_61_08, "0.61.08", strprintf("0.61.08 (%s)", _("current"))) - .add_enum_value(synfig::FILE_VERSION_0_61_07, "0.61.07", strprintf("0.61.07 %s", _("and older")))); - file_type_enum->set_value(0); + .add_enum_value(synfig::RELEASE_VERSION_0_61_09, "0.61.09", strprintf("0.61.09 (%s)", _("current"))) + .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", "0.61.08") + .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07") + .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older")))); + file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version Gtk::HBox *hbox = manage(new Gtk::HBox); hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0); @@ -1790,9 +2077,9 @@ App::dialog_save_file(const std::string &title, std::string &filename, std::stri if(dialog->run() == GTK_RESPONSE_ACCEPT) { if (preference == ANIMATION_DIR_PREFERENCE) - set_file_version(synfig::FileVersion(file_type_enum->get_value())); + set_file_version(synfig::ReleaseVersion(file_type_enum->get_value())); filename = dialog->get_filename(); - info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str()); + // info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str()); _preferences.set_value(preference, dirname(filename)); delete dialog; return true; @@ -1866,14 +2153,114 @@ App::dialog_not_implemented() dialog.run(); } +static bool +try_open_url(const std::string &url) +{ +#ifdef WIN32 + return ShellExecute(GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOW); +#else // !WIN32 + std::vector command_line; + std::vector browsers; + browsers.reserve(23); + + // Browser wrapper scripts +#ifdef USE_OPEN_FOR_URLS + browsers.push_back("open"); // Apple MacOS X wrapper, on Linux it opens a virtual console +#endif + browsers.push_back("xdg-open"); // XDG wrapper + browsers.push_back("sensible-browser"); // Debian wrapper + browsers.push_back("gnome-open"); // GNOME wrapper + browsers.push_back("kfmclient"); // KDE wrapper + browsers.push_back("exo-open"); // XFCE wrapper + + // Alternatives system + browsers.push_back("gnome-www-browser"); // Debian GNOME alternative + browsers.push_back("x-www-browser"); // Debian GUI alternative + + // Individual browsers + browsers.push_back("firefox"); + browsers.push_back("epiphany-browser"); + browsers.push_back("epiphany"); + browsers.push_back("konqueror"); + browsers.push_back("iceweasel"); + browsers.push_back("mozilla"); + browsers.push_back("netscape"); + browsers.push_back("icecat"); + browsers.push_back("galeon"); + browsers.push_back("midori"); + browsers.push_back("safari"); + browsers.push_back("opera"); + browsers.push_back("amaya"); + browsers.push_back("netsurf"); + browsers.push_back("dillo"); + + // Try the user-specified browser first + command_line.push_back(App::browser_command); + if( command_line[0] == "kfmclient" ) command_line.push_back("openURL"); + command_line.push_back(url); + + try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); return true; } + catch( Glib::SpawnError& exception ){ + + while ( !browsers.empty() ) + { + // Skip the browser if we already tried it + if( browsers[0] == App::browser_command ) + continue; + + // Construct the command line + command_line.clear(); + command_line.push_back(browsers[0]); + if( command_line[0] == "kfmclient" ) command_line.push_back("openURL"); + command_line.push_back(url); + + // Remove the browser from the list + browsers.erase(browsers.begin()); + + // Try to spawn the browser + try { Glib::spawn_async(".", command_line, Glib::SPAWN_SEARCH_PATH); } + // Failed, move on to the next one + catch(Glib::SpawnError& exception){ continue; } + return true; // No exception means we succeeded! + } + } + + return false; +#endif // !WIN32 +} + +void +App::dialog_help() +{ + if (!try_open_url("http://synfig.org/Documentation")) + { + Gtk::MessageDialog dialog(_("Documentation"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, true); + dialog.set_secondary_text(_("Documentation for Synfig Studio is available on the website:\n\nhttp://www.synfig.org/Documentation")); + dialog.set_title(_("Help")); + dialog.run(); + } +} + +void +App::open_url(const std::string &url) +{ + if(!try_open_url(url)) + { + Gtk::MessageDialog dialog(_("No browser was found. Please load this website manually:"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true); + dialog.set_secondary_text(url); + dialog.set_title(_("No browser found")); + dialog.run(); + } +} + bool App::dialog_entry(const std::string &title, const std::string &message,std::string &text) { Gtk::Dialog dialog( title, // Title true, // Modal - true // use_separator - ); + true); // use_separator + Gtk::Label label(message); label.show(); dialog.get_vbox()->pack_start(label); @@ -1882,11 +2269,13 @@ App::dialog_entry(const std::string &title, const std::string &message,std::stri entry.set_text(text); entry.show(); entry.set_activates_default(true); + dialog.get_vbox()->pack_start(entry); dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK); dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL); dialog.set_default_response(Gtk::RESPONSE_OK); + entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK)); dialog.show(); @@ -1898,8 +2287,39 @@ App::dialog_entry(const std::string &title, const std::string &message,std::stri return true; } +bool +App::dialog_paragraph(const std::string &title, const std::string &message,std::string &text) +{ + Gtk::Dialog dialog( + title, // Title + true, // Modal + true); // use_separator + + Gtk::Label label(message); + label.show(); + dialog.get_vbox()->pack_start(label); + + Glib::RefPtr text_buffer(Gtk::TextBuffer::create()); + text_buffer->set_text(text); + Gtk::TextView text_view(text_buffer); + text_view.show(); + + dialog.get_vbox()->pack_start(text_view); + + dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK); + dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL); + dialog.set_default_response(Gtk::RESPONSE_OK); + //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK)); + dialog.show(); + + if(dialog.run()!=Gtk::RESPONSE_OK) + return false; + + text=text_buffer->get_text(); + return true; +} bool App::open(std::string filename) @@ -1916,14 +2336,18 @@ App::open_as(std::string filename,std::string as) #ifdef WIN32 char long_name[1024]; if(GetLongPathName(as.c_str(),long_name,sizeof(long_name))); - as=long_name; + // when called from autorecover.cpp, filename doesn't exist, and so long_name is empty + // don't use it if that's the case + if (long_name[0] != '\0') + as=long_name; #endif try { OneMoment one_moment; + String errors, warnings; - etl::handle canvas(open_canvas_as(filename,as)); + etl::handle canvas(open_canvas_as(filename,as,errors,warnings)); if(canvas && get_instance(canvas)) { get_instance(canvas)->find_canvas_view(canvas)->present(); @@ -1933,15 +2357,21 @@ App::open_as(std::string filename,std::string as) else { if(!canvas) - throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str()); + throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors; + + if (warnings != "") + dialog_warning_blocking(_("Warnings"), strprintf("%s:\n\n%s", _("Warnings"), warnings.c_str())); - add_recent_file(as); + if (as.find(custom_filename_prefix.c_str()) != 0) + add_recent_file(as); handle instance(Instance::create(canvas)); if(!instance) throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str()); + set_recent_file_window_size(instance); + one_moment.hide(); 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)"))) @@ -1953,6 +2383,11 @@ App::open_as(std::string filename,std::string as) dialog_error_blocking(_("Error"), x); return false; } + catch(runtime_error x) + { + dialog_error_blocking(_("Error"), x.what()); + return false; + } catch(...) { dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)")); @@ -1967,19 +2402,22 @@ void App::new_instance() { handle canvas=synfig::Canvas::create(); - canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1)); - String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1)); + String file_name(strprintf("%s%d", App::custom_filename_prefix.c_str(), Instance::get_count()+1)); + canvas->set_name(file_name); + file_name += ".sifz"; canvas->rend_desc().set_frame_rate(24.0); canvas->rend_desc().set_time_start(0.0); canvas->rend_desc().set_time_end(5.0); canvas->rend_desc().set_x_res(DPI2DPM(72.0f)); canvas->rend_desc().set_y_res(DPI2DPM(72.0f)); - canvas->rend_desc().set_tl(Vector(-4,2.25)); - canvas->rend_desc().set_br(Vector(4,-2.25)); - canvas->rend_desc().set_w(480); - canvas->rend_desc().set_h(270); + // The top left and botton right positions are expressed in units + // Original convention is that 1 unit = 60 pixels + canvas->rend_desc().set_tl(Vector(-(preferred_x_size/60.0)/2.0,(preferred_y_size/60.0)/2.0)); + canvas->rend_desc().set_br(Vector((preferred_x_size/60.0)/2.0,-(preferred_y_size/60.0)/2.0)); + canvas->rend_desc().set_w(preferred_x_size); + canvas->rend_desc().set_h(preferred_y_size); canvas->rend_desc().set_antialias(1); canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN); canvas->set_file_name(file_name); @@ -1991,9 +2429,10 @@ App::new_instance() } void -App::dialog_open() +App::dialog_open(string filename) { - string filename="*.sif"; + if (filename.empty()) + filename="*.sif"; while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE)) {