Add less verbose proxy object accessor

This introduces an OPTION macro, as well as assignment operators and
convenience conversion operators to make it easier to treat the
OptionProxy object (renamed from Proxy) as a variable.
This commit is contained in:
Fabrice de Gans 2023-02-05 17:59:07 -08:00 committed by Rafael Kitover
parent 2b950e282f
commit 31e17c1ba4
6 changed files with 139 additions and 113 deletions

View File

@ -2559,32 +2559,32 @@ EVT_HANDLER(GameBoyConfigure, "Game Boy options...")
EVT_HANDLER(SetSize1x, "1x")
{
config::Proxy<config::OptionID::kDispScale>().Set(1);
OPTION(kDispScale) = 1;
}
EVT_HANDLER(SetSize2x, "2x")
{
config::Proxy<config::OptionID::kDispScale>().Set(2);
OPTION(kDispScale) = 2;
}
EVT_HANDLER(SetSize3x, "3x")
{
config::Proxy<config::OptionID::kDispScale>().Set(3);
OPTION(kDispScale) = 3;
}
EVT_HANDLER(SetSize4x, "4x")
{
config::Proxy<config::OptionID::kDispScale>().Set(4);
OPTION(kDispScale) = 4;
}
EVT_HANDLER(SetSize5x, "5x")
{
config::Proxy<config::OptionID::kDispScale>().Set(5);
OPTION(kDispScale) = 5;
}
EVT_HANDLER(SetSize6x, "6x")
{
config::Proxy<config::OptionID::kDispScale>().Set(6);
OPTION(kDispScale) = 6;
}
EVT_HANDLER(GameBoyAdvanceConfigure, "Game Boy Advance options...")
@ -2764,12 +2764,12 @@ EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY)
EVT_HANDLER_MASK(ChangeFilter, "Change Pixel Filter", CMDEN_NREC_ANY)
{
config::Proxy<config::OptionID::kDispFilter>().Next();
OPTION(kDispFilter).Next();
}
EVT_HANDLER_MASK(ChangeIFB, "Change Interframe Blending", CMDEN_NREC_ANY)
{
config::Proxy<config::OptionID::kDispIFB>().Next();
OPTION(kDispIFB).Next();
}
EVT_HANDLER_MASK(SoundConfigure, "Sound options...", CMDEN_NREC_ANY)

View File

