Blob Blame Raw
/* === S Y N F I G ========================================================= */
/*!	\file mainwindow.cpp
**	\brief MainWindow
**
**	$Id$
**
**	\legal
**	......... ... 2013 Ivan Mahonin
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
**	General Public License for more details.
**	\endlegal
*/
/* ========================================================================= */

/* === H E A D E R S ======================================================= */

#ifdef USING_PCH
#	include "pch.h"
#else
#ifdef HAVE_CONFIG_H
#	include <config.h>
#endif

#include "mainwindow.h"
#include "canvasview.h"
#include "docks/dockable.h"
#include "docks/dockmanager.h"
#include "docks/dockdroparea.h"

#include <synfigapp/main.h>

#include <gtkmm/menubar.h>
#include <gtkmm/box.h>

#include <gtkmm/inputdialog.h>

#endif

/* === U S I N G =========================================================== */

using namespace std;
using namespace etl;
using namespace synfig;
using namespace studio;

/* === M A C R O S ========================================================= */

#define GRAB_HINT_DATA(y)	{ \
		String x; \
		if(synfigapp::Main::settings().get_value(String("pref.")+y+"_hints",x)) \
		{ \
			set_type_hint((Gdk::WindowTypeHint)atoi(x.c_str()));	\
		} \
	}

/* === G L O B A L S ======================================================= */

/* === P R O C E D U R E S ================================================= */

/* === M E T H O D S ======================================================= */

MainWindow::MainWindow()
{
	set_default_size(600, 400);

	notebook_ = manage(new Gtk::Notebook());

	DockDropArea *dock_area = manage(new DockDropArea(notebook_));
	dock_area->show();

	notebook_->set_action_widget(dock_area, Gtk::PACK_END);
	notebook_->set_scrollable(true);
	notebook_->show();

	class Bin : public Gtk::Bin {
	public:
		Bin() { }
	protected:
		void on_size_allocate(Gtk::Allocation &allocation) {
			Gtk::Bin::on_size_allocate(allocation);
			if (get_child() != NULL)
				get_child()->size_allocate(allocation);
		}
		void on_size_request(Gtk::Requisition *requisition) {
			Gtk::Bin::on_size_request(requisition);
			if (get_child() != NULL && requisition != NULL)
				*requisition = get_child()->size_request();
		}
	};

	Gtk::Bin *bin = manage((Gtk::Bin*)new Bin());
	bin->add(*notebook_);
	bin->show();

	Gtk::VBox *vbox = manage(new Gtk::VBox());

	Gtk::Widget* menubar = App::ui_manager()->get_widget("/menubar-main");
	if (menubar != NULL)
	{
		menubar->show();
		vbox->pack_start(*menubar, false, false, 0);
	}

	vbox->pack_end(*bin, true, true, 0);
	vbox->show();
	add(*vbox);

	add_accel_group(App::ui_manager()->get_accel_group());

	init_menus();
	panels_action_group = Gtk::ActionGroup::create("mainwindow-recentfiles");
	App::ui_manager()->insert_action_group(panels_action_group);

	notebook_->signal_switch_page().connect(
		sigc::mem_fun(*this, &MainWindow::on_switch_page) );

	App::signal_recent_files_changed().connect(
		sigc::mem_fun(*this, &MainWindow::on_recent_files_changed) );

	signal_delete_event().connect(
		sigc::ptr_fun(App::shutdown_request) );

	App::dock_manager->signal_dockable_registered().connect(
		sigc::mem_fun(*this,&MainWindow::on_dockable_registered) );

	GRAB_HINT_DATA("canvas_view");
}

MainWindow::~MainWindow() { }

void MainWindow::create_stock_dialog1()
{
	// TODO:
	//DockDialog* dock_dialog(new DockDialog);
	//dock_dialog->set_contents("canvases history");
	//dock_dialog->set_composition_selector(true);
	//dock_dialog->present();
}
void MainWindow::create_stock_dialog2()
{
	// TODO:
	//DockDialog* dock_dialog(new DockDialog);
	//dock_dialog->set_contents("layers children keyframes | params");
	//dock_dialog->present();
}

void
MainWindow::save_all()
{
	std::list<etl::handle<Instance> >::iterator iter;
	for(iter=App::instance_list.begin();iter!=App::instance_list.end();iter++)
		(*iter)->save();
}

void
MainWindow::show_dialog_input()
{
	App::dialog_input->present();
}

