Blob Blame Raw


#include "exportpanel.h"

#include <QtGlobal>

// Tnz6 includes
#include "tapp.h"
#include "moviegenerator.h"
#include "menubarcommandids.h"
#include "fileselection.h"
#include "iocommand.h"
#include "filebrowser.h"
#include "flipbook.h"
#include "formatsettingspopups.h"
#include "fileviewerpopup.h"

// TnzQt includes
#include "toonzqt/icongenerator.h"
#include "toonzqt/menubarcommand.h"
#include "toonzqt/gutil.h"
#include "toonzqt/dvdialog.h"

// TnzLib includes
#include "toonz/tscenehandle.h"
#include "toonz/tcolumnhandle.h"
#include "toonz/txsheethandle.h"
#include "toonz/screensavermaker.h"
#include "toonz/toonzscene.h"
#include "toonz/tcamera.h"
#include "toonz/sceneproperties.h"
#include "toonz/onionskinmask.h"
#include "toonz/preferences.h"
#include "toutputproperties.h"

// TnzBase includes
#include "trasterfx.h"
#include "tenv.h"

// TnzCore includes
#include "timage_io.h"
#include "tfiletype.h"
#include "tstream.h"
#include "tconvert.h"
#include "tsystem.h"
#include "tiio.h"

// Qt includes
#include <QDrag>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QDragLeaveEvent>
#include <QUrl>
#include <QProgressDialog>
#include <QCheckBox>
#include <QPushButton>
#include <QLayout>
#include <QComboBox>
#include <QBoxLayout>
#include <QApplication>
#include <QBuffer>
#include <QPainter>
#include <QMenu>
#include <QAction>
#include <QMainWindow>
#include <QMimeData>
#include <QLabel>

//=============================================================================
// RenderLocker
//-----------------------------------------------------------------------------

class RenderLocker
{
	bool &m_rendering;

public:
	RenderLocker(bool &rendering) : m_rendering(rendering) { m_rendering = true; }
	~RenderLocker() { m_rendering = false; }
};

//=============================================================================
//
//-----------------------------------------------------------------------------
RenderController::RenderController()
	: m_progressDialog(0), m_frame(0), m_rendering(false), m_cancelled(false), m_properties(0), m_movieExt("mov"), m_useMarkers(false)
{
	m_properties = new TOutputProperties();
}

//-----------------------------------------------------------------------------

RenderController::~RenderController()
{
}

//-----------------------------------------------------------------------------

void RenderController::setUseMarkers(bool useMarkers)
{
	m_useMarkers = useMarkers;
}

//-----------------------------------------------------------------------------

void RenderController::setMovieExt(string ext)
{
	m_movieExt = ext;
}

//-----------------------------------------------------------------------------

bool RenderController::addScene(MovieGenerator &g, ToonzScene *scene)
{
	int frameCount = scene->getFrameCount();
	if (frameCount < 0)
		return false;
	int r0 = 0, r1 = frameCount - 1, step = 0;
	if (m_useMarkers) {
		int r0M, r1M, step;
		scene->getProperties()->getPreviewProperties()->getRange(r0M, r1M, step);
		if (r0M <= r1M) {
			r0 = r0M;
			r1 = r1M;
		}
	}
	if (r1 < r0)
		return false;
	g.setBackgroundColor(scene->getProperties()->getBgColor());
	g.addScene(*scene, r0, r1);
	return true;
}

//-----------------------------------------------------------------------------

bool RenderController::onFrameCompleted(int frameCount)
{
	if (m_cancelled) {
		m_cancelled = false;
		return false;
	}

	++m_frame;
	m_progressDialog->setValue(m_frame);
	qApp->processEvents();
	return true;
}

//-----------------------------------------------------------------------------

int RenderController::computeClipFrameCount(const TFilePath &clipPath, bool useMarkers, int *frameOffset)
{
	if (frameOffset)
		*frameOffset = 0;

	ToonzScene scene;
	scene.load(clipPath);
	if (useMarkers) {
		int r0, r1, step;
		scene.getProperties()->getPreviewProperties()->getRange(r0, r1, step);
		if (r1 >= r0) {
			if (frameOffset)
				*frameOffset = r0;
			return r1 - r0 + 1;
		}
	}
	return scene.getFrameCount();
}

