1 ////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // Nestopia - NES/Famicom emulator written in C++
4 //
5 // Copyright (C) 2003-2008 Martin Freij
6 //
7 // This file is part of Nestopia.
8 //
9 // Nestopia is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Nestopia is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Nestopia; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 //
23 ////////////////////////////////////////////////////////////////////////////////////////
24 
25 #include "NstResourceString.hpp"
26 #include "NstWindowUser.hpp"
27 #include "NstIoScreen.hpp"
28 #include "NstManager.hpp"
29 #include "NstManagerPreferences.hpp"
30 #include "NstManagerMachine.hpp"
31 #include "../core/api/NstApiMachine.hpp"
32 
33 namespace Nestopia
34 {
35 	namespace Managers
36 	{
37 		NST_COMPILE_ASSERT
38 		(
39 			IDM_MACHINE_SYSTEM_NTSC == IDM_MACHINE_SYSTEM_AUTO + 1 &&
40 			IDM_MACHINE_SYSTEM_PAL  == IDM_MACHINE_SYSTEM_AUTO + 2
41 		);
42 
Machine(Emulator & e,const Configuration & cfg,Window::Menu & m,const Preferences & p)43 		Machine::Machine(Emulator& e,const Configuration& cfg,Window::Menu& m,const Preferences& p)
44 		:
45 		Manager     ( e, m, this, &Machine::OnEmuEvent ),
46 		preferences ( p )
47 		{
48 			{
49 				static const Window::Menu::CmdHandler::Entry<Machine> commands[] =
50 				{
51 					{ IDM_MACHINE_POWER,       &Machine::OnCmdPower   },
52 					{ IDM_MACHINE_RESET_SOFT,  &Machine::OnCmdReset   },
53 					{ IDM_MACHINE_RESET_HARD,  &Machine::OnCmdReset   },
54 					{ IDM_MACHINE_PAUSE,       &Machine::OnCmdPause   },
55 					{ IDM_MACHINE_SYSTEM_AUTO, &Machine::OnCmdSystem  },
56 					{ IDM_MACHINE_SYSTEM_NTSC, &Machine::OnCmdSystem  },
57 					{ IDM_MACHINE_SYSTEM_PAL,  &Machine::OnCmdSystem  }
58 				};
59 
60 				menu.Commands().Add( this, commands );
61 			}
62 
63 			{
64 				const GenericString type( cfg["machine"]["region"].Str() );
65 
66 				SetRegion
67 				(
68 					type == L"ntsc" ? IDM_MACHINE_SYSTEM_NTSC :
69 					type == L"pal"  ? IDM_MACHINE_SYSTEM_PAL  :
70                                       IDM_MACHINE_SYSTEM_AUTO
71 				);
72 			}
73 
74 			UpdateMenu();
75 			UpdateMenuPowerState();
76 		}
77 
Save(Configuration & cfg) const78 		void Machine::Save(Configuration& cfg) const
79 		{
80 			cfg["machine"]["region"].Str() =
81 			(
82 				menu[IDM_MACHINE_SYSTEM_AUTO].Checked()       ? "auto" :
83 				Nes::Machine(emulator).Is(Nes::Machine::NTSC) ? "ntsc" :
84 																"pal"
85 			);
86 		}
87 
UpdateMenu() const88 		void Machine::UpdateMenu() const
89 		{
90 			const bool on = emulator.IsOn();
91 			const bool reset = (on && emulator.GetPlayer() == Emulator::MASTER);
92 			const bool pause = (on && emulator.NetPlayers() == 0);
93 
94 			menu[IDM_MACHINE_POWER].Text() << Resource::String( on ? IDS_MENU_POWER_OFF : IDS_MENU_POWER_ON );
95 			menu[IDM_MACHINE_RESET_SOFT].Enable( reset );
96 			menu[IDM_MACHINE_RESET_HARD].Enable( reset );
97 			menu[IDM_POS_MACHINE][IDM_POS_MACHINE_RESET].Enable( reset );
98 			menu[IDM_MACHINE_PAUSE].Enable( pause );
99 		}
100 
UpdateMenuPowerState() const101 		void Machine::UpdateMenuPowerState() const
102 		{
103 			menu[IDM_MACHINE_POWER].Enable( emulator.IsImage() && emulator.NetPlayers() == 0 );
104 		}
105 
SetRegion(const uint id) const106 		bool Machine::SetRegion(const uint id) const
107 		{
108 			const Nes::Result result = Nes::Machine(emulator).SetMode
109 			(
110 				id == IDM_MACHINE_SYSTEM_AUTO ? Nes::Machine(emulator).GetDesiredMode() :
111 				id == IDM_MACHINE_SYSTEM_NTSC ? Nes::Machine::NTSC : Nes::Machine::PAL
112 			);
113 
114 			if (NES_SUCCEEDED(result))
115 			{
116 				menu[id].Check( IDM_MACHINE_SYSTEM_AUTO, IDM_MACHINE_SYSTEM_PAL );
117 				return result != Nes::RESULT_NOP;
118 			}
119 
120 			return false;
121 		}
122 
OnCmdPower(uint)123 		void Machine::OnCmdPower(uint)
124 		{
125 			if (emulator.IsOn())
126 			{
127 				if
128 				(
129 					!preferences[Preferences::CONFIRM_RESET] ||
130 					Window::User::Confirm( IDS_ARE_YOU_SURE, IDS_MACHINE_POWER_OFF_TITLE )
131 				)
132 				{
133 					if (emulator.Power( false ))
134 						Io::Screen() << Resource::String(IDS_SCREEN_POWER_OFF);
135 				}
136 			}
137 			else if (emulator.Power( true ))
138 			{
139 				Io::Screen() << Resource::String(IDS_SCREEN_POWER_ON);
140 			}
141 		}
142 
OnCmdReset(uint hard)143 		void Machine::OnCmdReset(uint hard)
144 		{
145 			if
146 			(
147 				!preferences[Preferences::CONFIRM_RESET] ||
148 				Window::User::Confirm( IDS_ARE_YOU_SURE, IDS_MACHINE_RESET_TITLE )
149 			)
150 				emulator.SendCommand( Emulator::COMMAND_RESET, hard == IDM_MACHINE_RESET_HARD );
151 
152 			Resume();
153 		}
154 
OnCmdPause(uint)155 		void Machine::OnCmdPause(uint)
156 		{
157 			const bool pause = !emulator.Paused();
158 
159 			emulator.Pause( pause );
160 			Io::Screen() << Resource::String(pause ? IDS_SCREEN_PAUSE : IDS_SCREEN_RESUME);
161 
162 			if (!pause)
163 				Resume();
164 		}
165 
OnCmdSystem(uint id)166 		void Machine::OnCmdSystem(uint id)
167 		{
168 			if (SetRegion( id ))
169 				Io::Screen() << Resource::String(Nes::Machine(emulator).Is(Nes::Machine::NTSC) ? IDS_SCREEN_NTSC : IDS_SCREEN_PAL);
170 
171 			Resume();
172 		}
173 
OnEmuEvent(const Emulator::Event event,Emulator::Data)174 		void Machine::OnEmuEvent(const Emulator::Event event,Emulator::Data)
175 		{
176 			switch (event)
177 			{
178 				case Emulator::EVENT_RESET_SOFT:
179 				case Emulator::EVENT_RESET_HARD:
180 
181 					Io::Screen() << Resource::String(event == Emulator::EVENT_RESET_HARD ? IDS_SCREEN_RESET_HARD : IDS_SCREEN_RESET_SOFT);
182 					break;
183 
184 				case Emulator::EVENT_MODE_NTSC:
185 				case Emulator::EVENT_MODE_PAL:
186 
187 					if (menu[IDM_MACHINE_SYSTEM_AUTO].Unchecked())
188 						menu[event == Emulator::EVENT_MODE_NTSC ? IDM_MACHINE_SYSTEM_NTSC : IDM_MACHINE_SYSTEM_PAL].Check( IDM_MACHINE_SYSTEM_AUTO, IDM_MACHINE_SYSTEM_PAL );
189 
190 					break;
191 
192 				case Emulator::EVENT_PAUSE:
193 				case Emulator::EVENT_RESUME:
194 
195 					menu[IDM_MACHINE_PAUSE].Check( event == Emulator::EVENT_PAUSE );
196 					break;
197 
198 				case Emulator::EVENT_MOVIE_PLAYING:
199 				case Emulator::EVENT_MOVIE_PLAYING_STOPPED:
200 				case Emulator::EVENT_MOVIE_RECORDING:
201 				case Emulator::EVENT_MOVIE_RECORDING_STOPPED:
202 				{
203 					const bool noplay = (event != Emulator::EVENT_MOVIE_PLAYING);
204 					const bool stopped = (event == Emulator::EVENT_MOVIE_PLAYING_STOPPED || event == Emulator::EVENT_MOVIE_RECORDING_STOPPED);
205 
206 					menu[IDM_MACHINE_RESET_SOFT].Enable( noplay );
207 					menu[IDM_MACHINE_RESET_HARD].Enable( noplay );
208 					menu[IDM_POS_MACHINE][IDM_POS_MACHINE_RESET].Enable( noplay );
209 
210 					for (uint i=IDM_MACHINE_SYSTEM_AUTO; i <= IDM_MACHINE_SYSTEM_PAL; ++i)
211 						menu[i].Enable( stopped );
212 
213 					break;
214 				}
215 
216 				case Emulator::EVENT_POWER_ON:
217 				case Emulator::EVENT_POWER_OFF:
218 
219 					UpdateMenu();
220 					break;
221 
222 				case Emulator::EVENT_LOAD:
223 				case Emulator::EVENT_UNLOAD:
224 
225 					UpdateMenuPowerState();
226 
227 					if (emulator.NetPlayers())
228 					{
229 						const bool enable = (event == Emulator::EVENT_UNLOAD);
230 
231 						menu[IDM_POS_MACHINE][IDM_POS_MACHINE_REGION].Enable( enable );
232 
233 						for (uint i=IDM_MACHINE_SYSTEM_AUTO; i <= IDM_MACHINE_SYSTEM_PAL; ++i)
234 							menu[i].Enable( enable );
235 					}
236 					break;
237 			}
238 		}
239 	}
240 }
241