void
MainWindow::init_menus()
{
	Glib::RefPtr<Gtk::ActionGroup> action_group = Gtk::ActionGroup::create("mainwindow");

	// file
	action_group->add( Gtk::Action::create("new", Gtk::Stock::NEW),
		sigc::hide_return(sigc::ptr_fun(&studio::App::new_instance))
	);
	action_group->add( Gtk::Action::create("open", Gtk::Stock::OPEN),
		sigc::hide_return(sigc::bind(sigc::ptr_fun(&studio::App::dialog_open), ""))
	);
	action_group->add( Gtk::Action::create("save-all", Gtk::StockID("synfig-saveall")),
		sigc::ptr_fun(save_all)
	);
	action_group->add( Gtk::Action::create("input-devices", _("Input Devices...")),
		sigc::ptr_fun(&MainWindow::show_dialog_input)
	);
	action_group->add( Gtk::Action::create("setup", _("Setup...")),
		sigc::ptr_fun(&studio::App::show_setup)
	);
	action_group->add( Gtk::Action::create("reset-initial-preferences", _("Reset to default Setup values")),
		sigc::ptr_fun(&studio::App::reset_initial_preferences)
	);
	action_group->add( Gtk::Action::create("quit", Gtk::StockID("gtk-quit"), _("Quit")),
		sigc::hide_return(sigc::ptr_fun(&studio::App::quit))
	);

	// file -> panels
	action_group->add( Gtk::Action::create("panels-vertical", _("Vertical Dock: Canvases, History")),
		sigc::ptr_fun(&MainWindow::create_stock_dialog1)
	);
	action_group->add( Gtk::Action::create("panels-horizontal", _("Horizontal Dock: Layers, Library, Parameters")),
		sigc::ptr_fun(&MainWindow::create_stock_dialog2)
	);
	action_group->add( Gtk::Action::create("panels-reset", _("Reset Windows to Original Layout")),
		sigc::ptr_fun(App::reset_initial_window_configuration)
	);

	// help
	#define URL(action_name,title,url) \
		action_group->add( Gtk::Action::create(action_name, title), \
			sigc::bind(sigc::ptr_fun(&studio::App::open_url),url))
	#define WIKI(action_name,title,page) \
		URL(action_name,title, "http://synfig.org/wiki" + String(page))
	#define SITE(action_name,title,page) \
		URL(action_name,title, "http://synfig.org/cms" + String(page))

	action_group->add( Gtk::Action::create("help", Gtk::Stock::HELP),
		sigc::ptr_fun(studio::App::dialog_help)
	);

	// TRANSLATORS:         | Help menu entry:              | A wiki page:          |
	WIKI("help-tutorials",	_("Tutorials"),					_("/Category:Tutorials"));
	WIKI("help-reference",	_("Reference"),					_("/Category:Reference"));
	WIKI("help-faq",		_("Frequently Asked Questions"),_("/FAQ")				);
	SITE("help-support",	_("Get Support"),				_("/en/support")		);

	action_group->add( Gtk::Action::create("help-about", Gtk::StockID("synfig-about")),
		sigc::ptr_fun(studio::App::dialog_about)
	);

	// TODO: open recent
	//filemenu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Open Recent"),*recent_files_menu));

	App::ui_manager()->insert_action_group(action_group);
}


void
MainWindow::on_recent_files_changed()
{
	Glib::RefPtr<Gtk::ActionGroup> action_group = Gtk::ActionGroup::create("mainwindow-recentfiles");

	int index = 0;
	std::string menu_items;
	for(list<string>::const_iterator i=App::get_recent_files().begin();i!=App::get_recent_files().end();i++)
	{
		std::string raw = basename(*i);
		std::string quoted;
		size_t pos = 0, last_pos = 0;

		// replace _ in filenames by __ or it won't show up in the menu
		for (pos = last_pos = 0; (pos = raw.find('_', pos)) != string::npos; last_pos = pos)
			quoted += raw.substr(last_pos, ++pos - last_pos) + '_';
		quoted += raw.substr(last_pos);

		std::string action_name = strprintf("file-recent-%d", index++);
		menu_items += "<menuitem action='" + action_name +"' />";

		action_group->add( Gtk::Action::create(action_name, quoted),
			sigc::hide_return(sigc::bind(sigc::ptr_fun(&App::open),*i))
		);
	}

	std::string ui_info =
		"<menu action='menu-file'><menu action='menu-open-recent'>"
	  + menu_items
	  + "</menu></menu>";
	std::string ui_info_popup =
		"<ui><popup action='menu-main'>" + ui_info + "</popup></ui>";
	std::string ui_info_menubar =
		"<ui><menubar action='menubar-main'>" + ui_info + "</menubar></ui>";

	App::ui_manager()->insert_action_group(action_group);
	App::ui_manager()->add_ui_from_string(ui_info_popup);
	App::ui_manager()->add_ui_from_string(ui_info_menubar);
}

void
MainWindow::on_dockable_registered(Dockable* dockable)
{
	panels_action_group->add( Gtk::Action::create("panel-" + dockable->get_name(), dockable->get_local_name()),
		sigc::mem_fun(*dockable, &Dockable::present)
	);

	std::string ui_info =
		"<menu action='menu-file'><menu action='menu-panels'>"
	    "<menuitem action='panel-" + dockable->get_name() + "' />"
	    "</menu></menu>";
	std::string ui_info_popup =
		"<ui><popup action='menu-main'>" + ui_info + "</popup></ui>";
	std::string ui_info_menubar =
		"<ui><menubar action='menubar-main'>" + ui_info + "</menubar></ui>";

	App::ui_manager()->add_ui_from_string(ui_info_popup);
	App::ui_manager()->add_ui_from_string(ui_info_menubar);
}

void
MainWindow::on_switch_page(GtkNotebookPage* /* page */, guint page_num)
{
	Gtk::Notebook::PageList::iterator i = App::main_window->notebook().pages().find(page_num);
	if (i == App::main_window->notebook().pages().end())
		App::set_selected_canvas_view(NULL);
	else
		App::set_selected_canvas_view(dynamic_cast<CanvasView*>(i->get_child()));
}

/* === E N T R Y P O I N T ================================================= */