//-----------------------------------------------------------------------------

int RenderController::computeTotalFrameCount(const std::vector<TFilePath> &clipList, bool useMarkers)
{
	int count = 0;
	int i;
	for (i = 0; i < (int)clipList.size(); i++)
		count += computeClipFrameCount(clipList[i], useMarkers);
	return count;
}

//-----------------------------------------------------------------------------

void RenderController::myCancel()
{
	m_cancelled = true;
}

//-----------------------------------------------------------------------------

void RenderController::generateMovie(TFilePath outPath, bool emitSignal)
{
	if (outPath == TFilePath())
		return;
	if (m_clipList.empty())
		return;

	//verifico che il "generatore" sia libero.
	if (m_rendering)
		return;
	m_cancelled = false;

	RenderLocker locker(m_rendering);

	if (outPath.getName() == "")
		outPath = outPath.withName("untitled");

	int sceneCount = (int)m_clipList.size();
	if (sceneCount < 1)
		return; // non dovrebbe succedere mai

	//Risoluzione e Settings
	TDimension resolution(0, 0);
	TFilePath fp;
	TFilePath firstClipPath = fp = m_clipList[0];
	int sceneIndex;

	try {
		getMovieProperties(firstClipPath, resolution);

		for (sceneIndex = 1; sceneIndex < sceneCount; sceneIndex++) {
			TDimension testResolution(0, 0);
			fp = m_clipList[sceneIndex];
			getMovieProperties(fp, testResolution);
			if (testResolution != resolution) {
				/*wstring text = L"The ";
        text += fp.getLevelNameW();
        text += L" scene has a different resolution from the ";
        text += firstClipPath.getLevelNameW();
        text += L" scene.\nThe output result may differ from what you expect. What do you want to do?";*/
				QString text = tr("The %1  scene has a different resolution from the %2 scene.\n \
                          The output result may differ from what you expect. What do you want to do?")
								   .arg(QString::fromStdWString(fp.getLevelNameW()))
								   .arg(QString::fromStdWString(firstClipPath.getLevelNameW()));
				int ret = DVGui::MsgBox(text, tr("Continue"), tr("Cancel"));
				if (ret == 2)
					return;
				else
					break;
			}
		}
	} catch (TException &e) {
		QString msg;
		msg = QObject::tr("There were problems loading the scene %1.\n Some files may be missing.").arg(QString::fromStdWString(fp.getWideString()));

		DVGui::warning(msg);
		return;
	} catch (...) {
		QString msg = QObject::tr("There were problems loading the scene %1.\n Some files may be missing.").arg(QString::fromStdWString(fp.getWideString()));

		DVGui::warning(msg);
		return;
	}

	//Inizializzo la progressBar
	DVGui::ProgressDialog progress(tr("Exporting ..."), tr("Abort"), 0, 1, TApp::instance()->getMainWindow());
	progress.setWindowModality(Qt::WindowModal);
	progress.setWindowTitle(tr("Exporting"));
	progress.setValue(0);
	progress.show();
	connect(&progress, SIGNAL(canceled()), this, SLOT(myCancel()));
	qApp->processEvents();
	m_progressDialog = &progress;
	m_frame = 0;

	int totalFrameCount = computeTotalFrameCount(m_clipList, m_useMarkers);
	progress.setMaximum(totalFrameCount);

	try {
		//Inizializzo il movieGenerator
		MovieGenerator movieGenerator(outPath, resolution, *m_properties, m_useMarkers);
		movieGenerator.setListener(this);

		OnionSkinMask osMask; // = app->getOnionSkinMask(false);
		if (!osMask.isEmpty() && osMask.isEnabled())
			movieGenerator.setOnionSkin(TApp::instance()->getCurrentColumn()->getColumnIndex(), osMask);
		movieGenerator.setSceneCount(sceneCount);

		//Aggiungo i soundtrack al movieGenerator
		for (sceneIndex = 0; sceneIndex < sceneCount; sceneIndex++) {
			TFilePath fp = m_clipList[sceneIndex];
			int frameOffset;
			int sceneFrames = computeClipFrameCount(fp, m_useMarkers, &frameOffset);
			if (sceneFrames == 0)
				continue;
			ToonzScene scene;
			scene.load(fp);
			try {
				movieGenerator.addSoundtrack(scene, frameOffset, sceneFrames);
			} catch (const TException&) {
				QString text = tr("The %1 scene contains an audio file with different characteristics from the one used in the first exported scene.\nThe audio file will not be included in the rendered clip.").arg(QString::fromStdWString(fp.getLevelNameW()));
				DVGui::warning(text);
			}
		}

		//Aggiungo le scene al movieGenerator
		for (sceneIndex = 0; sceneIndex < sceneCount; sceneIndex++) {
			TFilePath fp = m_clipList[sceneIndex];
			int sceneFrames = computeClipFrameCount(fp, m_useMarkers);
			if (sceneFrames == 0)
				continue;
			ToonzScene scene;
			scene.load(fp);
			addScene(movieGenerator, &scene);
		}

		movieGenerator.close();
		if (m_frame >= totalFrameCount && Preferences::instance()->isGeneratedMovieViewEnabled()) {
			if (Preferences::instance()->isDefaultViewerEnabled() &&
				(outPath.getType() == "mov" || outPath.getType() == "avi" || outPath.getType() == "3gp")) {
				QString name = QString::fromStdString(outPath.getName());

				if (!TSystem::showDocument(outPath)) {
					QString msg(QObject::tr("It is not possible to display the file %1: no player associated with its format").arg(QString::fromStdWString(outPath.withoutParentDir().getWideString())));
					DVGui::warning(msg);
				}
			} else {
				int r0 = 1, r1 = totalFrameCount, step = 1;

				const TRenderSettings rs = m_properties->getRenderSettings();

				double timeStretchFactor;
				timeStretchFactor = (double)rs.m_timeStretchTo / rs.m_timeStretchFrom;
				int numFrames = troundp((r1 - r0 + 1) * timeStretchFactor);
				r0 = troundp(r0 * timeStretchFactor);
				r1 = r0 + numFrames - 1;

				TXsheet::SoundProperties *prop = new TXsheet::SoundProperties();
				prop->m_frameRate = m_properties->getFrameRate();
				TSoundTrack *snd = TApp::instance()->getCurrentXsheet()->getXsheet()->makeSound(prop);

				::viewFile(outPath, 1, totalFrameCount, step, rs.m_shrinkX, snd, 0);
			}
		}
	} catch (TException &) {
		return;
	} catch (...) {
		return;
	}
	// per sicurezza
	progress.setValue(totalFrameCount);

	if (emitSignal)
		emit movieGenerated();
}

