recording: Many adjustments on VirtualPad from review feedback

recording: Factor in DPIScaling when scaling VirtualPad window


recording: Add a reset button, hopefully better quality backgrounds for lower resolutions


recording: Improved VPad analog alignment

Co-authored-by: sonicfind
recording: Some final VirtualPad coordinate adjustments
This commit is contained in:
Tyler Wilding 2020-09-27 20:18:19 -04:00 committed by refractionpcsx2
parent 28a4d0390f
commit 400ed82715
18 changed files with 266 additions and 221 deletions

3
.gitattributes vendored
View File

@ -6,6 +6,3 @@
*.props text eol=crlf *.props text eol=crlf
*.vcxproj text eol=crlf *.vcxproj text eol=crlf
*.vcxproj.filters text eol=crlf *.vcxproj.filters text eol=crlf
# Hide generated files for easier pull-request reviewing
pcsx2/Recording/VirtualPad/img/*.h linguist-generated

View File

@ -78,13 +78,13 @@ jobs:
string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC)
message("::set-output name=timestamp::${current_date}") message("::set-output name=timestamp::${current_date}")
# - name: ccache cache files - name: ccache cache files
# uses: actions/cache@v2 uses: actions/cache@v2
# with: with:
# path: .ccache path: .ccache
# key: ${{ matrix.os }}-${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.compiler-version }}-ccache-${{ steps.ccache_cache_timestamp.outputs.timestamp }} key: ${{ matrix.os }}-${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.compiler-version }}-ccache-${{ steps.ccache_cache_timestamp.outputs.timestamp }}
# restore-keys: | restore-keys: |
# ${{ matrix.os }}-${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.compiler-version }}-ccache- ${{ matrix.os }}-${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.compiler-version }}-ccache-
- name: Install Packages - name: Install Packages
env: env:
@ -102,4 +102,3 @@ jobs:
chmod +x .github/workflows/scripts/build-linux.sh chmod +x .github/workflows/scripts/build-linux.sh
./.github/workflows/scripts/build-linux.sh generate_cmake ./.github/workflows/scripts/build-linux.sh generate_cmake
./.github/workflows/scripts/build-linux.sh compile ./.github/workflows/scripts/build-linux.sh compile
ls ./pcsx2/Recording/VirtualPad/img

View File

@ -507,7 +507,9 @@ set(pcsx2RecordingHeaders
set(res_rec_vp_src "${CMAKE_SOURCE_DIR}/pcsx2/Recording/VirtualPad/img") set(res_rec_vp_src "${CMAKE_SOURCE_DIR}/pcsx2/Recording/VirtualPad/img")
set(pcsx2RecordingVirtualPadResources set(pcsx2RecordingVirtualPadResources
${res_rec_vp_src}/circlePressed.h ${res_rec_vp_src}/circlePressed.h
${res_rec_vp_src}/controller.h ${res_rec_vp_src}/controllerFull.h
${res_rec_vp_src}/controllerHalf.h
${res_rec_vp_src}/controllerThreeQuarters.h
${res_rec_vp_src}/crossPressed.h ${res_rec_vp_src}/crossPressed.h
${res_rec_vp_src}/downPressed.h ${res_rec_vp_src}/downPressed.h
${res_rec_vp_src}/l1Pressed.h ${res_rec_vp_src}/l1Pressed.h
@ -760,7 +762,7 @@ endforeach()
### Generate Recording resource files ### Generate Recording resource files
### Drop them into the folder alongside the png files ### Drop them into the folder alongside the png files
foreach(res_file IN ITEMS foreach(res_file IN ITEMS
circlePressed controller crossPressed downPressed l1Pressed l2Pressed l3Pressed leftPressed circlePressed controllerFull controllerHalf controllerThreeQuarters crossPressed downPressed l1Pressed l2Pressed l3Pressed leftPressed
r1Pressed r2Pressed r3Pressed rightPressed selectPressed squarePressed startPressed trianglePressed upPressed) r1Pressed r2Pressed r3Pressed rightPressed selectPressed squarePressed startPressed trianglePressed upPressed)
add_custom_command(OUTPUT "${res_rec_vp_src}/${res_file}.h" COMMAND perl ${CMAKE_SOURCE_DIR}/linux_various/hex2h.pl "${res_rec_vp_src}/${res_file}.png" "${res_rec_vp_src}/${res_file}" ) add_custom_command(OUTPUT "${res_rec_vp_src}/${res_file}.h" COMMAND perl ${CMAKE_SOURCE_DIR}/linux_various/hex2h.pl "${res_rec_vp_src}/${res_file}.png" "${res_rec_vp_src}/${res_file}" )
endforeach() endforeach()

View File

@ -91,11 +91,9 @@ void InputRecording::ControllerInterrupt(u8 &data, u8 &port, u16 &bufCount, u8 b
if (bufCount == 1) if (bufCount == 1)
fInterruptFrame = data == READ_DATA_AND_VIBRATE_FIRST_BYTE; fInterruptFrame = data == READ_DATA_AND_VIBRATE_FIRST_BYTE;
else if (bufCount == 2) else if (bufCount == 2 && buf[bufCount] != READ_DATA_AND_VIBRATE_SECOND_BYTE)
{
if (buf[bufCount] != READ_DATA_AND_VIBRATE_SECOND_BYTE)
fInterruptFrame = false; fInterruptFrame = false;
}
// We do not want to record or save the first two bytes in the data returned from the PAD plugin // We do not want to record or save the first two bytes in the data returned from the PAD plugin
else if (fInterruptFrame && bufCount >= 3 && frameCounter >= 0 && frameCounter < INT_MAX) else if (fInterruptFrame && bufCount >= 3 && frameCounter >= 0 && frameCounter < INT_MAX)
{ {
@ -109,39 +107,32 @@ void InputRecording::ControllerInterrupt(u8 &data, u8 &port, u16 &bufCount, u8 b
{ {
// Overwrite value originally provided by the PAD plugin // Overwrite value originally provided by the PAD plugin
bufVal = tmp; bufVal = tmp;
// Update controller data state for future VirtualPad / logging usage.
padData[port]->UpdateControllerData(bufIndex, bufVal);
if (virtualPads[port] && virtualPads[port]->IsShown())
{
virtualPads[port]->UpdateControllerData(bufIndex, padData[port]);
}
} }
} }
// Update controller data state for future VirtualPad / logging usage. // Update controller data state for future VirtualPad / logging usage.
padData[port]->UpdateControllerData(bufIndex, bufVal); padData[port]->UpdateControllerData(bufIndex, bufVal);
if (virtualPads[port] && virtualPads[port]->IsShown()) if (virtualPads[port] &&
virtualPads[port]->IsShown() &&
virtualPads[port]->UpdateControllerData(bufIndex, padData[port]) &&
state != InputRecordingMode::Replaying)
{ {
// If the VirtualPad updated the PadData, we have to update the buffer // If the VirtualPad updated the PadData, we have to update the buffer
// before committing it to the recording / sending it to the game // before committing it to the recording / sending it to the game
// - Do not do this if we are in replay mode! // - Do not do this if we are in replay mode!
if (virtualPads[port]->UpdateControllerData(bufIndex, padData[port]) && state != InputRecordingMode::Replaying)
{
bufVal = padData[port]->PollControllerData(bufIndex); bufVal = padData[port]->PollControllerData(bufIndex);
} }
}
// If we have reached the end of the pad data, log it out // If we have reached the end of the pad data, log it out
if (bufIndex == PadData::END_INDEX_CONTROLLER_BUFFER) { if (bufIndex == PadData::END_INDEX_CONTROLLER_BUFFER)
{
padData[port]->LogPadData(port); padData[port]->LogPadData(port);
// As well as re-render the virtual pad UI, if applicable // As well as re-render the virtual pad UI, if applicable
// - Don't render if it's minimized // - Don't render if it's minimized
if (virtualPads[port] && virtualPads[port]->IsShown() && !virtualPads[port]->IsIconized()) if (virtualPads[port] && virtualPads[port]->IsShown() && !virtualPads[port]->IsIconized())
{
virtualPads[port]->Redraw(); virtualPads[port]->Redraw();
} }
}
// Finally, commit the byte to the movie file if we are recording // Finally, commit the byte to the movie file if we are recording
if (state == InputRecordingMode::Recording) if (state == InputRecordingMode::Recording)
@ -223,12 +214,16 @@ wxString InputRecording::RecordingModeTitleSegment()
void InputRecording::SetToRecordMode() void InputRecording::SetToRecordMode()
{ {
state = InputRecordingMode::Recording; state = InputRecordingMode::Recording;
virtualPads[CONTROLLER_PORT_ONE]->SetReadOnlyMode(false);
virtualPads[CONTROLLER_PORT_TWO]->SetReadOnlyMode(false);
recordingConLog("[REC]: Record mode ON.\n"); recordingConLog("[REC]: Record mode ON.\n");
} }
void InputRecording::SetToReplayMode() void InputRecording::SetToReplayMode()
{ {
state = InputRecordingMode::Replaying; state = InputRecordingMode::Replaying;
virtualPads[CONTROLLER_PORT_ONE]->SetReadOnlyMode(true);
virtualPads[CONTROLLER_PORT_TWO]->SetReadOnlyMode(true);
recordingConLog("[REC]: Replay mode ON.\n"); recordingConLog("[REC]: Replay mode ON.\n");
} }
@ -272,6 +267,8 @@ void InputRecording::SetStartingFrame(u32 newStartingFrame)
void InputRecording::Stop() void InputRecording::Stop()
{ {
state = InputRecordingMode::NotActive; state = InputRecordingMode::NotActive;
virtualPads[CONTROLLER_PORT_ONE]->SetReadOnlyMode(false);
virtualPads[CONTROLLER_PORT_TWO]->SetReadOnlyMode(false);
incrementUndo = false; incrementUndo = false;
if (inputRecordingData.Close()) if (inputRecordingData.Close())
recordingConLog(L"[REC]: InputRecording Recording Stopped.\n"); recordingConLog(L"[REC]: InputRecording Recording Stopped.\n");
@ -303,7 +300,7 @@ bool InputRecording::Create(wxString FileName, bool fromSaveState, wxString auth
inputRecordingData.GetHeader().SetGameName(resolveGameName()); inputRecordingData.GetHeader().SetGameName(resolveGameName());
// Write header contents // Write header contents
inputRecordingData.WriteHeader(); inputRecordingData.WriteHeader();
state = InputRecordingMode::Recording; SetToRecordMode();
g_InputRecordingControls.DisableFrameAdvance(); g_InputRecordingControls.DisableFrameAdvance();
recordingConLog(wxString::Format(L"[REC]: Started new recording - [%s]\n", FileName)); recordingConLog(wxString::Format(L"[REC]: Started new recording - [%s]\n", FileName));
return true; return true;
@ -348,7 +345,7 @@ bool InputRecording::Play(wxString fileName)
recordingConLog(L"[REC]: Recording was possibly constructed for a different game.\n"); recordingConLog(L"[REC]: Recording was possibly constructed for a different game.\n");
incrementUndo = true; incrementUndo = true;
state = InputRecordingMode::Replaying; SetToReplayMode();
g_InputRecordingControls.DisableFrameAdvance(); g_InputRecordingControls.DisableFrameAdvance();
recordingConLog(wxString::Format(L"[REC]: Replaying input recording - [%s]\n", inputRecordingData.GetFilename())); recordingConLog(wxString::Format(L"[REC]: Replaying input recording - [%s]\n", inputRecordingData.GetFilename()));
recordingConLog(wxString::Format(L"[REC]: PCSX2 Version Used: %s\n", inputRecordingData.GetHeader().emu)); recordingConLog(wxString::Format(L"[REC]: PCSX2 Version Used: %s\n", inputRecordingData.GetHeader().emu));

View File

@ -87,7 +87,7 @@ public:
bool Play(wxString filename); bool Play(wxString filename);
// Stop the active input recording // Stop the active input recording
void Stop(); void Stop();
// Initialze VirtualPad window
void setVirtualPadPtr(VirtualPad* ptr, int const port); void setVirtualPadPtr(VirtualPad* ptr, int const port);
private: private:

View File

@ -65,7 +65,8 @@ wxString NewRecordingFrame::GetFile() const
wxString path = m_filePicker->GetPath(); wxString path = m_filePicker->GetPath();
// wxWidget's removes the extension if it contains wildcards // wxWidget's removes the extension if it contains wildcards
// on wxGTK https://trac.wxwidgets.org/ticket/15285 // on wxGTK https://trac.wxwidgets.org/ticket/15285
if (!path.EndsWith(".p2m2")) { if (!path.EndsWith(".p2m2"))
{
return wxString::Format("%s.p2m2", path); return wxString::Format("%s.p2m2", path);
} }
return path; return path;

View File

@ -184,10 +184,8 @@ wxString PadData::RawPadBytesToString(int start, int end)
{ {
str += wxString::Format("%d", PollControllerData(i)); str += wxString::Format("%d", PollControllerData(i));
if (i != end - 1) if (i != end - 1)
{
str += ", "; str += ", ";
} }
}
return str; return str;
} }

View File

@ -20,6 +20,7 @@
#include <math.h> #include <math.h>
#include "App.h" #include "App.h"
#include "MSWstuff.h"
#include "Utilities/EmbeddedImage.h" #include "Utilities/EmbeddedImage.h"
#include "wx/dcbuffer.h" #include "wx/dcbuffer.h"
#include "wx/display.h" #include "wx/display.h"
@ -29,7 +30,9 @@
#include "Recording/VirtualPad/VirtualPadResources.h" #include "Recording/VirtualPad/VirtualPadResources.h"
#include "Recording/VirtualPad/img/circlePressed.h" #include "Recording/VirtualPad/img/circlePressed.h"
#include "Recording/VirtualPad/img/controller.h" #include "Recording/VirtualPad/img/controllerFull.h"
#include "Recording/VirtualPad/img/controllerThreeQuarters.h"
#include "Recording/VirtualPad/img/controllerHalf.h"
#include "Recording/VirtualPad/img/crossPressed.h" #include "Recording/VirtualPad/img/crossPressed.h"
#include "Recording/VirtualPad/img/downPressed.h" #include "Recording/VirtualPad/img/downPressed.h"
#include "Recording/VirtualPad/img/l1Pressed.h" #include "Recording/VirtualPad/img/l1Pressed.h"
@ -46,57 +49,72 @@
#include "Recording/VirtualPad/img/trianglePressed.h" #include "Recording/VirtualPad/img/trianglePressed.h"
#include "Recording/VirtualPad/img/upPressed.h" #include "Recording/VirtualPad/img/upPressed.h"
VirtualPad::VirtualPad(wxWindow* parent, int controllerPort, AppConfig::InputRecordingOptions& options) VirtualPad::VirtualPad(wxWindow* parent, int controllerPort, AppConfig::InputRecordingOptions& options)
: wxFrame(parent, wxID_ANY, wxEmptyString) : wxFrame(parent, wxID_ANY, wxEmptyString)
, options(options) , options(options)
{ {
// Images at 1.00 scale are designed to work well on HiDPI (4k) at 150% scaling (default recommended setting on windows) // Images at 1.00 scale are designed to work well on HiDPI (4k) at 150% scaling (default recommended setting on windows)
// Therefore, on a 1080p monitor we halve the scaling, on 1440p we reduce it by 25%, which from some quick tests looks comparable // Therefore, on a 1080p monitor we halve the scaling, on 1440p we reduce it by 25%, which from some quick tests looks comparable
// Side-note - It would be possible to factor in monitor scaling, but considering that is platform specific (with some platforms only supporting // Side-note - Getting the DPI scaling amount is platform specific (with some platforms only supporting
// integer scaling) this is likely not reliable. // integer scaling as well) this is likely not reliable.
// Slight multi-monitor support, will use whatever window pcsx2 is opened with, but won't currently re-init if // Slight multi-monitor support, will use whatever window pcsx2 is opened with, but won't currently re-init if
// windows are dragged between differing monitors! // windows are dragged between differing monitors!
wxDisplay display(wxDisplay::GetFromWindow(this)); wxDisplay display(wxDisplay::GetFromWindow(this));
const wxRect screen = display.GetClientArea(); const wxRect screen = display.GetClientArea();
float dpiScale = MSW_GetDPIScale(); // linux returns 1.0
if (screen.height > 1080 && screen.height <= 1440) // 1440p display if (screen.height > 1080 && screen.height <= 1440) // 1440p display
{ scalingFactor = 0.75 * dpiScale;
scalingFactor = 0.75;
}
else if (screen.height <= 1080) // 1080p display else if (screen.height <= 1080) // 1080p display
{ {
scalingFactor = 0.5; scalingFactor = 0.5 * dpiScale;
} // otherwise use default 1.0 scaling }
// otherwise use default 1.0 scaling
virtualPadData = VirtualPadData(); virtualPadData = VirtualPadData();
virtualPadData.background = NewBitmap(EmbeddedImage<res_controller>().Get(), wxPoint(0, 0)); // Based on the scaling factor, select the appropriate background image
// Don't scale these images as they've already been pre-scaled
if (floatCompare(scalingFactor, 0.5))
virtualPadData.background = NewBitmap(EmbeddedImage<res_controllerHalf>().Get(), wxPoint(0, 0), true);
else if (floatCompare(scalingFactor, 0.75))
virtualPadData.background = NewBitmap(EmbeddedImage<res_controllerThreeQuarters>().Get(), wxPoint(0, 0), true);
else
// Otherwise, scale down/up (or don't in the case of 1.0) the largst image
virtualPadData.background = NewBitmap(EmbeddedImage<res_controllerFull>().Get(), wxPoint(0, 0));
// Use the background image's size to define the window size // Use the background image's size to define the window size
SetClientSize(virtualPadData.background.width, virtualPadData.background.height); SetClientSize(virtualPadData.background.width, virtualPadData.background.height);
InitPressureButtonGuiElements(virtualPadData.cross, NewBitmap(EmbeddedImage<res_crossPressed>().Get(), wxPoint(938, 369)), this, wxPoint(1055, 525)); // These hard-coded pixels correspond to where the background image's components are (ie. the buttons)
InitPressureButtonGuiElements(virtualPadData.circle, NewBitmap(EmbeddedImage<res_circlePressed>().Get(), wxPoint(1024, 286)), this, wxPoint(1055, 565)); // Everything is automatically scaled and adjusted based on the `scalingFactor` variable
InitPressureButtonGuiElements(virtualPadData.triangle, NewBitmap(EmbeddedImage<res_trianglePressed>().Get(), wxPoint(938, 201)), this, wxPoint(1055, 605)); InitPressureButtonGuiElements(virtualPadData.square, NewBitmap(EmbeddedImage<res_squarePressed>().Get(), wxPoint(852, 287)), this, wxPoint(1055, 525));
InitPressureButtonGuiElements(virtualPadData.square, NewBitmap(EmbeddedImage<res_squarePressed>().Get(), wxPoint(852, 287)), this, wxPoint(1055, 645)); InitPressureButtonGuiElements(virtualPadData.triangle, NewBitmap(EmbeddedImage<res_trianglePressed>().Get(), wxPoint(938, 201)), this, wxPoint(1055, 565));
InitPressureButtonGuiElements(virtualPadData.circle, NewBitmap(EmbeddedImage<res_circlePressed>().Get(), wxPoint(1024, 286)), this, wxPoint(1055, 605));
InitPressureButtonGuiElements(virtualPadData.cross, NewBitmap(EmbeddedImage<res_crossPressed>().Get(), wxPoint(938, 369)), this, wxPoint(1055, 645));
InitPressureButtonGuiElements(virtualPadData.down, NewBitmap(EmbeddedImage<res_downPressed>().Get(), wxPoint(186, 359)), this, wxPoint(175, 525), true); InitPressureButtonGuiElements(virtualPadData.left, NewBitmap(EmbeddedImage<res_leftPressed>().Get(), wxPoint(110, 303)), this, wxPoint(175, 525), true);
InitPressureButtonGuiElements(virtualPadData.right, NewBitmap(EmbeddedImage<res_rightPressed>().Get(), wxPoint(248, 302)), this, wxPoint(175, 565), true); InitPressureButtonGuiElements(virtualPadData.up, NewBitmap(EmbeddedImage<res_upPressed>().Get(), wxPoint(186, 227)), this, wxPoint(175, 565), true);
InitPressureButtonGuiElements(virtualPadData.up, NewBitmap(EmbeddedImage<res_upPressed>().Get(), wxPoint(186, 227)), this, wxPoint(175, 605), true); InitPressureButtonGuiElements(virtualPadData.right, NewBitmap(EmbeddedImage<res_rightPressed>().Get(), wxPoint(248, 302)), this, wxPoint(175, 605), true);
InitPressureButtonGuiElements(virtualPadData.left, NewBitmap(EmbeddedImage<res_leftPressed>().Get(), wxPoint(110, 302)), this, wxPoint(175, 645), true); InitPressureButtonGuiElements(virtualPadData.down, NewBitmap(EmbeddedImage<res_downPressed>().Get(), wxPoint(186, 359)), this, wxPoint(175, 645), true);
InitPressureButtonGuiElements(virtualPadData.l1, NewBitmap(EmbeddedImage<res_l1Pressed>().Get(), wxPoint(156, 98)), this, wxPoint(170, 135)); InitPressureButtonGuiElements(virtualPadData.l1, NewBitmap(EmbeddedImage<res_l1Pressed>().Get(), wxPoint(156, 98)), this, wxPoint(170, 135));
InitPressureButtonGuiElements(virtualPadData.l2, NewBitmap(EmbeddedImage<res_l2Pressed>().Get(), wxPoint(156, 57)), this, wxPoint(170, 18)); InitPressureButtonGuiElements(virtualPadData.l2, NewBitmap(EmbeddedImage<res_l2Pressed>().Get(), wxPoint(156, 57)), this, wxPoint(170, 52), false, true);
InitPressureButtonGuiElements(virtualPadData.r1, NewBitmap(EmbeddedImage<res_r1Pressed>().Get(), wxPoint(921, 98)), this, wxPoint(1035, 135), true); InitPressureButtonGuiElements(virtualPadData.r1, NewBitmap(EmbeddedImage<res_r1Pressed>().Get(), wxPoint(921, 98)), this, wxPoint(1035, 135), true);
InitPressureButtonGuiElements(virtualPadData.r2, NewBitmap(EmbeddedImage<res_r2Pressed>().Get(), wxPoint(921, 57)), this, wxPoint(1035, 18), true); InitPressureButtonGuiElements(virtualPadData.r2, NewBitmap(EmbeddedImage<res_r2Pressed>().Get(), wxPoint(921, 57)), this, wxPoint(1035, 52), true, true);
InitNormalButtonGuiElements(virtualPadData.select, NewBitmap(EmbeddedImage<res_selectPressed>().Get(), wxPoint(457, 313)), this, wxPoint(530, 320)); InitNormalButtonGuiElements(virtualPadData.select, NewBitmap(EmbeddedImage<res_selectPressed>().Get(), wxPoint(458, 313)), this, wxPoint(530, 315));
InitNormalButtonGuiElements(virtualPadData.start, NewBitmap(EmbeddedImage<res_startPressed>().Get(), wxPoint(688, 311)), this, wxPoint(650, 320)); InitNormalButtonGuiElements(virtualPadData.start, NewBitmap(EmbeddedImage<res_startPressed>().Get(), wxPoint(688, 311)), this, wxPoint(646, 315));
InitNormalButtonGuiElements(virtualPadData.l3, NewBitmap(EmbeddedImage<res_r3Pressed>().Get(), wxPoint(726, 453)), this, wxPoint(440, 835)); // TODO - text for L3 / R3 InitNormalButtonGuiElements(virtualPadData.l3, NewBitmap(EmbeddedImage<res_l3Pressed>().Get(), wxPoint(336, 453)), this, wxPoint(560, 638));
InitNormalButtonGuiElements(virtualPadData.r3, NewBitmap(EmbeddedImage<res_l3Pressed>().Get(), wxPoint(336, 453)), this, wxPoint(844, 835)); // TODO - text for L3 / R3 InitNormalButtonGuiElements(virtualPadData.r3, NewBitmap(EmbeddedImage<res_r3Pressed>().Get(), wxPoint(726, 453)), this, wxPoint(615, 638));
InitAnalogStickGuiElements(virtualPadData.leftAnalog, this, wxPoint(405, 522), 101, wxPoint(312, 642), wxPoint(525, 431), false, wxPoint(507, 662), wxPoint(507, 622)); InitAnalogStickGuiElements(virtualPadData.leftAnalog, this, wxPoint(404, 522), 100, wxPoint(314, 642), wxPoint(526, 432), false, wxPoint(504, 685), wxPoint(570, 425), true);
InitAnalogStickGuiElements(virtualPadData.rightAnalog, this, wxPoint(795, 522), 101, wxPoint(703, 642), wxPoint(648, 431), true, wxPoint(695, 662), wxPoint(695, 622), true); InitAnalogStickGuiElements(virtualPadData.rightAnalog, this, wxPoint(794, 522), 100, wxPoint(706, 642), wxPoint(648, 432), true, wxPoint(700, 685), wxPoint(635, 425));
ignoreRealControllerBox = new wxCheckBox(this, wxID_ANY, wxEmptyString, ScaledPoint(wxPoint(586, 135)), wxDefaultSize);
resetButton = new wxButton(this, wxID_ANY, _("Reset"), ScaledPoint(wxPoint(1195, 5), wxSize(100, 50), true), ScaledSize(wxSize(100, 50)));
ignoreRealControllerBox = new wxCheckBox(this, wxID_ANY, wxEmptyString, ScaledPoint(575, 135), wxDefaultSize);
Bind(wxEVT_CHECKBOX, &VirtualPad::OnIgnoreRealController, this, ignoreRealControllerBox->GetId()); Bind(wxEVT_CHECKBOX, &VirtualPad::OnIgnoreRealController, this, ignoreRealControllerBox->GetId());
Bind(wxEVT_BUTTON, &VirtualPad::OnResetButton, this, resetButton->GetId());
// Bind Window Events // Bind Window Events
Bind(wxEVT_MOVE, &VirtualPad::OnMoveAround, this); Bind(wxEVT_MOVE, &VirtualPad::OnMoveAround, this);
@ -116,8 +134,10 @@ VirtualPad::VirtualPad(wxWindow* parent, int controllerPort, AppConfig::InputRec
SetBackgroundColour(*wxWHITE); SetBackgroundColour(*wxWHITE);
SetBackgroundStyle(wxBG_STYLE_PAINT); SetBackgroundStyle(wxBG_STYLE_PAINT);
// This window does not allow for resizing for sake of simplicity: all images are scaled initially and stored, ready to be rendered // This window does not allow for resizing for sake of simplicity: all images are scaled initially and stored, ready to be rendered
SetWindowStyle(wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER); SetWindowStyle(wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER & ~wxMAXIMIZE_BOX);
SetDoubleBuffered(true);
// Causes flickering, despite it supposed to be preventing it!
// SetDoubleBuffered(true);
} }
void VirtualPad::OnMoveAround(wxMoveEvent& event) void VirtualPad::OnMoveAround(wxMoveEvent& event)
@ -158,30 +178,28 @@ void VirtualPad::OnEraseBackground(wxEraseEvent& event)
void VirtualPad::OnPaint(wxPaintEvent& event) void VirtualPad::OnPaint(wxPaintEvent& event)
{ {
// DevCon.WriteLn("Paint Event Called"); // DevCon.WriteLn("Paint Event Called");
wxPaintDC dc(this); wxBufferedPaintDC dc(this, wxBUFFER_VIRTUAL_AREA);
Render(dc); Render(dc);
} }
void VirtualPad::Redraw() void VirtualPad::Redraw()
{ {
wxClientDC dc(this); wxClientDC cdc(this);
wxBufferedDC dc(&cdc);
Render(dc); Render(dc);
} }
void VirtualPad::Render(wxDC& dc) void VirtualPad::Render(wxDC& bdc)
{ {
// Update GUI Elements and figure out what needs to be rendered // Update GUI Elements and figure out what needs to be rendered
for (VirtualPadElement* virtualPadElement : virtualPadElements) for (VirtualPadElement* virtualPadElement : virtualPadElements)
{
virtualPadElement->UpdateGuiElement(renderQueue, clearScreenRequired); virtualPadElement->UpdateGuiElement(renderQueue, clearScreenRequired);
}
// Update Graphic Elements off render stack // Update Graphic Elements off render stack
// Before we start rendering (if we have to) clear and re-draw the background // Before we start rendering (if we have to) clear and re-draw the background
if (!manualRedrawMode || clearScreenRequired || !renderQueue.empty()) if (!manualRedrawMode || clearScreenRequired || !renderQueue.empty())
{ {
wxBufferedDC bdc(&dc, dc.GetSize()); bdc.SetBrush(*wxWHITE);
bdc.SetBrush(*wxRED);
bdc.DrawRectangle(wxPoint(0, 0), bdc.GetSize()); bdc.DrawRectangle(wxPoint(0, 0), bdc.GetSize());
bdc.SetBrush(wxNullBrush); bdc.SetBrush(wxNullBrush);
bdc.DrawBitmap(virtualPadData.background.image, virtualPadData.background.coords, true); bdc.DrawBitmap(virtualPadData.background.image, virtualPadData.background.coords, true);
@ -206,9 +224,7 @@ void VirtualPad::Render(wxDC& dc)
{ {
VirtualPadElement* element = renderQueue.front(); VirtualPadElement* element = renderQueue.front();
if (element) if (element)
{
element->Render(bdc); element->Render(bdc);
}
renderQueue.pop(); renderQueue.pop();
} }
} }
@ -219,33 +235,34 @@ bool VirtualPad::UpdateControllerData(u16 const bufIndex, PadData* padData)
return virtualPadData.UpdateVirtualPadData(bufIndex, padData, ignoreRealController && !readOnlyMode, readOnlyMode); return virtualPadData.UpdateVirtualPadData(bufIndex, padData, ignoreRealController && !readOnlyMode, readOnlyMode);
} }
void VirtualPad::enablePadElements(bool enable) void VirtualPad::enableUiElements(bool enable)
{ {
ignoreRealControllerBox->Enable(enable);
resetButton->Enable(enable);
for (VirtualPadElement* virtualPadElement : virtualPadElements) for (VirtualPadElement* virtualPadElement : virtualPadElements)
{
virtualPadElement->EnableWidgets(enable); virtualPadElement->EnableWidgets(enable);
} }
}
void VirtualPad::SetReadOnlyMode() void VirtualPad::SetReadOnlyMode(bool readOnly)
{ {
enablePadElements(false); enableUiElements(!readOnly);
readOnlyMode = true; readOnlyMode = readOnly;
} }
void VirtualPad::ClearReadOnlyMode() void VirtualPad::OnIgnoreRealController(wxCommandEvent& event)
{
enablePadElements(true);
readOnlyMode = false;
}
void VirtualPad::OnIgnoreRealController(wxCommandEvent const& event)
{ {
const wxCheckBox* ignoreButton = (wxCheckBox*)event.GetEventObject(); const wxCheckBox* ignoreButton = (wxCheckBox*)event.GetEventObject();
if (ignoreButton) if (ignoreButton)
{
ignoreRealController = ignoreButton->GetValue(); ignoreRealController = ignoreButton->GetValue();
} }
void VirtualPad::OnResetButton(wxCommandEvent& event)
{
if (readOnlyMode)
return;
for (VirtualPadElement* virtualPadElement : virtualPadElements)
virtualPadElement->Reset(this);
} }
void VirtualPad::OnNormalButtonPress(wxCommandEvent& event) void VirtualPad::OnNormalButtonPress(wxCommandEvent& event)
@ -254,15 +271,11 @@ void VirtualPad::OnNormalButtonPress(wxCommandEvent& event)
ControllerNormalButton* eventBtn = buttonElements[pressedButton->GetId()]; ControllerNormalButton* eventBtn = buttonElements[pressedButton->GetId()];
if (pressedButton) if (pressedButton)
{
eventBtn->pressed = pressedButton->GetValue(); eventBtn->pressed = pressedButton->GetValue();
}
if (!eventBtn->isControllerPressBypassed) if (!eventBtn->isControllerPressBypassed)
{
eventBtn->isControllerPressBypassed = true; eventBtn->isControllerPressBypassed = true;
} }
}
void VirtualPad::OnPressureButtonPressureChange(wxCommandEvent& event) void VirtualPad::OnPressureButtonPressureChange(wxCommandEvent& event)
{ {
@ -270,9 +283,8 @@ void VirtualPad::OnPressureButtonPressureChange(wxCommandEvent& event)
ControllerPressureButton* eventBtn = pressureElements[pressureSpinner->GetId()]; ControllerPressureButton* eventBtn = pressureElements[pressureSpinner->GetId()];
if (pressureSpinner) if (pressureSpinner)
{
eventBtn->pressure = pressureSpinner->GetValue(); eventBtn->pressure = pressureSpinner->GetValue();
}
eventBtn->pressed = eventBtn->pressure > 0; eventBtn->pressed = eventBtn->pressure > 0;
if (!eventBtn->isControllerPressureBypassed || !eventBtn->isControllerPressBypassed) if (!eventBtn->isControllerPressureBypassed || !eventBtn->isControllerPressBypassed)
@ -288,16 +300,13 @@ void VirtualPad::OnAnalogSpinnerChange(wxCommandEvent& event)
AnalogVector* eventVector = analogElements[analogSpinner->GetId()]; AnalogVector* eventVector = analogElements[analogSpinner->GetId()];
if (analogSpinner) if (analogSpinner)
{
eventVector->val = analogSpinner->GetValue(); eventVector->val = analogSpinner->GetValue();
}
eventVector->slider->SetValue(eventVector->val); eventVector->slider->SetValue(eventVector->val);
if (!eventVector->isControllerBypassed) if (!eventVector->isControllerBypassed)
{
eventVector->isControllerBypassed = true; eventVector->isControllerBypassed = true;
} }
}
void VirtualPad::OnAnalogSliderChange(wxCommandEvent& event) void VirtualPad::OnAnalogSliderChange(wxCommandEvent& event)
{ {
@ -305,46 +314,57 @@ void VirtualPad::OnAnalogSliderChange(wxCommandEvent& event)
AnalogVector* eventVector = analogElements[analogSlider->GetId()]; AnalogVector* eventVector = analogElements[analogSlider->GetId()];
if (analogSlider) if (analogSlider)
{
eventVector->val = analogSlider->GetValue(); eventVector->val = analogSlider->GetValue();
}
eventVector->spinner->SetValue(eventVector->val); eventVector->spinner->SetValue(eventVector->val);
if (!eventVector->isControllerBypassed) if (!eventVector->isControllerBypassed)
{
eventVector->isControllerBypassed = true; eventVector->isControllerBypassed = true;
} }
}
/// GUI Element Utility Functions /// GUI Element Utility Functions
wxPoint VirtualPad::ScaledPoint(wxPoint point, int widgetWidth, bool rightAligned) bool VirtualPad::floatCompare(float a, float b, float epsilon)
{ {
return ScaledPoint(point.x, point.y, widgetWidth, rightAligned); return (fabs(a - b) < epsilon);
} }
wxPoint VirtualPad::ScaledPoint(int x, int y, int widgetWidth, bool rightAligned) wxPoint VirtualPad::ScaledPoint(wxPoint point, wxSize widgetWidth, bool rightAlignedCoord, bool bottomAlignedCoord)
{
return ScaledPoint(point.x, point.y, widgetWidth.x, widgetWidth.y, rightAlignedCoord, bottomAlignedCoord);
}
wxPoint VirtualPad::ScaledPoint(int x, int y, int widgetWidth, int widgetHeight, bool rightAlignedCoord, bool bottomAlignedCoord)
{ {
wxPoint scaledPoint = wxPoint(x * scalingFactor, y * scalingFactor); wxPoint scaledPoint = wxPoint(x * scalingFactor, y * scalingFactor);
if (rightAligned) if (rightAlignedCoord)
{ {
scaledPoint.x -= widgetWidth * scalingFactor; scaledPoint.x -= widgetWidth * scalingFactor;
if (scaledPoint.x < 0) if (scaledPoint.x < 0)
{
scaledPoint.x = 0; scaledPoint.x = 0;
} }
if (bottomAlignedCoord)
{
scaledPoint.y -= widgetHeight * scalingFactor;
if (scaledPoint.y < 0)
scaledPoint.y = 0;
} }
return scaledPoint; return scaledPoint;
} }
wxSize VirtualPad::ScaledSize(wxSize size)
{
return ScaledSize(size.x, size.y);
}
wxSize VirtualPad::ScaledSize(int x, int y) wxSize VirtualPad::ScaledSize(int x, int y)
{ {
return wxSize(x * scalingFactor, y * scalingFactor); return wxSize(x * scalingFactor, y * scalingFactor);
} }
ImageFile VirtualPad::NewBitmap(wxImage resource, wxPoint imgCoord) ImageFile VirtualPad::NewBitmap(wxImage resource, wxPoint imgCoord, bool dontScale)
{ {
return NewBitmap(scalingFactor, resource, imgCoord); return NewBitmap(dontScale ? 1 : scalingFactor, resource, imgCoord);
} }
ImageFile VirtualPad::NewBitmap(float scalingFactor, wxImage resource, wxPoint imgCoord) ImageFile VirtualPad::NewBitmap(float scalingFactor, wxImage resource, wxPoint imgCoord)
@ -368,11 +388,10 @@ void VirtualPad::InitNormalButtonGuiElements(ControllerNormalButton& button, Ima
virtualPadElements.push_back(&button); virtualPadElements.push_back(&button);
} }
void VirtualPad::InitPressureButtonGuiElements(ControllerPressureButton& button, ImageFile image, wxWindow* parentWindow, wxPoint pressureSpinnerCoord, bool rightAlignedCoord) void VirtualPad::InitPressureButtonGuiElements(ControllerPressureButton& button, ImageFile image, wxWindow* parentWindow, wxPoint pressureSpinnerCoord, bool rightAlignedCoord, bool bottomAlignedCoord)
{ {
const int spinnerWidth = 100; const wxPoint scaledPoint = ScaledPoint(pressureSpinnerCoord, SPINNER_SIZE, rightAlignedCoord, bottomAlignedCoord);
const wxPoint scaledPoint = ScaledPoint(pressureSpinnerCoord.x, pressureSpinnerCoord.y, spinnerWidth, rightAlignedCoord); wxSpinCtrl* spinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, scaledPoint, ScaledSize(SPINNER_SIZE), wxSP_ARROW_KEYS, 0, 255, 0);
wxSpinCtrl* spinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, scaledPoint, ScaledSize(spinnerWidth, wxDefaultSize.GetHeight()), wxSP_ARROW_KEYS, 0, 255, 0);
button.icon = image; button.icon = image;
button.pressureSpinner = spinner; button.pressureSpinner = spinner;
@ -381,7 +400,8 @@ void VirtualPad::InitPressureButtonGuiElements(ControllerPressureButton& button,
virtualPadElements.push_back(&button); virtualPadElements.push_back(&button);
} }
void VirtualPad::InitAnalogStickGuiElements(AnalogStick& analog, wxWindow* parentWindow, wxPoint centerPoint, int radius, wxPoint xSliderPoint, wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners) void VirtualPad::InitAnalogStickGuiElements(AnalogStick& analog, wxWindow* parentWindow, wxPoint centerPoint, int radius,
wxPoint xSliderPoint, wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners)
{ {
AnalogPosition analogPos = AnalogPosition(); AnalogPosition analogPos = AnalogPosition();
analogPos.centerCoords = ScaledPoint(centerPoint); analogPos.centerCoords = ScaledPoint(centerPoint);
@ -389,14 +409,15 @@ void VirtualPad::InitAnalogStickGuiElements(AnalogStick& analog, wxWindow* paren
analogPos.radius = radius * scalingFactor; analogPos.radius = radius * scalingFactor;
analogPos.lineThickness = 6 * scalingFactor; analogPos.lineThickness = 6 * scalingFactor;
const int spinnerWidth = 90; const wxPoint xSpinnerScaledPoint = ScaledPoint(xSpinnerPoint, SPINNER_SIZE, rightAlignedSpinners);
const wxPoint xSpinnerScaledPoint = ScaledPoint(xSpinnerPoint, spinnerWidth, rightAlignedSpinners); const wxPoint ySpinnerScaledPoint = ScaledPoint(ySpinnerPoint, SPINNER_SIZE, rightAlignedSpinners, true);
const wxPoint ySpinnerScaledPoint = ScaledPoint(ySpinnerPoint, spinnerWidth, rightAlignedSpinners);
wxSlider* xSlider = new wxSlider(parentWindow, wxID_ANY, 127, 0, 255, ScaledPoint(xSliderPoint), ScaledSize(185, 30)); wxSlider* xSlider = new wxSlider(parentWindow, wxID_ANY, ANALOG_NEUTRAL, 0, ANALOG_MAX,
wxSlider* ySlider = new wxSlider(parentWindow, wxID_ANY, 127, 0, 255, ScaledPoint(ySliderPoint), ScaledSize(30, 185), flipYSlider ? wxSL_LEFT : wxSL_RIGHT); ScaledPoint(xSliderPoint), ScaledSize(ANALOG_SLIDER_WIDTH, ANALOG_SLIDER_HEIGHT));
wxSpinCtrl* xSpinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, xSpinnerScaledPoint, ScaledSize(90, wxDefaultSize.GetHeight()), wxSP_ARROW_KEYS, 0, 255, 127); wxSlider* ySlider = new wxSlider(parentWindow, wxID_ANY, ANALOG_NEUTRAL, 0, ANALOG_MAX,
wxSpinCtrl* ySpinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, ySpinnerScaledPoint, ScaledSize(90, wxDefaultSize.GetHeight()), wxSP_ARROW_KEYS, 0, 255, 127); ScaledPoint(ySliderPoint), ScaledSize(ANALOG_SLIDER_HEIGHT, ANALOG_SLIDER_WIDTH), flipYSlider ? wxSL_LEFT : wxSL_RIGHT);
wxSpinCtrl* xSpinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, xSpinnerScaledPoint, ScaledSize(SPINNER_SIZE), wxSP_ARROW_KEYS, 0, 255, 127);
wxSpinCtrl* ySpinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, ySpinnerScaledPoint, ScaledSize(SPINNER_SIZE), wxSP_ARROW_KEYS, 0, 255, 127);
analog.xVector.slider = xSlider; analog.xVector.slider = xSlider;
analog.yVector.slider = ySlider; analog.yVector.slider = ySlider;

View File

@ -43,14 +43,21 @@ public:
// - PadData will not be updated if ReadOnly mode is set // - PadData will not be updated if ReadOnly mode is set
// - returns a bool to indicate if the PadData has been updated // - returns a bool to indicate if the PadData has been updated
bool UpdateControllerData(u16 const bufIndex, PadData* padData); bool UpdateControllerData(u16 const bufIndex, PadData* padData);
// Enables ReadOnly mode and disables GUI widgets // Enables/Disables read only mode and enables/disables GUI widgets
void SetReadOnlyMode(); void SetReadOnlyMode(bool readOnly);
// Disables ReadOnly mode and re-enables GUI widgets
void ClearReadOnlyMode();
// To be called at maximum, once per frame to update widget's value and re-render the VirtualPad's graphics // To be called at maximum, once per frame to update widget's value and re-render the VirtualPad's graphics
void Redraw(); void Redraw();
private: private:
/// Constants
const wxSize SPINNER_SIZE = wxSize(100, 40);
static const int ANALOG_SLIDER_WIDTH = 185;
static const int ANALOG_SLIDER_HEIGHT = 30;
static const int PRESSURE_MAX = 255;
static const int ANALOG_NEUTRAL = 127;
static const int ANALOG_MAX = 255;
AppConfig::InputRecordingOptions& options; AppConfig::InputRecordingOptions& options;
bool clearScreenRequired = false; bool clearScreenRequired = false;
@ -65,10 +72,11 @@ private:
std::vector<VirtualPadElement*> virtualPadElements; std::vector<VirtualPadElement*> virtualPadElements;
std::queue<VirtualPadElement*> renderQueue; std::queue<VirtualPadElement*> renderQueue;
void enablePadElements(bool enable); void enableUiElements(bool enable);
/// GUI Elements /// GUI Elements
wxCheckBox* ignoreRealControllerBox; wxCheckBox* ignoreRealControllerBox;
wxButton* resetButton;
std::map<wxWindowID, ControllerNormalButton*> buttonElements; std::map<wxWindowID, ControllerNormalButton*> buttonElements;
std::map<wxWindowID, ControllerPressureButton*> pressureElements; std::map<wxWindowID, ControllerPressureButton*> pressureElements;
@ -84,21 +92,24 @@ private:
void OnAnalogSliderChange(wxCommandEvent& event); void OnAnalogSliderChange(wxCommandEvent& event);
void OnAnalogSpinnerChange(wxCommandEvent& event); void OnAnalogSpinnerChange(wxCommandEvent& event);
void OnIgnoreRealController(wxCommandEvent const& event); void OnIgnoreRealController(wxCommandEvent& event);
void OnNormalButtonPress(wxCommandEvent& event); void OnNormalButtonPress(wxCommandEvent& event);
void OnPressureButtonPressureChange(wxCommandEvent& event); void OnPressureButtonPressureChange(wxCommandEvent& event);
void OnResetButton(wxCommandEvent& event);
/// GUI Creation Utility Functions /// GUI Creation Utility Functions
float scalingFactor = 1.0; float scalingFactor = 1.0;
bool floatCompare(float A, float B, float epsilon = 0.005f);
wxSize ScaledSize(wxSize size);
wxSize ScaledSize(int x, int y); wxSize ScaledSize(int x, int y);
wxPoint ScaledPoint(wxPoint point, int widgetWidth = 0, bool rightAligned = false); wxPoint ScaledPoint(wxPoint point, wxSize widgetSize = wxDefaultSize, bool rightAlignedCoord = false, bool bottomAlignedCoord = false);
wxPoint ScaledPoint(int x, int y, int widgetWidth = 0, bool rightAligned = false); wxPoint ScaledPoint(int x, int y, int widgetWidth, int widgetHeight, bool rightAlignedCoord = false, bool bottomAlignedCoord = false);
ImageFile NewBitmap(wxImage resource, wxPoint imgCoord); ImageFile NewBitmap(wxImage resource, wxPoint imgCoord, bool dontScale = false);
ImageFile NewBitmap(float scalingFactor, wxImage resource, wxPoint imgCoord); ImageFile NewBitmap(float scalingFactor, wxImage resource, wxPoint imgCoord);
void InitPressureButtonGuiElements(ControllerPressureButton& button, ImageFile image, wxWindow* parentWindow, wxPoint pressureSpinnerCoord, bool rightAlignedCoord = false); void InitPressureButtonGuiElements(ControllerPressureButton& button, ImageFile image, wxWindow* parentWindow, wxPoint pressureSpinnerCoord, bool rightAlignedCoord = false, bool bottomAlignedCoord = false);
void InitNormalButtonGuiElements(ControllerNormalButton& btn, ImageFile image, wxWindow* parentWindow, wxPoint checkboxCoord); void InitNormalButtonGuiElements(ControllerNormalButton& btn, ImageFile image, wxWindow* parentWindow, wxPoint checkboxCoord);
void InitAnalogStickGuiElements(AnalogStick& analog, wxWindow* parentWindow, wxPoint centerPoint, int radius, wxPoint xSliderPoint, void InitAnalogStickGuiElements(AnalogStick& analog, wxWindow* parentWindow, wxPoint centerPoint, int radius, wxPoint xSliderPoint,
wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners = false); wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners = false);

View File

@ -22,21 +22,31 @@
#include "Recording/VirtualPad/VirtualPadResources.h" #include "Recording/VirtualPad/VirtualPadResources.h"
#include "Recording/PadData.h" #include "Recording/PadData.h"
wxCommandEvent VirtualPadElement::ConstructEvent(wxEventTypeTag<wxCommandEvent> eventType, wxWindow* obj)
{
wxCommandEvent event(eventType, obj->GetId());
event.SetEventObject(obj);
return event;
}
wxCommandEvent VirtualPadElement::ConstructEvent(wxEventTypeTag<wxSpinEvent> eventType, wxWindow* obj)
{
wxCommandEvent event(eventType, obj->GetId());
event.SetEventObject(obj);
return event;
}
void ControllerNormalButton::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) void ControllerNormalButton::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired)
{ {
ControllerNormalButton& button = *this; ControllerNormalButton& button = *this;
// This boolean is set when we parse the PadData in VirtualPadData::UpdateVirtualPadData // This boolean is set when we parse the PadData in VirtualPadData::UpdateVirtualPadData
// Updating wxWidget elements can be expensive, we only want to do this if required // Updating wxWidget elements can be expensive, we only want to do this if required
if (button.widgetUpdateRequired) if (button.widgetUpdateRequired)
{
button.pressedBox->SetValue(button.pressed); button.pressedBox->SetValue(button.pressed);
}
// We only render the button if it is pressed // We only render the button if it is pressed
if (button.pressed) if (button.pressed)
{
renderQueue.push(this); renderQueue.push(this);
}
// However, if the button has been drawn to the screen in the past // However, if the button has been drawn to the screen in the past
// we need to ensure the screen is cleared. // we need to ensure the screen is cleared.
// This is needed in the scenario where only a single button is being pressed/released // This is needed in the scenario where only a single button is being pressed/released
@ -52,14 +62,10 @@ void ControllerPressureButton::UpdateGuiElement(std::queue<VirtualPadElement*>&
{ {
ControllerPressureButton& button = *this; ControllerPressureButton& button = *this;
if (button.widgetUpdateRequired) if (button.widgetUpdateRequired)
{
button.pressureSpinner->SetValue(button.pressure); button.pressureSpinner->SetValue(button.pressure);
}
if (button.pressed) if (button.pressed)
{
renderQueue.push(this); renderQueue.push(this);
}
else if (button.currentlyRendered) else if (button.currentlyRendered)
{ {
button.currentlyRendered = false; button.currentlyRendered = false;
@ -83,9 +89,7 @@ void AnalogStick::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue,
// We render the analog sticks as long as they are not in the neutral position // We render the analog sticks as long as they are not in the neutral position
if (!(analogStick.xVector.val == PadData::ANALOG_VECTOR_NEUTRAL && analogStick.yVector.val == PadData::ANALOG_VECTOR_NEUTRAL)) if (!(analogStick.xVector.val == PadData::ANALOG_VECTOR_NEUTRAL && analogStick.yVector.val == PadData::ANALOG_VECTOR_NEUTRAL))
{
renderQueue.push(this); renderQueue.push(this);
}
else if (analogStick.currentlyRendered) else if (analogStick.currentlyRendered)
{ {
analogStick.currentlyRendered = false; analogStick.currentlyRendered = false;
@ -95,47 +99,20 @@ void AnalogStick::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue,
void ControllerNormalButton::EnableWidgets(bool enable) void ControllerNormalButton::EnableWidgets(bool enable)
{ {
ControllerNormalButton& button = *this; this->pressedBox->Enable(enable);
if (enable)
{
button.pressedBox->Enable();
}
else
{
button.pressedBox->Disable();
}
} }
void ControllerPressureButton::EnableWidgets(bool enable) void ControllerPressureButton::EnableWidgets(bool enable)
{ {
ControllerPressureButton& button = *this; this->pressureSpinner->Enable(enable);
if (enable)
{
button.pressureSpinner->Enable();
}
else
{
button.pressureSpinner->Disable();
}
} }
void AnalogStick::EnableWidgets(bool enable) void AnalogStick::EnableWidgets(bool enable)
{ {
AnalogStick& analog = *this; this->xVector.slider->Enable(enable);
if (enable) this->yVector.slider->Enable(enable);
{ this->xVector.spinner->Enable(enable);
analog.xVector.slider->Enable(); this->yVector.spinner->Enable(enable);
analog.yVector.slider->Enable();
analog.xVector.spinner->Enable();
analog.yVector.spinner->Enable();
}
else
{
analog.xVector.slider->Disable();
analog.yVector.slider->Disable();
analog.xVector.spinner->Disable();
analog.yVector.spinner->Disable();
}
} }
void ControllerNormalButton::Render(wxDC& dc) void ControllerNormalButton::Render(wxDC& dc)
@ -181,6 +158,30 @@ void AnalogStick::Render(wxDC& dc)
analogStick.currentlyRendered = true; analogStick.currentlyRendered = true;
} }
void ControllerNormalButton::Reset(wxEvtHandler* destWindow)
{
this->pressedBox->SetValue(false);
wxPostEvent(destWindow, ConstructEvent(wxEVT_CHECKBOX, this->pressedBox));
}
void ControllerPressureButton::Reset(wxEvtHandler* destWindow)
{
this->pressureSpinner->SetValue(0);
wxPostEvent(destWindow, ConstructEvent(wxEVT_SPINCTRL, this->pressureSpinner));
}
void AnalogStick::Reset(wxEvtHandler* destWindow)
{
this->xVector.slider->SetValue(127);
this->yVector.slider->SetValue(127);
wxPostEvent(destWindow, ConstructEvent(wxEVT_SLIDER, this->xVector.slider));
wxPostEvent(destWindow, ConstructEvent(wxEVT_SLIDER, this->yVector.slider));
this->xVector.spinner->SetValue(127);
this->xVector.spinner->SetValue(127);
wxPostEvent(destWindow, ConstructEvent(wxEVT_SPINCTRL, this->xVector.spinner));
wxPostEvent(destWindow, ConstructEvent(wxEVT_SPINCTRL, this->yVector.spinner));
}
bool ControllerNormalButton::UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly) bool ControllerNormalButton::UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly)
{ {
return this->UpdateButtonData(padDataVal, ignoreRealController, readOnly); return this->UpdateButtonData(padDataVal, ignoreRealController, readOnly);

View File

@ -25,6 +25,7 @@
#include "wx/gdicmn.h" #include "wx/gdicmn.h"
#include "wx/slider.h" #include "wx/slider.h"
#include "wx/spinctrl.h" #include "wx/spinctrl.h"
#include "wx/dcbuffer.h"
struct ImageFile struct ImageFile
{ {
@ -63,8 +64,12 @@ class VirtualPadElement
public: public:
bool currentlyRendered = false; bool currentlyRendered = false;
wxCommandEvent ConstructEvent(wxEventTypeTag<wxCommandEvent> eventType, wxWindow *obj);
wxCommandEvent ConstructEvent(wxEventTypeTag<wxSpinEvent> eventType, wxWindow *obj);
virtual void EnableWidgets(bool enable) = 0; virtual void EnableWidgets(bool enable) = 0;
virtual void Render(wxDC& dc) = 0; virtual void Render(wxDC& dc) = 0;
virtual void Reset(wxEvtHandler* destWindow) = 0;
virtual void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) = 0; virtual void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) = 0;
}; };
@ -88,6 +93,7 @@ public:
bool UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly); bool UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly);
void EnableWidgets(bool enable) override; void EnableWidgets(bool enable) override;
void Render(wxDC& dc) override; void Render(wxDC& dc) override;
void Reset(wxEvtHandler* destWindow) override;
void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override; void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override;
}; };
@ -106,6 +112,7 @@ public:
bool UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly); bool UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly);
void EnableWidgets(bool enable) override; void EnableWidgets(bool enable) override;
void Render(wxDC& dc) override; void Render(wxDC& dc) override;
void Reset(wxEvtHandler* destWindow) override;
void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override; void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override;
}; };
@ -119,6 +126,7 @@ public:
void EnableWidgets(bool enable) override; void EnableWidgets(bool enable) override;
void Render(wxDC& dc) override; void Render(wxDC& dc) override;
void Reset(wxEvtHandler* destWindow) override;
void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override; void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override;
}; };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@ -466,12 +466,14 @@ void MainEmuFrame::CreateCaptureMenu()
void MainEmuFrame::CreateRecordMenu() void MainEmuFrame::CreateRecordMenu()
{ {
#ifndef DISABLE_RECORDING
m_menuRecording.Append(MenuId_Recording_New, _("New")); m_menuRecording.Append(MenuId_Recording_New, _("New"));
m_menuRecording.Append(MenuId_Recording_Stop, _("Stop"))->Enable(false); m_menuRecording.Append(MenuId_Recording_Stop, _("Stop"))->Enable(false);
m_menuRecording.Append(MenuId_Recording_Play, _("Play")); m_menuRecording.Append(MenuId_Recording_Play, _("Play"));
m_menuRecording.AppendSeparator(); m_menuRecording.AppendSeparator();
m_menuRecording.Append(MenuId_Recording_VirtualPad_Port0, _("Virtual Pad (Port 1)")); m_menuRecording.Append(MenuId_Recording_VirtualPad_Port0, _("Virtual Pad (Port 1)"));
m_menuRecording.Append(MenuId_Recording_VirtualPad_Port1, _("Virtual Pad (Port 2)")); m_menuRecording.Append(MenuId_Recording_VirtualPad_Port1, _("Virtual Pad (Port 2)"));
#endif
} }
void MainEmuFrame::CreateHelpMenu() void MainEmuFrame::CreateHelpMenu()

View File

@ -145,7 +145,15 @@
<Outputs>%(RelativeDir)%(Filename).h</Outputs> <Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild> </CustomBuild>
<!-- Generate Recording GUI Image Headers --> <!-- Generate Recording GUI Image Headers -->
<CustomBuild Include="..\..\Recording\VirtualPad\img\controller.png"> <CustomBuild Include="..\..\Recording\VirtualPad\img\controllerFull.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="..\..\Recording\VirtualPad\img\controllerThreeQuarters.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="..\..\Recording\VirtualPad\img\controllerHalf.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command> <Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs> <Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild> </CustomBuild>