@ -248,13 +248,11 @@ std::array<Option, kNbOptions>& Option::All() {
Option(OptionID::kPrefLinkNumPlayers, &gopts.link_num_players, 2, 4),
#endif
Option(OptionID::kPrefMaxScale, &gopts.max_scale, 0, 100),
Option(OptionID::kPrefPauseWhenInactive, &pauseWhenInactive, 0,
1),
Option(OptionID::kPrefPauseWhenInactive, &pauseWhenInactive, 0, 1),
Option(OptionID::kPrefRTCEnabled, &coreOptions.rtcEnabled, 0, 1),
Option(OptionID::kPrefSaveType, &coreOptions.cpuSaveType, 0, 5),
Option(OptionID::kPrefShowSpeed, &showSpeed, 0, 2),
Option(OptionID::kPrefShowSpeedTransparent,
&showSpeedTransparent, 0, 1),
Option(OptionID::kPrefShowSpeedTransparent, &showSpeedTransparent, 0, 1),
Option(OptionID::kPrefSkipBios, &coreOptions.skipBios, 0, 1),
Option(OptionID::kPrefSkipSaveGameCheats, &coreOptions.skipSaveGameCheats, 0, 1),
Option(OptionID::kPrefSkipSaveGameBattery, &coreOptions.skipSaveGameBattery, 0, 1),

View File

@ -138,138 +138,174 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
// Less verbose accessor for a specific OptionID with compile-time type checks.
//
// Sample usage:
// if (Proxy<OptionID::kDispBilinear>::Get()) {
//
// if (OPTION(kDispBilinear)) {
// // Do something if bilinear filter is on.
// }
//
// Proxy<OptionID::kDispBilinear>::Set(false);
// // Set this Option to false.
// OPTION(kDispBilinear) = false;
#define OPTION(option_id) ::config::OptionProxy<::config::OptionID::option_id>()
template <OptionID ID, typename = void>
class Proxy {};
class OptionProxy {};
template <OptionID ID>
class Proxy<
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] == Option::Type::kBool>::type> {
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kBool>::type> {
public:
Proxy() : option_(Option::ByID(ID)) {}
~Proxy() = default;
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
bool Get() { return option_->GetBool(); }
bool Get() const { return option_->GetBool(); }
bool Set(bool value) { return option_->SetBool(value); }
bool operator=(bool value) { return Set(value); }
operator bool() const { return Get(); }
private:
Option* option_;
};
template <OptionID ID>
class Proxy<ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kDouble>::type> {
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kDouble>::type> {
public:
Proxy() : option_(Option::ByID(ID)) {}
~Proxy() = default;
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
double Get() { return option_->GetDouble(); }
double Get() const { return option_->GetDouble(); }
bool Set(double value) { return option_->SetDouble(value); }
double Min() const { return option_->GetDoubleMin(); }
double Max() const { return option_->GetDoubleMax(); }
bool operator=(double value) { return Set(value); }
operator double() const { return Get(); }
private:
Option* option_;
};
template <OptionID ID>
class Proxy<
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] == Option::Type::kInt>::type> {
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kInt>::type> {
public:
Proxy() : option_(Option::ByID(ID)) {}
~Proxy() = default;
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
int32_t Get() { return option_->GetInt(); }
int32_t Get() const { return option_->GetInt(); }
bool Set(int32_t value) { return option_->SetInt(value); }
int32_t Min() const { return option_->GetIntMin(); }
int32_t Max() const { return option_->GetIntMax(); }
bool operator=(int32_t value) { return Set(value); }
operator int32_t() const { return Get(); }
private:
Option* option_;
};
template <OptionID ID>
class Proxy<ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kUnsigned>::type> {
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kUnsigned>::type> {
public:
Proxy() : option_(Option::ByID(ID)) {}
~Proxy() = default;
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
uint32_t Get() { return option_->GetUnsigned(); }
uint32_t Get() const { return option_->GetUnsigned(); }
bool Set(uint32_t value) { return option_->SetUnsigned(value); }
uint32_t Min() const { return option_->GetUnsignedMin(); }
uint32_t Max() const { return option_->GetUnsignedMax(); }
bool operator=(int32_t value) { return Set(value); }
operator int32_t() const { return Get(); }
private:
Option* option_;
};
template <OptionID ID>
class Proxy<ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kString>::type> {
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kString>::type> {
public:
Proxy() : option_(Option::ByID(ID)) {}
~Proxy() = default;
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
const wxString& Get() { return option_->GetString(); }
const wxString& Get() const { return option_->GetString(); }
bool Set(const wxString& value) { return option_->SetString(value); }
bool operator=(wxString value) { return Set(value); }
operator wxString() const { return Get(); }
private:
Option* option_;
};
template <OptionID ID>
class Proxy<ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kFilter>::type> {
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kFilter>::type> {
public:
Proxy() : option_(Option::ByID(ID)) {}
~Proxy() = default;
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
Filter Get() { return option_->GetFilter(); }
Filter Get() const { return option_->GetFilter(); }
bool Set(Filter value) { return option_->SetFilter(value); }
void Next() { option_->NextFilter(); }
bool operator=(Filter value) { return Set(value); }
operator Filter() const { return Get(); }
private:
Option* option_;
};
template <OptionID ID>
class Proxy<ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kInterframe>::type> {
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kInterframe>::type> {
public:
Proxy() : option_(Option::ByID(ID)) {}
~Proxy() = default;
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
Interframe Get() { return option_->GetInterframe(); }
Interframe Get() const { return option_->GetInterframe(); }
bool Set(Interframe value) { return option_->SetInterframe(value); }
void Next() { option_->NextInterframe(); }
bool operator=(Interframe value) { return Set(value); }
operator Interframe() const { return Get(); }
private:
Option* option_;
};
template <OptionID ID>
class Proxy<ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kRenderMethod>::type> {
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kRenderMethod>::type> {
public:
Proxy() : option_(Option::ByID(ID)) {}
~Proxy() = default;
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
RenderMethod Get() { return option_->GetRenderMethod(); }
RenderMethod Get() const { return option_->GetRenderMethod(); }
bool Set(RenderMethod value) { return option_->SetRenderMethod(value); }
bool operator=(RenderMethod value) { return Set(value); }
operator RenderMethod() const { return Get(); }
private:
Option* option_;
};

View File

@ -354,7 +354,7 @@ void DisplayConfig::PopulatePluginOptions() {
plugin_selector_->Clear();
plugin_selector_->Append(_("None"), new wxStringClientData());
const wxString& selected_plugin = config::Proxy<config::OptionID::kDispFilterPlugin>().Get();
const wxString& selected_plugin = OPTION(kDispFilterPlugin);
bool is_plugin_selected = false;
for (const wxString& plugin : plugins) {
@ -389,7 +389,7 @@ void DisplayConfig::PopulatePluginOptions() {
}
if (!is_plugin_selected) {
config::Proxy<config::OptionID::kDispFilterPlugin>().Set(wxEmptyString);
OPTION(kDispFilterPlugin) = wxEmptyString;
}
plugin_selector_->SetValidator(PluginSelectorValidator());
@ -444,14 +444,14 @@ void DisplayConfig::HidePluginOptions() {
if (filter_selector_->GetCount() == config::kNbFilters) {
// Make sure we have not selected the plugin option. The validator
// will take care of updating the selector value.
if (config::Proxy<config::OptionID::kDispFilter>().Get() == config::Filter::kPlugin) {
config::Proxy<config::OptionID::kDispFilter>().Set(config::Filter::kNone);
if (OPTION(kDispFilter) == config::Filter::kPlugin) {
OPTION(kDispFilter) = config::Filter::kNone;
}
filter_selector_->Delete(config::kNbFilters - 1);
}
// Also erase the Plugin value to avoid issues down the line.
config::Proxy<config::OptionID::kDispFilterPlugin>().Set(wxEmptyString);
OPTION(kDispFilterPlugin) = wxEmptyString;
}
void DisplayConfig::ShowPluginOptions() {

View File

@ -47,7 +47,7 @@
namespace {
double GetFilterScale() {
switch (config::Proxy<config::OptionID::kDispFilter>().Get()) {
switch (OPTION(kDispFilter)) {
case config::Filter::kNone:
return 1.0;
case config::Filter::k2xsai:
@ -388,7 +388,7 @@ void GameArea::LoadGame(const wxString& name)
emusys = &GBASystem;
}
if (config::Proxy<config::OptionID::kGeomFullScreen>().Get()) {
if (OPTION(kGeomFullScreen)) {
GameArea::ShowFullScreen(true);
}
@ -794,7 +794,7 @@ void GameArea::AdjustMinSize()
{
wxWindow* frame = wxGetApp().frame;
double dpi_scale_factor = widgets::DPIScaleFactorForWindow(this);
double display_scale = config::Proxy<config::OptionID::kDispScale>().Get();
const double display_scale = OPTION(kDispScale);
// note: could safely set min size to 1x or less regardless of video_scale
// but setting it to scaled size makes resizing to default easier
@ -830,7 +830,7 @@ void GameArea::AdjustSize(bool force)
return;
double dpi_scale_factor = widgets::DPIScaleFactorForWindow(this);
double display_scale = config::Proxy<config::OptionID::kDispScale>().Get();
const double display_scale = OPTION(kDispScale);
const wxSize newsz(
(std::ceil(basic_width * display_scale) * dpi_scale_factor),
@ -1096,7 +1096,7 @@ void GameArea::OnIdle(wxIdleEvent& event)
return;
if (!panel) {
switch (config::Proxy<config::OptionID::kDispRenderMethod>().Get()) {
switch (OPTION(kDispRenderMethod)) {
case config::RenderMethod::kSimple:
panel = new BasicDrawingPanel(this, basic_width, basic_height);
break;
@ -1412,9 +1412,9 @@ DrawingPanelBase::DrawingPanelBase(int _width, int _height)
rpi_(nullptr) {
memset(delta, 0xff, sizeof(delta));
if (config::Proxy<config::OptionID::kDispFilter>().Get() == config::Filter::kPlugin) {
rpi_ = widgets::MaybeLoadFilterPlugin(
config::Proxy<config::OptionID::kDispFilterPlugin>().Get(), &filter_plugin_);
if (OPTION(kDispFilter) == config::Filter::kPlugin) {
rpi_ = widgets::MaybeLoadFilterPlugin(OPTION(kDispFilterPlugin),
&filter_plugin_);
if (rpi_) {
rpi_->Flags &= ~RPI_565_SUPP;
@ -1434,13 +1434,13 @@ DrawingPanelBase::DrawingPanelBase(int _width, int _height)
scale *= (rpi_->Flags & RPI_OUT_SCLMSK) >> RPI_OUT_SCLSH;
} else {
// This is going to delete the object. Do nothing more here.
config::Proxy<config::OptionID::kDispFilterPlugin>().Set(wxEmptyString);
config::Proxy<config::OptionID::kDispFilter>().Set(config::Filter::kNone);
OPTION(kDispFilterPlugin) = wxEmptyString;
OPTION(kDispFilter) = config::Filter::kNone;
return;
}
}
if (config::Proxy<config::OptionID::kDispFilter>().Get() != config::Filter::kPlugin) {
if (OPTION(kDispFilter) != config::Filter::kPlugin) {
scale *= GetFilterScale();
systemColorDepth = 32;
}
@ -1559,8 +1559,7 @@ public:
delta_ += instride * procy;
// FIXME: fugly hack
if (config::Proxy<config::OptionID::kDispRenderMethod>().Get() ==
config::RenderMethod::kOpenGL) {
if (OPTION(kDispRenderMethod) == config::RenderMethod::kOpenGL) {
dst_ += (int)std::ceil(outstride * (procy + 1) * scale_);
} else {
dst_ += (int)std::ceil(outstride * (procy + (1 / scale_)) * scale_);
@ -1579,7 +1578,7 @@ public:
// added procy param to provide offset into accum buffers
ApplyInterframe(instride, procy);
if (config::Proxy<config::OptionID::kDispFilter>().Get() == config::Filter::kNone) {
if (OPTION(kDispFilter) == config::Filter::kNone) {
if (nthreads_ == 1)
return 0;
@ -1608,7 +1607,7 @@ private:
// definitely not thread safe by default
// added procy param to provide offset into accum buffers
void ApplyInterframe(int instride, int procy) {
switch (config::Proxy<config::OptionID::kDispIFB>().Get()) {
switch (OPTION(kDispIFB)) {
case config::Interframe::kNone:
break;
@ -1636,7 +1635,7 @@ private:
// naturally, any of these with accumulation buffers like those
// of the IFB filters will screw up royally as well
void ApplyFilter(int instride, int outstride) {
switch (config::Proxy<config::OptionID::kDispFilter>().Get()) {
switch (OPTION(kDispFilter)) {
case config::Filter::k2xsai:
_2xSaI32(src_, instride, delta_, dst_, outstride, width_,
height_);
@ -1798,7 +1797,7 @@ void DrawingPanelBase::DrawArea(uint8_t** data)
pixbuf2 = (uint8_t*)calloc(allocstride, std::ceil((alloch + 2) * scale));
}
if (config::Proxy<config::OptionID::kDispFilter>().Get() == config::Filter::kNone) {
if (OPTION(kDispFilter) == config::Filter::kNone) {
todraw = *data;
// *data is assigned below, after old buf has been processed
pixbuf1 = pixbuf2;
@ -1811,8 +1810,8 @@ void DrawingPanelBase::DrawArea(uint8_t** data)
// First, apply filters, if applicable, in parallel, if enabled
// FIXME: && (gopts.ifb != FF_MOTION_BLUR || !renderer_can_motion_blur)
if (config::Proxy<config::OptionID::kDispFilter>().Get() != config::Filter::kNone ||
config::Proxy<config::OptionID::kDispIFB>().Get() != config::Interframe::kNone) {
if (OPTION(kDispFilter) != config::Filter::kNone ||
OPTION(kDispIFB) != config::Interframe::kNone) {
if (nthreads != gopts.max_threads) {
if (nthreads) {
if (nthreads > 1)
@ -1884,7 +1883,7 @@ void DrawingPanelBase::DrawArea(uint8_t** data)
}
// swap buffers now that src has been processed
if (config::Proxy<config::OptionID::kDispFilter>().Get() == config::Filter::kNone) {
if (OPTION(kDispFilter) == config::Filter::kNone) {
*data = pixbuf1;
}
@ -2070,8 +2069,8 @@ BasicDrawingPanel::BasicDrawingPanel(wxWindow* parent, int _width, int _height)
{
// wxImage is 24-bit RGB, so 24-bit is preferred. Filters require
// 16 or 32, though
if (config::Proxy<config::OptionID::kDispFilter>().Get() == config::Filter::kNone &&
config::Proxy<config::OptionID::kDispIFB>().Get() == config::Interframe::kNone) {
if (OPTION(kDispFilter) == config::Filter::kNone &&
OPTION(kDispIFB) == config::Interframe::kNone) {
// changing from 32 to 24 does not require regenerating color tables
systemColorDepth = 32;
}
@ -2102,7 +2101,7 @@ void BasicDrawingPanel::DrawArea(wxWindowDC& dc)
src += 2; // skip rhs border
}
} else if (config::Proxy<config::OptionID::kDispFilter>().Get() != config::Filter::kNone) {
} else if (OPTION(kDispFilter) != config::Filter::kNone) {
// scaled by filters, top/right borders, transform to 24-bit
im = new wxImage(std::ceil(width * scale), std::ceil(height * scale), false);
uint32_t* src = (uint32_t*)todraw + (int)std::ceil(width * scale) + 1; // skip top border

View File

@ -362,8 +362,7 @@ bool wxvbamApp::OnInit() {
// wxGLCanvas segfaults under wayland before wx 3.2
#if defined(HAVE_WAYLAND_SUPPORT) && !defined(HAVE_WAYLAND_EGL)
if (UsingWayland()) {
config::Proxy<config::OptionID::kDispRenderMethod>().Set(
config::RenderMethod::kSimple);
OPTION(kDispRenderMethod) = config::RenderMethod::kSimple;
}
#endif
@ -472,14 +471,12 @@ bool wxvbamApp::OnInit() {
config::GameControlState::Instance().OnGameBindingsChanged();
// create the main window
int x = config::Proxy<config::OptionID::kGeomWindowX>().Get();
int y = config::Proxy<config::OptionID::kGeomWindowY>().Get();
int width = config::Proxy<config::OptionID::kGeomWindowHeight>().Get();
int height = config::Proxy<config::OptionID::kGeomWindowHeight>().Get();
bool isFullscreen =
config::Proxy<config::OptionID::kGeomFullScreen>().Get();
bool isMaximized =
config::Proxy<config::OptionID::kGeomIsMaximized>().Get();
int x = OPTION(kGeomWindowX);
int y = OPTION(kGeomWindowY);
int width = OPTION(kGeomWindowHeight);
int height = OPTION(kGeomWindowHeight);
bool isFullscreen = OPTION(kGeomFullScreen);
bool isMaximized = OPTION(kGeomIsMaximized);
frame = wxDynamicCast(xr->LoadFrame(nullptr, "MainFrame"), MainFrame);
if (!frame) {
@ -842,8 +839,8 @@ void MainFrame::OnMove(wxMoveEvent&) {
if (!IsFullScreen() && !IsMaximized()) {
if (window_pos.x >= 0 && window_pos.y >= 0) {
config::Proxy<config::OptionID::kGeomWindowX>().Set(window_pos.x);
config::Proxy<config::OptionID::kGeomWindowY>().Set(window_pos.y);
OPTION(kGeomWindowX) = window_pos.x;
OPTION(kGeomWindowY) = window_pos.y;
}
}
}
@ -851,26 +848,22 @@ void MainFrame::OnMove(wxMoveEvent&) {
void MainFrame::OnSize(wxSizeEvent& event)
{
wxFrame::OnSize(event);
wxRect window_rect = GetRect();
wxPoint window_pos = GetScreenPosition();
config::Proxy<config::OptionID::kGeomWindowX> window_x;
config::Proxy<config::OptionID::kGeomWindowY> window_y;
const wxRect window_rect = GetRect();
const wxPoint window_pos = GetScreenPosition();
if (!IsFullScreen() && !IsMaximized()) {
if (window_rect.GetHeight() > 0 && window_rect.GetWidth() > 0) {
config::Proxy<config::OptionID::kGeomWindowHeight>().Set(
window_rect.GetHeight());
config::Proxy<config::OptionID::kGeomWindowWidth>().Set(
window_rect.GetWidth());
OPTION(kGeomWindowHeight) = window_rect.GetHeight();
OPTION(kGeomWindowWidth) = window_rect.GetWidth();
}
if (window_pos.x >= 0 && window_pos.y >= 0) {
window_x.Set(window_pos.x);
window_y.Set(window_pos.y);
OPTION(kGeomWindowX) = window_pos.x;
OPTION(kGeomWindowY) = window_pos.y;
}
}
config::Proxy<config::OptionID::kGeomIsMaximized>().Set(IsMaximized());
config::Proxy<config::OptionID::kGeomFullScreen>().Set(IsFullScreen());
OPTION(kGeomIsMaximized) = IsMaximized();
OPTION(kGeomFullScreen) = IsFullScreen();
}
int MainFrame::FilterEvent(wxEvent& event)