//-----------------------------------------------------------------------------

void RenderController::getMovieProperties(
	const TFilePath &scenePath,
	TDimension &resolution)
{
	if (scenePath == TFilePath())
		return;
	ToonzScene scene;
	scene.loadNoResources(scenePath);
	resolution = scene.getCurrentCamera()->getRes();
}

//-----------------------------------------------------------------------------

TFilePath RenderController::getClipPath(int index) const
{
	assert(0 <= index && index < getClipCount());
	return m_clipList[index];
}

//-----------------------------------------------------------------------------

void RenderController::setClipPath(int index, const TFilePath &path)
{
	assert(0 <= index && index < getClipCount());
	m_clipList[index] = path;
}

//-----------------------------------------------------------------------------

void RenderController::addClipPath(const TFilePath &path)
{
	m_clipList.push_back(path);
}

//-----------------------------------------------------------------------------

void RenderController::insertClipPath(int index, const TFilePath &path)
{
	assert(0 <= index && index <= getClipCount());
	m_clipList.insert(m_clipList.begin() + index, path);
}

//-----------------------------------------------------------------------------

void RenderController::removeClipPath(int index)
{
	assert(0 <= index && index < getClipCount());
	m_clipList.erase(m_clipList.begin() + index);
}

//-----------------------------------------------------------------------------

