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 "NstIoLog.hpp" 26 #include "NstIoStream.hpp" 27 #include "NstIoFile.hpp" 28 #include "NstApplicationInstance.hpp" 29 #include "NstWindowParam.hpp" 30 #include "NstWindowDropFiles.hpp" 31 #include "NstManagerPaths.hpp" 32 #include "NstDialogNetPlay.hpp" 33 #include "../core/NstXml.hpp" 34 #include <CommCtrl.h> 35 36 namespace Nestopia 37 { 38 namespace Window 39 { 40 struct Netplay::Handlers 41 { 42 static const MsgHandler::Entry<Netplay> messages[]; 43 static const MsgHandler::Entry<Netplay> commands[]; 44 static const Control::NotificationHandler::Entry<Netplay> notifications[]; 45 }; 46 47 const MsgHandler::Entry<Netplay> Netplay::Handlers::messages[] = 48 { 49 { WM_INITDIALOG, &Netplay::OnInitDialog }, 50 { WM_DROPFILES, &Netplay::OnDropFiles } 51 }; 52 53 const MsgHandler::Entry<Netplay> Netplay::Handlers::commands[] = 54 { 55 { IDC_NETPLAY_ADD, &Netplay::OnAdd }, 56 { IDC_NETPLAY_REMOVE, &Netplay::OnRemove }, 57 { IDC_NETPLAY_CLEAR, &Netplay::OnClear }, 58 { IDC_NETPLAY_DEFAULT, &Netplay::OnDefault }, 59 { IDC_NETPLAY_LAUNCH, &Netplay::OnLaunch }, 60 { IDC_NETPLAY_PLAY_FULLSCREEN, &Netplay::OnFullscreen } 61 }; 62 63 const Control::NotificationHandler::Entry<Netplay> Netplay::Handlers::notifications[] = 64 { 65 { LVN_KEYDOWN, &Netplay::OnKeyDown }, 66 { LVN_ITEMCHANGED, &Netplay::OnItemChanged }, 67 { LVN_INSERTITEM, &Netplay::OnInsertItem }, 68 { LVN_DELETEITEM, &Netplay::OnDeleteItem } 69 }; 70 operator ()(const Path & a,const Path & b) const71 bool Netplay::Games::Less::operator () (const Path& a,const Path& b) const 72 { 73 return a.Target().File() < b.Target().File(); 74 } 75 Games()76 Netplay::Games::Games() 77 : state(UNINITIALIZED) {} 78 Netplay(Managers::Emulator & e,const Managers::Paths & p,bool fullscreen)79 Netplay::Netplay(Managers::Emulator& e,const Managers::Paths& p,bool fullscreen) 80 : 81 dialog ( IDD_NETPLAY, this, Handlers::messages, Handlers::commands ), 82 doFullscreen ( fullscreen ), 83 paths ( p ), 84 emulator ( e ), 85 notifications ( IDC_NETPLAY_GAMELIST, dialog.Messages(), this, Handlers::notifications ) 86 { 87 } 88 ~Netplay()89 Netplay::~Netplay() 90 { 91 } 92 LoadFile()93 void Netplay::LoadFile() 94 { 95 try 96 { 97 //const Path path( Application::Instance::GetExePath(L"netplaylist.xml") ); 98 const Path path( Application::Instance::GetConfigPath(L"netplaylist.xml") );//bg 99 100 if (path.FileExists()) 101 { 102 typedef Nes::Core::Xml Xml; 103 Xml xml; 104 105 { 106 Io::Stream::In stream( path ); 107 xml.Read( stream ); 108 } 109 110 if (!xml.GetRoot().IsType( L"netplaylist" )) 111 throw 1; 112 113 for (Xml::Node node(xml.GetRoot().GetFirstChild()); node; node=node.GetNextSibling()) 114 { 115 if (!node.IsType( L"file" )) 116 throw 1; 117 118 Add( node.GetValue() ); 119 } 120 121 Io::Log() << "Netplay: loaded game list from \"netplaylist.xml\"\r\n"; 122 } 123 else 124 { 125 Io::Log() << "Netplay: game list file \"netplaylist.xml\" not present..\r\n"; 126 } 127 } 128 catch (...) 129 { 130 games.state = Games::DIRTY; 131 Io::Log() << "Netplay: warning, couldn't load game list \"netplaylist.xml\"!\r\n"; 132 } 133 } 134 SaveFile() const135 void Netplay::SaveFile() const 136 { 137 if (games.state == Games::DIRTY) 138 { 139 //const Path path( Application::Instance::GetExePath(L"netplaylist.xml") ); 140 const Path path( Application::Instance::GetConfigPath(L"netplaylist.xml") );//bg 141 142 if (!games.paths.empty()) 143 { 144 try 145 { 146 typedef Nes::Core::Xml Xml; 147 148 Xml xml; 149 Xml::Node root( xml.Create( L"netplaylist" ) ); 150 root.AddAttribute( L"version", L"1.0" ); 151 152 for (Games::Paths::const_iterator it(games.paths.begin()), end(games.paths.end()); it != end; ++it) 153 root.AddChild( L"file", it->Ptr() ); 154 155 Io::Stream::Out stream( path ); 156 xml.Write( root, stream ); 157 158 Io::Log() << "Netplay: saved game list to \"netplaylist.xml\"\r\n"; 159 } 160 catch (...) 161 { 162 Io::Log() << "Netplay: warning, couldn't save game list to \"netplaylist.xml\"!\r\n"; 163 } 164 } 165 else if (path.FileExists()) 166 { 167 if (Io::File::Delete( path.Ptr() )) 168 Io::Log() << "Netplay: game list empty, deleted \"netplaylist.xml\"\r\n"; 169 else 170 Io::Log() << "Netplay: warning, couldn't delete \"netplaylist.xml\"!\r\n"; 171 } 172 } 173 } 174 GetPath(wcstring const path) const175 wcstring Netplay::GetPath(wcstring const path) const 176 { 177 Games::Paths::const_iterator it(games.paths.find( path )); 178 return it != games.paths.end() ? it->Ptr() : NULL; 179 } 180 Add(Path path)181 void Netplay::Add(Path path) 182 { 183 enum 184 { 185 TYPES = Managers::Paths::File::GAME|Managers::Paths::File::ARCHIVE 186 }; 187 188 if (path.Length() && games.paths.size() < Games::LIMIT && paths.CheckFile( path, TYPES ) && games.paths.insert( path ).second) 189 { 190 games.state = Games::DIRTY; 191 192 if (dialog) 193 dialog.ListView( IDC_NETPLAY_GAMELIST ).Add( path.Target().File() ); 194 } 195 } 196 OnInitDialog(Param &)197 ibool Netplay::OnInitDialog(Param&) 198 { 199 dialog.CheckBox( IDC_NETPLAY_PLAY_FULLSCREEN ).Check( doFullscreen ); 200 dialog.CheckBox( IDC_NETPLAY_REMOVE ).Disable(); 201 202 if (games.state == Games::UNINITIALIZED) 203 { 204 LoadFile(); 205 } 206 else 207 { 208 Control::ListView list( dialog.ListView( IDC_NETPLAY_GAMELIST ) ); 209 list.Reserve( games.paths.size() ); 210 211 for (Games::Paths::const_iterator it(games.paths.begin()), end(games.paths.end()); it != end; ++it) 212 list.Add( it->Target().File().Ptr() ); 213 } 214 215 dialog.CheckBox( IDC_NETPLAY_CLEAR ).Enable( games.paths.size() ); 216 dialog.CheckBox( IDC_NETPLAY_LAUNCH ).Enable( games.paths.size() ); 217 218 return true; 219 } 220 OnAdd(Param & param)221 ibool Netplay::OnAdd(Param& param) 222 { 223 if (param.Button().Clicked()) 224 Add( paths.BrowseLoad(Managers::Paths::File::GAME|Managers::Paths::File::ARCHIVE) ); 225 226 return true; 227 } 228 OnRemove(Param & param)229 ibool Netplay::OnRemove(Param& param) 230 { 231 if (param.Button().Clicked()) 232 dialog.ListView( IDC_NETPLAY_GAMELIST ).Selection().Delete(); 233 234 return true; 235 } 236 OnClear(Param & param)237 ibool Netplay::OnClear(Param& param) 238 { 239 if (param.Button().Clicked()) 240 dialog.ListView( IDC_NETPLAY_GAMELIST ).Clear(); 241 242 return true; 243 } 244 OnDefault(Param & param)245 ibool Netplay::OnDefault(Param& param) 246 { 247 if (param.Button().Clicked()) 248 { 249 doFullscreen = false; 250 dialog.CheckBox( IDC_NETPLAY_PLAY_FULLSCREEN ).Check( false ); 251 } 252 253 return true; 254 } 255 OnLaunch(Param & param)256 ibool Netplay::OnLaunch(Param& param) 257 { 258 if (param.Button().Clicked()) 259 dialog.Close( LAUNCH ); 260 261 return true; 262 } 263 OnFullscreen(Param & param)264 ibool Netplay::OnFullscreen(Param& param) 265 { 266 if (param.Button().Clicked()) 267 doFullscreen = dialog.CheckBox( IDC_NETPLAY_PLAY_FULLSCREEN ).Checked(); 268 269 return true; 270 } 271 OnDropFiles(Param & param)272 ibool Netplay::OnDropFiles(Param& param) 273 { 274 DropFiles dropFiles( param ); 275 276 if (dropFiles.Inside( dialog.ListView( IDC_NETPLAY_GAMELIST ).GetWindow() )) 277 { 278 for (uint i=0, n=dropFiles.Size(); i < n; ++i) 279 Add( dropFiles[i] ); 280 } 281 282 return true; 283 } 284 OnKeyDown(const NMHDR & nmhdr)285 void Netplay::OnKeyDown(const NMHDR& nmhdr) 286 { 287 switch (reinterpret_cast<const NMLVKEYDOWN&>(nmhdr).wVKey) 288 { 289 case VK_INSERT: dialog.PostCommand( IDC_NETPLAY_ADD ); break; 290 case VK_DELETE: dialog.PostCommand( IDC_NETPLAY_REMOVE ); break; 291 } 292 } 293 OnItemChanged(const NMHDR & nmhdr)294 void Netplay::OnItemChanged(const NMHDR& nmhdr) 295 { 296 const NMLISTVIEW& nm = reinterpret_cast<const NMLISTVIEW&>(nmhdr); 297 298 if ((nm.uOldState ^ nm.uNewState) & LVIS_SELECTED) 299 dialog.CheckBox( IDC_NETPLAY_REMOVE ).Enable( nm.uNewState & LVIS_SELECTED ); 300 } 301 OnInsertItem(const NMHDR &)302 void Netplay::OnInsertItem(const NMHDR&) 303 { 304 dialog.CheckBox( IDC_NETPLAY_CLEAR ).Enable(); 305 dialog.CheckBox( IDC_NETPLAY_LAUNCH ).Enable(); 306 } 307 OnDeleteItem(const NMHDR & nmhdr)308 void Netplay::OnDeleteItem(const NMHDR& nmhdr) 309 { 310 Games::Paths::iterator it(games.paths.begin()); 311 312 for (int i=reinterpret_cast<const NMLISTVIEW&>(nmhdr).iItem; i > 0; --i) 313 ++it; 314 315 games.paths.erase( it ); 316 games.state = Games::DIRTY; 317 318 if (dialog.ListView( IDC_NETPLAY_GAMELIST ).Size() <= 1) 319 { 320 dialog.CheckBox( IDC_NETPLAY_CLEAR ).Disable(); 321 dialog.CheckBox( IDC_NETPLAY_LAUNCH ).Disable(); 322 dialog.CheckBox( IDC_NETPLAY_REMOVE ).Disable(); 323 } 324 } 325 } 326 } 327