Refactor the network link dialogs

* Unifies the network link options into a single dialog by removing the
  separate dialog for the timeout option.
* Cleans up the logic related to starting the network link.
* Moves more options to g_owned_opts.
* Separates the server and client port into 2 separate options.

Test: Locally with Mario Kart with 2 instances.
This commit is contained in:
Fabrice de Gans 2023-04-09 20:19:22 -07:00
parent 86bef62faf
commit 7a76a70aed
22 changed files with 1010 additions and 1178 deletions

File diff suppressed because it is too large Load Diff

View File

@ -623,7 +623,6 @@ set(
xrc/IOViewer.xrc xrc/IOViewer.xrc
xrc/JoyPanel.xrc xrc/JoyPanel.xrc
xrc/JoypadConfig.xrc xrc/JoypadConfig.xrc
xrc/LinkConfig.xrc
xrc/Logging.xrc xrc/Logging.xrc
xrc/MainFrame.xrc xrc/MainFrame.xrc
xrc/MainIcon.xrc xrc/MainIcon.xrc
@ -631,6 +630,8 @@ set(
xrc/MapViewer.xrc xrc/MapViewer.xrc
xrc/MemSelRegion.xrc xrc/MemSelRegion.xrc
xrc/MemViewer.xrc xrc/MemViewer.xrc
xrc/NetLinkClientPanel.xrc
xrc/NetLinkServerPanel.xrc
xrc/NetLink.xrc xrc/NetLink.xrc
xrc/OAMViewer.xrc xrc/OAMViewer.xrc
xrc/PaletteViewer.xrc xrc/PaletteViewer.xrc
@ -768,6 +769,7 @@ set(
dialogs/directories-config.cpp dialogs/directories-config.cpp
dialogs/display-config.cpp dialogs/display-config.cpp
dialogs/game-boy-config.cpp dialogs/game-boy-config.cpp
dialogs/net-link.cpp
widgets/group-check-box.cpp widgets/group-check-box.cpp
widgets/keep-on-top-styler.cpp widgets/keep-on-top-styler.cpp
widgets/keyedit.cpp widgets/keyedit.cpp
@ -817,6 +819,7 @@ set(
dialogs/directories-config.h dialogs/directories-config.h
dialogs/display-config.h dialogs/display-config.h
dialogs/game-boy-config.h dialogs/game-boy-config.h
dialogs/net-link.h
dialogs/validated-child.h dialogs/validated-child.h
widgets/dpi-support.h widgets/dpi-support.h
widgets/group-check-box.h widgets/group-check-box.h

View File

@ -3032,8 +3032,7 @@ EVT_HANDLER_MASK(LanLink, "Start Network link", CMDEN_LINK_ANY)
return; return;
} }
wxDialog* dlg = GetXRCDialog("NetLink"); ShowModal(GetXRCDialog("NetLink"));
ShowModal(dlg);
panel->SetFrameTitle(); panel->SetFrameTitle();
#endif #endif
} }
@ -3075,21 +3074,8 @@ EVT_HANDLER(SpeedOn, "Enable faster network protocol by default")
EVT_HANDLER(LinkProto, "Local host IPC") EVT_HANDLER(LinkProto, "Local host IPC")
{ {
GetMenuOptionConfig("LinkProto", config::OptionID::kGBALinkHost); GetMenuOptionConfig("LinkProto", config::OptionID::kGBALinkProto);
}
EVT_HANDLER(LinkConfigure, "Link options...")
{
#ifndef NO_LINK
wxDialog* dlg = GetXRCDialog("LinkConfig");
if (ShowModal(dlg) != wxID_OK)
return;
SetLinkTimeout(gopts.link_timeout);
update_opts();
EnableNetworkMenu(); EnableNetworkMenu();
#endif
} }
// Dummy for disabling system key bindings // Dummy for disabling system key bindings

View File