void RenderController::resetClipList()
{
	m_clipList.clear();
}

//=============================================================================
//
// ClipListViewer
//
//-----------------------------------------------------------------------------

ClipListViewer::ClipListViewer(QWidget *parent)
	: DvItemViewer(parent), m_dropInsertionPoint(-1), m_loadSceneFromExportPanel(false)
{
	resetList();
	setModel(this);
	setAcceptDrops(true);
	getPanel()->enableSingleColumn(true);
}

//-----------------------------------------------------------------------------

const char *ClipListViewer::m_mimeFormat = "application/vnd.toonz.cliplist";

//-----------------------------------------------------------------------------

RenderController *ClipListViewer::getController() const
{
	return RenderController::instance();
}

//-----------------------------------------------------------------------------

void ClipListViewer::resetList()
{
	if (!m_loadSceneFromExportPanel)
		getController()->resetClipList();
}

//-----------------------------------------------------------------------------

void ClipListViewer::removeSelectedClips()
{
	if (getPanel()->getSelection()->isEmpty())
		return;
	int i;
	for (i = getController()->getClipCount() - 1; i >= 0; i--) {
		if (getPanel()->getSelection()->isSelected(i))
			getController()->removeClipPath(i);
	}
	updateContentSize();
	getPanel()->getSelection()->selectNone();
	getPanel()->update();
}

//-----------------------------------------------------------------------------

void ClipListViewer::moveSelectedClips(int dstIndex)
{
	std::vector<TFilePath> selectedClips;
	int i;
	for (i = getController()->getClipCount() - 1; i >= 0; i--)
		if (getPanel()->getSelection()->isSelected(i)) {
			if (i < dstIndex)
				dstIndex--;
			selectedClips.push_back(getController()->getClipPath(i));
			getController()->removeClipPath(i);
		}
	if (dstIndex < 0)
		dstIndex = 0;
	else if (dstIndex > getController()->getClipCount())
		dstIndex = getController()->getClipCount();
	for (i = 0; i < (int)selectedClips.size(); i++)
		getController()->insertClipPath(dstIndex + i, selectedClips[i]);
	getPanel()->getSelection()->selectNone();
	getPanel()->update();
}

//-----------------------------------------------------------------------------

void ClipListViewer::getSelectedClips(std::vector<TFilePath> &selectedClips)
{
	int i;
	for (i = 0; i < getController()->getClipCount(); i++)
		if (getPanel()->getSelection()->isSelected(i))
			selectedClips.push_back(getController()->getClipPath(i));
}

//-----------------------------------------------------------------------------

QByteArray packStringList(const QStringList &lst)
{
	QByteArray ba;
	QDataStream ds(&ba, QIODevice::WriteOnly);
	ds << (qint32)lst.size();
	int i;
	for (i = 0; i < lst.size(); i++)
		ds << lst.at(i);
	return ba;
}

QStringList unpackStringList(const QByteArray &ba)
{
	QStringList lst;
	QDataStream ds(ba);
	qint32 n = 0;
	ds >> n;
	int i;
	for (i = 0; i < n; i++) {
		QString s;
		ds >> s;
		lst.append(s);
	}
	return lst;
}

//-----------------------------------------------------------------------------

void ClipListViewer::startDragDrop()
{
	std::vector<TFilePath> selectedClips;
	getSelectedClips(selectedClips);
	if (selectedClips.empty())
		return;

	QStringList slist;
	int i;
	for (i = 0; i < (int)selectedClips.size(); i++)
		slist << QString::fromStdWString(selectedClips[i].getWideString());

	QMimeData *mimeData = new QMimeData;
	mimeData->setData(m_mimeFormat, packStringList(slist));
	QDrag *drag = new QDrag(this);
	drag->setMimeData(mimeData);
	Qt::DropAction dropAction = drag->exec(Qt::MoveAction | Qt::CopyAction);
}

//-----------------------------------------------------------------------------

int ClipListViewer::getItemCount() const
{
	return getController()->getClipCount();
}

//-----------------------------------------------------------------------------

