]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/stand_gui.cpp
center popup window on main dialog
[taylor/freespace2.git] / src / network / stand_gui.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9
10
11 #include "stand_gui.h"
12 #include "osregistry.h"
13
14 #include "wx/statline.h"
15 #include "wx/filename.h"
16 #include "wx/stdpaths.h"
17 #include "wx/utils.h"
18 #include "wx/msgdlg.h"
19 #include "wx/process.h"
20
21
22 // taken from psnet.h and psnet2.h
23 #ifdef MAKE_FS1
24         #define DEFAULT_GAME_PORT 4000
25 #elif defined(FS2_DEMO)
26         #define DEFAULT_GAME_PORT 7802
27 #else
28         #define DEFAULT_GAME_PORT 7808
29 #endif
30
31
32
33 IMPLEMENT_APP(StandaloneApp)
34
35 bool StandaloneApp::OnInit()
36 {
37         if ( !wxApp::OnInit() ) {
38                 return false;
39         }
40
41         std_client = new Standalone(NULL);
42
43         try {
44                 if ( !std_client->startFreeSpace(argc, argv) ) {
45                         throw "Unable to start FreeSpace";
46                 }
47
48                 wxMilliSleep(500);
49
50                 if ( !std_client->wsInitialize() ) {
51                         throw "Unable to initialize WebSocket";
52                 }
53         } catch (const char *err) {
54                 wxMessageBox(err, "Error!");
55
56                 return false;
57         }
58
59         std_client->Show(true);
60         SetTopWindow(std_client);
61
62         return true;
63 }
64
65 StandaloneTimer::StandaloneTimer(Standalone *stand)
66 {
67         m_stand = stand;
68 }
69
70 StandaloneTimer::~StandaloneTimer()
71 {
72 }
73
74 void StandaloneTimer::Notify()
75 {
76         m_stand->wsDoFrame();
77 }
78
79 StandPopup::StandPopup( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
80 {
81         this->SetSizeHints( wxSize( 350,100 ), wxDefaultSize );
82
83         wxBoxSizer* bSizer2;
84         bSizer2 = new wxBoxSizer( wxVERTICAL );
85
86         wxFlexGridSizer* fgSizer3;
87         fgSizer3 = new wxFlexGridSizer( 0, 2, 0, 0 );
88         fgSizer3->AddGrowableRow(0, 1);
89
90         m_Label1 = new wxStaticText( this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
91         m_Label1->Wrap( -1 );
92         fgSizer3->Add( m_Label1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
93
94         m_Label2 = new wxStaticText( this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
95         m_Label2->Wrap( -1 );
96         fgSizer3->Add( m_Label2, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
97
98
99         bSizer2->Add( fgSizer3, 1, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 10 );
100
101
102         this->SetSizer( bSizer2 );
103         this->Layout();
104         bSizer2->Fit( this );
105
106         this->Centre( wxBOTH );
107 }
108
109 StandPopup::~StandPopup()
110 {
111 }
112
113 wxBEGIN_EVENT_TABLE(Standalone, wxDialog)
114         EVT_CLOSE(Standalone::OnClose)
115         EVT_BUTTON(ID_B_SHUTDOWN, Standalone::OnShutdown)
116         EVT_BUTTON(ID_B_KICK, Standalone::OnKick)
117         EVT_BUTTON(ID_B_MREFRESH, Standalone::OnMissionRefresh)
118         EVT_BUTTON(ID_B_RESET_ALL, Standalone::OnResetAll)
119         EVT_SLIDER(ID_FPS_SLIDER, Standalone::OnFPSSel)
120         EVT_TEXT_ENTER(ID_T_MSG, Standalone::OnServerMsg)
121         EVT_TEXT_ENTER(ID_T_SERVER_NAME, Standalone::OnServerNameChange)
122         EVT_TEXT_ENTER(ID_T_HOST_PASS, Standalone::OnHostPassChange)
123 wxEND_EVENT_TABLE()
124
125 Standalone::Standalone( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
126 {
127         this->SetSizeHints( wxDefaultSize, wxDefaultSize );
128
129         fspid = 0;
130         fsport = DEFAULT_GAME_PORT;
131         stand_context = NULL;
132         wsi_standalone = NULL;
133         m_rate_limit = 0;
134
135         m_timer = new StandaloneTimer(this);
136         m_timer->Start(1000/30);
137
138         m_popup = new StandPopup(this);
139         m_popup->Show(false);
140
141         wxBoxSizer* bSizer1;
142         bSizer1 = new wxBoxSizer( wxVERTICAL );
143
144         wxNotebook* nbook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
145
146         createTab_Server(nbook);
147         createTab_Multi(nbook);
148         createTab_Player(nbook);
149         createTab_GodStuff(nbook);
150         createTab_Debug(nbook);
151
152         bSizer1->Add( nbook, 1, wxEXPAND | wxALL, 5 );
153
154         wxButton* bshutdown = new wxButton( this, ID_B_SHUTDOWN, wxT("Shutdown"), wxDefaultPosition, wxDefaultSize, 0 );
155         bSizer1->Add( bshutdown, 0, wxALIGN_CENTER|wxALL, 5 );
156
157
158         this->SetSizer( bSizer1 );
159         bSizer1->Fit(this);
160         bSizer1->SetSizeHints(this);
161
162         this->Centre( wxBOTH );
163 }
164
165 Standalone::~Standalone()
166 {
167         delete m_timer;
168 }
169
170 void Standalone::OnClose( wxCloseEvent& WXUNUSED(event) )
171 {
172         Shutdown();
173 }
174
175 void Standalone::OnShutdown( wxCommandEvent& WXUNUSED(event) )
176 {
177         Shutdown();
178 }
179
180 void Standalone::Shutdown()
181 {
182         if (stand_context) {
183                 std::string msg("shutdown");
184                 wsSend(msg);
185
186                 lws_service(stand_context, 50);
187
188                 lws_context_destroy(stand_context);
189         }
190
191         if ( wxProcess::Exists(fspid) ) {
192                 // wait a little bit, and if process still exists then kill it
193                 wxSleep(1);
194
195                 if ( wxProcess::Exists(fspid) ) {
196                         wxProcess::Kill(fspid, wxSIGTERM);
197                 }
198         }
199
200         Destroy();
201 }
202
203 void Standalone::OnServerNameChange(wxCommandEvent& WXUNUSED(event) )
204 {
205         std::string msg("S:name ");
206
207         msg.append( m_S_ServerName->GetValue().c_str() );
208
209         wsSend(msg);
210 }
211
212 void Standalone::OnHostPassChange(wxCommandEvent& WXUNUSED(event) )
213 {
214         std::string msg("S:pass ");
215
216         msg.append( m_S_HostPass->GetValue().c_str() );
217
218         wsSend(msg);
219 }
220
221 void Standalone::OnKick( wxCommandEvent& WXUNUSED(event) )
222 {
223         std::string msg("S:kick ");
224
225         wxString id = m_S_Connections->GetStringSelection();
226
227         if ( id.IsEmpty() ) {
228                 return;
229         }
230
231         wxArrayString ipaddr = wxSplit(id, ',');
232
233         msg.append( ipaddr.Item(0).c_str() );
234
235         wsSend(msg);
236 }
237
238 void Standalone::OnMissionRefresh( wxCommandEvent& WXUNUSED(event) )
239 {
240         std::string msg("G:mrefresh");
241
242         wsSend(msg);
243 }
244
245 void Standalone::OnResetAll( wxCommandEvent& WXUNUSED(event) )
246 {
247 //      ResetAll();
248 }
249
250 void Standalone::OnFPSSel( wxCommandEvent& WXUNUSED(event) )
251 {
252         wxString fps = wxString::Format("%d", m_M_sliderFPS->GetValue());
253
254         m_M_FPS->SetLabel(fps);
255
256         std::string msg("M:fps ");
257         msg.append(fps);
258
259         wsSend(msg);
260 }
261
262 void Standalone::OnServerMsg( wxCommandEvent& WXUNUSED(event) )
263 {
264         if ( m_GS_msg->GetValue().IsEmpty() ) {
265                 return;
266         }
267
268         std::string msg("G:smsg ");
269
270         msg.append( m_GS_msg->GetValue().c_str() );
271
272         // strip off return char which GetValue() has
273         size_t pos = msg.find_last_not_of("\r\n");
274
275         if (pos != std::string::npos) {
276                 msg.erase(pos+1);
277         }
278
279         wsSend(msg);
280
281         m_GS_msg->Clear();
282 }
283
284 void Standalone::createTab_Server(wxNotebook* parent)
285 {
286         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
287
288         wxBoxSizer *panelSizer = new wxBoxSizer( wxVERTICAL );
289
290         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
291
292         wxFlexGridSizer* fgSizer5 = new wxFlexGridSizer( 0, 2, 0, 0 );
293         fgSizer5->AddGrowableCol(1, 1);
294
295         wxStaticText* m_staticText6 = new wxStaticText( panel, wxID_ANY, wxT("Server Name"), wxDefaultPosition, wxDefaultSize, 0 );
296         fgSizer5->Add( m_staticText6, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
297
298         m_S_ServerName = new wxTextCtrl( panel, ID_T_SERVER_NAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
299         m_S_ServerName->SetMaxLength( 31 );
300         fgSizer5->Add( m_S_ServerName, 0, wxALL|wxEXPAND, 5 );
301
302         wxStaticText* m_staticText7 = new wxStaticText( panel, wxID_ANY, wxT("Host Password"), wxDefaultPosition, wxDefaultSize, 0 );
303         fgSizer5->Add( m_staticText7, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
304
305         m_S_HostPass = new wxTextCtrl( panel, ID_T_HOST_PASS, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
306         m_S_HostPass->SetMaxLength( 16 );
307         fgSizer5->Add( m_S_HostPass, 0, wxALL|wxEXPAND, 5 );
308
309         bSizer->Add( fgSizer5, 0, wxEXPAND, 0 );
310
311         wxStaticLine* m_staticline1 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
312         bSizer->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 );
313
314         wxFlexGridSizer* fgSizer7 = new wxFlexGridSizer( 0, 2, 0, 0 );
315         fgSizer7->SetFlexibleDirection( wxBOTH );
316         fgSizer7->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
317
318         wxStaticText* m_staticText9 = new wxStaticText( panel, wxID_ANY, wxT("# Connections :"), wxDefaultPosition, wxDefaultSize, 0 );
319         fgSizer7->Add( m_staticText9, 0, wxALL, 5 );
320
321         m_S_NumConn = new wxStaticText( panel, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, 0|wxSUNKEN_BORDER );
322         fgSizer7->Add( m_S_NumConn, 0, wxALL, 5 );
323
324         bSizer->Add( fgSizer7, 0, wxEXPAND, 5 );
325
326         wxStaticText* m_staticText8 = new wxStaticText( panel, wxID_ANY, wxT("Address and Ping"), wxDefaultPosition, wxDefaultSize, 0 );
327         bSizer->Add( m_staticText8, 0, wxALL, 5 );
328
329         wxFlexGridSizer* fgSizer3 = new wxFlexGridSizer( 0, 2, 0, 0 );
330         fgSizer3->SetFlexibleDirection( wxBOTH );
331         fgSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
332
333         m_S_Connections = new wxTextCtrl( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 300,300 ), wxTE_MULTILINE|wxTE_READONLY );
334         fgSizer3->Add( m_S_Connections, 0, wxALL|wxEXPAND, 5 );
335
336         wxBoxSizer* bbSizer = new wxBoxSizer( wxVERTICAL );
337
338         m_S_btnKick = new wxButton( panel, ID_B_KICK, wxT("Kick"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
339         bbSizer->Add( m_S_btnKick, 1, wxALL, 5 );
340
341         m_S_btnMRefresh = new wxButton( panel, ID_B_MREFRESH, wxT(" Refresh\nMissions"), wxDefaultPosition, wxDefaultSize, 0 );
342         bbSizer->Add( m_S_btnMRefresh, 2, wxALL, 5 );
343
344         m_S_btnResetAll = new wxButton( panel, ID_B_RESET_ALL, wxT("Reset All"), wxDefaultPosition, wxDefaultSize, 0 );
345         bbSizer->Add( m_S_btnResetAll, 3, wxALL, 5 );
346
347         fgSizer3->Add( bbSizer, 1, wxEXPAND, 5 );
348
349         bSizer->Add( fgSizer3, 0, wxEXPAND, 5 );
350
351         panelSizer->Add( bSizer, 1, wxALL|wxEXPAND, 5 );
352
353         panel->SetSizer( panelSizer );
354         panelSizer->Fit( panel );
355         panelSizer->SetSizeHints( panel );
356
357         parent->AddPage( panel, wxT("Server"), true );
358 }
359
360 void Standalone::createTab_Multi(wxNotebook* parent)
361 {
362         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
363
364         wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL);
365
366         wxBoxSizer* bSizer = new wxBoxSizer(wxVERTICAL);
367
368         m_M_sliderFPS = new wxSlider( panel, ID_FPS_SLIDER, 30, 15, 60, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL );
369         bSizer->Add( m_M_sliderFPS, 0, wxALL|wxEXPAND, 5 );
370
371         wxFlexGridSizer* fgSizer8;
372         fgSizer8 = new wxFlexGridSizer( 0, 5, 0, 0 );
373         fgSizer8->AddGrowableCol(2, 1);
374
375         wxStaticText* m_staticText71 = new wxStaticText( panel, wxID_ANY, wxT("Frame Cap : "), wxDefaultPosition, wxDefaultSize, 0 );
376         m_staticText71->Wrap( -1 );
377         fgSizer8->Add( m_staticText71, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
378
379         wxPanel* fpsPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
380         wxBoxSizer* fpsSizer = new wxBoxSizer(wxHORIZONTAL);
381         m_M_FPS = new wxStaticText( fpsPanel, wxID_ANY, "30", wxDefaultPosition, wxSize(60, -1), 0 );
382         m_M_FPS->Wrap( -1 );
383         fpsSizer->Add( m_M_FPS, 0, wxALL, 2 );
384         fpsPanel->SetSizer(fpsSizer);
385         fpsSizer->Fit(fpsPanel);
386         fgSizer8->Add(fpsPanel, 0, wxALL, 3);
387
388
389         fgSizer8->Add( 0, 0, 1, wxEXPAND );
390
391         wxStaticText* m_staticText81 = new wxStaticText( panel, wxID_ANY, wxT("Realized FPS : "), wxDefaultPosition, wxDefaultSize, 0 );
392         m_staticText81->Wrap( -1 );
393         fgSizer8->Add( m_staticText81, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
394
395         wxPanel*fpscapPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
396         wxBoxSizer* fpscapSizer = new wxBoxSizer(wxHORIZONTAL);
397         m_M_FPSRel = new wxStaticText( fpscapPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(60, -1), 0 );
398         m_M_FPSRel->Wrap( -1 );
399         fpscapSizer->Add( m_M_FPSRel, 0, wxALL, 2 );
400         fpscapPanel->SetSizer(fpscapSizer);
401         fpscapSizer->Fit(fpscapPanel);
402         fgSizer8->Add(fpscapPanel, 0, wxALL, 3);
403
404
405         bSizer->Add( fgSizer8, 0, wxEXPAND, 5 );
406
407         wxStaticLine* m_staticline2 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
408         bSizer->Add( m_staticline2, 0, wxEXPAND | wxALL, 5 );
409
410
411         bSizer->Add( 0, 0, 0, wxALL, 20 );
412
413
414         wxFlexGridSizer* fgSizer9;
415         fgSizer9 = new wxFlexGridSizer( 0, 2, 0, 0 );
416         fgSizer9->SetFlexibleDirection( wxBOTH );
417         fgSizer9->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
418
419         wxStaticText* m_staticText91 = new wxStaticText( panel, wxID_ANY, wxT("Mission Name : "), wxDefaultPosition, wxDefaultSize, 0 );
420         m_staticText91->Wrap( -1 );
421         fgSizer9->Add( m_staticText91, 0, wxALL, 5 );
422
423         wxPanel* mnPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
424         wxBoxSizer* mnSizer = new wxBoxSizer(wxHORIZONTAL);
425         m_M_MissionName = new wxStaticText( mnPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0 );
426         m_M_MissionName->Wrap( -1 );
427         mnSizer->Add( m_M_MissionName, 0, wxALL, 2 );
428         mnPanel->SetSizer(mnSizer);
429         mnSizer->Fit(mnPanel);
430         fgSizer9->Add(mnPanel, 0, wxALL, 3);
431
432         wxStaticText* m_staticText101 = new wxStaticText( panel, wxID_ANY, wxT("Mission Time : "), wxDefaultPosition, wxDefaultSize, 0 );
433         m_staticText101->Wrap( -1 );
434         fgSizer9->Add( m_staticText101, 0, wxALL, 5 );
435
436         wxPanel* mtPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
437         wxBoxSizer* mtSizer = new wxBoxSizer(wxHORIZONTAL);
438         m_M_MissionTime = new wxStaticText( mtPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0 );
439         m_M_MissionTime->Wrap( -1 );
440         mtSizer->Add( m_M_MissionTime, 0, wxALL, 2 );
441         mtPanel->SetSizer(mtSizer);
442         mtSizer->Fit(mtPanel);
443         fgSizer9->Add(mtPanel, 0, wxALL, 3);
444
445
446         bSizer->Add( fgSizer9, 0, wxEXPAND, 5 );
447
448
449         bSizer->Add( 0, 0, 0, wxALL, 20 );
450
451         wxBoxSizer* bSizer3 = new wxBoxSizer(wxHORIZONTAL);
452
453         wxBoxSizer* bSizer4 = new wxBoxSizer(wxVERTICAL);
454
455         wxStaticText* m_staticText11 = new wxStaticText( panel, wxID_ANY, wxT("Mission Goals"), wxDefaultPosition, wxDefaultSize, 0 );
456         m_staticText11->Wrap( -1 );
457         bSizer4->Add( m_staticText11, 0, wxALL, 5 );
458
459         m_M_Goals = new wxTreeCtrl( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT );
460         bSizer4->Add( m_M_Goals, 1, wxALL|wxEXPAND, 5 );
461
462         bSizer3->Add(bSizer4, 1, wxEXPAND);
463
464         wxBoxSizer* bSizer5 = new wxBoxSizer(wxVERTICAL);
465
466         wxStaticText* m_staticText12 = new wxStaticText( panel, wxID_ANY, wxT("Netgame Information"), wxDefaultPosition, wxDefaultSize, 0 );
467         m_staticText12->Wrap( -1 );
468         bSizer5->Add( m_staticText12, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
469
470         wxFlexGridSizer* fgSizer11;
471         fgSizer11 = new wxFlexGridSizer( 0, 2, 0, 0 );
472         fgSizer11->AddGrowableRow(0, 1);
473         fgSizer11->AddGrowableRow(1, 1);
474         fgSizer11->AddGrowableRow(2, 1);
475         fgSizer11->AddGrowableRow(3, 1);
476
477         wxStaticText* m_staticText13 = new wxStaticText( panel, wxID_ANY, wxT("Max Players"), wxDefaultPosition, wxDefaultSize, 0 );
478         m_staticText13->Wrap( -1 );
479         fgSizer11->Add( m_staticText13, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
480
481         m_M_ngMaxPlayers = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
482         m_M_ngMaxPlayers->Wrap( -1 );
483         fgSizer11->Add( m_M_ngMaxPlayers, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
484
485         wxStaticText* m_staticText15 = new wxStaticText( panel, wxID_ANY, wxT("Max Observers"), wxDefaultPosition, wxDefaultSize, 0 );
486         m_staticText15->Wrap( -1 );
487         fgSizer11->Add( m_staticText15, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
488
489         m_M_ngMaxObservers = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
490         m_M_ngMaxObservers->Wrap( -1 );
491         fgSizer11->Add( m_M_ngMaxObservers, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
492
493         wxStaticText* m_staticText17 = new wxStaticText( panel, wxID_ANY, wxT("Security"), wxDefaultPosition, wxDefaultSize, 0 );
494         m_staticText17->Wrap( -1 );
495         fgSizer11->Add( m_staticText17, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
496
497         m_M_ngSecurity = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
498         m_M_ngSecurity->Wrap( -1 );
499         fgSizer11->Add( m_M_ngSecurity, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
500
501         wxStaticText* m_staticText19 = new wxStaticText( panel, wxID_ANY, wxT("Respawns"), wxDefaultPosition, wxDefaultSize, 0 );
502         m_staticText19->Wrap( -1 );
503         fgSizer11->Add( m_staticText19, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
504
505         m_M_ngRespawns = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
506         m_M_ngRespawns->Wrap( -1 );
507         fgSizer11->Add( m_M_ngRespawns, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
508
509         bSizer5->Add( fgSizer11, 1, wxEXPAND );
510
511         bSizer3->Add(bSizer5, 1, wxEXPAND);
512
513         bSizer->Add( bSizer3, 1, wxEXPAND, 5 );
514
515         panelSizer->Add(bSizer, 1, wxALL|wxEXPAND, 5);
516
517         panel->SetSizer( panelSizer );
518         panelSizer->Fit( panel );
519         panelSizer->SetSizeHints( panel );
520
521         parent->AddPage( panel, wxT("Multi-Player") );
522 }
523
524 void Standalone::createTab_Player(wxNotebook* parent)
525 {
526         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
527
528         wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
529
530         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
531
532         wxBoxSizer* bSizer21;
533         bSizer21 = new wxBoxSizer( wxHORIZONTAL );
534
535         wxStaticText* m_staticText211 = new wxStaticText( panel, wxID_ANY, wxT("Player"), wxDefaultPosition, wxDefaultSize, 0 );
536         m_staticText211->Wrap( -1 );
537         bSizer21->Add( m_staticText211, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
538
539         wxArrayString m_choice11Choices;
540         m_P_Players = new wxChoice( panel, wxID_ANY, wxDefaultPosition, wxSize(200, -1), m_choice11Choices, 0 );
541         m_P_Players->SetSelection( 0 );
542         bSizer21->Add( m_P_Players, 0, wxALL, 5 );
543
544         bSizer->Add( bSizer21, 0, wxEXPAND );
545
546
547         wxStaticLine* m_staticline4 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
548         bSizer->Add( m_staticline4, 0, wxEXPAND | wxALL, 5 );
549
550         wxFlexGridSizer* fgSizer14;
551         fgSizer14 = new wxFlexGridSizer( 0, 2, 0, 0 );
552
553         wxStaticText* m_staticText26 = new wxStaticText( panel, wxID_ANY, wxT("Ship Type"), wxDefaultPosition, wxDefaultSize, 0 );
554         m_staticText26->Wrap( -1 );
555         fgSizer14->Add( m_staticText26, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
556
557         wxPanel* stPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
558         wxBoxSizer* stSizer = new wxBoxSizer(wxHORIZONTAL);
559         m_P_ShipType = new wxStaticText( stPanel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(150, -1), 0 );
560         m_P_ShipType->Wrap( -1 );
561         stSizer->Add(m_P_ShipType, 0, wxALL, 2);
562         stPanel->SetSizer(stSizer);
563         stSizer->Fit(stPanel);
564         fgSizer14->Add( stPanel, 0, wxALL, 5 );
565
566         wxStaticText* m_staticText28 = new wxStaticText( panel, wxID_ANY, wxT("Avg Ping"), wxDefaultPosition, wxDefaultSize, 0 );
567         m_staticText28->Wrap( -1 );
568         fgSizer14->Add( m_staticText28, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
569
570         wxPanel* apPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
571         wxBoxSizer* apSizer = new wxBoxSizer(wxHORIZONTAL);
572         m_P_AvgPing = new wxStaticText( apPanel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(150, -1), 0 );
573         m_P_AvgPing->Wrap( -1 );
574         apSizer->Add(m_P_AvgPing, 0, wxALL, 2);
575         apPanel->SetSizer(apSizer);
576         apSizer->Fit(apPanel);
577         fgSizer14->Add( apPanel, 0, wxALL, 5 );
578
579         bSizer->Add( fgSizer14, 0, wxEXPAND );
580
581         bSizer->Add( 0, 0, 0, wxALL, 10);
582
583         wxBoxSizer* bSizer6;
584         bSizer6 = new wxBoxSizer( wxHORIZONTAL );
585
586         //
587         // All-Time Stats
588         //
589
590         wxBoxSizer* atsboxSizer = new wxBoxSizer( wxVERTICAL );
591
592         wxStaticText* atsText = new wxStaticText( panel, wxID_ANY, wxT("All Time Stats") );
593         atsboxSizer->Add( atsText, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
594
595         wxFlexGridSizer* atsgSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
596         atsgSizer->AddGrowableCol(1, 1);
597
598         // primary shots
599         {
600                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
601                 itxt->Wrap( -1 );
602                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
603                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
604                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
605                 m_P_atsPriShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
606                 m_P_atsPriShots->Wrap( -1 );
607                 p1sizer->Add( m_P_atsPriShots, 1, wxALL|wxEXPAND, 1);
608                 p1->SetSizer( p1sizer );
609                 p1sizer->Fit( p1 );
610                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
611         }
612
613         // primary hits
614         {
615                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
616                 itxt->Wrap( -1 );
617                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
618                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
619                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
620                 m_P_atsPriHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
621                 m_P_atsPriHits->Wrap( -1 );
622                 p1sizer->Add( m_P_atsPriHits, 0, wxALL|wxEXPAND, 1);
623                 p1->SetSizer( p1sizer );
624                 p1sizer->Fit( p1 );
625                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
626         }
627
628         // primary BH hits
629         {
630                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
631                 itxt->Wrap( -1 );
632                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
633                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
634                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
635                 m_P_atsPriBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
636                 m_P_atsPriBHHits->Wrap( -1 );
637                 p1sizer->Add( m_P_atsPriBHHits, 0, wxALL|wxEXPAND, 1);
638                 p1->SetSizer( p1sizer );
639                 p1sizer->Fit( p1 );
640                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
641         }
642
643         // primary hit %
644         {
645                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
646                 itxt->Wrap( -1 );
647                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
648                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
649                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
650                 m_P_atsPriHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
651                 m_P_atsPriHitPer->Wrap( -1 );
652                 p1sizer->Add( m_P_atsPriHitPer, 0, wxALL|wxEXPAND, 1);
653                 p1->SetSizer( p1sizer );
654                 p1sizer->Fit( p1 );
655                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
656         }
657
658         // primary BH hit %
659         {
660                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
661                 itxt->Wrap( -1 );
662                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
663                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
664                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
665                 m_P_atsPriBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
666                 m_P_atsPriBHHitPer->Wrap( -1 );
667                 p1sizer->Add( m_P_atsPriBHHitPer, 0, wxALL|wxEXPAND, 1);
668                 p1->SetSizer( p1sizer );
669                 p1sizer->Fit( p1 );
670                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
671         }
672
673         // secondary shots
674         {
675                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
676                 itxt->Wrap( -1 );
677                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
678                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
679                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
680                 m_P_atsSecShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
681                 m_P_atsSecShots->Wrap( -1 );
682                 p1sizer->Add( m_P_atsSecShots, 0, wxALL|wxEXPAND, 1);
683                 p1->SetSizer( p1sizer );
684                 p1sizer->Fit( p1 );
685                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
686         }
687
688         // secondary hits
689         {
690                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
691                 itxt->Wrap( -1 );
692                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
693                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
694                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
695                 m_P_atsSecHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
696                 m_P_atsSecHits->Wrap( -1 );
697                 p1sizer->Add( m_P_atsSecHits, 0, wxALL|wxEXPAND, 1);
698                 p1->SetSizer( p1sizer );
699                 p1sizer->Fit( p1 );
700                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
701         }
702
703         // secondary BH hits
704         {
705                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
706                 itxt->Wrap( -1 );
707                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
708                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
709                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
710                 m_P_atsSecBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
711                 m_P_atsSecBHHits->Wrap( -1 );
712                 p1sizer->Add( m_P_atsSecBHHits, 0, wxALL|wxEXPAND, 1);
713                 p1->SetSizer( p1sizer );
714                 p1sizer->Fit( p1 );
715                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
716         }
717
718         // secondary hit %
719         {
720                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
721                 itxt->Wrap( -1 );
722                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
723                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
724                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
725                 m_P_atsSecHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
726                 m_P_atsSecHitPer->Wrap( -1 );
727                 p1sizer->Add( m_P_atsSecHitPer, 0, wxALL|wxEXPAND, 1);
728                 p1->SetSizer( p1sizer );
729                 p1sizer->Fit( p1 );
730                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
731         }
732
733         // secondary BH hit %
734         {
735                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
736                 itxt->Wrap( -1 );
737                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
738                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
739                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
740                 m_P_atsSecBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
741                 m_P_atsSecBHHitPer->Wrap( -1 );
742                 p1sizer->Add( m_P_atsSecBHHitPer, 0, wxALL|wxEXPAND, 1);
743                 p1->SetSizer( p1sizer );
744                 p1sizer->Fit( p1 );
745                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
746         }
747
748         // assists
749         {
750                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Assists"), wxDefaultPosition, wxDefaultSize, 0 );
751                 itxt->Wrap( -1 );
752                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
753                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
754                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
755                 m_P_atsAssists = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
756                 m_P_atsAssists->Wrap( -1 );
757                 p1sizer->Add( m_P_atsAssists, 0, wxALL|wxEXPAND, 1);
758                 p1->SetSizer( p1sizer );
759                 p1sizer->Fit( p1 );
760                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
761         }
762
763         atsboxSizer->Add( atsgSizer, 1, wxEXPAND );
764
765         bSizer6->Add( atsboxSizer, 1, wxEXPAND, 5 );
766
767         wxStaticLine* m_staticline3 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
768         bSizer6->Add( m_staticline3, 0, wxEXPAND | wxALL, 5 );
769
770         //
771         // Mission Stats
772         //
773
774         wxBoxSizer* msboxSizer = new wxBoxSizer( wxVERTICAL );
775
776         wxStaticText* msText = new wxStaticText( panel, wxID_ANY, wxT("Mission Stats") );
777         msboxSizer->Add( msText, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
778
779         wxFlexGridSizer* msgSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
780         msgSizer->AddGrowableCol(1, 1);
781
782         // primary shots
783         {
784                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
785                 itxt->Wrap( -1 );
786                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
787                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
788                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
789                 m_P_msPriShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
790                 m_P_msPriShots->Wrap( -1 );
791                 p1sizer->Add( m_P_msPriShots, 1, wxALL|wxEXPAND, 1);
792                 p1->SetSizer( p1sizer );
793                 p1sizer->Fit( p1 );
794                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
795         }
796
797         // primary hits
798         {
799                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
800                 itxt->Wrap( -1 );
801                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
802                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
803                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
804                 m_P_msPriHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
805                 m_P_msPriHits->Wrap( -1 );
806                 p1sizer->Add( m_P_msPriHits, 0, wxALL|wxEXPAND, 1);
807                 p1->SetSizer( p1sizer );
808                 p1sizer->Fit( p1 );
809                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
810         }
811
812         // primary BH hits
813         {
814                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
815                 itxt->Wrap( -1 );
816                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
817                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
818                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
819                 m_P_msPriBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
820                 m_P_msPriBHHits->Wrap( -1 );
821                 p1sizer->Add( m_P_msPriBHHits, 0, wxALL|wxEXPAND, 1);
822                 p1->SetSizer( p1sizer );
823                 p1sizer->Fit( p1 );
824                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
825         }
826
827         // primary hit %
828         {
829                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
830                 itxt->Wrap( -1 );
831                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
832                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
833                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
834                 m_P_msPriHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
835                 m_P_msPriHitPer->Wrap( -1 );
836                 p1sizer->Add( m_P_msPriHitPer, 0, wxALL|wxEXPAND, 1);
837                 p1->SetSizer( p1sizer );
838                 p1sizer->Fit( p1 );
839                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
840         }
841
842         // primary BH hit %
843         {
844                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
845                 itxt->Wrap( -1 );
846                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
847                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
848                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
849                 m_P_msPriBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
850                 m_P_msPriBHHitPer->Wrap( -1 );
851                 p1sizer->Add( m_P_msPriBHHitPer, 0, wxALL|wxEXPAND, 1);
852                 p1->SetSizer( p1sizer );
853                 p1sizer->Fit( p1 );
854                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
855         }
856
857         // secondary shots
858         {
859                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
860                 itxt->Wrap( -1 );
861                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
862                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
863                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
864                 m_P_msSecShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
865                 m_P_msSecShots->Wrap( -1 );
866                 p1sizer->Add( m_P_msSecShots, 0, wxALL|wxEXPAND, 1);
867                 p1->SetSizer( p1sizer );
868                 p1sizer->Fit( p1 );
869                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
870         }
871
872         // secondary hits
873         {
874                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
875                 itxt->Wrap( -1 );
876                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
877                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
878                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
879                 m_P_msSecHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
880                 m_P_msSecHits->Wrap( -1 );
881                 p1sizer->Add( m_P_msSecHits, 0, wxALL|wxEXPAND, 1);
882                 p1->SetSizer( p1sizer );
883                 p1sizer->Fit( p1 );
884                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
885         }
886
887         // secondary BH hits
888         {
889                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
890                 itxt->Wrap( -1 );
891                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
892                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
893                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
894                 m_P_msSecBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
895                 m_P_msSecBHHits->Wrap( -1 );
896                 p1sizer->Add( m_P_msSecBHHits, 0, wxALL|wxEXPAND, 1);
897                 p1->SetSizer( p1sizer );
898                 p1sizer->Fit( p1 );
899                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
900         }
901
902         // secondary hit %
903         {
904                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
905                 itxt->Wrap( -1 );
906                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
907                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
908                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
909                 m_P_msSecHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
910                 m_P_msSecHitPer->Wrap( -1 );
911                 p1sizer->Add( m_P_msSecHitPer, 0, wxALL|wxEXPAND, 1);
912                 p1->SetSizer( p1sizer );
913                 p1sizer->Fit( p1 );
914                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
915         }
916
917         // secondary BH hit %
918         {
919                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
920                 itxt->Wrap( -1 );
921                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
922                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
923                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
924                 m_P_msSecBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
925                 m_P_msSecBHHitPer->Wrap( -1 );
926                 p1sizer->Add( m_P_msSecBHHitPer, 0, wxALL|wxEXPAND, 1);
927                 p1->SetSizer( p1sizer );
928                 p1sizer->Fit( p1 );
929                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
930         }
931
932         // assists
933         {
934                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Assists"), wxDefaultPosition, wxDefaultSize, 0 );
935                 itxt->Wrap( -1 );
936                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
937                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
938                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
939                 m_P_msAssists = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
940                 m_P_msAssists->Wrap( -1 );
941                 p1sizer->Add( m_P_msAssists, 0, wxALL|wxEXPAND, 1);
942                 p1->SetSizer( p1sizer );
943                 p1sizer->Fit( p1 );
944                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
945         }
946
947         msboxSizer->Add( msgSizer, 1, wxEXPAND );
948
949         bSizer6->Add( msboxSizer, 1, wxEXPAND );
950
951         bSizer->Add( bSizer6, 1, wxEXPAND );
952
953         panelSizer->Add( bSizer, 1, wxALL|wxEXPAND, 5 );
954
955         panel->SetSizer( panelSizer );
956         panelSizer->Fit( panel );
957         panelSizer->SetSizeHints(panel);
958
959         parent->AddPage( panel, wxT("Player Info") );
960 }
961
962 void Standalone::createTab_GodStuff(wxNotebook* parent)
963 {
964         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
965
966         wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
967
968         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
969
970         wxBoxSizer* bSizer2 = new wxBoxSizer( wxHORIZONTAL );
971
972         wxStaticText* m_staticText21 = new wxStaticText( panel, wxID_ANY, wxT("Player"), wxDefaultPosition, wxDefaultSize, 0 );
973         bSizer2->Add( m_staticText21, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
974
975         wxArrayString m_choice1Choices;
976         m_GS_Players = new wxChoice( panel, wxID_ANY, wxDefaultPosition, wxSize(200, -1), m_choice1Choices, 0 );
977         m_GS_Players->SetSelection( 0 );
978         bSizer2->Add( m_GS_Players, 0, wxALL|wxEXPAND, 5 );
979
980         bSizer->Add( bSizer2, 0, wxEXPAND, 5 );
981
982         bSizer->Add( 0, 0, 0, wxALL, 10 );
983
984         wxStaticText* m_staticText22 = new wxStaticText( panel, wxID_ANY, wxT("Server Message"), wxDefaultPosition, wxDefaultSize, 0 );
985         bSizer->Add( m_staticText22, 0, wxALL, 5 );
986
987         m_GS_msg = new wxTextCtrl( panel, ID_T_MSG, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
988         m_GS_msg->SetMaxLength(150);
989         bSizer->Add( m_GS_msg, 0, wxALL|wxEXPAND, 5 );
990
991         bSizer->Add( 0, 0, 0, wxALL, 5 );
992
993         m_GS_Messages = new wxTextCtrl( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY );
994         bSizer->Add( m_GS_Messages, 1, wxALL|wxEXPAND, 5 );
995
996         panelSizer->Add( bSizer, 1, wxALL|wxEXPAND, 5 );
997
998         panel->SetSizer( panelSizer );
999         panelSizer->Fit( panel );
1000         panelSizer->SetSizeHints( panel );
1001
1002         parent->AddPage( panel, wxT("God Stuff") );
1003 }
1004
1005 void Standalone::createTab_Debug(wxNotebook* parent)
1006 {
1007         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
1008
1009         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
1010
1011         wxBoxSizer* hbSizer = new wxBoxSizer( wxHORIZONTAL );
1012
1013         wxStaticText* m_staticText1 = new wxStaticText( panel, wxID_ANY, wxT("Standalone State :"), wxDefaultPosition, wxDefaultSize, 0 );
1014         hbSizer->Add( m_staticText1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
1015
1016         wxPanel* p1 = new wxPanel( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER );
1017
1018         wxBoxSizer* p1Sizer = new wxBoxSizer( wxHORIZONTAL );
1019
1020         m_D_State = new wxStaticText( p1, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
1021         p1Sizer->Add( m_D_State, 1, wxALL|wxEXPAND, 2);
1022
1023         p1->SetSizer( p1Sizer );
1024         p1Sizer->Fit( p1 );
1025
1026         hbSizer->Add( p1, 1, wxALL|wxEXPAND, 5 );
1027
1028         bSizer->Add( hbSizer, 0, wxALL|wxEXPAND, 5 );
1029
1030         panel->SetSizer( bSizer );
1031         panel->Layout();
1032
1033         bSizer->Fit( panel );
1034
1035         parent->AddPage( panel, wxT("Debug") );
1036 }
1037
1038 bool Standalone::startFreeSpace(int argc, wxCmdLineArgsArray &argv)
1039 {
1040         wxString epath = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath(true);
1041
1042 #ifdef MAKE_FS1
1043         epath.Append( wxT("freespace") );
1044 #else
1045         epath.Append( wxT("freespace2") );
1046 #endif
1047
1048 #ifdef FS2_DEMO
1049         epath.Append( wxT("_demo") );
1050 #endif
1051
1052 #ifdef _WIN32
1053         epath.Append( wxT(".exe") );
1054 #endif
1055
1056         epath.Append( wxT(" -standalone") );
1057
1058         for (int i = 1; i < argc; i++) {
1059                 wxString arg( argv[i] );
1060
1061                 // check if -port argument and set var
1062                 if ( arg.IsSameAs( wxT("-port"), false) && (argc > i+1) ) {
1063                         fsport = wxAtoi(argv[i+1]);
1064                 }
1065
1066                 epath.Append( wxT(" ") );
1067                 epath.Append(arg);
1068         }
1069
1070         fspid = wxExecute(epath, wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER | wxEXEC_HIDE_CONSOLE);
1071
1072         return (fspid > 0);
1073 }
1074
1075 void Standalone::ResetAll()
1076 {
1077         m_popup->Show(false);
1078
1079         m_S_ServerName->Clear();
1080         m_S_HostPass->Clear();
1081         m_S_NumConn->SetLabel( wxT("0") );
1082         m_S_Connections->Clear();
1083
1084         m_M_sliderFPS->SetValue(30);
1085         m_M_FPS->SetLabel("30");
1086         m_M_FPSRel->SetLabel( wxT("0.0") );
1087         m_M_MissionName->SetLabel("");
1088         m_M_MissionTime->SetLabel("");
1089         m_M_ngMaxPlayers->SetLabel("");
1090         m_M_ngMaxObservers->SetLabel("");
1091         m_M_ngSecurity->SetLabel("");
1092         m_M_ngRespawns->SetLabel("");
1093         m_M_Goals->DeleteAllItems();
1094
1095         m_P_Players->Clear();
1096         m_P_ShipType->SetLabel("");
1097         m_P_AvgPing->SetLabel("");
1098         m_P_atsPriShots->SetLabel("");
1099         m_P_atsPriHits->SetLabel("");
1100         m_P_atsPriBHHits->SetLabel("");
1101         m_P_atsPriHitPer->SetLabel("");
1102         m_P_atsPriBHHitPer->SetLabel("");
1103         m_P_atsSecShots->SetLabel("");
1104         m_P_atsSecHits->SetLabel("");
1105         m_P_atsSecBHHits->SetLabel("");
1106         m_P_atsSecHitPer->SetLabel("");
1107         m_P_atsSecBHHitPer->SetLabel("");
1108         m_P_atsAssists->SetLabel("");
1109         m_P_msPriShots->SetLabel("");
1110         m_P_msPriHits->SetLabel("");
1111         m_P_msPriBHHits->SetLabel("");
1112         m_P_msPriHitPer->SetLabel("");
1113         m_P_msPriBHHitPer->SetLabel("");
1114         m_P_msSecShots->SetLabel("");
1115         m_P_msSecHits->SetLabel("");
1116         m_P_msSecBHHits->SetLabel("");
1117         m_P_msSecHitPer->SetLabel("");
1118         m_P_msSecBHHitPer->SetLabel("");
1119         m_P_msAssists->SetLabel("");
1120
1121         m_GS_Players->Clear();
1122         m_GS_msg->Clear();
1123         m_GS_Messages->Clear();
1124
1125         m_D_State->SetLabel("");
1126 }
1127
1128 static int callback_standalone_client(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
1129 {
1130         #define MAX_BUF_SIZE    1050
1131         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_BUF_SIZE + LWS_SEND_BUFFER_POST_PADDING];
1132         unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
1133         int rval;
1134         int size;
1135
1136         switch (reason) {
1137                 case LWS_CALLBACK_CLIENT_ESTABLISHED:
1138                         lwsl_notice("CLIENT_ESTABLISHED\n");
1139                         lws_callback_on_writable(wsi);
1140                         break;
1141
1142                 case LWS_CALLBACK_CLOSED:
1143                         lwsl_notice("CLOSED\n");
1144                         wxGetApp().Client().wsDisconnect();
1145                         break;
1146
1147                 case LWS_CALLBACK_CLIENT_RECEIVE:
1148                         lwsl_notice("CLIENT_RECEIVE => in: %s, len: %lu\n", in ? (char*)in : "nul", len);
1149                         wxGetApp().Client().wsMessage( (const char *)in, len );
1150                         break;
1151
1152                 case LWS_CALLBACK_CLIENT_WRITEABLE: {
1153                         if ( !wxGetApp().Client().wsGetSendBuffer().empty() ) {
1154                                 std::string msg = wxGetApp().Client().wsGetSendBuffer().front();
1155
1156                                 lwsl_notice("CLIENT_WRITEABLE => msg: %s\n", msg.c_str());
1157                                 size = wxStrlcpy((char *)p, msg.c_str(), MAX_BUF_SIZE);
1158
1159                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
1160
1161                                 if (rval < size) {
1162                                         lwsl_err("ERROR sending buffer!\n");
1163                                         return -1;
1164                                 }
1165
1166                                 wxGetApp().Client().wsGetSendBuffer().pop_front();
1167
1168                                 lws_callback_on_writable(wsi);
1169                         } else lwsl_notice("CLIENT_WRITEABLE <empty>\n");
1170
1171
1172                         break;
1173                 }
1174
1175                 case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
1176                         lwsl_notice("CONNECTION_ERROR\n");
1177                         wxGetApp().Client().wsDisconnect();
1178                         break;
1179
1180                 default:
1181                         break;
1182         }
1183
1184         return 0;
1185 }
1186
1187 static struct lws_protocols protocols[] = {
1188         {
1189                 "standalone",
1190                 callback_standalone_client,
1191                 0,
1192                 0
1193         },
1194         { NULL, NULL, 0, 0 }
1195 };
1196
1197 bool Standalone::wsInitialize()
1198 {
1199         struct lws_context_creation_info info;
1200
1201         memset(&info, 0, sizeof(info));
1202         memset(&ccinfo, 0, sizeof(ccinfo));
1203
1204         info.port = CONTEXT_PORT_NO_LISTEN;
1205         info.protocols = protocols;
1206         info.gid = -1;
1207         info.uid = -1;
1208
1209         stand_context = lws_create_context(&info);
1210
1211         if (stand_context == NULL) {
1212                 return false;
1213         }
1214
1215         ccinfo.context = stand_context;
1216         ccinfo.address = "127.0.0.1";
1217         ccinfo.port = fsport;
1218         ccinfo.path = "/";
1219         ccinfo.host = ccinfo.address;
1220         ccinfo.origin = ccinfo.address;
1221         ccinfo.ietf_version_or_minus_one = -1;
1222         ccinfo.protocol = protocols[0].name;
1223
1224         // async call, actual connection to occur later
1225         wsi_standalone = lws_client_connect_via_info(&ccinfo);
1226
1227         lws_service(stand_context, 0);
1228
1229         return true;
1230 }
1231
1232 void Standalone::wsDoFrame()
1233 {
1234         if ( !stand_context ) {
1235                 return;
1236         }
1237
1238         // if connection is lost attempt reconnect every 2 seconds
1239         if ( !wsi_standalone && !(++m_rate_limit % 60) ) {
1240                 wsi_standalone = lws_client_connect_via_info(&ccinfo);
1241                 m_rate_limit = 0;
1242         }
1243
1244         lws_service(stand_context, 0);
1245 }
1246
1247 void Standalone::wsDisconnect()
1248 {
1249         lwsl_notice("disconnect!\n");
1250         wsi_standalone = NULL;
1251 }
1252
1253 void Standalone::wsMessage(const char *msg, size_t len)
1254 {
1255         if (msg == NULL || len < 5) {
1256                 return;
1257         }
1258
1259         if ( !wxStrcmp(msg, "reset") ) {
1260                 ResetAll();
1261                 return;
1262         }
1263
1264         if ( !wxStrncmp(msg, "popup ", 6) ) {
1265                 if (len == 6) {
1266                         m_popup->Show(false);
1267                 } else {
1268                         wxArrayString popmsg = wxSplit(msg+6, ';');
1269
1270                         m_popup->SetTitle( popmsg.Item(0) );
1271                         m_popup->SetLabel1( popmsg.Item(1) );
1272                         m_popup->SetLabel2( popmsg.Item(2) );
1273
1274                         m_popup->CenterOnParent();
1275                         m_popup->Show(true);
1276                 }
1277
1278                 return;
1279         }
1280
1281         char mtype = msg[0];
1282
1283         if (mtype == 'T') {
1284                 SetTitle(msg+2);
1285         } else if (mtype == 'D') {
1286                 m_D_State->SetLabel(msg+2);
1287         }
1288         // server tab
1289         else if (mtype == 'S') {
1290                 wxString cmd(msg+2, 4);
1291
1292                 if (cmd == "name") {
1293                         m_S_ServerName->SetValue(msg+7);
1294                 } else if (cmd == "pass") {
1295                         m_S_HostPass->SetValue(msg+7);
1296                 } else if (cmd == "conn") {
1297
1298                 } else if (cmd == "ping") {
1299
1300                 }
1301         }
1302         // multi-player tab
1303         else if (mtype == 'M') {
1304                 wxString cmd(msg+2, 4);
1305
1306                 if (cmd == "name") {
1307                         m_M_MissionName->SetLabel(msg+7);
1308                 } else if (cmd == "time") {
1309                         m_M_MissionTime->SetLabel(msg+7);
1310                 } else if (cmd == "info") {
1311                         wxArrayString ng_info = wxSplit(msg+7, ',');
1312
1313                         m_M_ngMaxPlayers->SetLabel( ng_info.Item(0) );
1314                         m_M_ngMaxObservers->SetLabel( ng_info.Item(1) );
1315                         m_M_ngSecurity->SetLabel( ng_info.Item(2) );
1316                         m_M_ngRespawns->SetLabel( ng_info.Item(3) );
1317                 } else if (cmd == "fps ") {
1318                         m_M_FPSRel->SetLabel(msg+6);
1319                 } else if (cmd == "goal") {
1320
1321                 }
1322         }
1323         // player tab
1324         else if (mtype == 'P') {
1325                 wxString cmd(msg+2, 4);
1326
1327                 if (cmd == "info") {
1328
1329                 }
1330         }
1331         // god stuff tab
1332         else if (mtype == 'G') {
1333                 wxString cmd(msg+2, 4);
1334
1335                 if (cmd == "mesg") {
1336                         m_GS_Messages->AppendText(msg+7);
1337                 }
1338         }
1339 }
1340
1341 void Standalone::wsSend(std::string &msg)
1342 {
1343         send_buf.push_back(msg);
1344
1345         if (wsi_standalone) {
1346                 lws_callback_on_writable(wsi_standalone);
1347         }
1348 }