@ -177,7 +177,12 @@ std::array<Option, kNbOptions>& Option::All() {
bool gba_lcd_filter = false; bool gba_lcd_filter = false;
bool link_auto = false; bool link_auto = false;
bool link_hacks = true; bool link_hacks = true;
wxString link_host = "127.0.0.1"; // quick fix for issues #48 and #445
wxString server_ip = "*";
int32_t link_port = 5738;
int32_t server_port = 5738;
bool link_proto = false; bool link_proto = false;
int32_t link_timeout = 500;
wxString gba_rom_dir; wxString gba_rom_dir;
/// Core /// Core
@ -190,6 +195,9 @@ std::array<Option, kNbOptions>& Option::All() {
uint32_t flash_size = 0; uint32_t flash_size = 0;
int32_t frame_skip = 0; int32_t frame_skip = 0;
bool gdb_break_on_load = false; bool gdb_break_on_load = false;
#ifndef NO_LINK
int32_t link_num_players = 2;
#endif
bool pause_when_inactive = false; bool pause_when_inactive = false;
uint32_t show_speed = 0; uint32_t show_speed = 0;
bool show_speed_transparent = false; bool show_speed_transparent = false;
@ -265,11 +273,12 @@ std::array<Option, kNbOptions>& Option::All() {
#ifndef NO_LINK #ifndef NO_LINK
Option(OptionID::kGBALinkAuto, &g_owned_opts.link_auto), Option(OptionID::kGBALinkAuto, &g_owned_opts.link_auto),
Option(OptionID::kGBALinkFast, &g_owned_opts.link_hacks), Option(OptionID::kGBALinkFast, &g_owned_opts.link_hacks),
Option(OptionID::kGBALinkHost, &gopts.link_host), Option(OptionID::kGBALinkHost, &g_owned_opts.link_host),
Option(OptionID::kGBAServerIP, &gopts.server_ip), Option(OptionID::kGBAServerIP, &g_owned_opts.server_ip),
Option(OptionID::kGBALinkPort, &gopts.link_port, 0, 65535), Option(OptionID::kGBALinkPort, &g_owned_opts.link_port, 0, 65535),
Option(OptionID::kGBAServerPort, &g_owned_opts.server_port, 0, 65535),
Option(OptionID::kGBALinkProto, &g_owned_opts.link_proto), Option(OptionID::kGBALinkProto, &g_owned_opts.link_proto),
Option(OptionID::kGBALinkTimeout, &gopts.link_timeout, 0, 9999999), Option(OptionID::kGBALinkTimeout, &g_owned_opts.link_timeout, 0, 9999999),
Option(OptionID::kGBALinkType, &gopts.gba_link_type, 0, 5), Option(OptionID::kGBALinkType, &gopts.gba_link_type, 0, 5),
#endif #endif
Option(OptionID::kGBAROMDir, &g_owned_opts.gba_rom_dir), Option(OptionID::kGBAROMDir, &g_owned_opts.gba_rom_dir),
@ -311,7 +320,7 @@ std::array<Option, kNbOptions>& Option::All() {
Option(OptionID::kPrefGDBBreakOnLoad, &g_owned_opts.gdb_break_on_load), Option(OptionID::kPrefGDBBreakOnLoad, &g_owned_opts.gdb_break_on_load),
Option(OptionID::kPrefGDBPort, &gopts.gdb_port, 0, 65535), Option(OptionID::kPrefGDBPort, &gopts.gdb_port, 0, 65535),
#ifndef NO_LINK #ifndef NO_LINK
Option(OptionID::kPrefLinkNumPlayers, &gopts.link_num_players, 2, 4), Option(OptionID::kPrefLinkNumPlayers, &g_owned_opts.link_num_players, 2, 4),
#endif #endif
Option(OptionID::kPrefMaxScale, &gopts.max_scale, 0, 100), Option(OptionID::kPrefMaxScale, &gopts.max_scale, 0, 100),
Option(OptionID::kPrefPauseWhenInactive, &g_owned_opts.pause_when_inactive), Option(OptionID::kPrefPauseWhenInactive, &g_owned_opts.pause_when_inactive),
@ -434,8 +443,8 @@ const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
}, },
OptionData{"GBA/LinkHost", "", _("Default network link client host")}, OptionData{"GBA/LinkHost", "", _("Default network link client host")},
OptionData{"GBA/ServerIP", "", _("Default network link server IP to bind")}, OptionData{"GBA/ServerIP", "", _("Default network link server IP to bind")},
OptionData{"GBA/LinkPort", "", OptionData{"GBA/LinkPort", "", _("Default network link port (client)")},
_("Default network link port (server and client)")}, OptionData{"GBA/ServerPort", "", _("Default network link port (server)")},
OptionData{"GBA/LinkProto", "LinkProto", _("Default network protocol")}, OptionData{"GBA/LinkProto", "LinkProto", _("Default network protocol")},
OptionData{"GBA/LinkTimeout", "LinkTimeout", _("Link timeout (ms)")}, OptionData{"GBA/LinkTimeout", "LinkTimeout", _("Link timeout (ms)")},
OptionData{"GBA/LinkType", "LinkType", _("Link cable type")}, OptionData{"GBA/LinkType", "LinkType", _("Link cable type")},
@ -571,7 +580,8 @@ const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
"AllowJoystickBackgroundInput", "AllowJoystickBackgroundInput",
_("Capture joy events while on background")}, _("Capture joy events while on background")},
OptionData{"ui/hideMenuBar", "", _("Hide menu bar when mouse is inactive")}, OptionData{"ui/hideMenuBar", "", _("Hide menu bar when mouse is inactive")},
OptionData{"ui/suspendScreenSaver", "", _("Suspend screensaver when game is running")}, OptionData{"ui/suspendScreenSaver", "",
_("Suspend screensaver when game is running")},
/// Sound /// Sound
OptionData{"Sound/AudioAPI", "", OptionData{"Sound/AudioAPI", "",

View File

@ -40,6 +40,7 @@ enum class OptionID {
kGBALinkHost, kGBALinkHost,
kGBAServerIP, kGBAServerIP,
kGBALinkPort, kGBALinkPort,
kGBAServerPort,
kGBALinkProto, kGBALinkProto,
kGBALinkTimeout, kGBALinkTimeout,
kGBALinkType, kGBALinkType,

View File

@ -43,7 +43,8 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
/*kGBALinkFast*/ Option::Type::kBool, /*kGBALinkFast*/ Option::Type::kBool,
/*kGBALinkHost*/ Option::Type::kString, /*kGBALinkHost*/ Option::Type::kString,
/*kGBAServerIP*/ Option::Type::kString, /*kGBAServerIP*/ Option::Type::kString,
/*kGBALinkPort*/ Option::Type::kUnsigned, /*kGBALinkPort*/ Option::Type::kInt,
/*kGBAServerPort*/ Option::Type::kInt,
/*kGBALinkProto*/ Option::Type::kBool, /*kGBALinkProto*/ Option::Type::kBool,
/*kGBALinkTimeout*/ Option::Type::kInt, /*kGBALinkTimeout*/ Option::Type::kInt,
/*kGBALinkType*/ Option::Type::kInt, /*kGBALinkType*/ Option::Type::kInt,

219
src/wx/dialogs/net-link.cpp Normal file
View File

@ -0,0 +1,219 @@
#include "net-link.h"
#if !defined(NO_LINK)
#include <wx/log.h>
#include <wx/msgdlg.h>
#include <wx/progdlg.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include <wx/valnum.h>
#include <wx/xrc/xmlres.h>
#include "../System.h"
#include "config/option-proxy.h"
#include "dialogs/validated-child.h"
#include "widgets/option-validator.h"
namespace dialogs {
LinkMode GetConfiguredLinkMode() {
switch (OPTION(kGBALinkType)) {
case 0:
return LINK_DISCONNECTED;
case 1:
if (OPTION(kGBALinkProto))
return LINK_CABLE_IPC;
else
return LINK_CABLE_SOCKET;
case 2:
if (OPTION(kGBALinkProto))
return LINK_RFU_IPC;
else
return LINK_RFU_SOCKET;
case 3:
return LINK_GAMECUBE_DOLPHIN;
case 4:
if (OPTION(kGBALinkProto))
return LINK_GAMEBOY_IPC;
else
return LINK_GAMEBOY_SOCKET;
default:
return LINK_DISCONNECTED;
}
}
// static
NetLink* NetLink::NewInstance(wxWindow* parent) {
assert(parent);
return new NetLink(parent);
}
NetLink::NetLink(wxWindow* parent) : wxDialog(), keep_on_top_styler_(this) {
#if !wxCHECK_VERSION(3, 1, 0)
// 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.
this->SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
#endif
assert(wxXmlResource::Get()->LoadDialog(this, parent, "NetLink"));
server_panel_ = GetValidatedChild(this, "NetLinkServerPanel");
client_panel_ = GetValidatedChild(this, "NetLinkClientPanel");
ok_button_ = this->FindWindow(wxID_OK);
assert(ok_button_);
wxWindow* server_button = GetValidatedChild(this, "Server");
server_button->Bind(
wxEVT_RADIOBUTTON,
std::bind(&NetLink::OnServerSelected, this, std::placeholders::_1),
server_button->GetId());
wxWindow* client_button = GetValidatedChild(this, "Client");
client_button->Bind(
wxEVT_RADIOBUTTON,
std::bind(&NetLink::OnClientSelected, this, std::placeholders::_1),
client_button->GetId());
// Server panel.
GetValidatedChild(this, "Link2P")
->SetValidator(widgets::OptionIntValidator(
config::OptionID::kPrefLinkNumPlayers, 2));
GetValidatedChild(this, "Link3P")
->SetValidator(widgets::OptionIntValidator(
config::OptionID::kPrefLinkNumPlayers, 3));
GetValidatedChild(this, "Link4P")
->SetValidator(widgets::OptionIntValidator(
config::OptionID::kPrefLinkNumPlayers, 4));
GetValidatedChild(this, "ServerIP")
->SetValidator(
widgets::OptionStringValidator(config::OptionID::kGBAServerIP));
GetValidatedChild(this, "ServerPort")
->SetValidator(
widgets::OptionSpinCtrlValidator(config::OptionID::kGBAServerPort));
GetValidatedChild(this, "LinkTimeout")
->SetValidator(widgets::OptionSpinCtrlValidator(
config::OptionID::kGBALinkTimeout));
// Client panel.
GetValidatedChild(this, "LinkHost")
->SetValidator(
widgets::OptionStringValidator(config::OptionID::kGBALinkHost));
GetValidatedChild(this, "LinkPort")
->SetValidator(
widgets::OptionSpinCtrlValidator(config::OptionID::kGBALinkPort));
// This should intercept wxID_OK before the dialog handler gets it.
ok_button_->Bind(
wxEVT_BUTTON,
std::bind(&NetLink::OnValidate, this, std::placeholders::_1),
ok_button_->GetId());
this->Fit();
}
void NetLink::OnServerSelected(wxCommandEvent& event) {
server_panel_->Enable(true);
client_panel_->Enable(false);
ok_button_->SetLabel(_("Start!"));
// Let the event propagate.
event.Skip();
}
void NetLink::OnClientSelected(wxCommandEvent& event) {
server_panel_->Enable(false);
client_panel_->Enable(true);
ok_button_->SetLabel(_("Connect"));
// Let the event propagate.
event.Skip();
}
void NetLink::OnValidate(wxCommandEvent& event) {
static const int kHostLength = 256;
if (!Validate() || !TransferDataFromWindow()) {
return;
}
const bool is_server_mode = server_panel_->IsEnabled();
if (!is_server_mode) {
const bool valid =
SetLinkServerHost(OPTION(kGBALinkHost).Get().utf8_str());
if (!valid) {
wxMessageBox(_("You must enter a valid host name"),
_("Host name invalid"), wxICON_ERROR | wxOK);
return;
}
}
// Close any previous link.
CloseLink();
wxString connection_message;
wxString title;
SetLinkTimeout(OPTION(kGBALinkTimeout));
EnableSpeedHacks(OPTION(kGBALinkFast));
EnableLinkServer(is_server_mode, OPTION(kPrefLinkNumPlayers) - 1);
if (is_server_mode) {
// Server mode.
IP_LINK_PORT = OPTION(kGBAServerPort);
IP_LINK_BIND_ADDRESS = OPTION(kGBAServerIP).Get();
std::array<char, kHostLength> host;
GetLinkServerHost(host.data(), kHostLength);
title.Printf(_("Waiting for clients..."));
connection_message.Printf(_("Server IP address is: %s\n"),
wxString(host.data(), wxConvLibc).c_str());
} else {
// Client mode.
title.Printf(_("Waiting for connection..."));
connection_message.Printf(_("Connecting to %s\n"), OPTION(kGBALinkHost).Get());
}
ConnectionState state = InitLink(GetConfiguredLinkMode());
// Display a progress dialog while the connection is establishing
if (state == LINK_NEEDS_UPDATE) {
wxProgressDialog pdlg(
title, connection_message, 100, this,
wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME);
while (state == LINK_NEEDS_UPDATE) {
// Ask the core for updates
std::array<char, kHostLength> message;
state = ConnectLinkUpdate(message.data(), kHostLength);
connection_message = wxString(message.data(), wxConvLibc);
// Does the user want to abort?
if (!pdlg.Pulse(connection_message)) {
state = LINK_ABORT;
}
}
}
// The user cancelled the connection attempt.
if (state == LINK_ABORT) {
CloseLink();
}
// Something failed during init.
if (state == LINK_ERROR) {
CloseLink();
wxLogError(_("Error occurred.\nPlease try again."));
}
if (GetLinkMode() != LINK_DISCONNECTED) {
connection_message.Replace("\n", " ");
systemScreenMessage(connection_message);
event.Skip(); // all OK
}
}
} // namespace dialogs
#endif // !defined(NO_LINK)

47
src/wx/dialogs/net-link.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef VBAM_WX_DIALOGS_NET_LINK_H_
#define VBAM_WX_DIALOGS_NET_LINK_H_
#if !defined(NO_LINK)
#include <wx/dialog.h>
#include "../gba/GBALink.h"
#include "widgets/keep-on-top-styler.h"
namespace dialogs {
// Helper function to get the current LinkMode.
LinkMode GetConfiguredLinkMode();
// Manages the Network Link dialog.
class NetLink : public wxDialog {
public:
static NetLink* NewInstance(wxWindow* parent);
~NetLink() override = default;
private:
// The constructor is private so initialization has to be done via the
// static method. This is because this class is destroyed when its
// owner, `parent` is destroyed. This prevents accidental deletion.
NetLink(wxWindow* parent);
// Modifies the dialog when the server option is selected.
void OnServerSelected(wxCommandEvent& event);
// Modifies the dialog when the client option is selected.
void OnClientSelected(wxCommandEvent& event);
// Custom validation for this dialog.
void OnValidate(wxCommandEvent& event);
wxWindow* server_panel_;
wxWindow* client_panel_;
wxWindow* ok_button_;
const widgets::KeepOnTopStyler keep_on_top_styler_;
};
} // namespace dialogs
#endif // !defined(NO_LINK)
#endif // VBAM_WX_DIALOGS_NET_LINK_H_

View File

@ -34,6 +34,10 @@
#include "opts.h" #include "opts.h"
#include "widgets/option-validator.h" #include "widgets/option-validator.h"
#ifndef NO_LINK
#include "dialogs/net-link.h"
#endif
#if defined(__WXGTK__) #if defined(__WXGTK__)
#include "wayland.h" #include "wayland.h"
#endif #endif
@ -70,126 +74,6 @@ const
// Event handlers must be methods of wxEvtHandler-derived objects // Event handlers must be methods of wxEvtHandler-derived objects
// manage the network link dialog
#ifndef NO_LINK
static class NetLink_t : public wxEvtHandler {
public:
wxDialog* dlg;
int n_players;
bool server;
NetLink_t()
: n_players(2)
, server(false)
{
}
wxButton* okb;
void ServerOKButton(wxCommandEvent& ev)
{
(void)ev; // unused params
okb->SetLabel(_("Start!"));
}
void BindServerIP(wxCommandEvent& ev)
{
(void)ev; // unused param
auto *tc = XRCCTRL(*dlg, "ServerIP", wxTextCtrl);
tc->SetValidator(wxTextValidator(wxFILTER_NONE, &gopts.server_ip));
tc->SetValue(gopts.server_ip);
}
void BindLinkHost(wxCommandEvent& ev)
{
(void)ev; // unused param
auto *tc = XRCCTRL(*dlg, "ServerIP", wxTextCtrl);
tc->SetValidator(wxTextValidator(wxFILTER_NONE, &gopts.link_host));
tc->SetValue(gopts.link_host);
}
void ClientOKButton(wxCommandEvent& ev)
{
(void)ev; // unused params
okb->SetLabel(_("Connect"));
}
// attached to OK, so skip when OK
void NetConnect(wxCommandEvent& ev)
{
static const int length = 256;
if (!dlg->Validate() || !dlg->TransferDataFromWindow())
return;
IP_LINK_PORT = gopts.link_port;
IP_LINK_BIND_ADDRESS = gopts.server_ip;
if (!server) {
bool valid = SetLinkServerHost(gopts.link_host.utf8_str());
if (!valid) {
wxMessageBox(_("You must enter a valid host name"),
_("Host name invalid"), wxICON_ERROR | wxOK);
return;
}
}
gopts.link_num_players = n_players;
update_opts(); // save fast flag and client host
// Close any previous link
CloseLink();
wxString connmsg;
wxString title;
SetLinkTimeout(gopts.link_timeout);
EnableSpeedHacks(OPTION(kGBALinkFast));
EnableLinkServer(server, gopts.link_num_players - 1);
if (server) {
char host[length];
GetLinkServerHost(host, length);
title.Printf(_("Waiting for clients..."));
connmsg.Printf(_("Server IP address is: %s\n"), wxString(host, wxConvLibc).c_str());
} else {
title.Printf(_("Waiting for connection..."));
connmsg.Printf(_("Connecting to %s\n"), gopts.link_host.c_str());
}
// Init link
MainFrame* mf = wxGetApp().frame;
ConnectionState state = InitLink(mf->GetConfiguredLinkMode());
// Display a progress dialog while the connection is establishing
if (state == LINK_NEEDS_UPDATE) {
wxProgressDialog pdlg(title, connmsg,
100, dlg, wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME);
while (state == LINK_NEEDS_UPDATE) {
// Ask the core for updates
char message[length];
state = ConnectLinkUpdate(message, length);
connmsg = wxString(message, wxConvLibc);
// Does the user want to abort?
if (!pdlg.Pulse(connmsg)) {
state = LINK_ABORT;
}
}
}
// The user canceled the connection attempt
if (state == LINK_ABORT) {
CloseLink();
}
// Something failed during init
if (state == LINK_ERROR) {
CloseLink();
wxLogError(_("Error occurred.\nPlease try again."));
}
if (GetLinkMode() != LINK_DISCONNECTED) {
connmsg.Replace(wxT("\n"), wxT(" "));
systemScreenMessage(connmsg);
ev.Skip(); // all OK
}
}
} net_link_handler;
#endif
// manage the cheat list dialog // manage the cheat list dialog
static class CheatList_t : public wxEvtHandler { static class CheatList_t : public wxEvtHandler {
public: public:
@ -2528,7 +2412,7 @@ bool MainFrame::BindControls()
#endif #endif
#ifdef NO_LINK #ifdef NO_LINK
if (cmdtab[i].cmd_id == XRCID("LanLink") || cmdtab[i].cmd_id == XRCID("LinkType0Nothing") || cmdtab[i].cmd_id == XRCID("LinkType1Cable") || cmdtab[i].cmd_id == XRCID("LinkType2Wireless") || cmdtab[i].cmd_id == XRCID("LinkType3GameCube") || cmdtab[i].cmd_id == XRCID("LinkType4Gameboy") || cmdtab[i].cmd_id == XRCID("LinkAuto") || cmdtab[i].cmd_id == XRCID("SpeedOn") || cmdtab[i].cmd_id == XRCID("LinkProto") || cmdtab[i].cmd_id == XRCID("LinkConfigure")) { if (cmdtab[i].cmd_id == XRCID("LanLink") || cmdtab[i].cmd_id == XRCID("LinkType0Nothing") || cmdtab[i].cmd_id == XRCID("LinkType1Cable") || cmdtab[i].cmd_id == XRCID("LinkType2Wireless") || cmdtab[i].cmd_id == XRCID("LinkType3GameCube") || cmdtab[i].cmd_id == XRCID("LinkType4Gameboy") || cmdtab[i].cmd_id == XRCID("LinkAuto") || cmdtab[i].cmd_id == XRCID("SpeedOn") || cmdtab[i].cmd_id == XRCID("LinkProto")) {
if (mi) if (mi)
mi->GetMenu()->Remove(mi); mi->GetMenu()->Remove(mi);
@ -2819,7 +2703,7 @@ bool MainFrame::BindControls()
d->Fit(); d->Fit();
//// Emulation menu //// Emulation menu
#ifndef NO_LINK #ifndef NO_LINK
d = LoadXRCDialog("NetLink"); dialogs::NetLink::NewInstance(this);
#endif #endif
wxRadioButton* rb; wxRadioButton* rb;
#define getrbo(name, option_id, value) \ #define getrbo(name, option_id, value) \
@ -2833,109 +2717,12 @@ bool MainFrame::BindControls()
rb = SafeXRCCTRL<wxRadioButton>(d, n); \ rb = SafeXRCCTRL<wxRadioButton>(d, n); \
rb->SetValidator(wxBoolIntValidator(&o, v)); \ rb->SetValidator(wxBoolIntValidator(&o, v)); \
} while (0) } while (0)
wxBoolEnValidator* benval;
wxBoolEnHandler* ben;
#define getbe(n, o, cv, t, wt) \
do { \
cv = SafeXRCCTRL<t>(d, n); \
cv->SetValidator(wxBoolEnValidator(&o)); \
benval = wxStaticCast(cv->GetValidator(), wxBoolEnValidator); \
static wxBoolEnHandler _ben; \
ben = &_ben; \
wx##wt##BoolEnHandlerConnect(cv, wxID_ANY, _ben); \
} while (0)
// brenval & friends are here just to allow yes/no radioboxes in place
// of checkboxes. A lot of work for little benefit.
wxBoolRevEnValidator* brenval;
#define getbre(n, o, cv, t, wt) \
do { \
cv = SafeXRCCTRL<t>(d, n); \
cv->SetValidator(wxBoolRevEnValidator(&o)); \
brenval = wxStaticCast(cv->GetValidator(), wxBoolRevEnValidator); \
wx##wt##BoolEnHandlerConnect(rb, wxID_ANY, *ben); \
} while (0)
#define addbe(n) \
do { \
ben->controls.push_back(n); \
benval->controls.push_back(n); \
} while (0)
#define addrbe(n) \
do { \
addbe(n); \
brenval->controls.push_back(n); \
} while (0)
#define addber(n, r) \
do { \
ben->controls.push_back(n); \
ben->reverse.push_back(r); \
benval->controls.push_back(n); \
benval->reverse.push_back(r); \
} while (0)
#define addrber(n, r) \
do { \
addber(n, r); \
brenval->controls.push_back(n); \
brenval->reverse.push_back(r); \
} while (0)
#define getrbbe(n, o) getbe(n, o, rb, wxRadioButton, RBE)
#define getrbbd(n, o) getbre(n, o, rb, wxRadioButton, RBD)
wxTextCtrl* tc; wxTextCtrl* tc;
#define gettc(n, o) \ #define gettc(n, o) \
do { \ do { \
tc = SafeXRCCTRL<wxTextCtrl>(d, n); \ tc = SafeXRCCTRL<wxTextCtrl>(d, n); \
tc->SetValidator(wxTextValidator(wxFILTER_NONE, &o)); \ tc->SetValidator(wxTextValidator(wxFILTER_NONE, &o)); \
} while (0) } while (0)
#define getutc(n, o) \
do { \
tc = SafeXRCCTRL<wxTextCtrl>(d, n); \
tc->SetValidator(wxUIntValidator(&o)); \
} while (0)
#ifndef NO_LINK
{
net_link_handler.dlg = d;
net_link_handler.n_players = gopts.link_num_players;
getrbbe("Server", net_link_handler.server);
getrbbd("Client", net_link_handler.server);
getlab("PlayersLab");
addrber(lab, false);
getrbi("Link2P", net_link_handler.n_players, 2);
addrber(rb, false);
getrbi("Link3P", net_link_handler.n_players, 3);
addrber(rb, false);
getrbi("Link4P", net_link_handler.n_players, 4);
addrber(rb, false);
getlab("ServerIPLab");
gettc("ServerIP", gopts.link_host);
getutc("ServerPort", gopts.link_port);
wxWindow* okb = d->FindWindow(wxID_OK);
if (okb) // may be gone if style guidlines removed it
{
net_link_handler.okb = wxStaticCast(okb, wxButton);
d->Connect(XRCID("Server"), wxEVT_COMMAND_RADIOBUTTON_SELECTED,
wxCommandEventHandler(NetLink_t::ServerOKButton),
NULL, &net_link_handler);
d->Connect(XRCID("Client"), wxEVT_COMMAND_RADIOBUTTON_SELECTED,
wxCommandEventHandler(NetLink_t::ClientOKButton),
NULL, &net_link_handler);
}
// Bind server IP when the server radio button is selected.
d->Connect(XRCID("Server"), wxEVT_COMMAND_RADIOBUTTON_SELECTED,
wxCommandEventHandler(NetLink_t::BindServerIP),
NULL, &net_link_handler);
// Bind client link_host when client radio button is selected.
d->Connect(XRCID("Client"), wxEVT_COMMAND_RADIOBUTTON_SELECTED,
wxCommandEventHandler(NetLink_t::BindLinkHost),
NULL, &net_link_handler);
// this should intercept wxID_OK before the dialog handler gets it
d->Connect(wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(NetLink_t::NetConnect),
NULL, &net_link_handler);
d->Fit();
}
#endif
d = LoadXRCDialog("CheatList"); d = LoadXRCDialog("CheatList");
{ {
cheat_list_handler.dlg = d; cheat_list_handler.dlg = d;
@ -3363,16 +3150,6 @@ bool MainFrame::BindControls()
joyDialog->Fit(); joyDialog->Fit();
} }
#ifndef NO_LINK
d = LoadXRCDialog("LinkConfig");
{
getlab("LinkTimeoutLab");
addbe(lab);
getsc("LinkTimeout", gopts.link_timeout);
addbe(sc);
d->Fit();
}
#endif
d = LoadXRCDialog("AccelConfig"); d = LoadXRCDialog("AccelConfig");
{ {
wxTreeCtrl* tc; wxTreeCtrl* tc;
@ -3504,36 +3281,31 @@ bool MainFrame::BindControls()
} }
#ifndef NO_LINK #ifndef NO_LINK
LinkMode link_mode = GetConfiguredLinkMode(); LinkMode link_mode = dialogs::GetConfiguredLinkMode();
if (link_mode == LINK_GAMECUBE_DOLPHIN) { if (link_mode == LINK_GAMECUBE_DOLPHIN) {
bool isv = !gopts.link_host.empty(); const wxString& link_host = OPTION(kGBALinkHost).Get();
if (link_host.empty()) {
if (isv) {
isv = SetLinkServerHost(gopts.link_host.utf8_str());
}
if (!isv) {
wxLogError(_("JoyBus host invalid; disabling")); wxLogError(_("JoyBus host invalid; disabling"));
} else { } else {
if (SetLinkServerHost(link_host.utf8_str())) {
link_mode = LINK_DISCONNECTED; link_mode = LINK_DISCONNECTED;
} }
} }
}
ConnectionState linkState = InitLink(link_mode); if (InitLink(link_mode) != LINK_OK) {
if (linkState != LINK_OK) {
CloseLink(); CloseLink();
} }
if (GetLinkMode() != LINK_DISCONNECTED) { if (GetLinkMode() != LINK_DISCONNECTED) {
cmd_enable |= CMDEN_LINK_ANY; cmd_enable |= CMDEN_LINK_ANY;
SetLinkTimeout(gopts.link_timeout); SetLinkTimeout(OPTION(kGBALinkTimeout));
EnableSpeedHacks(OPTION(kGBALinkFast)); EnableSpeedHacks(OPTION(kGBALinkFast));
} }
EnableNetworkMenu(); EnableNetworkMenu();
#endif #endif
enable_menus(); enable_menus();
panel->SetFrameTitle(); panel->SetFrameTitle();
// All OK; activate idle loop // All OK; activate idle loop

View File

@ -27,11 +27,6 @@ extern struct opts_t {
/// GBA /// GBA
wxString gba_bios; wxString gba_bios;
// quick fix for issues #48 and #445
wxString link_host = "127.0.0.1";
wxString server_ip = "*";
uint32_t link_port = 5738;
int link_timeout = 500;
int gba_link_type; int gba_link_type;
/// General /// General
@ -48,7 +43,6 @@ extern struct opts_t {
/// Core /// Core
int gdb_port = 55555; int gdb_port = 55555;
int link_num_players = 2;
int max_scale = 0; int max_scale = 0;
/// Sound /// Sound

View File

@ -32,6 +32,7 @@
#include "config/option-proxy.h" #include "config/option-proxy.h"
#include "config/option.h" #include "config/option.h"
#include "config/user-input.h" #include "config/user-input.h"
#include "dialogs/net-link.h"
#include "drawing.h" #include "drawing.h"
#include "filters.h" #include "filters.h"
#include "wayland.h" #include "wayland.h"
@ -523,9 +524,9 @@ void GameArea::LoadGame(const wxString& name)
#ifndef NO_LINK #ifndef NO_LINK
if (OPTION(kGBALinkAuto)) { if (OPTION(kGBALinkAuto)) {
BootLink(mf->GetConfiguredLinkMode(), UTF8(gopts.link_host), BootLink(dialogs::GetConfiguredLinkMode(), UTF8(OPTION(kGBALinkHost)),
gopts.link_timeout, OPTION(kGBALinkFast), OPTION(kGBALinkTimeout), OPTION(kGBALinkFast),
gopts.link_num_players); OPTION(kPrefLinkNumPlayers));
} }
#endif #endif

View File

@ -4,6 +4,7 @@
#include <wx/choice.h> #include <wx/choice.h>
#include <wx/radiobut.h> #include <wx/radiobut.h>
#include <wx/spinctrl.h> #include <wx/spinctrl.h>
#include <wx/textctrl.h>
namespace widgets { namespace widgets {
@ -142,4 +143,63 @@ bool OptionChoiceValidator::WriteToOption() {
return option()->SetUnsigned(choice->GetSelection()); return option()->SetUnsigned(choice->GetSelection());
} }
OptionIntValidator::OptionIntValidator(config::OptionID option_id,
int32_t value)
: OptionValidator(option_id), value_(value) {
assert(option()->is_int());
assert(option()->GetIntMin() <= value_);
assert(option()->GetIntMax() >= value_);
}
wxObject* OptionIntValidator::Clone() const {
return new OptionIntValidator(option()->id(), value_);
}
bool OptionIntValidator::IsWindowValueValid() {
return true;
}
bool OptionIntValidator::WriteToWindow() {
wxRadioButton* radio_button = wxDynamicCast(GetWindow(), wxRadioButton);
assert(radio_button);
radio_button->SetValue(option()->GetInt() == value_);
return true;
}
bool OptionIntValidator::WriteToOption() {
const wxRadioButton* radio_button =
wxDynamicCast(GetWindow(), wxRadioButton);
assert(radio_button);
if (radio_button->GetValue()) {
option()->SetInt(value_);
}
return true;
}
OptionStringValidator::OptionStringValidator(config::OptionID option_id)
: OptionValidator(option_id) {
assert(option()->is_string());
}
wxObject* OptionStringValidator::Clone() const {
return new OptionStringValidator(option()->id());
}
bool OptionStringValidator::IsWindowValueValid() {
return true;
}
bool OptionStringValidator::WriteToWindow() {
wxTextCtrl* text_control = wxDynamicCast(GetWindow(), wxTextCtrl);
assert(text_control);
text_control->SetValue(option()->GetString());
return true;
}
bool OptionStringValidator::WriteToOption() {
const wxTextCtrl* text_control = wxDynamicCast(GetWindow(), wxTextCtrl);
assert(text_control);
return option()->SetString(text_control->GetValue());
}
} // namespace widgets } // namespace widgets

View File

@ -140,6 +140,42 @@ private:
bool WriteToOption() override; bool WriteToOption() override;
}; };
// Validator for a wxRadioButton widget with a selected kInt Option. This will
// keep the kInt Option and the wxRadioButton selection in sync.
class OptionIntValidator : public OptionValidator {
public:
explicit OptionIntValidator(config::OptionID option_id, int32_t value);
~OptionIntValidator() override = default;
// Returns a copy of the object.
wxObject* Clone() const override;
private:
// OptionValidator implementation.
bool IsWindowValueValid() override;
bool WriteToWindow() override;
bool WriteToOption() override;
const int32_t value_;
};
// Validator for a wxTextCtrl widget with a selected kString Option. This will
// keep the kString Option and the wxTextCtrl in sync.
class OptionStringValidator : public OptionValidator {
public:
explicit OptionStringValidator(config::OptionID option_id);
~OptionStringValidator() override = default;
// Returns a copy of the object.
wxObject* Clone() const override;
private:
// OptionValidator implementation.
bool IsWindowValueValid() override;
bool WriteToWindow() override;
bool WriteToOption() override;
};
} // namespace widgets } // namespace widgets
#endif // VBAM_WX_WIDGETS_OPTION_VALIDATOR_H_ #endif // VBAM_WX_WIDGETS_OPTION_VALIDATOR_H_

View File

@ -52,36 +52,6 @@ protected:
uint32_t* uint_val; uint32_t* uint_val;
}; };
// boolean copy-only validator with reversed value
// may be attached to radio button or checkbox
class wxBoolRevValidator : public wxValidator {
public:
wxBoolRevValidator(bool* _vptr)
: wxValidator()
, vptr(_vptr)
{
}
wxBoolRevValidator(const wxBoolRevValidator& v)
: wxValidator()
, vptr(v.vptr)
{
}
wxObject* Clone() const
{
return new wxBoolRevValidator(vptr);
}
bool TransferToWindow();
bool TransferFromWindow();
bool Validate(wxWindow* p)
{
(void)p; // unused params
return true;
}
protected:
bool* vptr;
};
// wxFilePickerCtrl/wxDirPickerCtrl copy-only vvalidator // wxFilePickerCtrl/wxDirPickerCtrl copy-only vvalidator
class wxFileDirPickerValidator : public wxValidator { class wxFileDirPickerValidator : public wxValidator {
public: public:
@ -114,139 +84,6 @@ protected:
wxStaticText* vlabel; wxStaticText* vlabel;
}; };
// Copy-only validators for checkboxes and radio buttons that enables a set
// of dependent widgets
// Requires an event handler during run-time
// there's probably a standard wxWindowList or some such, but it's
// undocumented and I prefer arrays
typedef std::vector<wxWindow*> wxWindow_v;
class wxBoolEnValidator : public wxGenericValidator {
public:
wxBoolEnValidator(bool* vptr)
: wxGenericValidator(vptr)
{
}
wxBoolEnValidator(bool* vptr, wxWindow_v& cnt, std::vector<int> rev = std::vector<int>())
: wxGenericValidator(vptr)
, controls(cnt)
, reverse(rev)
{
}
wxBoolEnValidator(const wxBoolEnValidator& v)
: wxGenericValidator(v)
, controls(v.controls)
, reverse(v.reverse)
{
}
wxObject* Clone() const
{
return new wxBoolEnValidator(*this);
}
// set these after init, rather than in constructor
wxWindow_v controls;
// set reverse entries to true if disabled when checkbox checked
// controls past the end of the reverse array are not reversed
std::vector<int> reverse;
// inherit validate, xferfrom from parent
bool TransferToWindow();
};
class wxBoolIntEnValidator : public wxBoolIntValidator {
public:
wxBoolIntEnValidator(int* vptr, int val, int mask = ~0)
: wxBoolIntValidator(vptr, val, mask)
{
}
wxBoolIntEnValidator(int* vptr, int val, int mask, wxWindow_v& cnt,
std::vector<int> rev = std::vector<int>())
: wxBoolIntValidator(vptr, val, mask)
, controls(cnt)
, reverse(rev)
{
}
wxBoolIntEnValidator(const wxBoolIntEnValidator& v)
: wxBoolIntValidator(v)
, controls(v.controls)
, reverse(v.reverse)
{
}
wxObject* Clone() const
{
return new wxBoolIntEnValidator(*this);
}
// set these after init, rather than in constructor
wxWindow_v controls;
// set reverse entries to true if disabled when checkbox checked
// controls past the end of the reverse array are not reversed
std::vector<int> reverse;
// inherit validate, xferfrom from parent
bool TransferToWindow();
};
class wxBoolRevEnValidator : public wxBoolRevValidator {
public:
wxBoolRevEnValidator(bool* vptr)
: wxBoolRevValidator(vptr)
{
}
wxBoolRevEnValidator(bool* vptr, wxWindow_v& cnt, std::vector<int> rev = std::vector<int>())
: wxBoolRevValidator(vptr)
, controls(cnt)
, reverse(rev)
{
}
wxBoolRevEnValidator(const wxBoolRevEnValidator& v)
: wxBoolRevValidator(v)
, controls(v.controls)
, reverse(v.reverse)
{
}
wxObject* Clone() const
{
return new wxBoolRevEnValidator(*this);
}
// set these after init, rather than in constructor
wxWindow_v controls;
// set reverse entries to true if disabled when checkbox checked
// controls past the end of the reverse array are not reversed
std::vector<int> reverse;
// inherit validate, xferfrom from parent
bool TransferToWindow();
};
// and here's an event handler that can be attached to the widget or a parent
// of the widget
// It is a descendent of wxEvtHandler so its methods can be used as
// event handlers
class wxBoolEnHandler : public wxEvtHandler {
public:
wxWindow_v controls;
std::vector<int> reverse;
void ToggleCheck(wxCommandEvent& ev);
void Enable(wxCommandEvent& ev);
void Disable(wxCommandEvent& ev);
};
// use this to connect to the handler of id in win to obj
#define wxCBBoolEnHandlerConnect(win, id, obj) \
(win)->Connect(id, \
wxEVT_COMMAND_CHECKBOX_CLICKED, \
wxCommandEventHandler(wxBoolEnHandler::ToggleCheck), \
NULL, \
&obj)
#define wxRBBoolEnHandlerConnect(win, id, obj, f) \
(win)->Connect(id, \
wxEVT_COMMAND_RADIOBUTTON_SELECTED, \
wxCommandEventHandler(wxBoolEnHandler::f), \
NULL, \
&obj)
#define wxRBEBoolEnHandlerConnect(win, id, obj) wxRBBoolEnHandlerConnect(win, id, obj, Enable)
#define wxRBDBoolEnHandlerConnect(win, id, obj) wxRBBoolEnHandlerConnect(win, id, obj, Disable)
// for wxTextValidator include lists // for wxTextValidator include lists
extern const wxArrayString val_hexdigits, val_sigdigits, val_unsdigits; extern const wxArrayString val_hexdigits, val_sigdigits, val_unsdigits;

View File

@ -1,12 +1,15 @@
// utility widgets // utility widgets
#include "wx/wxmisc.h"
#include <cctype> #include <cctype>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include "wx/wxmisc.h" #include <wx/checkbox.h>
#include <wx/wx.h> #include <wx/filepicker.h>
#include <wx/radiobut.h>
#include <wx/spinctrl.h> #include <wx/spinctrl.h>
#include <wx/textctrl.h>
bool wxBoolIntValidator::TransferToWindow() bool wxBoolIntValidator::TransferToWindow()
{ {
@ -57,51 +60,6 @@ bool wxBoolIntValidator::TransferFromWindow()
return true; return true;
} }
bool wxBoolRevValidator::TransferToWindow()
{
if (!vptr)
return false;
wxCheckBox* cb = wxDynamicCast(GetWindow(), wxCheckBox);
if (cb) {
cb->SetValue(!*vptr);
return true;
}
wxRadioButton* rb = wxDynamicCast(GetWindow(), wxRadioButton);
if (rb) {
rb->SetValue(!*vptr);
return true;
}
return false;
}
bool wxBoolRevValidator::TransferFromWindow()
{
if (!vptr)
return false;
wxCheckBox* cb = wxDynamicCast(GetWindow(), wxCheckBox);
if (cb)
*vptr = !cb->GetValue();
else {
wxRadioButton* rb = wxDynamicCast(GetWindow(), wxRadioButton);
if (rb)
*vptr = !rb->GetValue();
else
return false;
}
return true;
}
#include <wx/filepicker.h>
bool wxFileDirPickerValidator::TransferToWindow() bool wxFileDirPickerValidator::TransferToWindow()
{ {
if (!vptr) if (!vptr)
@ -148,70 +106,6 @@ bool wxFileDirPickerValidator::TransferFromWindow()
return false; return false;
} }
static void enable(wxWindow_v controls, std::vector<int> reverse, bool en)
{
for (size_t i = 0; i < controls.size(); i++)
controls[i]->Enable(reverse.size() <= i || !reverse[i] ? en : !en);
}
#define boolen(r) \
do { \
int en; \
wxCheckBox* cb = wxDynamicCast(GetWindow(), wxCheckBox); \
if (cb) \
en = cb->GetValue(); \
else { \
wxRadioButton* rb = wxDynamicCast(GetWindow(), wxRadioButton); \
if (!rb) \
return false; \
en = rb->GetValue(); \
} \
enable(controls, reverse, r ? !en : en); \
return true; \
} while (0)
bool wxBoolEnValidator::TransferToWindow()
{
if (!wxGenericValidator::TransferToWindow())
return false;
boolen(false);
}
bool wxBoolIntEnValidator::TransferToWindow()
{
if (!wxBoolIntValidator::TransferToWindow())
return false;
boolen(false);
}
bool wxBoolRevEnValidator::TransferToWindow()
{
if (!wxBoolRevValidator::TransferToWindow())
return false;
boolen(true);
}
void wxBoolEnHandler::ToggleCheck(wxCommandEvent& ev)
{
enable(controls, reverse, ev.IsChecked());
ev.Skip();
}
void wxBoolEnHandler::Enable(wxCommandEvent& ev)
{
enable(controls, reverse, true);
ev.Skip();
}
void wxBoolEnHandler::Disable(wxCommandEvent& ev)
{
enable(controls, reverse, false);
ev.Skip();
}
static const wxString val_hexdigits_s[] = { static const wxString val_hexdigits_s[] = {
wxT("0"), wxT("1"), wxT("2"), wxT("3"), wxT("4"), wxT("5"), wxT("6"), wxT("0"), wxT("1"), wxT("2"), wxT("3"), wxT("4"), wxT("5"), wxT("6"),
wxT("7"), wxT("8"), wxT("9"), wxT("A"), wxT("B"), wxT("C"), wxT("D"), wxT("7"), wxT("8"), wxT("9"), wxT("A"), wxT("B"), wxT("C"), wxT("D"),

View File

@ -1212,49 +1212,6 @@ void MainFrame::StopModal()
panel->Resume(); panel->Resume();
} }
LinkMode MainFrame::GetConfiguredLinkMode()
{
switch (gopts.gba_link_type) {
case 0:
return LINK_DISCONNECTED;
break;
case 1:
if (OPTION(kGBALinkProto))
return LINK_CABLE_IPC;
else
return LINK_CABLE_SOCKET;
break;
case 2:
if (OPTION(kGBALinkProto))
return LINK_RFU_IPC;
else
return LINK_RFU_SOCKET;
break;
case 3:
return LINK_GAMECUBE_DOLPHIN;
break;
case 4:
if (OPTION(kGBALinkProto))
return LINK_GAMEBOY_IPC;
else
return LINK_GAMEBOY_SOCKET;
break;
default:
return LINK_DISCONNECTED;
break;
}
return LINK_DISCONNECTED;
}
void MainFrame::IdentifyRom() void MainFrame::IdentifyRom()
{ {
if (!panel->rom_name.empty()) if (!panel->rom_name.empty())

View File

@ -280,9 +280,6 @@ public:
return focused; return focused;
} }
// Returns the link mode to set according to the options
LinkMode GetConfiguredLinkMode();
void IdentifyRom(); void IdentifyRom();
// Start GDB listener // Start GDB listener

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwidgets.org/wxxrc" version="2.5.3.0">
<object class="wxDialog" name="LinkConfig">
<title>Link configuration</title>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<object class="wxBoxSizer">
<object class="sizeritem">
<object class="wxStaticText" name="LinkTimeoutLab">
<label>Link timeout (in milliseconds)</label>
</object>
<flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxSpinCtrl" name="LinkTimeout">
<min>0</min>
<max>9999999</max>
</object>
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object>
<orient>wxHORIZONTAL</orient>
</object>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxStdDialogButtonSizer">
<object class="button">
<object class="wxButton" name="wxID_OK"/>
</object>
<object class="button">
<object class="wxButton" name="wxID_CANCEL"/>
</object>
</object>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object>
</object>
</object>
</resource>

View File

@ -306,9 +306,6 @@
<label>_Speed hack</label> <label>_Speed hack</label>
<checkable>1</checkable> <checkable>1</checkable>
</object> </object>
<object class="wxMenuItem" name="LinkConfigure">
<label>_Configure...</label>
</object>
</object> </object>
<object class="wxMenu"> <object class="wxMenu">
<label>_Video</label> <label>_Video</label>

View File

@ -5,106 +5,47 @@
<object class="wxBoxSizer"> <object class="wxBoxSizer">
<orient>wxVERTICAL</orient> <orient>wxVERTICAL</orient>
<object class="sizeritem"> <object class="sizeritem">
<object class="wxGridSizer"> <object class="wxFlexGridSizer">
<rows>2</rows>
<cols>2</cols>
<object class="sizeritem"> <object class="sizeritem">
<object class="wxRadioButton" name="Server"> <flag>wxALL|wxALIGN_LEFT</flag>
<label>Server</label>
<style>wxRB_GROUP</style>
</object>
<flag>wxALL|wxALIGN_CENTRE</flag>
<border>5</border> <border>5</border>
<object class="wxRadioButton" name="Server">
<style>wxRB_GROUP</style>
<label>Server</label>
</object>
</object> </object>
<object class="sizeritem"> <object class="sizeritem">
<flag>wxALL|wxALIGN_LEFT</flag>
<border>5</border>
<object class="wxRadioButton" name="Client"> <object class="wxRadioButton" name="Client">
<label>Client</label> <label>Client</label>
</object> </object>
<flag>wxALL|wxALIGN_CENTRE</flag>
<border>5</border>
</object>
</object>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object> </object>
<object class="sizeritem"> <object class="sizeritem">
<object class="wxFlexGridSizer">
<object class="sizeritem">
<object class="wxStaticText" name="PlayersLab">
<label>Players:</label>
</object>
<flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxGridSizer">
<object class="sizeritem">
<object class="wxRadioButton" name="Link2P">
<label>2</label>
<style>wxRB_GROUP</style>
</object>
<flag>wxALL|wxALIGN_CENTRE</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxRadioButton" name="Link3P">
<label>3</label>
</object>
<flag>wxALL|wxALIGN_CENTRE</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxRadioButton" name="Link4P">
<label>4</label>
</object>
<flag>wxALL|wxALIGN_CENTRE</flag>
<border>5</border>
</object>
<cols>3</cols>
</object>
<flag>wxEXPAND</flag> <flag>wxEXPAND</flag>
<border>5</border>
<object_ref name="NetLinkServerPanel" ref="NetLinkServerPanel" />
</object> </object>
<object class="sizeritem"> <object class="sizeritem">
<object class="wxStaticText" name="ServerIPLab">
<label>Server:</label>
<wrap>200</wrap>
</object>
<flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxTextCtrl" name="ServerIP"/>
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxStaticText" name="ServerPortLab">
<label>Port:</label>
</object>
<flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxTextCtrl" name="ServerPort"/>
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object>
</object>
<flag>wxEXPAND</flag> <flag>wxEXPAND</flag>
<border>5</border>
<object_ref name="NetLinkClientPanel" ref="NetLinkClientPanel" />
</object>
</object>
</object> </object>
<object class="sizeritem"> <object class="sizeritem">
<flag>wxALIGN_RIGHT|wxALL</flag>
<border>5</border>
<object class="wxStdDialogButtonSizer"> <object class="wxStdDialogButtonSizer">
<object class="button"> <object class="button">
<object class="wxButton" name="wxID_OK"> <object class="wxButton" name="wxID_OK" />
<label>Connect</label>
</object>
</object> </object>
<object class="button"> <object class="button">
<object class="wxButton" name="wxID_CANCEL" /> <object class="wxButton" name="wxID_CANCEL" />
</object> </object>
</object> </object>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object> </object>
</object> </object>
</object> </object>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwidgets.org/wxxrc" version="2.5.3.0">
<object class="wxPanel" name="NetLinkClientPanel">
<object class="wxFlexGridSizer">
<rows>2</rows>
<cols>2</cols>
<object class="sizeritem">
<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL</flag>
<border>5</border>
<object class="wxStaticText" name="LinkHostLab">
<label>Server:</label>
</object>
</object>
<object class="sizeritem">
<flag>wxALIGN_LEFT|wxALL</flag>
<border>5</border>
<object class="wxTextCtrl" name="LinkHost"/>
</object>
<object class="sizeritem">
<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL</flag>
<border>5</border>
<object class="wxStaticText" name="LinkPortLab">
<label>Port:</label>
</object>
</object>
<object class="sizeritem">
<flag>wxALIGN_LEFT|wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxSpinCtrl" name="LinkPort">
<min>0</min>
<max>65535</max>
</object>
</object>
</object>
</object>
</resource>

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwidgets.org/wxxrc" version="2.5.3.0">
<object class="wxPanel" name="NetLinkServerPanel">
<object class="wxFlexGridSizer">
<rows>4</rows>
<cols>2</cols>
<object class="sizeritem">
<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL</flag>
<border>5</border>
<object class="wxStaticText" name="PlayersLab">
<label>Players:</label>
</object>
</object>
<object class="sizeritem">
<flag>wxALIGN_LEFT|wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<flag>wxALL|wxALIGN_CENTER</flag>
<border>5</border>
<object class="wxRadioButton" name="Link2P">
<style>wxRB_GROUP</style>
<label>2</label>
</object>
</object>
<object class="sizeritem">
<flag>wxALL|wxALIGN_CENTER</flag>
<border>5</border>
<object class="wxRadioButton" name="Link3P">
<label>3</label>
</object>
</object>
<object class="sizeritem">
<flag>wxALL|wxALIGN_CENTER</flag>
<border>5</border>
<object class="wxRadioButton" name="Link4P">
<label>4</label>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL</flag>
<border>5</border>
<object class="wxStaticText" name="ServerIPLab">
<label>Server:</label>
</object>
</object>
<object class="sizeritem">
<flag>wxALIGN_LEFT|wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxTextCtrl" name="ServerIP" />
</object>
<object class="sizeritem">
<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL</flag>
<border>5</border>
<object class="wxStaticText" name="ServerPortLab">
<label>Port:</label>
</object>
</object>
<object class="sizeritem">
<flag>wxALIGN_LEFT|wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxSpinCtrl" name="ServerPort">
<min>0</min>
<max>65535</max>
</object>
</object>
<object class="sizeritem">
<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL</flag>
<border>5</border>
<object class="wxStaticText" name="LinkTimeoutLab">
<label>Timeout:</label>
</object>
</object>
<object class="sizeritem">
<flag>wxALIGN_LEFT|wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxSpinCtrl" name="LinkTimeout">
<style>wxSP_ARROW_KEYS</style>
<min>0</min>
<max>9999999</max>
</object>
</object>
</object>
</object>
</resource>