QVariant ClipListViewer::getItemData(int index, DataType dataType, bool isSelected)
{
	if (index < 0 || index >= getController()->getClipCount())
		return QVariant();
	TFilePath fp = getController()->getClipPath(index);
	ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();

	if (dataType == Name)
		return QString::fromStdString(fp.getName());
	else if (dataType == ToolTip || dataType == FullPath)
		return QString::fromStdWString(fp.getWideString());
	else if (dataType == Thumbnail) {
		QSize iconSize = getPanel()->getIconSize();
		QPixmap icon = IconGenerator::instance()->getIcon(fp);
		return scalePixmapKeepingAspectRatio(icon, iconSize, Qt::transparent);
	}

	return QVariant();
}

//-----------------------------------------------------------------------------

QMenu *ClipListViewer::getContextMenu(QWidget *parent, int index)
{
	QMenu *menu = new QMenu(parent);
	CommandManager *cm = CommandManager::instance();
	const std::set<int> &selectedIndices = getPanel()->getSelectedIndices();
	if (selectedIndices.size() == 1) {
		int index = *selectedIndices.begin();
		if (0 <= index && index < getController()->getClipCount()) {
			QAction *action = new QAction(tr("Load Scene"), menu);
			connect(action, SIGNAL(triggered()), this, SLOT(loadScene()));
			menu->addAction(action);
		}
	}
	menu->addAction(cm->getAction(MI_Clear));
	return menu;
}

//-----------------------------------------------------------------------------

void ClipListViewer::setDropInsertionPoint(const QPoint &pos)
{
	int old = m_dropInsertionPoint;
	m_dropInsertionPoint = getItemCount();
	DvItemViewerPanel *panel = getPanel();
	QPoint panelPos = panel->mapFromParent(pos);
	int i;
	for (i = 0; i < getItemCount(); i++) {
		QRect itemRect = getPanel()->index2pos(i);
		int y = (itemRect.bottom() + itemRect.top()) / 2;
		if (panelPos.y() < y) {
			m_dropInsertionPoint = i;
			break;
		}
	}
	if (old != m_dropInsertionPoint)
		getPanel()->update();
}

//-----------------------------------------------------------------------------

void ClipListViewer::dragEnterEvent(QDragEnterEvent *event)
{

	if (event->mimeData()->hasUrls()) {
		foreach (QUrl url, event->mimeData()->urls()) {
			TFilePath fp(url.toLocalFile().toStdString());
			if (fp.getType() != "tnz")
				return;
		}
		setDropInsertionPoint(event->pos());
		event->setDropAction(Qt::CopyAction);
		event->acceptProposedAction();
		update();
	} else if (event->mimeData()->hasFormat(m_mimeFormat)) {
		setDropInsertionPoint(event->pos());
		event->setDropAction(Qt::MoveAction);
		event->acceptProposedAction();
		update();
	}
}

//-----------------------------------------------------------------------------

void ClipListViewer::dragMoveEvent(QDragMoveEvent *event)
{
	int oldDropInsertionPoint = m_dropInsertionPoint;
	setDropInsertionPoint(event->pos());
	if (oldDropInsertionPoint != m_dropInsertionPoint)
		update();
}

//-----------------------------------------------------------------------------

void ClipListViewer::dropEvent(QDropEvent *event)
{
	if (event->mimeData()->hasUrls()) {
		int j = m_dropInsertionPoint;
		if (j < 0)
			j = getItemCount();
		foreach (QUrl url, event->mimeData()->urls()) {
			TFilePath fp(url.toLocalFile().toStdString());
			if (fp.getType() == "tnz")
				getController()->insertClipPath((j++), fp);
		}
		event->setDropAction(Qt::CopyAction);
		event->acceptProposedAction();
	} else if (event->mimeData()->hasFormat(m_mimeFormat) && m_dropInsertionPoint >= 0) {
		moveSelectedClips(m_dropInsertionPoint);
		event->setDropAction(Qt::MoveAction);
		event->acceptProposedAction();
	}

	updateContentSize();
	m_dropInsertionPoint = -1;
	getPanel()->update();
	update();
}

