Hide the root canvas if we have saved the position and size of other canvases and...
[synfig.git] / synfig-studio / trunk / src / gtkmm / app.cpp
index 979939d..27a7373 100644 (file)
@@ -6,7 +6,8 @@
 **
 **     \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
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
@@ -51,6 +52,8 @@
 
 #include <gtk/gtk.h>
 
+#include <gdkmm/general.h>
+
 #include <synfig/loadcanvas.h>
 #include <synfig/savecanvas.h>
 
@@ -203,6 +206,8 @@ App::signal_instance_deleted() { return signal_instance_deleted_; }
 static std::list<std::string> recent_files;
 const std::list<std::string>& App::get_recent_files() { return recent_files; }
 
+static std::list<std::string> recent_files_window_size;
+
 int    App::Busy::count;
 bool App::shutdown_in_progress;
 
@@ -261,7 +266,11 @@ 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;
+String studio::App::browser_command("firefox");
 
 static int max_recent_files_=25;
 int studio::App::get_max_recent_files() { return max_recent_files_; }
@@ -472,16 +481,28 @@ 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=="browser_command")
+               {
+                       value=App::browser_command;
+                       return true;
+               }
 
                return synfigapp::Settings::get_value(key,value);
        }
@@ -532,12 +553,25 @@ 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=="browser_command")
+               {
+                       App::browser_command=value;
+                       return true;
+               }
 
                return synfigapp::Settings::set_value(key,value);
        }
@@ -550,8 +584,12 @@ 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("browser_command");
                return ret;
        }
 };
@@ -1298,8 +1336,118 @@ 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> 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 {
+                       canvas = instance->get_canvas()->find_canvas(String(canvas_window_size, current, separator-current));
+               }
+               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;
+               }
+
+               CanvasView::Handle canvasview = instance->find_canvas_view(canvas);
+               canvasview->present();
+
+               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"));
+               canvasview->move(x,y);
+
+               if (w > SCALE_FACTOR) w = 150; if (w < 0) w = 0;
+               if (h > SCALE_FACTOR) h = 150; if (h < 0) h = 0;
+               w=w*screen_w/SCALE_FACTOR;
+               h=h*screen_h/SCALE_FACTOR;
+               canvasview->set_default_size(w,h);
+               canvasview->set_size_request(w,h);
+
+               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> 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<synfig::Canvas> 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 +1464,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<string>::iterator iter;
+       list<string>::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 +1542,23 @@ App::save_settings()
                        for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
                                file<<*iter<<endl;
                }while(0);
+               do{
+                       std::string filename=get_config_file("recentfiles")+std::string("_window_size");
 
+                       std::ofstream file(filename.c_str());
+
+                       if(!file)
+                       {
+                               synfig::warning("Unable to save %s",filename.c_str());
+                               break;
+                       }
+
+                       list<string>::reverse_iterator iter;
+
+                       for(iter=recent_files_window_size.rbegin();iter!=recent_files_window_size.rend();iter++)
+                               file<<*iter<<endl;
+
+               }while(0);
                std::string filename=get_config_file("settings");
                synfigapp::Main::settings().save_to_file(filename);
        setlocale(LC_NUMERIC,old_locale);
@@ -1406,16 +1582,41 @@ App::load_settings()
                        Gtk::AccelMap::load(filename);
                }
                {
+                       bool window_size_broken = false;
+
                        std::string filename=get_config_file("recentfiles");
+                       std::string filename_window_size=filename+std::string("_window_size");
 
                        std::ifstream file(filename.c_str());
+                       std::ifstream file_window_size(filename_window_size.c_str());
+
+                       if(!file_window_size)
+                               window_size_broken = true;
 
                        while(file)
                        {
                                std::string recent_file;
+                               std::string recent_file_window_size;
                                getline(file,recent_file);
+                               if(!window_size_broken)
+                                       getline(file_window_size,recent_file_window_size);
                                if(!recent_file.empty())
-                                       add_recent_file(recent_file);
+                               {
+                                       if(!window_size_broken && !file_window_size)
+                                               window_size_broken = true;
+                                       if(!window_size_broken)
+                                               add_recent_file(recent_file,recent_file_window_size);
+                                       else
+                                               add_recent_file(recent_file);
+                               }
+                       }
+                       if(!window_size_broken && file_window_size)
+                               window_size_broken = true;
+
+                       if(window_size_broken)
+                       {
+                               recent_files_window_size.clear();
+                               recent_files_window_size.resize(recent_files.size());
                        }
                }
                std::string filename=get_config_file("settings");
@@ -1451,7 +1652,10 @@ App::reset_initial_window_configuration()
        synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
        synfigapp::Main::settings().set_value("pref.distance_system","pt");
        synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
+#ifdef SINGLE_THREADED
        synfigapp::Main::settings().set_value("pref.single_threaded","0");
+#endif
+       synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
        synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
 }
 
@@ -1752,7 +1956,7 @@ 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());
@@ -1867,6 +2071,49 @@ 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
+       gchar* argv[3] = {strdup(App::browser_command.c_str()), strdup(url.c_str()), NULL};
+
+       GError* gerror = NULL;
+       gboolean retval;
+       retval = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &gerror);
+       free(argv[0]);
+       free(argv[1]);
+
+       if (!retval)
+    {
+               error(_("Could not execute specified web browser: %s"), gerror->message);
+               g_error_free(gerror);
+               return false;
+    }
+
+       return true;
+#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)
+{
+       try_open_url(url);
+}
+
 bool
 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
 {
@@ -1943,6 +2190,8 @@ App::open_as(std::string filename,std::string as)
                        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)")))
@@ -1968,9 +2217,10 @@ void
 App::new_instance()
 {
        handle<synfig::Canvas> 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", DEFAULT_FILENAME_PREFIX, 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);
@@ -1992,9 +2242,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))
        {