/[pcsx2_0.9.7]/trunk/pcsx2/gui/FrameForGS.cpp
ViewVC logotype

Contents of /trunk/pcsx2/gui/FrameForGS.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 1 month ago) by william
File size: 13691 byte(s)
re-commit (had local access denied errors when committing)
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "PrecompiledHeader.h"
17 #include "App.h"
18 #include "GSFrame.h"
19 #include "AppAccelerators.h"
20
21 #include "GS.h"
22 #include "MSWstuff.h"
23
24 #include <wx/utils.h>
25
26 void GSPanel::InitDefaultAccelerators()
27 {
28 // Note! These don't really work yet due to some hacks to get things working for
29 // old legacy PAD plugins. (the global accelerator tables are used instead) --air
30
31 typedef KeyAcceleratorCode AAC;
32
33 if( !m_Accels ) m_Accels = new AcceleratorDictionary;
34
35 m_Accels->Map( AAC( WXK_F1 ), "States_FreezeCurrentSlot" );
36 m_Accels->Map( AAC( WXK_F3 ), "States_DefrostCurrentSlot");
37 m_Accels->Map( AAC( WXK_F2 ), "States_CycleSlotForward" );
38 m_Accels->Map( AAC( WXK_F2 ).Shift(), "States_CycleSlotBackward" );
39
40 m_Accels->Map( AAC( WXK_F4 ), "Framelimiter_MasterToggle");
41 m_Accels->Map( AAC( WXK_F4 ).Shift(), "Frameskip_Toggle");
42 m_Accels->Map( AAC( WXK_TAB ), "Framelimiter_TurboToggle" );
43 m_Accels->Map( AAC( WXK_TAB ).Shift(), "Framelimiter_MasterToggle" );
44
45 m_Accels->Map( AAC( WXK_ESCAPE ), "Sys_Suspend" );
46 m_Accels->Map( AAC( WXK_F8 ), "Sys_TakeSnapshot" );
47 m_Accels->Map( AAC( WXK_F8 ).Shift(), "Sys_TakeSnapshot");
48 m_Accels->Map( AAC( WXK_F8 ).Shift().Cmd(), "Sys_TakeSnapshot");
49 m_Accels->Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle");
50
51 //m_Accels->Map( AAC( WXK_F10 ), "Sys_LoggingToggle" );
52 m_Accels->Map( AAC( WXK_F11 ), "Sys_FreezeGS" );
53 m_Accels->Map( AAC( WXK_F12 ), "Sys_RecordingToggle" );
54
55 m_Accels->Map( AAC( WXK_RETURN ).Alt(), "FullscreenToggle" );
56 }
57
58 GSPanel::GSPanel( wxWindow* parent )
59 : wxWindow()
60 , m_HideMouseTimer( this )
61 {
62 m_CursorShown = true;
63 m_HasFocus = false;
64
65 if ( !wxWindow::Create(parent, wxID_ANY) )
66 throw Exception::RuntimeError().SetDiagMsg( L"GSPanel constructor esplode!!" );
67
68 SetName( L"GSPanel" );
69
70 InitDefaultAccelerators();
71
72 if( g_Conf->GSWindow.AlwaysHideMouse )
73 {
74 SetCursor( wxCursor(wxCURSOR_BLANK) );
75 m_CursorShown = false;
76 }
77
78 Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSPanel::OnCloseWindow));
79 Connect(wxEVT_SIZE, wxSizeEventHandler (GSPanel::OnResize));
80 Connect(wxEVT_KEY_DOWN, wxKeyEventHandler (GSPanel::OnKeyDown));
81
82 Connect(wxEVT_SET_FOCUS, wxFocusEventHandler (GSPanel::OnFocus));
83 Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler (GSPanel::OnFocusLost));
84
85 Connect(m_HideMouseTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(GSPanel::OnHideMouseTimeout) );
86
87 // Any and all events which should result in the mouse cursor being made visible
88 // are connected here. If I missed one, feel free to add it in! --air
89
90 Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler (GSPanel::OnShowMouse));
91 Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler (GSPanel::OnShowMouse));
92 Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler (GSPanel::OnShowMouse));
93 Connect(wxEVT_RIGHT_UP, wxMouseEventHandler (GSPanel::OnShowMouse));
94 Connect(wxEVT_MOTION, wxMouseEventHandler (GSPanel::OnShowMouse));
95 Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler (GSPanel::OnShowMouse));
96 Connect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler (GSPanel::OnShowMouse));
97 Connect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler (GSPanel::OnShowMouse));
98 Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler (GSPanel::OnShowMouse));
99 }
100
101 GSPanel::~GSPanel() throw()
102 {
103 //CoreThread.Suspend( false ); // Just in case...!
104 }
105
106 void GSPanel::DoShowMouse()
107 {
108 if( g_Conf->GSWindow.AlwaysHideMouse ) return;
109
110 if( !m_CursorShown )
111 {
112 SetCursor( wxCursor( wxCURSOR_DEFAULT ) );
113 m_CursorShown = true;
114 }
115 m_HideMouseTimer.Start( 1750, true );
116 }
117
118 void GSPanel::DoResize()
119 {
120 if( GetParent() == NULL ) return;
121 wxSize client = GetParent()->GetClientSize();
122 wxSize viewport = client;
123
124 switch( g_Conf->GSWindow.AspectRatio )
125 {
126 case AspectRatio_Stretch:
127 // Default to matching client size.
128 // Add a few pixels here, so the outermost pixels of the GS plugin output are "hidden".
129 // This avoids issues with flashing pixels on the edges, especially when Anti Aliasing is used.
130 viewport.x+=4;
131 viewport.y+=4;
132 break;
133
134 case AspectRatio_4_3:
135 if( client.x/4 <= client.y/3 )
136 viewport.y = (int)(client.x * (3.0/4.0));
137 else
138 viewport.x = (int)(client.y * (4.0/3.0));
139 break;
140
141 case AspectRatio_16_9:
142 if( client.x/16 <= client.y/9 )
143 viewport.y = (int)(client.x * (9.0/16.0));
144 else
145 viewport.x = (int)(client.y * (16.0/9.0));
146 break;
147 }
148
149 SetSize( viewport );
150 CenterOnParent();
151 }
152
153 void GSPanel::OnResize(wxSizeEvent& event)
154 {
155 if( IsBeingDeleted() ) return;
156 DoResize();
157 //Console.Error( "Size? %d x %d", GetSize().x, GetSize().y );
158 //event.
159 }
160
161 void GSPanel::OnCloseWindow(wxCloseEvent& evt)
162 {
163 CoreThread.Suspend();
164 evt.Skip(); // and close it.
165 }
166
167 void GSPanel::OnShowMouse( wxMouseEvent& evt )
168 {
169 if( IsBeingDeleted() ) return;
170 evt.Skip();
171 DoShowMouse();
172 }
173
174 void GSPanel::OnHideMouseTimeout( wxTimerEvent& evt )
175 {
176 if( IsBeingDeleted() || !m_HasFocus ) return;
177 if( CoreThread.GetExecutionMode() != SysThreadBase::ExecMode_Opened ) return;
178
179 SetCursor( wxCursor( wxCURSOR_BLANK ) );
180 m_CursorShown = false;
181 }
182
183 void GSPanel::OnKeyDown( wxKeyEvent& evt )
184 {
185 // HACK: Legacy PAD plugins expect PCSX2 to ignore keyboard messages on the GS Window while
186 // the PAD plugin is open, so ignore here (PCSX2 will direct messages routed from PAD directly
187 // to the APP level message handler, which in turn routes them right back here -- yes it's
188 // silly, but oh well).
189
190 if( (PADopen != NULL) && CoreThread.IsOpen() ) return;
191 DirectKeyCommand( evt );
192 }
193
194 void GSPanel::DirectKeyCommand( wxKeyEvent& evt )
195 {
196 const GlobalCommandDescriptor* cmd = NULL;
197 m_Accels->TryGetValue( KeyAcceleratorCode( evt ).val32, cmd );
198 if( cmd == NULL ) return;
199
200 DbgCon.WriteLn( "(gsFrame) Invoking command: %s", cmd->Id );
201 cmd->Invoke();
202 }
203
204 void GSPanel::OnFocus( wxFocusEvent& evt )
205 {
206 evt.Skip();
207 m_HasFocus = true;
208
209 if( g_Conf->GSWindow.AlwaysHideMouse )
210 {
211 SetCursor( wxCursor(wxCURSOR_BLANK) );
212 m_CursorShown = false;
213 }
214 else
215 DoShowMouse();
216
217 //Console.Warning("GS frame > focus set");
218 }
219
220 void GSPanel::OnFocusLost( wxFocusEvent& evt )
221 {
222 evt.Skip();
223 m_HasFocus = false;
224 DoShowMouse();
225 //Console.Warning("GS frame > focus lost");
226 }
227
228 void GSPanel::AppStatusEvent_OnSettingsApplied()
229 {
230 if( IsBeingDeleted() ) return;
231 DoResize();
232 DoShowMouse();
233 Show( !EmuConfig.GS.DisableOutput );
234 }
235
236 // --------------------------------------------------------------------------------------
237 // GSFrame Implementation
238 // --------------------------------------------------------------------------------------
239
240 static const uint TitleBarUpdateMs = 333;
241
242 GSFrame::GSFrame(wxWindow* parent, const wxString& title)
243 : wxFrame(parent, wxID_ANY, title,
244 g_Conf->GSWindow.WindowPos, wxSize( 640, 480 ),
245 (g_Conf->GSWindow.DisableResizeBorders ? 0 : wxRESIZE_BORDER) | wxCAPTION | wxCLIP_CHILDREN |
246 wxSYSTEM_MENU | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCLOSE_BOX
247 )
248 , m_timer_UpdateTitle( this )
249 {
250 SetIcons( wxGetApp().GetIconBundle() );
251 SetClientSize( g_Conf->GSWindow.WindowSize );
252 SetBackgroundColour( *wxBLACK );
253
254 wxStaticText* label = new wxStaticText( this, wxID_ANY, _("GS Output is Disabled!") );
255 m_id_OutputDisabled = label->GetId();
256 label->SetFont( wxFont( 20, wxDEFAULT, wxNORMAL, wxBOLD ) );
257 label->SetForegroundColour( *wxWHITE );
258 label->Show( EmuConfig.GS.DisableOutput );
259
260 GSPanel* gsPanel = new GSPanel( this );
261 gsPanel->Show( !EmuConfig.GS.DisableOutput );
262 m_id_gspanel = gsPanel->GetId();
263
264 // TODO -- Implement this GS window status window! Whee.
265 // (main concern is retaining proper client window sizes when closing/re-opening the window).
266 //m_statusbar = CreateStatusBar( 2 );
267
268 Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSFrame::OnCloseWindow) );
269 Connect( wxEVT_MOVE, wxMoveEventHandler (GSFrame::OnMove) );
270 Connect( wxEVT_SIZE, wxSizeEventHandler (GSFrame::OnResize) );
271 Connect( wxEVT_ACTIVATE, wxActivateEventHandler (GSFrame::OnActivate) );
272
273 Connect(m_timer_UpdateTitle.GetId(), wxEVT_TIMER, wxTimerEventHandler(GSFrame::OnUpdateTitle) );
274 }
275
276 GSFrame::~GSFrame() throw()
277 {
278 }
279
280 void GSFrame::OnCloseWindow(wxCloseEvent& evt)
281 {
282 sApp.OnGsFrameClosed( GetId() );
283 evt.Skip(); // and close it.
284 }
285
286 bool GSFrame::ShowFullScreen(bool show, long style)
287 {
288 if( show != IsFullScreen() )
289 Console.WriteLn( Color_StrongMagenta, "(gsFrame) Switching to %s mode...", show ? "Fullscreen" : "Windowed" );
290
291 if( g_Conf->GSWindow.IsFullscreen != show )
292 {
293 g_Conf->GSWindow.IsFullscreen = show;
294 wxGetApp().PostIdleMethod( AppSaveSettings );
295 }
296
297 // IMPORTANT! On MSW platforms you must ALWAYS show the window prior to calling
298 // ShowFullscreen(), otherwise the window will be oddly unstable (lacking input and unable
299 // to properly flip back into fullscreen mode after alt-enter). I don't know if that
300 // also happens on Linux.
301
302 if( !IsShown() ) Show();
303 bool retval = _parent::ShowFullScreen( show );
304
305 return retval;
306 }
307
308 wxStaticText* GSFrame::GetLabel_OutputDisabled() const
309 {
310 return (wxStaticText*)FindWindowById( m_id_OutputDisabled );
311 }
312
313 void GSFrame::CoreThread_OnResumed()
314 {
315 m_timer_UpdateTitle.Start( TitleBarUpdateMs );
316 }
317
318 void GSFrame::CoreThread_OnSuspended()
319 {
320 if( !IsBeingDeleted() && g_Conf->GSWindow.CloseOnEsc ) Hide();
321 }
322
323 void GSFrame::CoreThread_OnStopped()
324 {
325 //if( !IsBeingDeleted() ) Destroy();
326 }
327
328 void GSFrame::CorePlugins_OnShutdown()
329 {
330 if( !IsBeingDeleted() ) Destroy();
331 }
332
333 // overrides base Show behavior.
334 bool GSFrame::Show( bool shown )
335 {
336 if( shown )
337 {
338 GSPanel* gsPanel = GetViewport();
339
340 if( !gsPanel || gsPanel->IsBeingDeleted() )
341 {
342 gsPanel = new GSPanel( this );
343 m_id_gspanel = gsPanel->GetId();
344 }
345
346 gsPanel->Show( !EmuConfig.GS.DisableOutput );
347 gsPanel->DoResize();
348 gsPanel->SetFocus();
349
350 if( wxStaticText* label = GetLabel_OutputDisabled() )
351 label->Show( EmuConfig.GS.DisableOutput );
352
353 if( !m_timer_UpdateTitle.IsRunning() )
354 m_timer_UpdateTitle.Start( TitleBarUpdateMs );
355 }
356 else
357 {
358 m_timer_UpdateTitle.Stop();
359 }
360
361 return _parent::Show( shown );
362 }
363
364 void GSFrame::AppStatusEvent_OnSettingsApplied()
365 {
366 if( IsBeingDeleted() ) return;
367
368 if( g_Conf->GSWindow.CloseOnEsc )
369 {
370 if( IsShown() && !CorePlugins.IsOpen(PluginId_GS) )
371 Show( false );
372 }
373
374 if( wxStaticText* label = GetLabel_OutputDisabled() )
375 label->Show( EmuConfig.GS.DisableOutput );
376 }
377
378 GSPanel* GSFrame::GetViewport()
379 {
380 return (GSPanel*)FindWindowById( m_id_gspanel );
381 }
382
383
384 void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
385 {
386 double fps = wxGetApp().FpsManager.GetFramerate();
387
388 char gsDest[128];
389 GSgetTitleInfo2( gsDest, sizeof(gsDest) );
390
391 const wxChar* limiterStr = L"None";
392
393 if( g_Conf->EmuOptions.GS.FrameLimitEnable )
394 {
395 switch( g_LimiterMode )
396 {
397 case Limit_Nominal: limiterStr = L"Normal"; break;
398 case Limit_Turbo: limiterStr = L"Turbo"; break;
399 case Limit_Slomo: limiterStr = L"Slomo"; break;
400 }
401 }
402
403 FastFormatUnicode cpuUsage;
404 if( m_CpuUsage.IsImplemented() )
405 {
406 m_CpuUsage.UpdateStats();
407 cpuUsage.Write( L" | EE: %3d%% | GS: %3d%% | UI: %3d%%", m_CpuUsage.GetEEcorePct(), m_CpuUsage.GetGsPct(), m_CpuUsage.GetGuiPct() );
408 }
409
410 const u64& smode2 = *(u64*)PS2GS_BASE(GS_SMODE2);
411
412 SetTitle( pxsFmt( L"%s | %s (%s) | Limiter: %s | fps: %6.02f%s",
413 fromUTF8(gsDest).c_str(),
414 (smode2 & 1) ? L"Interlaced" : L"Progressive",
415 (smode2 & 2) ? L"frame" : L"field",
416 limiterStr, fps, cpuUsage.c_str() )
417 );
418
419 //States_GetCurrentSlot()
420 }
421
422 void GSFrame::OnActivate( wxActivateEvent& evt )
423 {
424 if( IsBeingDeleted() ) return;
425
426 evt.Skip();
427 if( wxWindow* gsPanel = GetViewport() ) gsPanel->SetFocus();
428 }
429
430 void GSFrame::OnMove( wxMoveEvent& evt )
431 {
432 if( IsBeingDeleted() ) return;
433
434 evt.Skip();
435
436 g_Conf->GSWindow.IsMaximized = IsMaximized();
437
438 // evt.GetPosition() returns the client area position, not the window frame position.
439 if( !g_Conf->GSWindow.IsMaximized && !IsFullScreen() && !IsIconized() && IsVisible() )
440 g_Conf->GSWindow.WindowPos = GetScreenPosition();
441
442 // wxGTK note: X sends gratuitous amounts of OnMove messages for various crap actions
443 // like selecting or deselecting a window, which muck up docking logic. We filter them
444 // out using 'lastpos' here. :)
445
446 //static wxPoint lastpos( wxDefaultCoord, wxDefaultCoord );
447 //if( lastpos == evt.GetPosition() ) return;
448 //lastpos = evt.GetPosition();
449 }
450
451 void GSFrame::SetFocus()
452 {
453 _parent::SetFocus();
454 if( GSPanel* gsPanel = GetViewport() )
455 gsPanel->SetFocusFromKbd();
456 }
457
458 void GSFrame::OnResize( wxSizeEvent& evt )
459 {
460 if( IsBeingDeleted() ) return;
461
462 if( !IsFullScreen() && !IsMaximized() && IsVisible() )
463 {
464 g_Conf->GSWindow.WindowSize = GetClientSize();
465 }
466
467 if( wxStaticText* label = GetLabel_OutputDisabled() )
468 label->CentreOnParent();
469
470 if( GSPanel* gsPanel = GetViewport() )
471 {
472 gsPanel->DoResize();
473 gsPanel->SetFocus();
474 }
475
476 //wxPoint hudpos = wxPoint(-10,-10) + (GetClientSize() - m_hud->GetSize());
477 //m_hud->SetPosition( hudpos ); //+ GetScreenPosition() + GetClientAreaOrigin() );
478
479 // if we skip, the panel is auto-sized to fit our window anyway, which we do not want!
480 //evt.Skip();
481 }

  ViewVC Help
Powered by ViewVC 1.1.22