//-----------------------------------------------------------------------------

void ClipListViewer::dragLeaveEvent(QDragLeaveEvent *event)
{
	m_dropInsertionPoint = -1;
	getPanel()->update();
}

//-----------------------------------------------------------------------------

void ClipListViewer::enableSelectionCommands(TSelection *selection)
{
	selection->enableCommand(this, MI_Clear, &ClipListViewer::removeSelectedClips);
}

//-----------------------------------------------------------------------------

void ClipListViewer::draw(QPainter &p)
{
	if (m_dropInsertionPoint >= 0) {
		p.setPen(Qt::black);
		// p.drawLine(0,0,width(),height());
		int y = getPanel()->index2pos(m_dropInsertionPoint).topLeft().y() - 2;
		p.drawLine(10, y, width() - 10, y);
	}
}

//-----------------------------------------------------------------------------

void ClipListViewer::loadScene()
{
	// se non ho selezionato una sola scena, diversa da quella corrente, esco.
	const std::set<int> &selectedIndices = getPanel()->getSelectedIndices();
	if (selectedIndices.size() != 1)
		return;
	int index = *selectedIndices.begin();
	if (!(0 <= index && index < getController()->getClipCount()))
		return;
	// selectedScenePath e' la scena da caricare
	TFilePath selectedScenePath = getController()->getClipPath(index);

	m_loadSceneFromExportPanel = true;

	// se necessario salvo la scena corrente (e le assegno un filepath)
	// se l'utente sceglie "cancel" esco
	if (!IoCmd::saveSceneIfNeeded(tr("Load Scene")))
		return;

	// Nella clip list assegno un path esplicito all'eventuale scena corrente
	// (se la scena corrente non e' stata salvata dall'utente elimino il riferimento)
	ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
	TFilePath scenePath;
	if (!scene->isUntitled())
		scenePath = scene->getScenePath();
	// carico la scena corrente
	IoCmd::loadScene(selectedScenePath);
	m_loadSceneFromExportPanel = false;
}

//=============================================================================
//
// ExportPanel
//
//-----------------------------------------------------------------------------

