**
** \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
# include <config.h>
#endif
+#ifdef WIN32
+#define WINVER 0x0500
+#include <windows.h>
+#endif
+
#include <fstream>
#include <iostream>
#include <locale>
+#include <cstring>
#ifdef HAVE_SYS_ERRNO_H
#include <sys/errno.h>
#include <gtkmm/inputdialog.h>
#include <gtkmm/accelmap.h>
#include <gtkmm/uimanager.h>
+#include <gtkmm/textview.h>
#include <gtk/gtk.h>
+#include <gdkmm/general.h>
+
#include <synfig/loadcanvas.h>
+#include <synfig/savecanvas.h>
#include "app.h"
#include "about.h"
+#include "splash.h"
#include "instance.h"
#include "canvasview.h"
#include "dialog_setup.h"
#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"
#include "devicetracker.h"
#include "dialog_tooloptions.h"
+#include "widget_enum.h"
#include "autorecover.h"
#include <fmod.h>
#endif
-#ifdef WIN32
-#define _WIN32_WINNT 0x0500
-#include <windows.h>
-#endif
#include <gtkmm/accelmap.h>
#include <gtkmm/filechooser.h>
#include <gtkmm/filechooserdialog.h>
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;
etl::handle<Instance> App::selected_instance;
etl::handle<CanvasView> App::selected_canvas_view;
+studio::About *studio::App::about=NULL;
+
studio::Toolbox *studio::App::toolbox=NULL;
studio::AutoRecover *studio::App::auto_recover=NULL;
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::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_; }
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;
+ }
+ 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);
}
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;
+ }
+ 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);
}
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");
+ 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;
}
};
menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
+ menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
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"));
DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
+ for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
+ DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
DEFINE_ACTION("play", _("Play"));
// DEFINE_ACTION("pause", _("Pause"));
DEFINE_ACTION("stop", _("Stop"));
DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
+ DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
+ DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
" <menuitem action='copy'/>"
" <menuitem action='paste'/>"
" <separator name='bleh06'/>"
-" <menuitem action='select-all-ducks'/>"
+" <menuitem action='select-all-layers'/>"
" <menuitem action='unselect-all-layers'/>"
+" <menuitem action='select-all-ducks'/>"
+" <menuitem action='unselect-all-ducks'/>"
" <separator name='bleh07'/>"
" <menuitem action='properties'/>"
" </menu>"
" <menuitem action='quality-09' />"
" <menuitem action='quality-10' />"
" </menu>"
+" <menu action='menu-lowres-pixel'>"
+" <menuitem action='decrease-low-res-pixel-size'/>"
+" <menuitem action='increase-low-res-pixel-size'/>"
+" <separator name='pixel-size-separator'/>"
+;
+
+ for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
+ ui_info += strprintf(" <menuitem action='lowres-pixel-%d' />", *iter);
+
+ ui_info +=
+" </menu>"
" <separator name='bleh08'/>"
" <menuitem action='play'/>"
//" <menuitem action='pause'/>"
}
ACCEL("<Actions>//select-all-ducks","<Control>a");
- ACCEL("<Actions>//unselect-all-layers","<Control>d");
+ ACCEL("<Actions>//unselect-all-ducks","<Control>d");
+ ACCEL("<Actions>//select-all-layers","<Control><Shift>a");
+ ACCEL("<Actions>//unselect-all-layers","<Control><Shift>d");
ACCEL("<Actions>//render","F9");
ACCEL("<Actions>//preview","F11");
ACCEL("<Actions>//properties","F8");
ACCEL("<Actions>//time-zoom-in","+");
ACCEL("<Actions>//time-zoom-out","_");
*/
+ ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
+ ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
+
ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
- ACCEL2(Gtk::AccelKey('o',Gdk::CONTROL_MASK,"<Actions>//toggle-onion-skin"));
+ ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
ACCEL("<Actions>//play", "<Control>p");
ACCEL("<Actions>//seek-begin","Home");
ACCEL("<Actions>//seek-end","End");
ACCEL("<Actions>//state-normal", "<Mod1>a");
ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
- ACCEL("<Actions>//state-scale", "<Mod1>d");
- ACCEL("<Actions>//state-rotate", "<Mod1>s");
+ ACCEL("<Actions>//state-scale", "<Mod1>s");
+ ACCEL("<Actions>//state-rotate", "<Mod1>t");
+ ACCEL("<Actions>//state-mirror", "<Mod1>m");
- ACCEL("<Actions>//state-bline", "<Mod1>b");
ACCEL("<Actions>//state-circle", "<Mod1>c");
ACCEL("<Actions>//state-rectangle", "<Mod1>r");
+ ACCEL("<Actions>//state-star", "<Mod1>q");
ACCEL("<Actions>//state-gradient", "<Mod1>g");
+ ACCEL("<Actions>//state-polygon", "<Mod1>p");
- ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
+ ACCEL("<Actions>//state-bline", "<Mod1>b");
+ ACCEL("<Actions>//state-text", "<Mod1>x");
ACCEL("<Actions>//state-fill", "<Mod1>f");
+ ACCEL("<Actions>//state-eyedrop", "<Mod1>e");
ACCEL("<Actions>//state-zoom", "<Mod1>z");
- ACCEL("<Actions>//state-polygon", "<Mod1>p");
- ACCEL("<Actions>//state-draw", "<Mod1>w");
+ ACCEL("<Actions>//state-draw", "<Mod1>d");
ACCEL("<Actions>//state-sketch", "<Mod1>k");
- ACCEL("<Actions>//state-width", "<Mod1>t");
- ACCEL("<Actions>//state-mirror", "<Mod1>m");
+ ACCEL("<Actions>//state-width", "<Mod1>w");
ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
}
Glib::set_application_name(_("Synfig Studio"));
- About about_window;
- about_window.set_can_self_destruct(false);
- about_window.show();
+ Splash splash_screen;
+ splash_screen.show();
shutdown_in_progress=false;
- SuperCallback synfig_init_cb(about_window.get_callback(),0,9000,10000);
- SuperCallback studio_init_cb(about_window.get_callback(),9000,10000,10000);
+ SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
+ SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
// Initialize the Synfig library
try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
studio_init_cb.task(_("Init Toolbox..."));
toolbox=new studio::Toolbox();
+ studio_init_cb.task(_("Init About Dialog..."));
+ about=new studio::About();
+
studio_init_cb.task(_("Init Tool Options..."));
dialog_tool_options=new studio::Dialog_ToolOptions();
dock_manager->register_dockable(*dialog_tool_options);
device_tracker=new studio::DeviceTracker();
studio_init_cb.task(_("Init Tools..."));
+
+ /* row 1 */
state_manager->add_state(&state_normal);
state_manager->add_state(&state_smooth_move);
state_manager->add_state(&state_scale);
state_manager->add_state(&state_rotate);
+ studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
- state_manager->add_state(&state_bline);
-
-
+ /* row 2 */
state_manager->add_state(&state_circle);
state_manager->add_state(&state_rectangle);
-
+ state_manager->add_state(&state_star);
state_manager->add_state(&state_gradient);
- state_manager->add_state(&state_eyedrop);
- state_manager->add_state(&state_fill);
+ if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
+ /* row 3 */
+ 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);
- // Enabled - it's useful to be able to work with polygons without tangent ducks getting in the way.
- // I know we can switch tangent ducks off, but why not allow this kind of layer as well?
- if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon);
-
- // Enabled for now. Let's see whether they're good enough yet.
- if(!getenv("SYNFIG_DISABLE_DRAW" )) state_manager->add_state(&state_draw);
+ 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);
-
- // Disabled by default - it doesn't work properly?
- if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
+ 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();
- studio_init_cb.task(_("Init ModMirror..."));
- module_list_.push_back(new ModMirror()); module_list_.back()->start();
-
-
studio_init_cb.task(_("Init Setup Dialog..."));
dialog_setup=new studio::Dialog_Setup();
studio_init_cb.amount_complete(9900,10000);
+ bool opened_any = false;
if(auto_recover->recovery_needed())
{
- about_window.hide();
- if(
- get_ui_interface()->yes_no(
- _("Auto Recovery"),
- _("Synfig Studio seems to have crashed\n"
- "before you could save all your files.\n"
- "Would you like to re-open those files\n"
- "and recover your unsaved changes?")
- )==synfigapp::UIInterface::RESPONSE_YES
- )
+ splash_screen.hide();
+ if (get_ui_interface()->yes_no(_("Auto Recovery"),
+ _("Synfig Studio seems to have crashed\n"
+ "before you could save all your files.\n"
+ "Would you like to re-open those files\n"
+ "and recover your unsaved changes?")) ==
+ synfigapp::UIInterface::RESPONSE_YES)
{
- if(!auto_recover->recover())
- {
- get_ui_interface()->error(_("Unable to fully recover from previous crash"));
- }
+ int number_recovered;
+ if(!auto_recover->recover(number_recovered))
+ if (number_recovered)
+ get_ui_interface()->error(_("Unable to fully recover from previous crash"));
+ else
+ get_ui_interface()->error(_("Unable to recover from previous crash"));
else
- get_ui_interface()->error(
- _("Synfig Studio has attempted to recover\n"
- "from a previous crash. The files that it has\n"
- "recovered are NOT YET SAVED. It would be a good\n"
- "idea to review them and save them now.")
- );
+ get_ui_interface()->error(
+ _("Synfig Studio has attempted to recover\n"
+ "from a previous crash. The files that it has\n"
+ "recovered are NOT YET SAVED. It would be a good\n"
+ "idea to review them and save them now."));
+
+ if (number_recovered)
+ opened_any = true;
}
- about_window.show();
+ splash_screen.show();
}
// Look for any files given on the command line,
if((*argv)[*argc] && (*argv)[*argc][0]!='-')
{
studio_init_cb.task(_("Loading files..."));
- about_window.hide();
+ splash_screen.hide();
open((*argv)[*argc]);
- about_window.show();
+ opened_any = true;
+ splash_screen.show();
}
+ // if no file was specified to be opened, create a new document to help new users get started more easily
+ if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
+ new_instance();
+
studio_init_cb.task(_("Done."));
studio_init_cb.amount_complete(10000,10000);
selected_instance=0;
// Unload all of the modules
- for(;!module_list_.empty();module_list_.pop_back());
+ for(;!module_list_.empty();module_list_.pop_back())
+ ;
delete state_manager;
delete auto_recover;
+ delete about;
+
toolbox->hide();
// studio::App::iteration(false);
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
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::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;
+ }
+
+ 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 std::string &file_name)
+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);
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_();
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);
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 (std::ifstream(recent_file.c_str()))
+ {
+ 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");
if(!synfigapp::Main::settings().load_from_file(filename))
{
- //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
+ //std::string filename=Glib::locale_from_utf8(Glib::build_filename(Glib::get_home_dir(),".synfigrc"));
//if(!synfigapp::Main::settings().load_from_file(filename))
{
gamma.set_gamma(1.0/2.2);
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("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
+ synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
+ synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
+ synfigapp::Main::settings().set_value("pref.predefined_size",DEFAULT_PREDEFINED_SIZE);
synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
}
bool
App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
{
- info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
+ // info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
#ifdef USE_WIN32_FILE_DIALOGS
static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
if(dialog->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;
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") ;
dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
+ 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::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);
+ hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
+ hbox->show_all();
+
+ dialog->set_extra_widget(*hbox);
+ }
+
if (filename.empty())
dialog->set_filename(prev_path);
else
}
if(dialog->run() == GTK_RESPONSE_ACCEPT) {
+ if (preference == ANIMATION_DIR_PREFERENCE)
+ 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;
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<std::string> command_line;
+ std::vector<std::string> 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);
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();
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<Gtk::TextBuffer> 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)
#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;
- etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
+ etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as,errors));
if(canvas && get_instance(canvas))
{
get_instance(canvas)->find_canvas_view(canvas)->present();
- throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
+ info("%s is already open", filename.c_str());
+ // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
}
- if(!canvas)
- throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
+ else
+ {
+ if(!canvas)
+ throw (String)strprintf(_("Unable to load \"%s\":\n\n"),filename.c_str()) + errors;
+
+ if (as.find(custom_filename_prefix.c_str()) != 0)
+ add_recent_file(as);
- add_recent_file(as);
+ handle<Instance> instance(Instance::create(canvas));
- handle<Instance> instance(Instance::create(canvas));
+ if(!instance)
+ throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
- if(!instance)
- throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
+ set_recent_file_window_size(instance);
- one_moment.hide();
+ 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)")))
- instance->dialog_cvs_update();
+ 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)")))
+ instance->dialog_cvs_update();
+ }
}
catch(String x)
{
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", 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(00.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);
handle<Instance> instance = Instance::create(canvas);
- if (!getenv("SYNFIG_DISABLE_NEW_CANVAS_EDIT_PROPERTIES"))
+ if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
instance->find_canvas_view(canvas)->canvas_properties.present();
}
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))
{
void
App::dialog_about()
{
- (new class About())->show();
+ if(about)
+ about->show();
}
void