mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-14 00:09:24 +01:00
Merge pull request #5194 from lioncash/dialog
Frame: Make TAS dialogs private
This commit is contained in:
commit
86e48fc1ca
@ -2,6 +2,8 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Core/Movie.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
@ -10,6 +12,7 @@
|
|||||||
#include <mbedtls/md.h>
|
#include <mbedtls/md.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
@ -34,7 +37,6 @@
|
|||||||
#include "Core/HW/WiimoteEmu/WiimoteHid.h"
|
#include "Core/HW/WiimoteEmu/WiimoteHid.h"
|
||||||
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
|
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
|
||||||
#include "Core/IOS/USB/Bluetooth/WiimoteDevice.h"
|
#include "Core/IOS/USB/Bluetooth/WiimoteDevice.h"
|
||||||
#include "Core/Movie.h"
|
|
||||||
#include "Core/NetPlayProto.h"
|
#include "Core/NetPlayProto.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/State.h"
|
#include "Core/State.h"
|
||||||
@ -91,8 +93,8 @@ static bool s_bPolled = false;
|
|||||||
static std::mutex s_input_display_lock;
|
static std::mutex s_input_display_lock;
|
||||||
static std::string s_InputDisplay[8];
|
static std::string s_InputDisplay[8];
|
||||||
|
|
||||||
static GCManipFunction gcmfunc = nullptr;
|
static GCManipFunction s_gc_manip_func;
|
||||||
static WiiManipFunction wiimfunc = nullptr;
|
static WiiManipFunction s_wii_manip_func;
|
||||||
|
|
||||||
// NOTE: Host / CPU Thread
|
// NOTE: Host / CPU Thread
|
||||||
static void EnsureTmpInputSize(size_t bound)
|
static void EnsureTmpInputSize(size_t bound)
|
||||||
@ -1440,25 +1442,25 @@ void SaveRecording(const std::string& filename)
|
|||||||
|
|
||||||
void SetGCInputManip(GCManipFunction func)
|
void SetGCInputManip(GCManipFunction func)
|
||||||
{
|
{
|
||||||
gcmfunc = func;
|
s_gc_manip_func = std::move(func);
|
||||||
}
|
}
|
||||||
void SetWiiInputManip(WiiManipFunction func)
|
void SetWiiInputManip(WiiManipFunction func)
|
||||||
{
|
{
|
||||||
wiimfunc = func;
|
s_wii_manip_func = std::move(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: CPU Thread
|
// NOTE: CPU Thread
|
||||||
void CallGCInputManip(GCPadStatus* PadStatus, int controllerID)
|
void CallGCInputManip(GCPadStatus* PadStatus, int controllerID)
|
||||||
{
|
{
|
||||||
if (gcmfunc)
|
if (s_gc_manip_func)
|
||||||
(*gcmfunc)(PadStatus, controllerID);
|
s_gc_manip_func(PadStatus, controllerID);
|
||||||
}
|
}
|
||||||
// NOTE: CPU Thread
|
// NOTE: CPU Thread
|
||||||
void CallWiiInputManip(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext,
|
void CallWiiInputManip(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext,
|
||||||
const wiimote_key key)
|
const wiimote_key key)
|
||||||
{
|
{
|
||||||
if (wiimfunc)
|
if (s_wii_manip_func)
|
||||||
(*wiimfunc)(data, rptf, controllerID, ext, key);
|
s_wii_manip_func(data, rptf, controllerID, ext, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: GPU Thread
|
// NOTE: GPU Thread
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
@ -181,8 +182,9 @@ std::string GetInputDisplay();
|
|||||||
std::string GetRTCDisplay();
|
std::string GetRTCDisplay();
|
||||||
|
|
||||||
// Done this way to avoid mixing of core and gui code
|
// Done this way to avoid mixing of core and gui code
|
||||||
typedef void (*GCManipFunction)(GCPadStatus*, int);
|
using GCManipFunction = std::function<void(GCPadStatus*, int)>;
|
||||||
typedef void (*WiiManipFunction)(u8*, WiimoteEmu::ReportFeatures, int, int, wiimote_key);
|
using WiiManipFunction =
|
||||||
|
std::function<void(u8*, WiimoteEmu::ReportFeatures, int, int, wiimote_key)>;
|
||||||
|
|
||||||
void SetGCInputManip(GCManipFunction);
|
void SetGCInputManip(GCManipFunction);
|
||||||
void SetWiiInputManip(WiiManipFunction);
|
void SetWiiInputManip(WiiManipFunction);
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <fstream>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "DolphinWX/Frame.h"
|
#include "DolphinWX/Frame.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -47,6 +48,7 @@
|
|||||||
#include "Core/HW/GCKeyboard.h"
|
#include "Core/HW/GCKeyboard.h"
|
||||||
#include "Core/HW/GCPad.h"
|
#include "Core/HW/GCPad.h"
|
||||||
#include "Core/HW/Wiimote.h"
|
#include "Core/HW/Wiimote.h"
|
||||||
|
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||||
#include "Core/HotkeyManager.h"
|
#include "Core/HotkeyManager.h"
|
||||||
#include "Core/IOS/IPC.h"
|
#include "Core/IOS/IPC.h"
|
||||||
#include "Core/IOS/USB/Bluetooth/BTBase.h"
|
#include "Core/IOS/USB/Bluetooth/BTBase.h"
|
||||||
@ -389,11 +391,7 @@ CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, wxRect geo
|
|||||||
m_LogWindow->Hide();
|
m_LogWindow->Hide();
|
||||||
m_LogWindow->Disable();
|
m_LogWindow->Disable();
|
||||||
|
|
||||||
for (int i = 0; i < 8; ++i)
|
InitializeTASDialogs();
|
||||||
g_TASInputDlg[i] = new TASInputDlg(this);
|
|
||||||
|
|
||||||
Movie::SetGCInputManip(GCTASManipFunction);
|
|
||||||
Movie::SetWiiInputManip(WiiTASManipFunction);
|
|
||||||
|
|
||||||
State::SetOnAfterLoadCallback(OnAfterLoadCallback);
|
State::SetOnAfterLoadCallback(OnAfterLoadCallback);
|
||||||
Core::SetOnStoppedCallback(OnStoppedCallback);
|
Core::SetOnStoppedCallback(OnStoppedCallback);
|
||||||
@ -502,6 +500,21 @@ void CFrame::BindEvents()
|
|||||||
Bind(DOLPHIN_EVT_STOP_SOFTWARE, &CFrame::OnStop, this);
|
Bind(DOLPHIN_EVT_STOP_SOFTWARE, &CFrame::OnStop, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CFrame::InitializeTASDialogs()
|
||||||
|
{
|
||||||
|
std::generate(m_tas_input_dialogs.begin(), m_tas_input_dialogs.end(),
|
||||||
|
[this] { return new TASInputDlg{this}; });
|
||||||
|
|
||||||
|
Movie::SetGCInputManip([this](GCPadStatus* pad_status, int controller_id) {
|
||||||
|
m_tas_input_dialogs[controller_id]->GetValues(pad_status);
|
||||||
|
});
|
||||||
|
|
||||||
|
Movie::SetWiiInputManip([this](u8* data, WiimoteEmu::ReportFeatures rptf, int controller_id,
|
||||||
|
int ext, wiimote_key key) {
|
||||||
|
m_tas_input_dialogs[controller_id + 4]->GetValues(data, rptf, ext, key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool CFrame::RendererIsFullscreen()
|
bool CFrame::RendererIsFullscreen()
|
||||||
{
|
{
|
||||||
bool fullscreen = false;
|
bool fullscreen = false;
|
||||||
@ -1034,21 +1047,6 @@ void OnStoppedCallback()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCTASManipFunction(GCPadStatus* PadStatus, int controllerID)
|
|
||||||
{
|
|
||||||
if (main_frame)
|
|
||||||
main_frame->g_TASInputDlg[controllerID]->GetValues(PadStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiiTASManipFunction(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext,
|
|
||||||
const wiimote_key key)
|
|
||||||
{
|
|
||||||
if (main_frame)
|
|
||||||
{
|
|
||||||
main_frame->g_TASInputDlg[controllerID + 4]->GetValues(data, rptf, ext, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CFrame::OnKeyDown(wxKeyEvent& event)
|
void CFrame::OnKeyDown(wxKeyEvent& event)
|
||||||
{
|
{
|
||||||
// On OS X, we claim all keyboard events while
|
// On OS X, we claim all keyboard events while
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -16,9 +17,7 @@
|
|||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Event.h"
|
#include "Common/Event.h"
|
||||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
|
||||||
#include "DolphinWX/Globals.h"
|
#include "DolphinWX/Globals.h"
|
||||||
#include "InputCommon/GCPadStatus.h"
|
|
||||||
|
|
||||||
#if defined(HAVE_X11) && HAVE_X11
|
#if defined(HAVE_X11) && HAVE_X11
|
||||||
#include "UICommon/X11Utils.h"
|
#include "UICommon/X11Utils.h"
|
||||||
@ -88,7 +87,6 @@ public:
|
|||||||
CCodeWindow* g_pCodeWindow = nullptr;
|
CCodeWindow* g_pCodeWindow = nullptr;
|
||||||
NetPlaySetupFrame* g_NetPlaySetupDiag = nullptr;
|
NetPlaySetupFrame* g_NetPlaySetupDiag = nullptr;
|
||||||
wxCheatsWindow* g_CheatsWindow = nullptr;
|
wxCheatsWindow* g_CheatsWindow = nullptr;
|
||||||
TASInputDlg* g_TASInputDlg[8];
|
|
||||||
|
|
||||||
void DoStop();
|
void DoStop();
|
||||||
void UpdateGUI();
|
void UpdateGUI();
|
||||||
@ -140,6 +138,7 @@ private:
|
|||||||
CLogWindow* m_LogWindow = nullptr;
|
CLogWindow* m_LogWindow = nullptr;
|
||||||
LogConfigWindow* m_LogConfigWindow = nullptr;
|
LogConfigWindow* m_LogConfigWindow = nullptr;
|
||||||
FifoPlayerDlg* m_FifoPlayerDlg = nullptr;
|
FifoPlayerDlg* m_FifoPlayerDlg = nullptr;
|
||||||
|
std::array<TASInputDlg*, 8> m_tas_input_dialogs{};
|
||||||
bool UseDebugger = false;
|
bool UseDebugger = false;
|
||||||
bool m_bBatchMode = false;
|
bool m_bBatchMode = false;
|
||||||
bool m_bEdit = false;
|
bool m_bEdit = false;
|
||||||
@ -174,6 +173,8 @@ private:
|
|||||||
wxToolBar* OnCreateToolBar(long style, wxWindowID id, const wxString& name) override;
|
wxToolBar* OnCreateToolBar(long style, wxWindowID id, const wxString& name) override;
|
||||||
wxMenuBar* CreateMenuBar() const;
|
wxMenuBar* CreateMenuBar() const;
|
||||||
|
|
||||||
|
void InitializeTASDialogs();
|
||||||
|
|
||||||
// Utility
|
// Utility
|
||||||
wxWindow* GetNotebookPageFromId(wxWindowID Id);
|
wxWindow* GetNotebookPageFromId(wxWindowID Id);
|
||||||
wxAuiNotebook* GetNotebookFromId(u32 NBId);
|
wxAuiNotebook* GetNotebookFromId(u32 NBId);
|
||||||
@ -339,8 +340,3 @@ private:
|
|||||||
|
|
||||||
void OnAfterLoadCallback();
|
void OnAfterLoadCallback();
|
||||||
void OnStoppedCallback();
|
void OnStoppedCallback();
|
||||||
|
|
||||||
// For TASInputDlg
|
|
||||||
void GCTASManipFunction(GCPadStatus* PadStatus, int controllerID);
|
|
||||||
void WiiTASManipFunction(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext,
|
|
||||||
const wiimote_key key);
|
|
||||||
|
@ -369,17 +369,18 @@ void CFrame::OnTASInput(wxCommandEvent& event)
|
|||||||
if (SConfig::GetInstance().m_SIDevice[i] != SerialInterface::SIDEVICE_NONE &&
|
if (SConfig::GetInstance().m_SIDevice[i] != SerialInterface::SIDEVICE_NONE &&
|
||||||
SConfig::GetInstance().m_SIDevice[i] != SerialInterface::SIDEVICE_GC_GBA)
|
SConfig::GetInstance().m_SIDevice[i] != SerialInterface::SIDEVICE_GC_GBA)
|
||||||
{
|
{
|
||||||
g_TASInputDlg[i]->CreateGCLayout();
|
m_tas_input_dialogs[i]->CreateGCLayout();
|
||||||
g_TASInputDlg[i]->Show();
|
m_tas_input_dialogs[i]->Show();
|
||||||
g_TASInputDlg[i]->SetTitle(wxString::Format(_("TAS Input - GameCube Controller %d"), i + 1));
|
m_tas_input_dialogs[i]->SetTitle(
|
||||||
|
wxString::Format(_("TAS Input - GameCube Controller %d"), i + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_wiimote_sources[i] == WIIMOTE_SRC_EMU &&
|
if (g_wiimote_sources[i] == WIIMOTE_SRC_EMU &&
|
||||||
!(Core::IsRunning() && !SConfig::GetInstance().bWii))
|
!(Core::IsRunning() && !SConfig::GetInstance().bWii))
|
||||||
{
|
{
|
||||||
g_TASInputDlg[i + 4]->CreateWiiLayout(i);
|
m_tas_input_dialogs[i + 4]->CreateWiiLayout(i);
|
||||||
g_TASInputDlg[i + 4]->Show();
|
m_tas_input_dialogs[i + 4]->Show();
|
||||||
g_TASInputDlg[i + 4]->SetTitle(wxString::Format(_("TAS Input - Wii Remote %d"), i + 1));
|
m_tas_input_dialogs[i + 4]->SetTitle(wxString::Format(_("TAS Input - Wii Remote %d"), i + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ bool ControlDialog::Validate()
|
|||||||
UpdateGUI();
|
UpdateGUI();
|
||||||
|
|
||||||
const auto parse_status = control_reference->GetParseStatus();
|
const auto parse_status = control_reference->GetParseStatus();
|
||||||
return parse_status == ParseStatus::Success || parse_status == ParseStatus::NoDevice;
|
return parse_status == ParseStatus::Successful || parse_status == ParseStatus::NoDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputConfigDialog::SetDevice(wxCommandEvent&)
|
void InputConfigDialog::SetDevice(wxCommandEvent&)
|
||||||
|
@ -203,7 +203,7 @@ public:
|
|||||||
if (tok.type == TOK_EOF)
|
if (tok.type == TOK_EOF)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ParseStatus::Success;
|
return ParseStatus::Successful;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -373,11 +373,11 @@ public:
|
|||||||
{
|
{
|
||||||
ExpressionNode* node;
|
ExpressionNode* node;
|
||||||
ParseStatus status = Toplevel(&node);
|
ParseStatus status = Toplevel(&node);
|
||||||
if (status != ParseStatus::Success)
|
if (status != ParseStatus::Successful)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
*expr_out = new Expression(node);
|
*expr_out = new Expression(node);
|
||||||
return ParseStatus::Success;
|
return ParseStatus::Successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -409,7 +409,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
*expr_out = new ControlExpression(tok.qualifier, device, control);
|
*expr_out = new ControlExpression(tok.qualifier, device, control);
|
||||||
return ParseStatus::Success;
|
return ParseStatus::Successful;
|
||||||
}
|
}
|
||||||
case TOK_LPAREN:
|
case TOK_LPAREN:
|
||||||
return Paren(expr_out);
|
return Paren(expr_out);
|
||||||
@ -439,7 +439,7 @@ private:
|
|||||||
if (status == ParseStatus::SyntaxError)
|
if (status == ParseStatus::SyntaxError)
|
||||||
return status;
|
return status;
|
||||||
*expr_out = new UnaryExpression(tok.type, atom_expr);
|
*expr_out = new UnaryExpression(tok.type, atom_expr);
|
||||||
return ParseStatus::Success;
|
return ParseStatus::Successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Atom(expr_out);
|
return Atom(expr_out);
|
||||||
@ -478,7 +478,7 @@ private:
|
|||||||
*expr_out = new BinaryExpression(tok.type, *expr_out, unary_expr);
|
*expr_out = new BinaryExpression(tok.type, *expr_out, unary_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseStatus::Success;
|
return ParseStatus::Successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseStatus Paren(ExpressionNode** expr_out)
|
ParseStatus Paren(ExpressionNode** expr_out)
|
||||||
@ -486,7 +486,7 @@ private:
|
|||||||
ParseStatus status;
|
ParseStatus status;
|
||||||
|
|
||||||
// lparen already chewed
|
// lparen already chewed
|
||||||
if ((status = Toplevel(expr_out)) != ParseStatus::Success)
|
if ((status = Toplevel(expr_out)) != ParseStatus::Successful)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
if (!Expects(TOK_RPAREN))
|
if (!Expects(TOK_RPAREN))
|
||||||
@ -495,7 +495,7 @@ private:
|
|||||||
return ParseStatus::SyntaxError;
|
return ParseStatus::SyntaxError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseStatus::Success;
|
return ParseStatus::Successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseStatus Toplevel(ExpressionNode** expr_out) { return Binary(expr_out); }
|
ParseStatus Toplevel(ExpressionNode** expr_out) { return Binary(expr_out); }
|
||||||
@ -530,21 +530,21 @@ static ParseStatus ParseExpressionInner(const std::string& str, ControlFinder& f
|
|||||||
*expr_out = nullptr;
|
*expr_out = nullptr;
|
||||||
|
|
||||||
if (str == "")
|
if (str == "")
|
||||||
return ParseStatus::Success;
|
return ParseStatus::Successful;
|
||||||
|
|
||||||
Lexer l(str);
|
Lexer l(str);
|
||||||
std::vector<Token> tokens;
|
std::vector<Token> tokens;
|
||||||
status = l.Tokenize(tokens);
|
status = l.Tokenize(tokens);
|
||||||
if (status != ParseStatus::Success)
|
if (status != ParseStatus::Successful)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
Parser p(tokens, finder);
|
Parser p(tokens, finder);
|
||||||
status = p.Parse(&expr);
|
status = p.Parse(&expr);
|
||||||
if (status != ParseStatus::Success)
|
if (status != ParseStatus::Successful)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
*expr_out = expr;
|
*expr_out = expr;
|
||||||
return ParseStatus::Success;
|
return ParseStatus::Successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseStatus ParseExpression(const std::string& str, ControlFinder& finder, Expression** expr_out)
|
ParseStatus ParseExpression(const std::string& str, ControlFinder& finder, Expression** expr_out)
|
||||||
@ -561,7 +561,7 @@ ParseStatus ParseExpression(const std::string& str, ControlFinder& finder, Expre
|
|||||||
if (control)
|
if (control)
|
||||||
{
|
{
|
||||||
*expr_out = new Expression(new ControlExpression(qualifier, device, control));
|
*expr_out = new Expression(new ControlExpression(qualifier, device, control));
|
||||||
return ParseStatus::Success;
|
return ParseStatus::Successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseExpressionInner(str, finder, expr_out);
|
return ParseExpressionInner(str, finder, expr_out);
|
||||||
|
@ -61,7 +61,7 @@ public:
|
|||||||
|
|
||||||
enum class ParseStatus
|
enum class ParseStatus
|
||||||
{
|
{
|
||||||
Success,
|
Successful,
|
||||||
SyntaxError,
|
SyntaxError,
|
||||||
NoDevice,
|
NoDevice,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user