#if QT_VERSION >= 0x050500
ExportPanel::ExportPanel(QWidget *parent, Qt::WindowFlags flags)
#else
ExportPanel::ExportPanel(QWidget *parent, Qt::WFlags flags)
#endif
	: TPanel(parent), m_clipListViewer(0), m_saveInFileFld(0), m_fileNameFld(0), m_useMarker(0)
{
	setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
	setWindowTitle(tr("Export"));

	setMinimumWidth(270);

	RenderController *renderController = RenderController::instance();

	QFrame *box = new QFrame(this);
	box->setObjectName("exportPanel");
	box->setFrameStyle(QFrame::StyledPanel);
	box->setStyleSheet("#exportPanel { margin: 1px; border: 0px; }");

	QVBoxLayout *mainLayout = new QVBoxLayout();
	mainLayout->setMargin(0);
	mainLayout->setSpacing(0);
	mainLayout->setAlignment(Qt::AlignTop);
//ClipList
	m_clipListViewer = new ClipListViewer(box);
	m_clipListViewer->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding);

	TSceneHandle *sceneHandle = TApp::instance()->getCurrentScene();

	connect(sceneHandle, SIGNAL(sceneSwitched()), this, SLOT(onSceneSwitched()));

	// Settings Box
	QFrame *settingsBox = new QFrame(box);
	settingsBox->setObjectName("settingsBox");
	settingsBox->setFrameStyle(QFrame::StyledPanel);
	QVBoxLayout *settingsLayout = new QVBoxLayout();
	settingsLayout->setMargin(15);
	settingsLayout->setSpacing(5);
	settingsLayout->setAlignment(Qt::AlignTop);

	ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
	std::wstring sceneName = scene->getSceneName();
	TFilePath scenePath = scene->getProperties()->getOutputProperties()->getPath().getParentDir();

	//Label + saveInFileFld
	QHBoxLayout *saveIn = new QHBoxLayout;
	saveIn->setMargin(0);
	saveIn->setSpacing(5);
	m_saveInFileFld = new DVGui::FileField(settingsBox);
	m_saveInFileFld->setPath(QString::fromStdWString(scenePath.getWideString()));
	QLabel *dirLabel = new QLabel(tr("Save in:"));
	dirLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
	dirLabel->setFixedSize(55, m_saveInFileFld->height());
	saveIn->addWidget(dirLabel);
	saveIn->addWidget(m_saveInFileFld);

	//Label + m_fileNameFld
	QHBoxLayout *fileNname = new QHBoxLayout;
	fileNname->setMargin(0);
	fileNname->setSpacing(5);
	m_fileNameFld = new DVGui::LineEdit(QString::fromStdWString(sceneName), settingsBox);
	QLabel *nameLabel = new QLabel(tr("File Name:"));
	nameLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
	nameLabel->setFixedSize(55, m_fileNameFld->height());
	fileNname->addWidget(nameLabel);
	fileNname->addWidget(m_fileNameFld);

	//file formats
	QHBoxLayout *fileFormatLayout = new QHBoxLayout();
	m_fileFormat = new QComboBox();
	QStringList formats;
	TImageWriter::getSupportedFormats(formats, true);
	TLevelWriter::getSupportedFormats(formats, true);
	Tiio::Writer::getSupportedFormats(formats, true);
	formats.sort();

	m_fileFormat->addItems(formats);
	m_fileFormat->setMaximumHeight(DVGui::WidgetHeight);
	connect(m_fileFormat, SIGNAL(currentIndexChanged(const QString &)),
			SLOT(onFormatChanged(const QString &)));
	m_fileFormat->setCurrentIndex(formats.indexOf("mov"));

	QPushButton *fileFormatButton = new QPushButton(QString(tr("Options")));
	fileFormatButton->setFixedSize(60, DVGui::WidgetHeight);
	connect(fileFormatButton, SIGNAL(pressed()), this, SLOT(openSettingsPopup()));
	QLabel *fileFormat = new QLabel(tr("File Format:"));
	fileFormat->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
	fileFormat->setFixedSize(55, fileFormatButton->height());

	fileFormatLayout->addWidget(fileFormat);
	fileFormatLayout->addWidget(m_fileFormat);
	fileFormatLayout->addWidget(fileFormatButton);

// Use Marker checkbox
	m_useMarker = new QCheckBox(tr("Use Markers"), settingsBox);
	m_useMarker->setMinimumHeight(30);
	m_useMarker->setChecked(false);
	connect(m_useMarker, SIGNAL(toggled(bool)), this, SLOT(onUseMarkerToggled(bool)));

	// Export button
	QFrame *exportBox = new QFrame(box);
	exportBox->setFrameStyle(QFrame::StyledPanel);
	exportBox->setObjectName("exportBox");

	QVBoxLayout *exportLayout = new QVBoxLayout();
	QPushButton *exportButton = new QPushButton(tr("Export"), exportBox);
	exportButton->setFixedSize(65, DVGui::WidgetHeight);
	connect(exportButton, SIGNAL(pressed()), this, SLOT(generateMovie()));
	exportLayout->addWidget(exportButton, 0, Qt::AlignCenter);
	exportBox->setLayout(exportLayout);

	settingsLayout->addLayout(saveIn);
	settingsLayout->addLayout(fileNname);
	settingsLayout->addLayout(fileFormatLayout);
	settingsLayout->addWidget(m_useMarker);
	settingsBox->setLayout(settingsLayout);

	if (m_clipListViewer)
		mainLayout->addWidget(m_clipListViewer);
	mainLayout->addWidget(new DVGui::Separator("", this));
	mainLayout->addWidget(settingsBox, 0);
	mainLayout->addWidget(new DVGui::Separator("", this));
	mainLayout->addWidget(exportBox, 0);

	connect(RenderController::instance(), SIGNAL(movieGenerated()), this, SLOT(onMovieGenerated()));

	box->setLayout(mainLayout);
	setWidget(box);
	loadExportSettings();
}

//-----------------------------------------------------------------------------

