**
** \legal
** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+** 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>
+#include "general.h"
+
#endif
/* === U S I N G =========================================================== */
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_; }
static synfig::String app_base_path_;
namespace studio {
+
+bool
+really_delete_widget(Gtk::Widget *widget)
+{
+ // synfig::info("really delete %p", (void*)widget);
+ delete widget;
+ return false;
+}
+
+// nasty workaround - when we've finished with a popup menu, we want to delete it
+// attaching to the signal_hide() signal gets us here before the action on the menu has run,
+// so schedule the real delete to happen in 50ms, giving the action a chance to run
+void
+delete_widget(Gtk::Widget *widget)
+{
+ // synfig::info("delete %p", (void*)widget);
+ Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
+}
+
}; // END of namespace studio
studio::StateManager* state_manager;
/* === P R O C E D U R E S ================================================= */
-typedef unsigned char U8;
-typedef unsigned short U16;
-typedef unsigned long U32;
-
-typedef union {
- struct {
- U32 serial;
- U32 checksum;
- } element;
- U8 raw[8];
-} V_KeyUnwound;
-
-static inline U32 hash_U32(U32 i)
-{
- i=i*1664525+1013904223;
- i=i*1664525+1013904223;
- i=i*1664525+1013904223;
- return i;
-}
-
-#ifdef BIG_ENDIAN
-static const int endian_fix_table[8] = { 3, 2, 1, 0, 7, 6, 5, 4 } ;
-#define endian_fix(x) (endian_fix_table[x])
-#else
-#define endian_fix(x) (x)
-#endif
-
-int v_unwind_key(V_KeyUnwound* unwound, const char* key)
-{
- int i;
- unwound->element.serial=0;
- unwound->element.checksum=0;
-
- for(i=0;i<16;i++)
- {
- U8 data;
-
- switch(key[i])
- {
- case '0': data=0; break;
- case '1': data=1; break;
- case '2': data=2; break;
- case '3': data=3; break;
- case '4': data=4; break;
- case '5': data=5; break;
- case '6': data=6; break;
- case '7': data=7; break;
- case '8': data=8; break;
- case '9': data=9; break;
- case 'a': case 'A': data=10; break;
- case 'b': case 'B': data=11; break;
- case 'c': case 'C': data=12; break;
- case 'd': case 'D': data=13; break;
- case 'e': case 'E': data=14; break;
- case 'f': case 'F': data=15; break;
- default: return 0; break;
- }
- int bit=i*2;
- unwound->element.checksum|=(((U32)data&3)<<bit);
- unwound->element.serial|=(((U32)(data>>2)&3)<<bit);
- }
- return 1;
-}
-
-int v_key_check(const char* key, U32* serial, U32 appid)
-{
- V_KeyUnwound unwound_key;
- U32 appid_mask_a=hash_U32(appid);
- U32 appid_mask_b=hash_U32(appid_mask_a);
-
- if(!v_unwind_key(&unwound_key, key))
- {
- // Invalid characters in key
- return 0;
- }
-
-
- // Undo obfuscation pass
- {
- U32 next=hash_U32(unwound_key.raw[endian_fix(7)]);
- int i;
- for(i=0;i<7;i++)
- {
- next=hash_U32(next);
- unwound_key.raw[endian_fix(i)]^=(next>>24);
- }
- }
-
- unwound_key.element.serial^=appid_mask_a;
- unwound_key.element.checksum^=appid_mask_b;
-
- *serial=unwound_key.element.serial;
-
- return unwound_key.element.checksum==hash_U32(unwound_key.element.serial);
-}
-
-
-#ifdef _WIN32
-# ifdef LICENSE_KEY_REQUIRED
-int check_license(String basedir)
-# else
-int check_license(String /*basedir*/)
-# endif
-#else
-int check_license(String /*basedir*/)
-#endif
-{
-#ifdef LICENSE_KEY_REQUIRED
- String key;
- String license_file;
-
-#ifndef _WIN32
- license_file="/usr/local/etc/.synfiglicense";
-#else
- license_file=basedir+"\\etc\\.synfiglicense";
-#endif
-
- try {
- key=Glib::file_get_contents(license_file);
- } catch (Glib::FileError) { }
- U32 serial(0);
- if(!v_key_check(key.c_str(),&serial,0xdeadbeef))
- {
- while(!v_key_check(key.c_str(),&serial,0xdeadbeef))
- {
- key.clear();
-
- if(!App::dialog_entry(
- _("Synfig Studio Authentication"),
- _("Please enter your license key below. You will not\nbe able to use this software without a valid license key."),
- key
- ))
- throw String("No License");
- }
-
- FILE* file=fopen(license_file.c_str(),"w");
- if(file)
- {
- fprintf(file,"%s",key.c_str());
- fclose(file);
- }
- else
- synfig::error("Unable to save license key!");
- }
- synfig::info("License Authenticated -- Serial #%05d",serial);
- return serial;
-#else
- return 1;
-#endif
-}
-
/*
void
studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
{
ui_manager->insert_action_group(group,0);
return;
- DEBUGPOINT();
std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
- DEBUGPOINT();
for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
{
- DEBUGPOINT();
if(*iter && (*iter)->get_name()!="menus")
{
synfig::info("Removing action group "+(*iter)->get_name());
ui_manager->remove_action_group(*iter);
}
}
- DEBUGPOINT();
ui_manager->insert_action_group(group,0);
- DEBUGPOINT();
for(;!prev_groups.empty();prev_groups.pop_front())
{
if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
ui_manager->insert_action_group(prev_groups.front(),1);
}
- DEBUGPOINT();
}
*/
class Preferences : public synfigapp::Settings
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;
}
};
Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
- menus_action_group->add( Gtk::Action::create("menu-file", "_File") );
- menus_action_group->add( Gtk::Action::create("menu-edit", "_Edit") );
- menus_action_group->add( Gtk::Action::create("menu-view", "_View") );
- menus_action_group->add( Gtk::Action::create("menu-canvas", "_Canvas") );
- 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-layer-new", "New Layer") );
- menus_action_group->add( Gtk::Action::create("menu-keyframe", "Keyframe") );
- menus_action_group->add( Gtk::Action::create("menu-group", "Group") );
- menus_action_group->add( Gtk::Action::create("menu-state", "State") );
- menus_action_group->add( Gtk::Action::create("menu-toolbox", "Toolbox") );
+ menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
+ menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
+ menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
+ menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
+ 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")) );
+ menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
+ menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
// Add the synfigapp actions...
synfigapp::Action::Book::iterator iter;
DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
+ DEFINE_ACTION("new", Gtk::Stock::NEW);
DEFINE_ACTION("open", Gtk::Stock::OPEN);
DEFINE_ACTION("save", Gtk::Stock::SAVE);
DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
DEFINE_ACTION("sound", _("Sound File"));
DEFINE_ACTION("options", _("Options"));
- DEFINE_ACTION("close", _("Close"));
+ DEFINE_ACTION("close", _("Close View"));
+ DEFINE_ACTION("close-document", _("Close Document"));
+ DEFINE_ACTION("quit", Gtk::Stock::QUIT);
DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
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("pause", _("Pause"));
DEFINE_ACTION("stop", _("Stop"));
DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
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"));
" </popup>"
" <popup name='menu-main' action='menu-main'>"
" <menu action='menu-file'>"
+" <menuitem action='new' />"
+" <menuitem action='open' />"
" <menuitem action='save' />"
" <menuitem action='save-as' />"
" <menuitem action='revert' />"
" <separator name='bleh04'/>"
" <menuitem action='options' />"
" <menuitem action='close' />"
+" <menuitem action='close-document' />"
+" <menuitem action='quit' />"
" </menu>"
" <menu action='menu-edit'>"
" <menuitem action='undo'/>"
" <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'/>"
+//" <menuitem action='pause'/>"
" <menuitem action='stop'/>"
" <menuitem action='dialog-flipbook'/>"
" <separator name='bleh09'/>"
}
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");
App::App(int *argc, char ***argv):
Gtk::Main(argc,argv),
- IconControler(etl::dirname((*argv)[0]))
+ IconController(etl::dirname((*argv)[0]))
{
app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
- int serial_;
- serial_=check_license(app_base_path_);
-
ui_interface_=new GlobalUIInterface();
gdk_rgb_init();
- Glib::thread_init();
+ // don't call thread_init() if threads are already initialized
+ // on some machines bonobo_init() initialized threads before we get here
+ if (!g_thread_supported())
+ Glib::thread_init();
distance_system=Distance::SYSTEM_UNITS;
ipc=new IPC();
- try
+ if(!SYNFIG_CHECK_VERSION())
{
- if(!SYNFIG_CHECK_VERSION())
- {
cerr<<"FATAL: Synfig Version Mismatch"<<endl;
dialog_error_blocking("Synfig Studio",
"This copy of Synfig Studio was compiled against a\n"
"different version of libsynfig than what is currently\n"
"installed. Synfig Studio will now abort. Try downloading\n"
"the latest version from the Synfig website at\n"
- "http://www.synfig.com/ "
+ "http://synfig.org/Download"
);
throw 40;
- }
- }
- catch(synfig::SoftwareExpired)
- {
- cerr<<"FATAL: Software Expired"<<endl;
- dialog_error_blocking("Synfig Studio",
- "This copy of Synfig Studio has expired.\n"
- "Please erase this copy, or download and\n"
- "install the latest copy from the Synfig\n"
- "website at http://www.synfig.com/ ."
- );
- throw 39;
}
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)); }
catch(...)
{
- get_ui_interface()->error("Failed to initialize synfig!");
+ get_ui_interface()->error(_("Failed to initialize synfig!"));
throw;
}
try
{
- studio_init_cb.task("Init UI Manager...");
+ studio_init_cb.task(_("Init UI Manager..."));
App::ui_manager_=studio::UIManager::create();
init_ui_manager();
- studio_init_cb.task("Init Dock Manager...");
+ studio_init_cb.task(_("Init Dock Manager..."));
dock_manager=new studio::DockManager();
- studio_init_cb.task("Init State Manager...");
+ studio_init_cb.task(_("Init State Manager..."));
state_manager=new StateManager();
- studio_init_cb.task("Init Toolbox...");
+ studio_init_cb.task(_("Init Toolbox..."));
toolbox=new studio::Toolbox();
- studio_init_cb.task("Init Tool Options...");
+ 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);
- studio_init_cb.task("Init History...");
+ studio_init_cb.task(_("Init History..."));
dock_history=new studio::Dock_History();
dock_manager->register_dockable(*dock_history);
- studio_init_cb.task("Init Canvases...");
+ studio_init_cb.task(_("Init Canvases..."));
dock_canvases=new studio::Dock_Canvases();
dock_manager->register_dockable(*dock_canvases);
- studio_init_cb.task("Init Keyframes...");
+ studio_init_cb.task(_("Init Keyframes..."));
dock_keyframes=new studio::Dock_Keyframes();
dock_manager->register_dockable(*dock_keyframes);
- studio_init_cb.task("Init Layers...");
+ studio_init_cb.task(_("Init Layers..."));
dock_layers=new studio::Dock_Layers();
dock_manager->register_dockable(*dock_layers);
- studio_init_cb.task("Init Params...");
+ studio_init_cb.task(_("Init Params..."));
dock_params=new studio::Dock_Params();
dock_manager->register_dockable(*dock_params);
- studio_init_cb.task("Init MetaData...");
+ studio_init_cb.task(_("Init MetaData..."));
dock_meta_data=new studio::Dock_MetaData();
dock_manager->register_dockable(*dock_meta_data);
- studio_init_cb.task("Init Children...");
+ studio_init_cb.task(_("Init Children..."));
dock_children=new studio::Dock_Children();
dock_manager->register_dockable(*dock_children);
- studio_init_cb.task("Init Info...");
+ studio_init_cb.task(_("Init Info..."));
dock_info = new studio::Dock_Info();
dock_manager->register_dockable(*dock_info);
- studio_init_cb.task("Init Navigator...");
+ studio_init_cb.task(_("Init Navigator..."));
dock_navigator = new studio::Dock_Navigator();
dock_manager->register_dockable(*dock_navigator);
- studio_init_cb.task("Init Timetrack...");
+ studio_init_cb.task(_("Init Timetrack..."));
dock_timetrack = new studio::Dock_Timetrack();
dock_manager->register_dockable(*dock_timetrack);
- studio_init_cb.task("Init Curve Editor...");
+ studio_init_cb.task(_("Init Curve Editor..."));
dock_curves = new studio::Dock_Curves();
dock_manager->register_dockable(*dock_curves);
- studio_init_cb.task("Init Layer Groups...");
+ studio_init_cb.task(_("Init Layer Groups..."));
dock_layer_groups = new studio::Dock_LayerGroups();
dock_manager->register_dockable(*dock_layer_groups);
- studio_init_cb.task("Init Color Dialog...");
+ studio_init_cb.task(_("Init Color Dialog..."));
dialog_color=new studio::Dialog_Color();
- studio_init_cb.task("Init Gradient Dialog...");
+ studio_init_cb.task(_("Init Gradient Dialog..."));
dialog_gradient=new studio::Dialog_Gradient();
- studio_init_cb.task("Init DeviceTracker...");
+ studio_init_cb.task(_("Init DeviceTracker..."));
device_tracker=new studio::DeviceTracker();
- studio_init_cb.task("Init Tools...");
+ 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);
+ if(!getenv("SYNFIG_DISABLE_WIDTH" )) state_manager->add_state(&state_width); // Enabled since 0.61.09
- // Disabled by default - it doesn't work properly?
- if(getenv("SYNFIG_ENABLE_WIDTH" )) state_manager->add_state(&state_width);
-
- studio_init_cb.task("Init ModPalette...");
+ 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...");
+ studio_init_cb.task(_("Init Setup Dialog..."));
dialog_setup=new studio::Dialog_Setup();
- studio_init_cb.task("Init Input Dialog...");
+ studio_init_cb.task(_("Init Input Dialog..."));
dialog_input=new Gtk::InputDialog();
dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
- studio_init_cb.task("Init auto recovery...");
+ studio_init_cb.task(_("Init auto recovery..."));
auto_recover=new AutoRecover();
studio_init_cb.amount_complete(9250,10000);
- studio_init_cb.task("Loading Settings...");
+ studio_init_cb.task(_("Loading Settings..."));
load_settings();
- studio_init_cb.task("Checking auto-recover...");
+ studio_init_cb.task(_("Checking auto-recover..."));
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,
for(;*argc>=1;(*argc)--)
if((*argv)[*argc] && (*argv)[*argc][0]!='-')
{
- studio_init_cb.task("Loading files...");
- about_window.hide();
+ studio_init_cb.task(_("Loading files..."));
+ splash_screen.hide();
open((*argv)[*argc]);
- about_window.show();
+ opened_any = true;
+ splash_screen.show();
}
- studio_init_cb.task("Done.");
+ // 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);
toolbox->present();
}
+ catch(String x)
+ {
+ get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
+ }
catch(...)
{
get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
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 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)
+App::add_recent_file(const std::string &file_name, const std::string &window_size)
{
std::string filename(file_name);
if(basename(filename)[0]=='.')
return;
- // If we aren't an absolute path, turn outselves into one
+ // If we aren't an absolute path, turn ourselves into one
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.1.comp_selector","1");
- synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
- synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
- synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
- synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
- synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
- synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
- synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
- synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
- 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");
- synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
+ reset_initial_window_configuration();
}
}
setlocale(LC_NUMERIC,old_locale);
}
}
+void
+App::reset_initial_window_configuration()
+{
+ synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
+ synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
+ synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
+ synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
+ synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
+ synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
+ synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
+ synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
+ synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
+ 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::shutdown_request(GdkEventAny*)
{
if(shutdown_in_progress)return;
- get_ui_interface()->task("Quit Request");
+ get_ui_interface()->task(_("Quit Request"));
if(Busy::count)
{
- dialog_error_blocking("Cannot quit!","Tasks are currently running.\nPlease cancel the current tasks and try again");
+ dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
return;
}
Gtk::Main::quit();
auto_recover->normal_shutdown();
- get_ui_interface()->task("Quit Request sent");
+ get_ui_interface()->task(_("Quit Request sent"));
}
void
#endif
bool
-App::dialog_open_file(const std::string &title, std::string &filename)
+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());
+
#ifdef USE_WIN32_FILE_DIALOGS
static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
#else
synfig::String prev_path;
- if(!_preferences.get_value("curr_path",prev_path))
- prev_path=".";
+
+ if(!_preferences.get_value(preference, prev_path))
+ prev_path = ".";
+
prev_path = absolute_path(prev_path);
- Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_OPEN);
+ Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
+
dialog->set_current_folder(prev_path);
dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
- if(!filename.empty())
- if (is_absolute_path(filename))
- dialog->set_filename(filename);
- else
- dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
- if(dialog->run()==GTK_RESPONSE_ACCEPT) {
- filename=dialog->get_filename();
+
+ if (filename.empty())
+ dialog->set_filename(prev_path);
+ else if (is_absolute_path(filename))
+ dialog->set_filename(filename);
+ else
+ dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
+
+ 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());
+ _preferences.set_value(preference, dirname(filename));
delete dialog;
return true;
}
+
delete dialog;
return false;
+
/*
GtkWidget *ok;
if(val==1)
{
filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
- _preferences.set_value("curr_path",dirname(filename));
+ _preferences.set_value(preference,dirname(filename));
}
else
{
}
bool
-App::dialog_save_file(const std::string &title, std::string &filename)
+App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
{
-#ifdef USE_WIN32_FILE_DIALOGS
+ // 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") ;
GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
if(GetSaveFileName(&ofn))
{
filename=szFilename;
+ _preferences.set_value(preference,dirname(filename));
return true;
}
return false;
#else
synfig::String prev_path;
- if(!_preferences.get_value("curr_path",prev_path))
+
+ if(!_preferences.get_value(preference, prev_path))
prev_path=".";
+
prev_path = absolute_path(prev_path);
- Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
+ Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
+
dialog->set_current_folder(prev_path);
dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
- if(!filename.empty())
- if (is_absolute_path(filename))
- dialog->set_filename(filename);
- else
- dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
- if(dialog->run()==GTK_RESPONSE_ACCEPT) {
- filename=dialog->get_filename();
- delete dialog;
- return true;
- }
- delete dialog;
- return false;
-// return dialog_open_file(title, filename);
-#endif
-}
-
-bool
-App::dialog_saveas_file(const std::string &title, std::string &filename)
-{
-#if USE_WIN32_FILE_DIALOGS
- static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
-
- GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
- HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
- HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
- ofn.lStructSize=sizeof(OPENFILENAME);
- ofn.hwndOwner = hWnd;
- ofn.hInstance = hInstance;
- ofn.lpstrFilter = szFilter;
-// ofn.lpstrCustomFilter=NULL;
-// ofn.nMaxCustFilter=0;
-// ofn.nFilterIndex=0;
-// ofn.lpstrFile=NULL;
- ofn.nMaxFile=MAX_PATH;
-// ofn.lpstrFileTitle=NULL;
-// ofn.lpstrInitialDir=NULL;
-// ofn.lpstrTitle=NULL;
- ofn.Flags=OFN_OVERWRITEPROMPT;
-// ofn.nFileOffset=0;
-// ofn.nFileExtension=0;
- ofn.lpstrDefExt=TEXT("sif");
-// ofn.lCustData = 0l;
- ofn.lpfnHook=NULL;
-// ofn.lpTemplateName=NULL;
-
- CHAR szFilename[MAX_PATH];
- CHAR szTitle[500];
- strcpy(szFilename,filename.c_str());
- strcpy(szTitle,title.c_str());
-
- ofn.lpstrFile=szFilename;
- ofn.lpstrFileTitle=szTitle;
-
- if(GetSaveFileName(&ofn))
+ Widget_Enum *file_type_enum = 0;
+ if (preference == ANIMATION_DIR_PREFERENCE)
{
- filename=szFilename;
- return true;
+ 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);
}
- return false;
-#else
- synfig::String prev_path;
- if(!_preferences.get_value("curr_path",prev_path))
- prev_path=".";
- prev_path = absolute_path(prev_path);
- Gtk::FileChooserDialog *dialog=new Gtk::FileChooserDialog(title,Gtk::FILE_CHOOSER_ACTION_SAVE);
- dialog->set_current_folder(prev_path);
- dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- dialog->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
- if(!filename.empty())
+ if (filename.empty())
+ dialog->set_filename(prev_path);
+ else
+ {
+ std::string full_path;
if (is_absolute_path(filename))
- dialog->set_filename(filename);
+ full_path = filename;
else
- dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
- if(dialog->run()==GTK_RESPONSE_ACCEPT) {
- filename=dialog->get_filename();
+ full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
+
+ // select the file if it exists
+ dialog->set_filename(full_path);
+
+ // if the file doesn't exist, put its name into the filename box
+ struct stat s;
+ if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
+ dialog->set_current_name(basename(filename));
+ }
+
+ 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());
+ _preferences.set_value(preference, dirname(filename));
delete dialog;
return true;
}
+
delete dialog;
return false;
-// return dialog_open_file(title, filename);
#endif
}
void
App::dialog_not_implemented()
{
- Gtk::MessageDialog dialog("Feature not available", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
- dialog.set_secondary_text("Sorry, this feature has not yet been implemented.");
+ Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
+ dialog.set_secondary_text(_("Sorry, this feature has not yet been 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<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)
return open_as(filename,filename);
}
+// this is called from autorecover.cpp:
+// App::open_as(get_shadow_file_name(filename),filename)
+// other than that, 'filename' and 'as' are the same
bool
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;
- 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)
{
return false;
}
- _preferences.set_value("curr_path",dirname(as));
-
return true;
}
App::new_instance()
{
handle<synfig::Canvas> canvas=synfig::Canvas::create();
- canvas->set_name(strprintf("Untitled%d",Instance::get_count()));
- String file_name(strprintf("untitled%d.sif",Instance::get_count()));
+ 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);
- Instance::create(canvas)->find_canvas_view(canvas)->canvas_properties.present();
+ handle<Instance> instance = Instance::create(canvas);
+
+ 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))
+ while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
{
// If the filename still has wildcards, then we should
// continue looking for the file we want
}
etl::loose_handle<Instance>
-App::get_instance(Canvas::Handle canvas)
+App::get_instance(etl::handle<synfig::Canvas> canvas)
{
if(!canvas) return 0;
canvas=canvas->get_root();
void
App::dialog_about()
{
- (new class About())->show();
+ if(about)
+ about->show();
}
void