//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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. // // You should have received a copy of the GNU General Public License // along with Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "NstIoLog.hpp" #include "NstIoStream.hpp" #include "NstIoScreen.hpp" #include "NstResourceString.hpp" #include "NstWindowUser.hpp" #include "NstManagerPaths.hpp" #include "NstDialogMovie.hpp" #include "NstManagerAviConverter.hpp" #include "NstManagerMovie.hpp" namespace Nestopia { namespace Managers { Movie::Movie(Emulator& e,Window::Menu& m,const Paths& p) : Manager ( e, m, this, &Movie::OnEmuEvent ), file ( e ), dialog ( new Window::Movie(p) ), paths ( p ) { static const Window::Menu::CmdHandler::Entry commands[] = { { IDM_FILE_MOVIE_FILE, &Movie::OnCmdFile }, { IDM_FILE_MOVIE_RECORD, &Movie::OnCmdRecord }, { IDM_FILE_MOVIE_PLAY, &Movie::OnCmdPlay }, { IDM_FILE_MOVIE_STOP, &Movie::OnCmdStop }, { IDM_FILE_MOVIE_REWIND, &Movie::OnCmdRewind }, { IDM_FILE_MOVIE_FORWARD, &Movie::OnCmdForward }, { IDM_FILE_MOVIE_EXPORT_AVI, &Movie::OnCmdExportAvi } }; menu.Commands().Add( this, commands ); static const Window::Menu::PopupHandler::Entry popups[] = { { Window::Menu::PopupHandler::Pos::ID, &Movie::OnMenu } }; menu.Popups().Add( this, popups ); } Movie::~Movie() { } bool Movie::Load(const Path& path,const Alert alert) { if (path.Archive().Length()) { dialog->ClearMovieFile(); if (alert == NOISY) Window::User::Fail( IDS_FILE_ERR_CANT_USE_IN_ARCHIVE ); else Io::Log() << "Movie: ignoring file, can't use it while it's archived..\r\n"; } else { dialog->SetMovieFile( path ); } file.Update( dialog->GetMovieFile() ); return !file.GetPath().Empty(); } void Movie::OnMenu(const Window::Menu::PopupHandler::Param& param) { param.menu[ IDM_FILE_MOVIE_PLAY ].Enable( !param.show || file.CanPlay() ); param.menu[ IDM_FILE_MOVIE_RECORD ].Enable( !param.show || file.CanRecord() ); param.menu[ IDM_FILE_MOVIE_STOP ].Enable( !param.show || file.CanStop() ); param.menu[ IDM_FILE_MOVIE_REWIND ].Enable( !param.show || file.CanRewind() ); param.menu[ IDM_FILE_MOVIE_FORWARD ].Enable( !param.show || file.CanForward() ); param.menu[ IDM_FILE_MOVIE_EXPORT_AVI ].Enable( !param.show || file.CanPlay() ); } void Movie::OnCmdFile(uint) { dialog->Open(); file.Update( dialog->GetMovieFile() ); } void Movie::OnCmdRecord(uint) { if (file.Start( File::MODE_RECORD ) && !emulator.Power( true )) Nes::Movie(emulator).Stop(); Resume(); } void Movie::OnCmdPlay(uint) { if (file.Start( File::MODE_PLAY )) { if (emulator.Power( true )) emulator.AskBeforeSaving(); else Nes::Movie(emulator).Stop(); } Resume(); } void Movie::OnCmdExportAvi(uint) { if (file.CanPlay()) { if (const uint ids = AviConverter( emulator ).Record( file.GetPath(), paths.BrowseSave( Paths::File::AVI, Paths::SUGGEST, file.GetPath() ) )) { if (ids == IDS_AVI_WRITE_ABORT || ids == IDS_AVI_WRITE_FINISHED) Window::User::Inform( ids ); else Window::User::Fail( ids ); } } } void Movie::OnCmdStop(uint) { Nes::Movie(emulator).Stop(); Resume(); } void Movie::OnCmdRewind(uint) { if (file.Rewind()) Io::Screen() << Resource::String( IDS_SCREEN_MOVIE_REWOUND ); Resume(); } void Movie::OnCmdForward(uint) { if (file.Forward()) Io::Screen() << Resource::String( IDS_SCREEN_MOVIE_FORWARDED ); Resume(); } void Movie::OnEmuEvent(const Emulator::Event event,const Emulator::Data data) { switch (event) { case Emulator::EVENT_MOVIE_PLAYING: case Emulator::EVENT_MOVIE_PLAYING_STOPPED: case Emulator::EVENT_MOVIE_RECORDING: case Emulator::EVENT_MOVIE_RECORDING_STOPPED: if (event == Emulator::EVENT_MOVIE_PLAYING || event == Emulator::EVENT_MOVIE_RECORDING) { Io::Screen() << Resource::String ( event == Emulator::EVENT_MOVIE_PLAYING ? IDS_SCREEN_MOVIE_PLAY_STARTED : IDS_SCREEN_MOVIE_REC_STARTED ); } else { const uint op = ( event == Emulator::EVENT_MOVIE_PLAYING_STOPPED ? IDS_SCREEN_MOVIE_PLAY_STOPPED : IDS_SCREEN_MOVIE_REC_STOPPED ); const Nes::Result result = static_cast(data); if (NES_SUCCEEDED(result)) { file.Stop( event == Emulator::EVENT_MOVIE_PLAYING_STOPPED ? File::POS_BEG : File::POS_END ); Io::Screen() << Resource::String( op ); } else { file.Stop( File::POS_BEG ); const uint msg = Emulator::ResultToString( result ); Io::Screen() << Resource::String( op ) << ' ' << Resource::String( msg ? msg : IDS_ERR_GENERIC ); } } break; case Emulator::EVENT_POWER_ON: case Emulator::EVENT_POWER_OFF: if (emulator.NetPlayers()) menu[IDM_FILE_MOVIE_FILE].Enable( event == Emulator::EVENT_POWER_OFF ); break; } } Movie::File::File(Emulator& e) : stream(NULL), pos(POS_BEG), emulator(e) { } Movie::File::~File() { Nes::Movie(emulator).Stop(); Stop(); } const Path& Movie::File::GetPath() const { return path; } void Movie::File::Update(const Path& newPath) { if (path != newPath) { Nes::Movie(emulator).Stop(); path = newPath; pos = POS_BEG; } } bool Movie::File::Start(const Mode mode) { if (!(mode == MODE_PLAY ? CanPlay() : CanRecord())) return false; uint msg; if (mode == MODE_PLAY || !path.FileProtected()) { try { stream = new Io::Stream::InOut ( path, mode == MODE_PLAY ? Io::Stream::InOut::READ : pos == POS_BEG ? Io::Stream::InOut::READ|Io::Stream::InOut::WRITE|Io::Stream::InOut::TRUNCATE : Io::Stream::InOut::READ|Io::Stream::InOut::WRITE ); const Nes::Result result = ( mode == MODE_RECORD ? Nes::Movie(emulator).Record( *stream, pos == POS_BEG ? Nes::Movie::CLEAN : Nes::Movie::APPEND ) : Nes::Movie(emulator).Play( *stream ) ); if (NES_SUCCEEDED(result)) return true; msg = Emulator::ResultToString( result ); } catch (...) { msg = IDS_FILE_ERR_OPEN; } } else { msg = IDS_FILE_ERR_WRITE_PROTECTED; } if (msg) { Io::Screen() << Resource::String( mode == MODE_RECORD ? IDS_EMU_ERR_MOVIE_REC : IDS_EMU_ERR_MOVIE_PLAY ) << ' ' << Resource::String( msg ); } Stop(); return false; } void Movie::File::Stop(Pos p) { pos = p; delete stream; stream = NULL; } bool Movie::File::Rewind() { if (CanRewind()) { pos = POS_BEG; return true; } return false; } bool Movie::File::Forward() { if (CanForward()) { pos = POS_END; return true; } return false; } bool Movie::File::CanPlay() const { return IsReady() && !emulator.NetPlayers() && Nes::Movie(emulator).IsStopped() && path.FileExists(); } bool Movie::File::CanRecord() const { return IsReady() && Nes::Movie(emulator).IsStopped(); } bool Movie::File::CanStop() const { return stream; } bool Movie::File::CanRewind() const { return pos != POS_BEG && CanSetPos(); } bool Movie::File::CanForward() const { return pos != POS_END && CanSetPos(); } bool Movie::File::IsReady() const { return path.Length() && emulator.IsGame(); } bool Movie::File::CanSetPos() const { return IsReady() && Nes::Movie(emulator).IsStopped() && path.FileExists(); } } }