Move display options to owned_opts

This also removes limits on the main window position so it can now be
negative. This is necessary on Windows where multiple screens to the
left and top of the main screen have negative coordinates. A check at
startup ensures we always restore the window within the drawable area.
This commit is contained in:
Fabrice de Gans 2023-02-05 17:44:04 -08:00 committed by Rafael Kitover
parent 216bf4d7e4
commit 950a4070c1
16 changed files with 240 additions and 129 deletions

View File

@ -765,6 +765,7 @@ set(
config/option.cpp config/option.cpp
config/user-input.cpp config/user-input.cpp
dialogs/display-config.cpp dialogs/display-config.cpp
widgets/keep-on-top-styler.cpp
widgets/keyedit.cpp widgets/keyedit.cpp
widgets/joyedit.cpp widgets/joyedit.cpp
widgets/option-validator.cpp widgets/option-validator.cpp
@ -811,6 +812,7 @@ set(
config/user-input.h config/user-input.h
dialogs/display-config.h dialogs/display-config.h
widgets/dpi-support.h widgets/dpi-support.h
widgets/keep-on-top-styler.h
widgets/option-validator.h widgets/option-validator.h
widgets/render-plugin.h widgets/render-plugin.h
widgets/wx/keyedit.h widgets/wx/keyedit.h

View File

@ -2267,12 +2267,6 @@ EVT_HANDLER(Logging, "Logging...")
{ {
wxDialog* dlg = wxGetApp().frame->logdlg; wxDialog* dlg = wxGetApp().frame->logdlg;
dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER); dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top)
dlg->SetWindowStyle(dlg->GetWindowStyle() | wxSTAY_ON_TOP);
else
dlg->SetWindowStyle(dlg->GetWindowStyle() & ~wxSTAY_ON_TOP);
dlg->Show(); dlg->Show();
dlg->Raise(); dlg->Raise();
} }
@ -2741,15 +2735,6 @@ EVT_HANDLER(GameBoyAdvanceConfigure, "Game Boy Advance options...")
EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY) EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY)
{ {
if (gopts.max_threads != 1) {
gopts.max_threads = wxThread::GetCPUCount();
}
// Just in case GetCPUCount() returns 0 or -1
if (gopts.max_threads < 0) {
gopts.max_threads = 1;
}
wxDialog* dlg = GetXRCDialog("DisplayConfig"); wxDialog* dlg = GetXRCDialog("DisplayConfig");
if (ShowModal(dlg) != wxID_OK) { if (ShowModal(dlg) != wxID_OK) {
return; return;
@ -2965,18 +2950,12 @@ EVT_HANDLER(wxID_ABOUT, "About...")
EVT_HANDLER(Bilinear, "Use bilinear filter with 3d renderer") EVT_HANDLER(Bilinear, "Use bilinear filter with 3d renderer")
{ {
GetMenuOptionBool("Bilinear", &gopts.bilinear); GetMenuOptionConfig("Bilinear", config::OptionID::kDispBilinear);
// Force new panel with new bilinear option.
panel->ResetPanel();
update_opts();
} }
EVT_HANDLER(RetainAspect, "Retain aspect ratio when resizing") EVT_HANDLER(RetainAspect, "Retain aspect ratio when resizing")
{ {
GetMenuOptionBool("RetainAspect", &gopts.retain_aspect); GetMenuOptionConfig("RetainAspect", config::OptionID::kDispStretch);
// Force new panel with new aspect ratio options.
panel->ResetPanel();
update_opts();
} }
EVT_HANDLER(Printer, "Enable printer emulation") EVT_HANDLER(Printer, "Enable printer emulation")
@ -3080,15 +3059,7 @@ EVT_HANDLER(ApplyPatches, "Apply IPS/UPS/IPF patches if found")
EVT_HANDLER(KeepOnTop, "Keep window on top") EVT_HANDLER(KeepOnTop, "Keep window on top")
{ {
GetMenuOptionBool("KeepOnTop", &gopts.keep_on_top); GetMenuOptionConfig("KeepOnTop", config::OptionID::kDispKeepOnTop);
MainFrame* mf = wxGetApp().frame;
if (gopts.keep_on_top)
mf->SetWindowStyle(mf->GetWindowStyle() | wxSTAY_ON_TOP);
else
mf->SetWindowStyle(mf->GetWindowStyle() & ~wxSTAY_ON_TOP);
update_opts();
} }
EVT_HANDLER(StatusBar, "Enable status bar") EVT_HANDLER(StatusBar, "Enable status bar")

View File

@ -6,6 +6,7 @@
#include <wx/log.h> #include <wx/log.h>
#include <algorithm> #include <algorithm>
#include <limits>
#include "../common/ConfigManager.h" #include "../common/ConfigManager.h"
#include "../gb/gbGlobals.h" #include "../gb/gbGlobals.h"
@ -145,20 +146,27 @@ wxString AllEnumValuesForArray(const std::array<wxString, SIZE>& input) {
// static // static
std::array<Option, kNbOptions>& Option::All() { std::array<Option, kNbOptions>& Option::All() {
struct OwnedOptions { struct OwnedOptions {
double video_scale = 3; /// Display
wxString filter_plugin = wxEmptyString; bool bilinear = true;
Filter filter = Filter::kNone; Filter filter = Filter::kNone;
wxString filter_plugin = wxEmptyString;
Interframe interframe = Interframe::kNone; Interframe interframe = Interframe::kNone;
bool keep_on_top = false;
int32_t max_threads = 0;
#if defined(NO_OGL) #if defined(NO_OGL)
RenderMethod render_method = RenderMethod::kSimple; RenderMethod render_method = RenderMethod::kSimple;
#else #else
RenderMethod render_method = RenderMethod::kOpenGL; RenderMethod render_method = RenderMethod::kOpenGL;
#endif #endif
double video_scale = 3;
bool retain_aspect = true;
/// Geometry
bool window_maximized = false; bool window_maximized = false;
uint32_t window_height = 0; uint32_t window_height = 0;
uint32_t window_width = 0; uint32_t window_width = 0;
int window_pos_x = -1; int32_t window_pos_x = -1;
int window_pos_y = -1; int32_t window_pos_y = -1;
}; };
static OwnedOptions g_owned_opts; static OwnedOptions g_owned_opts;
@ -170,15 +178,15 @@ std::array<Option, kNbOptions>& Option::All() {
// clang-format off // clang-format off
static std::array<Option, kNbOptions> g_all_opts = { static std::array<Option, kNbOptions> g_all_opts = {
/// Display /// Display
Option(OptionID::kDispBilinear, &gopts.bilinear), Option(OptionID::kDispBilinear, &g_owned_opts.bilinear),
Option(OptionID::kDispFilter, &g_owned_opts.filter), Option(OptionID::kDispFilter, &g_owned_opts.filter),
Option(OptionID::kDispFilterPlugin, &g_owned_opts.filter_plugin), Option(OptionID::kDispFilterPlugin, &g_owned_opts.filter_plugin),
Option(OptionID::kDispIFB, &g_owned_opts.interframe), Option(OptionID::kDispIFB, &g_owned_opts.interframe),
Option(OptionID::kDispKeepOnTop, &gopts.keep_on_top), Option(OptionID::kDispKeepOnTop, &g_owned_opts.keep_on_top),
Option(OptionID::kDispMaxThreads, &gopts.max_threads, 1, 256), Option(OptionID::kDispMaxThreads, &g_owned_opts.max_threads, 0, 256),
Option(OptionID::kDispRenderMethod, &g_owned_opts.render_method), Option(OptionID::kDispRenderMethod, &g_owned_opts.render_method),
Option(OptionID::kDispScale, &g_owned_opts.video_scale, 1, 6), Option(OptionID::kDispScale, &g_owned_opts.video_scale, 1, 6),
Option(OptionID::kDispStretch, &gopts.retain_aspect), Option(OptionID::kDispStretch, &g_owned_opts.retain_aspect),
/// GB /// GB
Option(OptionID::kGBBiosFile, &gopts.gb_bios), Option(OptionID::kGBBiosFile, &gopts.gb_bios),
@ -270,8 +278,8 @@ std::array<Option, kNbOptions>& Option::All() {
Option(OptionID::kGeomIsMaximized, &g_owned_opts.window_maximized), Option(OptionID::kGeomIsMaximized, &g_owned_opts.window_maximized),
Option(OptionID::kGeomWindowHeight, &g_owned_opts.window_height, 0, 99999), Option(OptionID::kGeomWindowHeight, &g_owned_opts.window_height, 0, 99999),
Option(OptionID::kGeomWindowWidth, &g_owned_opts.window_width, 0, 99999), Option(OptionID::kGeomWindowWidth, &g_owned_opts.window_width, 0, 99999),
Option(OptionID::kGeomWindowX, &g_owned_opts.window_pos_x, -1, 99999), Option(OptionID::kGeomWindowX, &g_owned_opts.window_pos_x, std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max()),
Option(OptionID::kGeomWindowY, &g_owned_opts.window_pos_y, -1, 99999), Option(OptionID::kGeomWindowY, &g_owned_opts.window_pos_y, std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max()),
/// UI /// UI
Option(OptionID::kUIAllowKeyboardBackgroundInput, &allowKeyboardBackgroundInput), Option(OptionID::kUIAllowKeyboardBackgroundInput, &allowKeyboardBackgroundInput),

View File

@ -4,7 +4,7 @@
namespace config { namespace config {
enum class OptionID { enum class OptionID {
// Display /// Display
kDispBilinear = 0, kDispBilinear = 0,
kDispFilter, kDispFilter,
kDispFilterPlugin, kDispFilterPlugin,

View File

@ -18,6 +18,7 @@
#include "config/option-id.h" #include "config/option-id.h"
#include "config/option-proxy.h" #include "config/option-proxy.h"
#include "config/option.h" #include "config/option.h"
#include "keep-on-top-styler.h"
#include "rpi.h" #include "rpi.h"
#include "wayland.h" #include "wayland.h"
#include "widgets/option-validator.h" #include "widgets/option-validator.h"
@ -250,7 +251,8 @@ DisplayConfig::DisplayConfig(wxWindow* parent)
interframe_observer_(config::OptionID::kDispIFB, interframe_observer_(config::OptionID::kDispIFB,
std::bind(&DisplayConfig::OnInterframeChanged, std::bind(&DisplayConfig::OnInterframeChanged,
this, this,
std::placeholders::_1)) { std::placeholders::_1)),
keep_on_top_styler_(this) {
#if !wxCHECK_VERSION(3, 1, 0) #if !wxCHECK_VERSION(3, 1, 0)
// This needs to be set before loading any element on the window. This also // This needs to be set before loading any element on the window. This also
// has no effect since wx 3.1.0, where it became the default. // has no effect since wx 3.1.0, where it became the default.
@ -337,6 +339,9 @@ void DisplayConfig::OnDialogShowEvent(wxShowEvent& event) {
} else { } else {
StopPluginHandler(); StopPluginHandler();
} }
// Let the event propagate.
event.Skip();
} }
void DisplayConfig::PopulatePluginOptions() { void DisplayConfig::PopulatePluginOptions() {
@ -408,6 +413,9 @@ void DisplayConfig::UpdatePlugin(wxCommandEvent& event) {
config::Filter::kPlugin); config::Filter::kPlugin);
plugin_label_->Enable(is_plugin); plugin_label_->Enable(is_plugin);
plugin_selector_->Enable(is_plugin); plugin_selector_->Enable(is_plugin);
// Let the event propagate.
event.Skip();
} }
void DisplayConfig::OnFilterChanged(config::Option* option) { void DisplayConfig::OnFilterChanged(config::Option* option) {

View File

@ -5,6 +5,7 @@
#include <wx/event.h> #include <wx/event.h>
#include "config/option-observer.h" #include "config/option-observer.h"
#include "widgets/keep-on-top-styler.h"
// Forward declarations. // Forward declarations.
class wxChoice; class wxChoice;
@ -55,8 +56,9 @@ private:
wxChoice* plugin_selector_; wxChoice* plugin_selector_;
wxChoice* filter_selector_; wxChoice* filter_selector_;
wxChoice* interframe_selector_; wxChoice* interframe_selector_;
config::OptionsObserver filter_observer_; const config::OptionsObserver filter_observer_;
config::OptionsObserver interframe_observer_; const config::OptionsObserver interframe_observer_;
const widgets::KeepOnTopStyler keep_on_top_styler_;
}; };
} // namespace dialogs } // namespace dialogs

View File

@ -26,6 +26,7 @@
#include "../gba/CheatSearch.h" #include "../gba/CheatSearch.h"
#include "config/game-control.h" #include "config/game-control.h"
#include "config/option.h" #include "config/option.h"
#include "config/option-proxy.h"
#include "config/user-input.h" #include "config/user-input.h"
#include "dialogs/display-config.h" #include "dialogs/display-config.h"
#include "opts.h" #include "opts.h"
@ -322,7 +323,7 @@ public:
wxDialog* subdlg = GetXRCDialog("CheatEdit"); wxDialog* subdlg = GetXRCDialog("CheatEdit");
dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER); dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top) if (OPTION(kDispKeepOnTop))
subdlg->SetWindowStyle(subdlg->GetWindowStyle() | wxSTAY_ON_TOP); subdlg->SetWindowStyle(subdlg->GetWindowStyle() | wxSTAY_ON_TOP);
else else
subdlg->SetWindowStyle(subdlg->GetWindowStyle() & ~wxSTAY_ON_TOP); subdlg->SetWindowStyle(subdlg->GetWindowStyle() & ~wxSTAY_ON_TOP);
@ -545,7 +546,7 @@ public:
wxDialog* subdlg = GetXRCDialog("CheatEdit"); wxDialog* subdlg = GetXRCDialog("CheatEdit");
dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER); dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top) if (OPTION(kDispKeepOnTop))
subdlg->SetWindowStyle(subdlg->GetWindowStyle() | wxSTAY_ON_TOP); subdlg->SetWindowStyle(subdlg->GetWindowStyle() | wxSTAY_ON_TOP);
else else
subdlg->SetWindowStyle(subdlg->GetWindowStyle() & ~wxSTAY_ON_TOP); subdlg->SetWindowStyle(subdlg->GetWindowStyle() & ~wxSTAY_ON_TOP);
@ -1075,7 +1076,7 @@ public:
wxDialog* subdlg = GetXRCDialog("CheatAdd"); wxDialog* subdlg = GetXRCDialog("CheatAdd");
dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER); dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top) if (OPTION(kDispKeepOnTop))
subdlg->SetWindowStyle(subdlg->GetWindowStyle() | wxSTAY_ON_TOP); subdlg->SetWindowStyle(subdlg->GetWindowStyle() | wxSTAY_ON_TOP);
else else
subdlg->SetWindowStyle(subdlg->GetWindowStyle() & ~wxSTAY_ON_TOP); subdlg->SetWindowStyle(subdlg->GetWindowStyle() & ~wxSTAY_ON_TOP);
@ -3785,7 +3786,7 @@ bool MainFrame::BindControls()
else else
mf->GetStatusBar()->Hide(); mf->GetStatusBar()->Hide();
if (gopts.keep_on_top) if (OPTION(kDispKeepOnTop))
mf->SetWindowStyle(mf->GetWindowStyle() | wxSTAY_ON_TOP); mf->SetWindowStyle(mf->GetWindowStyle() | wxSTAY_ON_TOP);
else else
mf->SetWindowStyle(mf->GetWindowStyle() & ~wxSTAY_ON_TOP); mf->SetWindowStyle(mf->GetWindowStyle() & ~wxSTAY_ON_TOP);

View File

@ -8,6 +8,7 @@
#include <wx/display.h> #include <wx/display.h>
#include "config/option-observer.h" #include "config/option-observer.h"
#include "config/option-proxy.h"
#include "config/option.h" #include "config/option.h"
#include "strutils.h" #include "strutils.h"
#include "wxvbam.h" #include "wxvbam.h"
@ -308,14 +309,6 @@ wxAcceleratorEntry_v sys_accels;
// This constructor only works with globally allocated gopts. // This constructor only works with globally allocated gopts.
opts_t::opts_t() opts_t::opts_t()
{ {
// handle erroneous thread count values appropriately
max_threads = wxThread::GetCPUCount();
if (max_threads > 256)
max_threads = 256;
if (max_threads < 1)
max_threads = 1;
recent = new wxFileHistory(10); recent = new wxFileHistory(10);
// These are globals being set here. // These are globals being set here.
@ -556,6 +549,20 @@ void load_opts() {
cfg->SetPath(wxT("/")); cfg->SetPath(wxT("/"));
cfg->Flush(); cfg->Flush();
// We default the MaxThreads option to 0, so set it to the CPU count here.
config::OptionProxy<config::OptionID::kDispMaxThreads> max_threads;
if (max_threads == 0) {
// Handle erroneous thread count values appropriately.
const int cpu_count = wxThread::GetCPUCount();
if (cpu_count > 256) {
max_threads = 256;
} else if (cpu_count < 1) {
max_threads = 1;
} else {
max_threads = cpu_count;
}
}
InitializeOptionObservers(); InitializeOptionObservers();
} }

View File

@ -23,11 +23,7 @@ extern struct opts_t {
// I instead organized this by opts.cpp table order // I instead organized this by opts.cpp table order
/// Display /// Display
bool bilinear = true;
wxVideoMode fs_mode; wxVideoMode fs_mode;
int max_threads = 0;
bool retain_aspect = true;
bool keep_on_top = false;
/// GB /// GB
wxString gb_bios; wxString gb_bios;

View File

@ -110,8 +110,9 @@ GameArea::GameArea()
pointer_blanked(false), pointer_blanked(false),
mouse_active_time(0), mouse_active_time(0),
render_observer_( render_observer_(
{config::OptionID::kDispRenderMethod, config::OptionID::kDispFilter, {config::OptionID::kDispBilinear, config::OptionID::kDispFilter,
config::OptionID::kDispIFB}, config::OptionID::kDispRenderMethod, config::OptionID::kDispIFB,
config::OptionID::kDispStretch},
std::bind(&GameArea::ResetPanel, this)), std::bind(&GameArea::ResetPanel, this)),
scale_observer_(config::OptionID::kDispScale, scale_observer_(config::OptionID::kDispScale,
std::bind(&GameArea::AdjustSize, this, true)) { std::bind(&GameArea::AdjustSize, this, true)) {
@ -1158,32 +1159,28 @@ void GameArea::OnIdle(wxIdleEvent& event)
AdjustMinSize(); AdjustMinSize();
AdjustSize(false); AdjustSize(false);
unsigned frame_priority = gopts.retain_aspect ? 0 : 1; const bool retain_aspect = OPTION(kDispStretch);
const unsigned frame_priority = retain_aspect ? 0 : 1;
GetSizer()->Clear(); GetSizer()->Clear();
// add spacers on top and bottom to center panel vertically // add spacers on top and bottom to center panel vertically
// but not on 2.8 which does not handle this correctly // but not on 2.8 which does not handle this correctly
if (gopts.retain_aspect) if (retain_aspect) {
#if wxCHECK_VERSION(2, 9, 0)
GetSizer()->Add(0, 0, wxEXPAND); GetSizer()->Add(0, 0, wxEXPAND);
#else }
frame_priority = 1;
#endif
// this triggers an assertion dialog in <= 3.1.2 in debug mode // this triggers an assertion dialog in <= 3.1.2 in debug mode
GetSizer()->Add(w, frame_priority, gopts.retain_aspect ? (wxSHAPED | wxALIGN_CENTER | wxEXPAND) : wxEXPAND); GetSizer()->Add(
w, frame_priority,
retain_aspect ? (wxSHAPED | wxALIGN_CENTER | wxEXPAND) : wxEXPAND);
#if wxCHECK_VERSION(2, 9, 0) if (retain_aspect) {
if (gopts.retain_aspect)
GetSizer()->Add(0, 0, wxEXPAND); GetSizer()->Add(0, 0, wxEXPAND);
#endif }
Layout(); Layout();
#if wxCHECK_VERSION(2, 9, 0)
SendSizeEvent(); SendSizeEvent();
#endif
if (pointer_blanked) if (pointer_blanked)
w->SetCursor(wxCursor(wxCURSOR_BLANK)); w->SetCursor(wxCursor(wxCURSOR_BLANK));
@ -1196,7 +1193,8 @@ void GameArea::OnIdle(wxIdleEvent& event)
utilUpdateSystemColorMaps(gopts.gba_lcd_filter); utilUpdateSystemColorMaps(gopts.gba_lcd_filter);
else if (loaded == IMAGE_GB) else if (loaded == IMAGE_GB)
utilUpdateSystemColorMaps(gopts.gb_lcd_filter); utilUpdateSystemColorMaps(gopts.gb_lcd_filter);
else utilUpdateSystemColorMaps(false); else
utilUpdateSystemColorMaps(false);
} }
mf->PollJoysticks(); mf->PollJoysticks();
@ -1806,13 +1804,13 @@ void DrawingPanelBase::DrawArea(uint8_t** data)
todraw = pixbuf2; todraw = pixbuf2;
// FIXME: filters race condition? // FIXME: filters race condition?
gopts.max_threads = 1; const int max_threads = 1;
// First, apply filters, if applicable, in parallel, if enabled // First, apply filters, if applicable, in parallel, if enabled
// FIXME: && (gopts.ifb != FF_MOTION_BLUR || !renderer_can_motion_blur) // FIXME: && (gopts.ifb != FF_MOTION_BLUR || !renderer_can_motion_blur)
if (OPTION(kDispFilter) != config::Filter::kNone || if (OPTION(kDispFilter) != config::Filter::kNone ||
OPTION(kDispIFB) != config::Interframe::kNone) { OPTION(kDispIFB) != config::Interframe::kNone) {
if (nthreads != gopts.max_threads) { if (nthreads != max_threads) {
if (nthreads) { if (nthreads) {
if (nthreads > 1) if (nthreads > 1)
for (int i = 0; i < nthreads; i++) { for (int i = 0; i < nthreads; i++) {
@ -1826,7 +1824,7 @@ void DrawingPanelBase::DrawArea(uint8_t** data)
delete[] threads; delete[] threads;
} }
nthreads = gopts.max_threads; nthreads = max_threads;
threads = new FilterThread[nthreads]; threads = new FilterThread[nthreads];
// first time around, no threading in order to avoid // first time around, no threading in order to avoid
// static initializer conflicts // static initializer conflicts
@ -2217,6 +2215,8 @@ void GLDrawingPanel::DrawingPanelInit()
AdjustViewport(); AdjustViewport();
const bool bilinear = OPTION(kDispBilinear);
// taken from GTK front end almost verbatim // taken from GTK front end almost verbatim
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
@ -2241,9 +2241,9 @@ void GLDrawingPanel::DrawingPanelInit()
glGenTextures(1, &texid); glGenTextures(1, &texid);
glBindTexture(GL_TEXTURE_2D, texid); glBindTexture(GL_TEXTURE_2D, texid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
gopts.bilinear ? GL_LINEAR : GL_NEAREST); bilinear ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
gopts.bilinear ? GL_LINEAR : GL_NEAREST); bilinear ? GL_LINEAR : GL_NEAREST);
#define int_fmt out_16 ? GL_RGB5 : GL_RGB #define int_fmt out_16 ? GL_RGB5 : GL_RGB
#define tex_fmt out_16 ? GL_BGRA : GL_RGBA, \ #define tex_fmt out_16 ? GL_BGRA : GL_RGBA, \

View File

@ -1,5 +1,6 @@
#include "../common/SoundSDL.h" #include "../common/SoundSDL.h"
#include "config/game-control.h" #include "config/game-control.h"
#include "config/option-proxy.h"
#include "wxvbam.h" #include "wxvbam.h"
#include "SDL.h" #include "SDL.h"
#include <wx/ffile.h> #include <wx/ffile.h>
@ -777,7 +778,7 @@ public:
{ {
dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER); dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top) if (OPTION(kDispKeepOnTop))
dlg->SetWindowStyle(dlg->GetWindowStyle() | wxSTAY_ON_TOP); dlg->SetWindowStyle(dlg->GetWindowStyle() | wxSTAY_ON_TOP);
else else
dlg->SetWindowStyle(dlg->GetWindowStyle() & ~wxSTAY_ON_TOP); dlg->SetWindowStyle(dlg->GetWindowStyle() & ~wxSTAY_ON_TOP);

View File

@ -4,11 +4,13 @@
#include "../common/cstdint.h" #include "../common/cstdint.h"
#include "../gba/armdis.h"
#include "viewsupt.h"
#include "wxvbam.h"
#include <wx/ffile.h> #include <wx/ffile.h>
#include <wx/vlbox.h> #include <wx/vlbox.h>
#include "../gba/armdis.h"
#include "config/option-proxy.h"
#include "keep-on-top-styler.h"
#include "viewsupt.h"
#include "wxvbam.h"
// avoid exporting classes // avoid exporting classes
namespace Viewers { namespace Viewers {
@ -515,8 +517,7 @@ void MainFrame::IOViewer()
baddialog(); \ baddialog(); \
cb->SetValidator(wxBoolIntValidator(&systemVerbose, val, val)); \ cb->SetValidator(wxBoolIntValidator(&systemVerbose, val, val)); \
} while (0) } while (0)
LogDialog::LogDialog() LogDialog::LogDialog() : keep_on_top_styler_(this) {
{
const wxString dname = wxT("Logging"); const wxString dname = wxT("Logging");
if (!wxXmlResource::Get()->LoadDialog(this, wxGetApp().frame, dname)) if (!wxXmlResource::Get()->LoadDialog(this, wxGetApp().frame, dname))
@ -727,7 +728,7 @@ public:
selreg_len->SetValue(s); selreg_len->SetValue(s);
selregion->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER); selregion->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top) if (OPTION(kDispKeepOnTop))
selregion->SetWindowStyle(selregion->GetWindowStyle() | wxSTAY_ON_TOP); selregion->SetWindowStyle(selregion->GetWindowStyle() | wxSTAY_ON_TOP);
else else
selregion->SetWindowStyle(selregion->GetWindowStyle() & ~wxSTAY_ON_TOP); selregion->SetWindowStyle(selregion->GetWindowStyle() & ~wxSTAY_ON_TOP);
@ -752,7 +753,7 @@ public:
selreg_len->SetValue(wxEmptyString); selreg_len->SetValue(wxEmptyString);
selregion->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER); selregion->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top) if (OPTION(kDispKeepOnTop))
selregion->SetWindowStyle(selregion->GetWindowStyle() | wxSTAY_ON_TOP); selregion->SetWindowStyle(selregion->GetWindowStyle() | wxSTAY_ON_TOP);
else else
selregion->SetWindowStyle(selregion->GetWindowStyle() & ~wxSTAY_ON_TOP); selregion->SetWindowStyle(selregion->GetWindowStyle() & ~wxSTAY_ON_TOP);

View File

@ -0,0 +1,44 @@
#include "widgets/keep-on-top-styler.h"
#include <wx/toplevel.h>
#include "config/option-proxy.h"
#include "config/option.h"
namespace widgets {
KeepOnTopStyler::KeepOnTopStyler(wxTopLevelWindow* window)
: window_(window),
on_top_observer_(config::OptionID::kDispKeepOnTop,
std::bind(&KeepOnTopStyler::OnKeepOnTopChanged,
this,
std::placeholders::_1)) {
assert(window_);
window_->Bind(wxEVT_SHOW, &KeepOnTopStyler::OnShow, this);
}
KeepOnTopStyler::~KeepOnTopStyler() {
// Need to manually unbind to stop processing events for this window.
window_->Unbind(wxEVT_SHOW, &KeepOnTopStyler::OnShow, this);
}
void KeepOnTopStyler::OnShow(wxShowEvent& show_event) {
if (show_event.IsShown()) {
// This must be called when the window is shown or it has no effect.
OnKeepOnTopChanged(
config::Option::ByID(config::OptionID::kDispKeepOnTop));
}
// Let the event propagate.
show_event.Skip();
}
void KeepOnTopStyler::OnKeepOnTopChanged(config::Option* option) {
if (option->GetBool()) {
window_->SetWindowStyle(window_->GetWindowStyle() | wxSTAY_ON_TOP);
} else {
window_->SetWindowStyle(window_->GetWindowStyle() & ~wxSTAY_ON_TOP);
}
}
} // namespace widgets

View File

@ -0,0 +1,58 @@
#ifndef VBAM_WX_DIALOGS_BASE_DIALOG_H_
#define VBAM_WX_DIALOGS_BASE_DIALOG_H_
#include <wx/event.h>
#include "config/option-observer.h"
// Forward declarations.
class wxTopLevelWindow;
namespace config {
class Option;
}
namespace widgets {
// Helper class to automatically set and unset the wxSTAY_ON_TOP to any
// top-level window. Simply add it as a private member to any top-level window
// implementation and pass the reference to the window in the constructor.
//
// Sample usage:
//
// class MyDialog: public wxDialog {
// public:
// MyDialog() : wxDialog(), keep_on_top_styler_(this) {}
// ~MyDialog() override = default;
// private:
// KeepOnTopStyler keep_on_top_styler_;
// };
class KeepOnTopStyler {
public:
// `window` must outlive this object. The easiest way to do so is to add
// this object as a private member of the top-level window.
explicit KeepOnTopStyler(wxTopLevelWindow* window);
~KeepOnTopStyler();
// Disable copy and assignment.
KeepOnTopStyler(const KeepOnTopStyler&) = delete;
KeepOnTopStyler& operator=(const KeepOnTopStyler&) = delete;
private:
// Callback for the `window` wxEVT_SHOW event.
void OnShow(wxShowEvent& show_event);
// Callback fired when the KeepOnTop setting has changed.
void OnKeepOnTopChanged(config::Option* option);
// The non-owned window whose style should be modified.
wxTopLevelWindow *const window_;
// Observer for the KeepOnTop setting changed event.
const config::OptionsObserver on_top_observer_;
};
} // namespace widgets
#endif // VBAM_WX_DIALOGS_BASE_DIALOG_H_

View File

@ -11,6 +11,7 @@
#include <stdio.h> #include <stdio.h>
#include <wx/cmdline.h> #include <wx/cmdline.h>
#include <wx/display.h>
#include <wx/file.h> #include <wx/file.h>
#include <wx/filesys.h> #include <wx/filesys.h>
#include <wx/fs_arc.h> #include <wx/fs_arc.h>
@ -39,10 +40,10 @@
#ifdef __WXMSW__ #ifdef __WXMSW__
int WinMain(HINSTANCE hInstance, int __stdcall WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, LPSTR lpCmdLine,
int nCmdShow) { int nCmdShow) {
bool console_attached = AttachConsole(ATTACH_PARENT_PROCESS) != FALSE; bool console_attached = AttachConsole(ATTACH_PARENT_PROCESS) != FALSE;
#ifdef DEBUG #ifdef DEBUG
// In debug builds, create a console if none is attached. // In debug builds, create a console if none is attached.
@ -470,32 +471,45 @@ bool wxvbamApp::OnInit() {
// and command line overrides have been applied. // and command line overrides have been applied.
config::GameControlState::Instance().OnGameBindingsChanged(); config::GameControlState::Instance().OnGameBindingsChanged();
// create the main window // We need to gather this information before crating the MainFrame as the
int x = OPTION(kGeomWindowX); // OnSize / OnMove event handlers can fire during construction.
int y = OPTION(kGeomWindowY); const wxRect client_rect(
int width = OPTION(kGeomWindowHeight); OPTION(kGeomWindowX).Get(),
int height = OPTION(kGeomWindowHeight); OPTION(kGeomWindowY).Get(),
bool isFullscreen = OPTION(kGeomFullScreen); OPTION(kGeomWindowWidth).Get(),
bool isMaximized = OPTION(kGeomIsMaximized); OPTION(kGeomWindowHeight).Get());
frame = wxDynamicCast(xr->LoadFrame(nullptr, "MainFrame"), MainFrame); const bool is_fullscreen = OPTION(kGeomFullScreen);
const bool is_maximized = OPTION(kGeomIsMaximized);
// Create the main window.
frame = wxDynamicCast(xr->LoadFrame(nullptr, "MainFrame"), MainFrame);
if (!frame) { if (!frame) {
wxLogError(_("Could not create main window")); wxLogError(_("Could not create main window"));
return false; return false;
} }
// Create() cannot be overridden easily // Create() cannot be overridden easily
if (!frame->BindControls()) if (!frame->BindControls()) {
return false; return false;
}
if (x >= 0 && y >= 0 && width > 0 && height > 0) // Measure the full display area.
frame->SetSize(x, y, width, height); wxRect display_rect;
for (unsigned int i = 0; i < wxDisplay::GetCount(); i++) {
display_rect.Union(wxDisplay(i).GetClientArea());
}
if (isMaximized) // Ensure we are not drawing out of bounds.
if (display_rect.Intersects(client_rect)) {
frame->SetSize(client_rect);
}
if (is_maximized) {
frame->Maximize(); frame->Maximize();
}
if (is_fullscreen && wxGetApp().pending_load != wxEmptyString)
frame->ShowFullScreen(is_fullscreen);
if (isFullscreen && wxGetApp().pending_load != wxEmptyString)
frame->ShowFullScreen(isFullscreen);
frame->Show(true); frame->Show(true);
#ifndef NO_ONLINEUPDATES #ifndef NO_ONLINEUPDATES
@ -760,12 +774,12 @@ wxvbamApp::~wxvbamApp() {
} }
MainFrame::MainFrame() MainFrame::MainFrame()
: wxFrame() : wxFrame(),
, paused(false) paused(false),
, menus_opened(0) menus_opened(0),
, dialog_opened(0) dialog_opened(0),
, focused(false) focused(false),
{ keep_on_top_styler_(this) {
jpoll = new JoystickPoller(); jpoll = new JoystickPoller();
this->Connect(wxID_ANY, wxEVT_SHOW, wxShowEventHandler(JoystickPoller::ShowDialog), jpoll, jpoll); this->Connect(wxID_ANY, wxEVT_SHOW, wxShowEventHandler(JoystickPoller::ShowDialog), jpoll, jpoll);
} }
@ -835,13 +849,10 @@ void MainFrame::OnMenu(wxContextMenuEvent& event)
} }
void MainFrame::OnMove(wxMoveEvent&) { void MainFrame::OnMove(wxMoveEvent&) {
wxPoint window_pos = GetScreenPosition();
if (!IsFullScreen() && !IsMaximized()) { if (!IsFullScreen() && !IsMaximized()) {
if (window_pos.x >= 0 && window_pos.y >= 0) { const wxPoint window_pos = GetScreenPosition();
OPTION(kGeomWindowX) = window_pos.x; OPTION(kGeomWindowX) = window_pos.x;
OPTION(kGeomWindowY) = window_pos.y; OPTION(kGeomWindowY) = window_pos.y;
}
} }
} }
@ -856,10 +867,8 @@ void MainFrame::OnSize(wxSizeEvent& event)
OPTION(kGeomWindowHeight) = window_rect.GetHeight(); OPTION(kGeomWindowHeight) = window_rect.GetHeight();
OPTION(kGeomWindowWidth) = window_rect.GetWidth(); OPTION(kGeomWindowWidth) = window_rect.GetWidth();
} }
if (window_pos.x >= 0 && window_pos.y >= 0) { OPTION(kGeomWindowX) = window_pos.x;
OPTION(kGeomWindowX) = window_pos.x; OPTION(kGeomWindowY) = window_pos.y;
OPTION(kGeomWindowY) = window_pos.y;
}
} }
OPTION(kGeomIsMaximized) = IsMaximized(); OPTION(kGeomIsMaximized) = IsMaximized();
@ -1161,7 +1170,7 @@ int MainFrame::ShowModal(wxDialog* dlg)
{ {
dlg->SetWindowStyle(dlg->GetWindowStyle() | wxCAPTION | wxRESIZE_BORDER); dlg->SetWindowStyle(dlg->GetWindowStyle() | wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top) if (OPTION(kDispKeepOnTop))
dlg->SetWindowStyle(dlg->GetWindowStyle() | wxSTAY_ON_TOP); dlg->SetWindowStyle(dlg->GetWindowStyle() | wxSTAY_ON_TOP);
else else
dlg->SetWindowStyle(dlg->GetWindowStyle() & ~wxSTAY_ON_TOP); dlg->SetWindowStyle(dlg->GetWindowStyle() & ~wxSTAY_ON_TOP);

View File

@ -13,6 +13,7 @@
#include "config/option-observer.h" #include "config/option-observer.h"
#include "widgets/dpi-support.h" #include "widgets/dpi-support.h"
#include "widgets/keep-on-top-styler.h"
#include "wx/joyedit.h" #include "wx/joyedit.h"
#include "wx/keyedit.h" #include "wx/keyedit.h"
#include "wx/sdljoy.h" #include "wx/sdljoy.h"
@ -212,7 +213,7 @@ extern bool pause_next;
class MainFrame : public wxFrame { class MainFrame : public wxFrame {
public: public:
MainFrame(); MainFrame();
~MainFrame(); ~MainFrame() override;
bool BindControls(); bool BindControls();
void MenuOptionIntMask(const wxString& menuName, int field, int mask); void MenuOptionIntMask(const wxString& menuName, int field, int mask);
@ -361,14 +362,15 @@ private:
// joystick reader // joystick reader
wxJoyPoller joy; wxJoyPoller joy;
JoystickPoller* jpoll = nullptr; JoystickPoller* jpoll = nullptr;
// quicker & more accurate than FindFocus() != NULL
bool focused;
const widgets::KeepOnTopStyler keep_on_top_styler_;
// helper function for adding menu to accel editor // helper function for adding menu to accel editor
void add_menu_accels(wxTreeCtrl* tc, wxTreeItemId& parent, wxMenu* menu); void add_menu_accels(wxTreeCtrl* tc, wxTreeItemId& parent, wxMenu* menu);
// for detecting window focus // for detecting window focus
void OnActivate(wxActivateEvent&); void OnActivate(wxActivateEvent&);
// quicker & more accurate than FindFocus() != NULL
bool focused;
// may work, may not... if so, load dropped file // may work, may not... if so, load dropped file
void OnDropFile(wxDropFilesEvent&); void OnDropFile(wxDropFilesEvent&);
// pop up menu in fullscreen mode // pop up menu in fullscreen mode
@ -689,6 +691,7 @@ public:
private: private:
wxTextCtrl* log; wxTextCtrl* log;
widgets::KeepOnTopStyler keep_on_top_styler_;
void Save(wxCommandEvent& ev); void Save(wxCommandEvent& ev);
void Clear(wxCommandEvent& ev); void Clear(wxCommandEvent& ev);