Commit f5cb7b2b authored by Rafael Kitover's avatar Rafael Kitover
Browse files

support Wx built with --enable-stl #134

When Wx is built with --enable-stl, wxString to wxChar*/char* implicit
conversions and vice-versa no longer work.

Change all wxChar* data members to wxString and change all pointer
arithmetic code (mostly in opts.cpp, cmdevents.cpp and
widgets/joyedit.cpp) to use wxString methods instead.

Also make mostly minor changes in various other files for all of this to
work.
parent 142dbc0a
......@@ -274,7 +274,7 @@ EVT_HANDLER(wxID_FILE10, "Load recent ROM 10")
}
static const struct rom_maker {
const wxChar *code, *name;
const wxString code, name;
} makers[] = {
{ wxT("01"), wxT("Nintendo") },
{ wxT("02"), wxT("Rocket Games") },
......@@ -503,7 +503,7 @@ static bool maker_lt(const rom_maker& r1, const rom_maker& r2)
return wxStrcmp(r1.code, r2.code) < 0;
}
void SetDialogLabel(wxDialog* dlg, wxChar* id, wxString ts, size_t l)
void SetDialogLabel(wxDialog* dlg, const wxString& id, wxString ts, size_t l)
{
ts.Replace(wxT("&"), wxT("&&"), true);
(dynamic_cast<wxControl*>((*dlg).FindWindow(wxXmlResource::GetXRCID(id))))->SetLabel(ts);
......@@ -557,7 +557,7 @@ EVT_HANDLER_MASK(RomInformation, "ROM information...", CMDEN_GB | CMDEN_GBA)
setlab("MakerName");
setblab("UnitCode", gbRom[0x146]);
const wxChar* type;
wxString type;
switch (gbRom[0x147]) {
case 0x00:
......@@ -1187,15 +1187,15 @@ EVT_HANDLER_MASK(RecordSoundStartRecording, "Start sound recording...", CMDEN_NS
sound_path = GetGamePath(gopts.recording_dir);
wxString def_name = panel->game_name();
const wxChar* extoff = sound_exts.c_str();
wxString extoff = sound_exts;
for (int i = 0; i < sound_extno; i++) {
extoff = wxStrchr(extoff, wxT('|')) + 1;
extoff = wxStrchr(extoff, wxT('|')) + 1;
extoff = extoff.Mid(extoff.Find(wxT('|')) + 1);
extoff = extoff.Mid(extoff.Find(wxT('|')) + 1);
}
extoff = wxStrchr(extoff, wxT('|')) + 2; // skip *
def_name += wxString(extoff, wxStrcspn(extoff, wxT(";|")));
extoff = extoff.Mid(extoff.Find(wxT('|')) + 2); // skip *
def_name += extoff.Left(wxStrcspn(extoff, wxT(";|")));
wxFileDialog dlg(this, _("Select output file"), sound_path, def_name,
sound_exts, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
dlg.SetFilterIndex(sound_extno);
......@@ -1260,15 +1260,15 @@ EVT_HANDLER_MASK(RecordAVIStartRecording, "Start video recording...", CMDEN_NVRE
vid_path = GetGamePath(gopts.recording_dir);
wxString def_name = panel->game_name();
const wxChar* extoff = vid_exts.c_str();
wxString extoff = vid_exts;
for (int i = 0; i < vid_extno; i++) {
extoff = wxStrchr(extoff, wxT('|')) + 1;
extoff = wxStrchr(extoff, wxT('|')) + 1;
extoff = extoff.Mid(extoff.Find(wxT('|')) + 1);
extoff = extoff.Mid(extoff.Find(wxT('|')) + 1);
}
extoff = wxStrchr(extoff, wxT('|')) + 2; // skip *
def_name += wxString(extoff, wxStrcspn(extoff, wxT(";|")));
extoff = extoff.Mid(extoff.Find(wxT('|')) + 2); // skip *
def_name += extoff.Left(wxStrcspn(extoff, wxT(";|")));
wxFileDialog dlg(this, _("Select output file"), vid_path, def_name,
vid_exts, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
dlg.SetFilterIndex(vid_extno);
......
......@@ -96,7 +96,7 @@ bool DirectSound::init(long sampleRate)
if (gopts.audio_dev.empty())
dev = DSDEVID_DefaultPlayback;
else
CLSIDFromString(const_cast<wxChar*>(gopts.audio_dev.wx_str()), &dev);
CLSIDFromString(gopts.audio_dev.wc_str(), &dev);
pDirectSound->Initialize(&dev);
......
......@@ -1117,7 +1117,7 @@ void MainFrame::OAMViewer()
namespace Viewers {
static int ptype = 0;
static wxString pdir;
void savepal(wxWindow* parent, const uint8_t* data, int ncols, const wxChar* type)
void savepal(wxWindow* parent, const uint8_t* data, int ncols, const wxString type)
{
// no attempt is made here to translate the palette type name
// it's just a suggested name, anyway
......
......@@ -2292,7 +2292,19 @@ public:
/////////////////////////////
//Check if a pointer from the XRC file is valid. If it's not, throw an error telling the user.
template <typename T>
void CheckThrowXRCError(T pointer, std::string name)
void CheckThrowXRCError(T pointer, const wxString& name)
{
if (pointer == NULL) {
std::string errormessage = "Unable to load a \"";
errormessage += typeid(pointer).name();
errormessage += "\" from the builtin xrc file: ";
errormessage += name.utf8_str();
throw std::runtime_error(errormessage);
}
}
template <typename T>
void CheckThrowXRCError(T pointer, const char* name)
{
if (pointer == NULL) {
std::string errormessage = "Unable to load a \"";
......@@ -2302,6 +2314,7 @@ void CheckThrowXRCError(T pointer, std::string name)
throw std::runtime_error(errormessage);
}
}
wxDialog* MainFrame::LoadXRCDialog(const char* name)
{
wxString dname = wxString::FromUTF8(name);
......@@ -2347,7 +2360,15 @@ T* SafeXRCCTRL(wxWindow* parent, const char* name)
wxString dname = wxString::FromUTF8(name);
//This is needed to work around a bug in XRCCTRL
wxString Ldname = dname;
T* output = XRCCTRL(*parent, dname, T);
T* output = XRCCTRL_D(*parent, dname, T);
CheckThrowXRCError(output, name);
return output;
}
template <typename T>
T* SafeXRCCTRL(wxWindow* parent, const wxString& name)
{
T* output = XRCCTRL_D(*parent, name, T);
CheckThrowXRCError(output, name);
return output;
}
......@@ -3214,7 +3235,7 @@ bool MainFrame::BindControls()
// "Unable to load dialog GameBoyConfig from resources", this is
// probably the reason.
pn.Printf(wxT("cp%d"), i + 1);
wxWindow* w = SafeXRCCTRL<wxWindow>(d, ToString(pn).c_str());
wxWindow* w = SafeXRCCTRL<wxWindow>(d, pn);
GBColorConfigHandler[i].p = w;
GBColorConfigHandler[i].pno = i;
wxFarRadio* cb = SafeXRCCTRL<wxFarRadio>(w, "UsePalette");
......@@ -3231,7 +3252,7 @@ bool MainFrame::BindControls()
for (int j = 0; j < 8; j++) {
wxString s;
s.Printf(wxT("Color%d"), j);
wxColourPickerCtrl* cp = SafeXRCCTRL<wxColourPickerCtrl>(w, ToString(s).c_str());
wxColourPickerCtrl* cp = SafeXRCCTRL<wxColourPickerCtrl>(w, s);
GBColorConfigHandler[i].cp[j] = cp;
cp->SetValidator(wxColorValidator(&systemGbPalette[i * 8 + j]));
}
......@@ -3433,7 +3454,7 @@ bool MainFrame::BindControls()
// "Unable to load dialog JoypadConfig from resources", this is
// probably the reason.
pn.Printf(wxT("joy%d"), i + 1);
wxWindow* w = SafeXRCCTRL<wxWindow>(joyDialog, ToString(pn).c_str());
wxWindow* w = SafeXRCCTRL<wxWindow>(joyDialog, pn);
wxFarRadio* cb;
cb = SafeXRCCTRL<wxFarRadio>(w, "DefaultConfig");
......@@ -3447,7 +3468,7 @@ bool MainFrame::BindControls()
for (int j = 0; j < NUM_KEYS; j++) {
wxJoyKeyTextCtrl* tc = XRCCTRL_D(*w, joynames[j], wxJoyKeyTextCtrl);
CheckThrowXRCError(tc, ToString(joynames[j]));
CheckThrowXRCError(tc, joynames[j]);
wxWindow* p = tc->GetParent();
if (p == prevp)
......
......@@ -3,9 +3,9 @@
struct IOData {
uint16_t* address;
uint16_t offset;
const wxChar* name;
const wxString name;
uint16_t write;
const wxChar* bits[16];
wxString bits[16];
};
/* const */ IOData ioregs[] = // not const so tranlation can be done once
......
#include "../common/ConfigManager.h"
#include "wxvbam.h"
#include <algorithm>
#include <string>
#include <vector>
#include <wx/display.h>
/*
......@@ -19,15 +21,15 @@
}
#define INTOPT(c, n, d, v, min, max) \
{ \
wxT(c), (n), d, NULL, &v, NULL, min, max \
wxT(c), (n), d, NULL, &v, "", min, max \
}
#define DOUBLEOPT(c, n, d, v, min, max) \
{ \
wxT(c), (n), d, NULL, NULL, NULL, min, max, NULL, &v \
wxT(c), (n), d, NULL, NULL, "", min, max, NULL, &v \
}
#define BOOLOPT(c, n, d, v) \
{ \
wxT(c), (n), d, NULL, NULL, NULL, 0, 0, &v \
wxT(c), (n), d, NULL, NULL, "", 0, 0, &v \
}
#define ENUMOPT(c, n, d, v, e) \
{ \
......@@ -117,7 +119,7 @@ const int num_def_accels = sizeof(default_accels) / sizeof(default_accels[0]);
// Note: this must match GUI widget names or GUI won't work
// This table's order determines tab order as well
const wxChar* const joynames[NUM_KEYS] = {
const wxString joynames[NUM_KEYS] = {
wxT("Up"), wxT("Down"), wxT("Left"), wxT("Right"),
wxT("A"), wxT("B"), wxT("L"), wxT("R"),
wxT("Select"), wxT("Start"),
......@@ -331,6 +333,31 @@ bool opt_lt(const opt_desc& opt1, const opt_desc& opt2)
return wxStrcmp(opt1.opt, opt2.opt) < 0;
}
// From: https://stackoverflow.com/a/7408245/262458
static std::vector<wxString> split(const wxString& text_, const wxString& sep_) {
std::vector<wxString> tokens;
std::size_t start = 0, end = 0;
std::string text = text_.ToStdString(), sep = sep_.ToStdString();
while ((end = text.find(sep, start)) != std::string::npos) {
tokens.push_back(text.substr(start, end - start));
start = end + 1;
}
tokens.push_back(text.substr(start));
return tokens;
}
static std::size_t enum_idx(std::vector<wxString>& opts, const wxString& val) {
auto it = std::find(opts.begin(), opts.end(), val);
if (it == opts.end())
return wxNOT_FOUND;
return std::distance(opts.begin(), it);
}
// FIXME: simulate MakeInstanceFilename(vbam.ini) using subkeys (Slave%d/*)
void load_opts()
......@@ -479,51 +506,34 @@ void load_opts()
if (opt.stropt) {
opt.curstr = *opt.stropt;
} else if (opt.enumvals) {
opt.curint = *opt.intopt;
bool gotit = cfg->Read(opt.opt, &s);
const wxChar* ev = opt.enumvals;
} else if (!opt.enumvals.empty()) {
auto enum_opts = split(opt.enumvals.MakeLower(), wxT("|"));
opt.curint = *opt.intopt;
bool gotit = cfg->Read(opt.opt, &s); s.MakeLower();
if (gotit && s.size()) {
// wx provides no case-insensitive Find()
s.MakeLower();
for (; (ev = wxStrstr(ev, (const wxChar*)s.c_str())); ev++) {
if (ev != opt.enumvals && ev[-1] != wxT('|'))
continue;
if (!ev[s.size()] || ev[s.size()] == wxT('|'))
break;
}
if (gotit && !s.empty()) {
const std::size_t found_pos = enum_idx(enum_opts, s);
const bool matched = found_pos != wxNOT_FOUND;
if (!ev) {
if (!matched) {
opt.curint = 0;
ev = opt.enumvals;
const wxChar* evx = wxGetTranslation(ev);
const wxString ev = opt.enumvals;
const wxString evx = wxGetTranslation(ev);
bool isx = wxStrcmp(ev, evx) != 0;
// technically, the translation for this string could incorproate
// the equals sign if necessary instead of doing it this way
wxLogWarning(_("Invalid value %s for option %s; valid values are %s%s%s"),
s.c_str(), opt.opt, ev,
s, opt.opt, ev,
isx ? wxT(" = ") : wxT(""),
isx ? evx : wxT(""));
s = wxString(ev, wxStrchr(ev, wxT('|')) - ev);
cfg->Write(opt.opt, s);
} else {
const wxChar* ev2;
for (ev2 = opt.enumvals, opt.curint = 0; ev2 != ev; opt.curint++)
ev2 = wxStrchr(ev2, wxT('|')) + 1;
}
// write first option
cfg->Write(opt.opt, enum_opts[0]);
} else
opt.curint = found_pos;
*opt.intopt = opt.curint;
} else {
for (int i = 0; i != opt.curint; i++)
ev = wxStrchr(ev, wxT('|')) + 1;
const wxChar* ev2 = wxStrchr(ev, wxT('|'));
s = ev2 ? wxString(ev, ev2 - ev) : wxString(ev);
cfg->Write(opt.opt, s);
cfg->Write(opt.opt, enum_opts[opt.curint]);
}
} else if (opt.intopt) {
cfg->Read(opt.opt, &opt.curint, *opt.intopt);
......@@ -649,17 +659,12 @@ void update_opts()
opt.curstr = *opt.stropt;
cfg->Write(opt.opt, opt.curstr);
}
} else if (opt.enumvals) {
} else if (!opt.enumvals.empty()) {
if (*opt.intopt != opt.curint) {
opt.curint = *opt.intopt;
const wxChar* ev = opt.enumvals;
auto enum_opts = split(opt.enumvals.MakeLower(), wxT("|"));
for (int i = 0; i != opt.curint; i++)
ev = wxStrchr(ev, wxT('|')) + 1;
const wxChar* ev2 = wxStrchr(ev, wxT('|'));
wxString s = ev2 ? wxString(ev, ev2 - ev) : wxString(ev);
cfg->Write(opt.opt, s);
cfg->Write(opt.opt, enum_opts[opt.curint]);
}
} else if (opt.intopt) {
if (*opt.intopt != opt.curint)
......@@ -771,7 +776,7 @@ void update_opts()
cfg->Flush();
}
bool opt_set(const wxChar* name, const wxChar* val)
bool opt_set(const wxString& name, const wxString& val)
{
const opt_desc dummy = { name };
const opt_desc* opt = std::lower_bound(&opts[0], &opts[num_opts], dummy, opt_lt);
......@@ -780,41 +785,30 @@ bool opt_set(const wxChar* name, const wxChar* val)
if (opt->stropt)
*opt->stropt = wxString(val);
else if (opt->boolopt) {
if (!*val || val[1] || (*val != wxT('0') && *val != wxT('1')))
if (!(val == wxT('0') || val == wxT('1')))
wxLogWarning(_("Invalid flag option %s - %s ignored"),
name, val);
else
*opt->boolopt = *val == wxT('1');
} else if (opt->enumvals) {
wxString s(val);
s.MakeLower();
const wxChar* ev;
for (ev = opt->enumvals; (ev = wxStrstr(ev, (const wxChar*)s.c_str())); ev++) {
if (ev != opt->enumvals && ev[-1] != wxT('|'))
continue;
*opt->boolopt = val == wxT('1');
} else if (!opt->enumvals.empty()) {
wxString s = val; s.MakeLower();
wxString ev = opt->enumvals; ev.MakeLower();
auto enum_opts = split(ev, wxT("|"));
if (!ev[s.size()] || ev[s.size()] == wxT('|'))
break;
}
const std::size_t found_pos = enum_idx(enum_opts, s);
const bool matched = found_pos != wxNOT_FOUND;
if (!ev) {
const wxChar* evx = wxGetTranslation(opt->enumvals);
if (!matched) {
const wxString evx = wxGetTranslation(opt->enumvals);
bool isx = wxStrcmp(opt->enumvals, evx) != 0;
// technically, the translation for this string could incorproate
// the equals sign if necessary instead of doing it this way
wxLogWarning(_("Invalid value %s for option %s; valid values are %s%s%s"),
s.c_str(), opt->opt, opt->enumvals,
s, opt->opt, opt->enumvals,
isx ? wxT(" = ") : wxT(""),
isx ? evx : wxT(""));
} else {
const wxChar* ev2;
int val;
for (ev2 = opt->enumvals, val = 0; ev2 != ev; val++)
ev2 = wxStrchr(ev2, wxT('|')) + 1;
*opt->intopt = val;
*opt->intopt = found_pos;
}
} else if (opt->intopt) {
const wxString s(val);
......@@ -866,33 +860,33 @@ bool opt_set(const wxChar* name, const wxChar* val)
return true;
} else {
const wxChar* slat = wxStrchr(name, wxT('/'));
if (!slat)
if (name.Find(wxT('/')) == wxNOT_FOUND)
return false;
if (!wxStrncmp(name, wxT("Keyboard"), (int)(slat - name))) {
const cmditem dummy2 = { slat + 1 };
cmditem* cmd = std::lower_bound(&cmdtab[0], &cmdtab[ncmds], dummy2, cmditem_lt);
auto parts = split(name, wxT("/"));
if (parts[0] != wxT("Keyboard")) {
const cmditem parts_1 = { parts[1] };
cmditem* cmd = std::lower_bound(&cmdtab[0], &cmdtab[ncmds], parts_1, cmditem_lt);
if (cmd == &cmdtab[ncmds] || wxStrcmp(slat + 1, cmd->cmd))
if (cmd == &cmdtab[ncmds] || wxStrcmp(parts[1], cmd->cmd))
return false;
for (wxAcceleratorEntry_v::iterator i = gopts.accels.begin();
i < gopts.accels.end(); ++i)
for (auto i = gopts.accels.begin(); i < gopts.accels.end(); ++i)
if (i->GetCommand() == cmd->cmd_id) {
wxAcceleratorEntry_v::iterator j;
auto j = i;
for (j = i; j < gopts.accels.end(); ++j)
for (; j < gopts.accels.end(); ++j)
if (j->GetCommand() != cmd->cmd_id)
break;
gopts.accels.erase(i, j);
break;
}
if (*val) {
wxAcceleratorEntry_v aval = wxKeyTextCtrl::FromString(val);
if (!val.empty()) {
auto aval = wxKeyTextCtrl::FromString(val);
for (int i = 0; i < aval.size(); i++)
aval[i].Set(aval[i].GetFlags(), aval[i].GetKeyCode(),
......@@ -905,24 +899,24 @@ bool opt_set(const wxChar* name, const wxChar* val)
}
return true;
} else if (!wxStrncmp(name, wxT("Joypad"), (int)(slat - name))) {
if (slat[1] < wxT('1') || slat[1] > wxT('4') || slat[2] != wxT('/'))
} else if (!wxStrncmp(name, wxT("Joypad"), wxStrlen(wxT("Joypad")))) {
if (parts[1] < wxT('1') || parts[1] > wxT('4') || parts.size() < 3)
return false;
int jno = slat[1] - wxT('1');
int jno = parts[1][0] - wxT('1');
int kno;
for (kno = 0; kno < NUM_KEYS; kno++)
if (!wxStrcmp(joynames[kno], slat + 3))
if (!wxStrcmp(joynames[kno], parts[2]))
break;
if (kno == NUM_KEYS)
return false;
if (!*val)
if (val.empty())
gopts.joykey_bindings[jno][kno].clear();
else {
wxJoyKeyBinding_v b = wxJoyKeyTextCtrl::FromString(val);
auto b = wxJoyKeyTextCtrl::FromString(val);
if (!b.size())
wxLogWarning(_("Invalid key binding %s for %s"), val, name);
......
......@@ -2,7 +2,7 @@
#define WX_OPTS_H
#define NUM_KEYS 21
extern const wxChar* const joynames[NUM_KEYS];
extern const wxString joynames[NUM_KEYS];
extern wxJoyKeyBinding defkeys[NUM_KEYS * 2]; // keyboard + joystick defaults
extern struct opts_t {
......@@ -84,12 +84,12 @@ extern struct opts_t {
} gopts;
extern struct opt_desc {
const wxChar* opt;
wxString opt;
const char* cmd;
const wxChar* desc;
wxString desc;
wxString* stropt;
int* intopt;
const wxChar* enumvals;
wxString enumvals;
double min, max;
bool* boolopt;
double* doubleopt;
......@@ -112,6 +112,6 @@ void load_opts();
// will detect changes and write config if necessary
void update_opts();
// returns true if option name correct; prints error if val invalid
bool opt_set(const wxChar* name, const wxChar* val);
bool opt_set(const wxString& name, const wxString& val);
#endif /* WX_OPTS_H */
#include <cmath>
#include <cstring>
#include <wx/dcbuffer.h>
#include <SDL_joystick.h>
......@@ -1785,11 +1786,14 @@ void DrawingPanelBase::DrawArea(uint8_t** data)
if (!disableStatusMessages && !panel->osdtext.empty()) {
if (systemGetClock() - panel->osdtime < OSD_TIME) {
std::string message = ToString(panel->osdtext);
wxString message = panel->osdtext;
int linelen = std::ceil(width * scale - 20) / 8;
int nlines = (message.length() + linelen - 1) / linelen;
int nlines = (message.size() + linelen - 1) / linelen;
int cury = height - 14 - nlines * 10;
char* ptr = const_cast<char*>(message.c_str());
const char* msg_data = message.utf8_str();
char buf[message.size() + 1];
char* ptr = &buf[0];
std::strncpy(ptr, msg_data, message.size() + 1);
while (nlines > 1) {
char lchar = ptr[linelen];
......@@ -2223,7 +2227,7 @@ void DXDrawingPanel::DrawArea(wxWindowDC& dc)
#endif
#ifndef NO_FFMPEG
static const wxChar* media_err(MediaRet ret)
static const wxString media_err(MediaRet ret)
{
switch (ret) {
case MRET_OK:
......
......@@ -354,7 +354,7 @@ public:
baddialog();
addr->Clear();
const wxChar* longline = lline;
wxString longline = lline;
int lwidth = 0;
for (int i = 0; i < NUM_IOREGS; i++) {
......@@ -470,14 +470,14 @@ public:
Update(sel);
}
static const wxChar* lline;
static wxString lline;
wxChoice* addr;
wxControl* val;
wxCheckBox* bit[16];
wxControl* bitlab[16];
DECLARE_EVENT_TABLE()
};
const wxChar* IOViewer::lline = NULL;
wxString IOViewer::lline;
BEGIN_EVENT_TABLE(IOViewer, Viewer)
EVT_BUTTON(XRCID("Refresh"), IOViewer::RefreshEv)
EVT_BUTTON(wxID_APPLY, IOViewer::Apply)
......@@ -500,7 +500,7 @@ void MainFrame::IOViewer()
} while (0)
LogDialog::LogDialog()
{
const wxChar* dname = wxT("Logging");
const wxString dname = wxT("Logging");
if (!wxXmlResource::Get()->LoadDialog(this, wxGetApp().frame, dname))
baddialog();
......@@ -625,7 +625,7 @@ public:
Goto(0);
// initialize load/save support dialog already
{
const wxChar* dname = wxT("MemSelRegion");
const wxString dname = wxT("MemSelRegion");
selregion = wxXmlResource::Get()->LoadDialog(this, dname);
if (!selregion)
......
......@@ -21,7 +21,7 @@ void Viewer::CloseDlg(wxCloseEvent& ev)
Destroy();
}
Viewer::Viewer(const wxChar* name)
Viewer::Viewer(const wxString& name)
: wxDialog()
, auto_update(false)
{
......@@ -1075,7 +1075,7 @@ EVT_LEFT_UP(GfxPanel::Click)
EVT_MOTION(GfxPanel::MouseMove)
END_EVENT_TABLE()