ExportPanel::~ExportPanel()
{
	saveExportSettings();
}

//-----------------------------------------------------------------------------

void ExportPanel::loadExportSettings()
{
	TFilePath exportPath = TEnv::getConfigDir() + "exportsettings.txt";
	if (!TSystem::doesExistFileOrLevel(exportPath))
		return;
	TIStream is(exportPath);
	std::string tagName;
	try {
		while (is.matchTag(tagName)) {
			if (tagName == "ExportDir") {
				TFilePath outPath;
				is >> outPath;
				m_saveInFileFld->setPath(QString::fromStdWString(outPath.getWideString()));
			} else if (tagName == "ExportFormat") {
				std::string ext;
				is >> ext;
				int index = m_fileFormat->findText(QString::fromStdString(ext));
				m_fileFormat->setCurrentIndex(index);
			} else if (tagName == "FormatSettings") {
				TOutputProperties *outProp = RenderController::instance()->getOutputPropertites();
				std::string ext = m_fileFormat->currentText().toStdString();
				TPropertyGroup *props = outProp->getFileFormatProperties(ext);
				props->loadData(is);
			} else if (tagName == "UseMarkers") {
				int value;
				is >> value;
				m_useMarker->setChecked(value);
			}
			is.closeChild();
		}
	} catch (...) {
	}
}

//-----------------------------------------------------------------------------

void ExportPanel::saveExportSettings()
{
	QString path = m_saveInFileFld->getPath();
	TFilePath outPath(path.toStdWString());

	TFilePath exportPath = TEnv::getConfigDir() + "exportsettings.txt";
	TOStream os(exportPath);
	os.child("ExportDir") << outPath;
	std::string ext = m_fileFormat->currentText().toStdString();
	os.child("ExportFormat") << ext;

	os.openChild("FormatSettings");
	TOutputProperties *outProp = RenderController::instance()->getOutputPropertites();
	TPropertyGroup *props = outProp->getFileFormatProperties(ext);
	props->saveData(os);
	os.closeChild();

	os.child("UseMarkers") << (int)m_useMarker->isChecked();
}

//-----------------------------------------------------------------------------

void ExportPanel::generateMovie()
{
	ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
	std::string ext = RenderController::instance()->getMovieExt();
	QString path = m_saveInFileFld->getPath();
	TFilePath outPath(path.toStdWString());
	outPath = (outPath + m_fileNameFld->text().toStdWString()).withType(ext);
	if (TFileType::getInfo(outPath) == TFileType::RASTER_IMAGE || outPath.getType() == "pct" || outPath.getType() == "pic" || outPath.getType() == "pict") //pct e' un formato"livello" (ha i settings di quicktime) ma fatto di diversi frames
		outPath = outPath.withFrame(TFrameId::EMPTY_FRAME);
	RenderController::instance()->generateMovie(scene->decodeFilePath(outPath));
}

//-----------------------------------------------------------------------------

void ExportPanel::onUseMarkerToggled(bool toggled)
{
	RenderController::instance()->setUseMarkers(toggled);
}

//-----------------------------------------------------------------------------

void ExportPanel::onSceneSwitched()
{
	if (m_clipListViewer) {
		m_clipListViewer->resetList();
		m_clipListViewer->update();
	}
	ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
	m_fileNameFld->setText(QString::fromStdWString(scene->getSceneName()));
}

//-----------------------------------------------------------------------------

void ExportPanel::onFormatChanged(const QString &format)
{
	RenderController::instance()->setMovieExt(format.toStdString());
}

//-----------------------------------------------------------------------------

void ExportPanel::openSettingsPopup()
{
	ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
	if (!scene)
		return;
	std::string ext = RenderController::instance()->getMovieExt();

	TOutputProperties *outProps = RenderController::instance()->getOutputPropertites();
	if (!outProps) {
		//non dovrebbe mai capitare!
		assert(0);
		outProps = new TOutputProperties();
		RenderController::instance()->setOutputPropertites(outProps);
	}

	TPropertyGroup *props = outProps->getFileFormatProperties(ext);
	openFormatSettingsPopup(this, ext, props);
}