Merge pull request #4068 from EmptyChaos/wx-hidpi

WX: Comprehensive HiDPI Patch
This commit is contained in:
shuffle2 2016-10-03 20:06:08 -07:00 committed by GitHub
commit b8731eb818
100 changed files with 4436 additions and 3184 deletions

View File

@ -218,6 +218,9 @@ void wxTipWindow::Close()
*m_windowPtr = NULL;
m_windowPtr = NULL;
}
// XXX: Dolphin: Prevents an assertion failure due to Close being called multiple times.
if (!IsShown())
return;
#if wxUSE_POPUPWIN
Show(false);

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <cinttypes>
#include <climits>
#include <memory>
#include "Common/CDUtils.h"
@ -138,8 +139,8 @@ void SConfig::SaveInterfaceSettings(IniFile& ini)
interface->Set("OnScreenDisplayMessages", bOnScreenDisplayMessages);
interface->Set("HideCursor", bHideCursor);
interface->Set("AutoHideCursor", bAutoHideCursor);
interface->Set("MainWindowPosX", (iPosX == -32000) ? 0 : iPosX); // TODO - HAX
interface->Set("MainWindowPosY", (iPosY == -32000) ? 0 : iPosY); // TODO - HAX
interface->Set("MainWindowPosX", iPosX);
interface->Set("MainWindowPosY", iPosY);
interface->Set("MainWindowWidth", iWidth);
interface->Set("MainWindowHeight", iHeight);
interface->Set("LanguageCode", m_InterfaceLanguage);
@ -402,10 +403,10 @@ void SConfig::LoadInterfaceSettings(IniFile& ini)
interface->Get("OnScreenDisplayMessages", &bOnScreenDisplayMessages, true);
interface->Get("HideCursor", &bHideCursor, false);
interface->Get("AutoHideCursor", &bAutoHideCursor, false);
interface->Get("MainWindowPosX", &iPosX, 100);
interface->Get("MainWindowPosY", &iPosY, 100);
interface->Get("MainWindowWidth", &iWidth, 800);
interface->Get("MainWindowHeight", &iHeight, 600);
interface->Get("MainWindowPosX", &iPosX, INT_MIN);
interface->Get("MainWindowPosY", &iPosY, INT_MIN);
interface->Get("MainWindowWidth", &iWidth, -1);
interface->Get("MainWindowHeight", &iHeight, -1);
interface->Get("LanguageCode", &m_InterfaceLanguage, "");
interface->Get("ShowToolbar", &m_InterfaceToolbar, true);
interface->Get("ShowStatusbar", &m_InterfaceStatusbar, true);
@ -663,10 +664,10 @@ void SConfig::LoadDefaults()
bDPL2Decoder = false;
iLatency = 14;
iPosX = 100;
iPosY = 100;
iWidth = 800;
iHeight = 600;
iPosX = INT_MIN;
iPosY = INT_MIN;
iWidth = -1;
iHeight = -1;
m_analytics_id = "";
m_analytics_enabled = false;

View File

@ -4,6 +4,7 @@
#pragma once
#include <limits>
#include <string>
#include <vector>
@ -129,8 +130,10 @@ struct SConfig : NonCopyable
// Display settings
std::string strFullscreenResolution;
int iRenderWindowXPos = -1, iRenderWindowYPos = -1;
int iRenderWindowWidth = 640, iRenderWindowHeight = 480;
int iRenderWindowXPos = std::numeric_limits<int>::min();
int iRenderWindowYPos = std::numeric_limits<int>::min();
int iRenderWindowWidth = -1;
int iRenderWindowHeight = -1;
bool bRenderWindowAutoSize = false, bKeepWindowOnTop = false;
bool bFullscreen = false, bRenderToMain = false;
bool bProgressive = false, bPAL60 = false;

View File

@ -20,8 +20,8 @@ AboutDolphin::AboutDolphin(wxWindow* parent, wxWindowID id, const wxString& titl
const wxPoint& position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style)
{
wxGenericStaticBitmap* const sbDolphinLogo =
new wxGenericStaticBitmap(this, wxID_ANY, WxUtils::LoadResourceBitmap("dolphin_logo"));
wxGenericStaticBitmap* const sbDolphinLogo = new wxGenericStaticBitmap(
this, wxID_ANY, WxUtils::LoadScaledResourceBitmap("dolphin_logo", this));
const wxString DolphinText = _("Dolphin");
const wxString RevisionText = scm_desc_str;
@ -80,6 +80,12 @@ AboutDolphin::AboutDolphin(wxWindow* parent, wxWindowID id, const wxString& titl
wxSizerFlags center_flag;
center_flag.Center();
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
const int space15 = FromDIP(15);
const int space30 = FromDIP(30);
const int space40 = FromDIP(40);
const int space75 = FromDIP(75);
wxBoxSizer* const sCheckUpdates = new wxBoxSizer(wxHORIZONTAL);
sCheckUpdates->Add(UpdateText, center_flag);
@ -94,30 +100,30 @@ AboutDolphin::AboutDolphin(wxWindow* parent, wxWindowID id, const wxString& titl
wxBoxSizer* const sInfo = new wxBoxSizer(wxVERTICAL);
sInfo->Add(Dolphin);
sInfo->AddSpacer(5);
sInfo->AddSpacer(space5);
sInfo->Add(Revision);
sInfo->AddSpacer(10);
sInfo->AddSpacer(space10);
sInfo->Add(Branch);
sInfo->Add(sCheckUpdates);
sInfo->Add(Message);
sInfo->Add(sLinks);
wxBoxSizer* const sLogo = new wxBoxSizer(wxVERTICAL);
sLogo->AddSpacer(75);
sLogo->AddSpacer(space75);
sLogo->Add(sbDolphinLogo);
sLogo->AddSpacer(40);
sLogo->AddSpacer(space40);
wxBoxSizer* const sMainHor = new wxBoxSizer(wxHORIZONTAL);
sMainHor->AddSpacer(30);
sMainHor->AddSpacer(space30);
sMainHor->Add(sLogo);
sMainHor->AddSpacer(30);
sMainHor->AddSpacer(space30);
sMainHor->Add(sInfo);
sMainHor->AddSpacer(30);
sMainHor->AddSpacer(space30);
wxBoxSizer* const sFooter = new wxBoxSizer(wxVERTICAL);
sFooter->AddSpacer(15);
sFooter->AddSpacer(space15);
sFooter->Add(Copyright, 0, wxALIGN_CENTER_HORIZONTAL);
sFooter->AddSpacer(5);
sFooter->AddSpacer(space5);
wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
sMain->Add(sMainHor, 1, wxEXPAND);

View File

@ -40,6 +40,7 @@ set(GUI_SRCS
NetPlay/NetPlaySetupFrame.cpp
NetPlay/NetWindow.cpp
NetPlay/PadMapDialog.cpp
DolphinSlider.cpp
FifoPlayerDlg.cpp
Frame.cpp
FrameAui.cpp

View File

@ -27,10 +27,7 @@
#include "DolphinWX/Cheats/CreateCodeDialog.h"
#include "DolphinWX/WxUtils.h"
namespace
{
const unsigned int MAX_CHEAT_SEARCH_RESULTS_DISPLAY = 1024;
}
static constexpr unsigned int MAX_CHEAT_SEARCH_RESULTS_DISPLAY = 1024;
CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
{
@ -39,13 +36,25 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
// first scan button
m_btn_init_scan = new wxButton(this, wxID_ANY, _("New Scan"));
m_btn_init_scan->SetToolTip(_("Perform a full index of the game's RAM at the current Data Size. "
"Required before any Searching can be performed."));
m_btn_init_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNewScanClicked, this);
m_btn_init_scan->Disable();
// next scan button
m_btn_next_scan = new wxButton(this, wxID_ANY, _("Next Scan"));
m_btn_next_scan->SetToolTip(_("Eliminate items from the current scan results that do not match "
"the current Search settings."));
m_btn_next_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNextScanClicked, this);
m_btn_next_scan->Disable();
m_label_scan_disabled = new wxStaticText(this, wxID_ANY, _("No game is running."));
// create AR code button
m_btn_create_code = new wxButton(this, wxID_ANY, _("Create AR Code"));
m_btn_create_code->Bind(wxEVT_BUTTON, &CheatSearchTab::OnCreateARCodeClicked, this);
m_btn_create_code->Disable();
// data sizes radiobox
std::array<wxString, 3> data_size_names = {{_("8-bit"), _("16-bit"), _("32-bit")}};
m_data_sizes = new wxRadioBox(this, wxID_ANY, _("Data Size"), wxDefaultPosition, wxDefaultSize,
@ -54,30 +63,39 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
// ListView for search results
m_lview_search_results = new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_REPORT | wxLC_SINGLE_SEL);
ResetListViewColumns();
m_lview_search_results->AppendColumn(_("Address"));
m_lview_search_results->AppendColumn(_("Value"));
m_lview_search_results->AppendColumn(_("Value (float)"));
m_lview_search_results->AppendColumn(_("Value (double)"));
m_lview_search_results->Bind(wxEVT_LIST_ITEM_ACTIVATED, &CheatSearchTab::OnListViewItemActivated,
this);
m_lview_search_results->Bind(wxEVT_LIST_ITEM_SELECTED, &CheatSearchTab::OnListViewItemSelected,
this);
m_lview_search_results->Bind(wxEVT_LIST_ITEM_DESELECTED, &CheatSearchTab::OnListViewItemSelected,
this);
// Result count
m_label_results_count = new wxStaticText(this, wxID_ANY, _("Count:"));
// create AR code button
wxButton* const button_cheat_search_copy_address =
new wxButton(this, wxID_ANY, _("Create AR Code"));
button_cheat_search_copy_address->Bind(wxEVT_BUTTON, &CheatSearchTab::OnCreateARCodeClicked,
this);
const int space5 = FromDIP(5);
// results groupbox
wxStaticBoxSizer* const sizer_cheat_search_results =
new wxStaticBoxSizer(wxVERTICAL, this, _("Results"));
sizer_cheat_search_results->Add(m_label_results_count, 0, wxALIGN_LEFT | wxALL, 5);
sizer_cheat_search_results->Add(m_lview_search_results, 1, wxEXPAND | wxALL, 5);
sizer_cheat_search_results->Add(button_cheat_search_copy_address, 0,
wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
sizer_cheat_search_results->AddSpacer(space5);
sizer_cheat_search_results->Add(m_label_results_count, 0, wxLEFT | wxRIGHT, space5);
sizer_cheat_search_results->AddSpacer(space5);
sizer_cheat_search_results->Add(m_lview_search_results, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer_cheat_search_results->AddSpacer(space5);
sizer_cheat_search_results->Add(m_btn_create_code, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer_cheat_search_results->AddSpacer(space5);
// search value textbox
m_textctrl_value_x = new wxTextCtrl(this, wxID_ANY, "0x0", wxDefaultPosition, wxSize(96, -1));
wxBoxSizer* const sizer_cheat_filter_text = new wxBoxSizer(wxHORIZONTAL);
sizer_cheat_filter_text->Add(m_textctrl_value_x, 1, wxALIGN_CENTER_VERTICAL, 5);
m_textctrl_value_x = new wxTextCtrl(this, wxID_ANY, "0x0");
m_textctrl_value_x->SetMinSize(WxUtils::GetTextWidgetMinSize(m_textctrl_value_x, "0x00000000 "));
m_textctrl_value_x->SetToolTip(
_("Value to match against. Can be Hex (\"0x\"), Octal (\"0\") or Decimal. "
"Leave blank to filter each result against its own previous value."));
// Filter types in the compare dropdown
// TODO: Implement between search
@ -93,33 +111,46 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
wxStaticBoxSizer* const sizer_cheat_search_filter =
new wxStaticBoxSizer(wxVERTICAL, this, _("Search (clear to use previous value)"));
sizer_cheat_search_filter->Add(sizer_cheat_filter_text, 0, wxALL | wxEXPAND, 5);
sizer_cheat_search_filter->Add(m_search_type, 0, wxALL, 5);
// left sizer
wxBoxSizer* const sizer_left = new wxBoxSizer(wxVERTICAL);
sizer_left->Add(sizer_cheat_search_results, 1, wxEXPAND, 5);
sizer_cheat_search_filter->AddSpacer(space5);
sizer_cheat_search_filter->Add(m_textctrl_value_x, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer_cheat_search_filter->AddSpacer(space5);
sizer_cheat_search_filter->Add(m_search_type, 0, wxLEFT | wxRIGHT, space5);
sizer_cheat_search_filter->AddSpacer(space5);
// button sizer
wxBoxSizer* boxButtons = new wxBoxSizer(wxHORIZONTAL);
boxButtons->Add(m_btn_init_scan, 1, wxRIGHT, 5);
boxButtons->Add(m_btn_next_scan, 1);
boxButtons->Add(m_btn_init_scan, 1);
boxButtons->Add(m_btn_next_scan, 1, wxLEFT, space5);
// right sizer
wxBoxSizer* const sizer_right = new wxBoxSizer(wxVERTICAL);
sizer_right->Add(m_data_sizes, 0, wxEXPAND | wxBOTTOM, 5);
sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxBOTTOM, 5);
sizer_right->Add(m_data_sizes, 0, wxEXPAND);
sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxTOP, space5);
sizer_right->AddStretchSpacer(1);
sizer_right->Add(boxButtons, 0, wxTOP | wxEXPAND, 5);
sizer_right->Add(m_label_scan_disabled, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, space5);
sizer_right->Add(boxButtons, 0, wxEXPAND | wxTOP, space5);
// main sizer
wxBoxSizer* const sizer_main = new wxBoxSizer(wxHORIZONTAL);
sizer_main->Add(sizer_left, 1, wxEXPAND | wxALL, 5);
sizer_main->Add(sizer_right, 0, wxEXPAND | wxALL, 5);
sizer_main->AddSpacer(space5);
sizer_main->Add(sizer_cheat_search_results, 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
sizer_main->AddSpacer(space5);
sizer_main->Add(sizer_right, 0, wxEXPAND | wxTOP | wxBOTTOM, space5);
sizer_main->AddSpacer(space5);
SetSizerAndFit(sizer_main);
}
void CheatSearchTab::UpdateGUI()
{
bool core_running = Core::IsRunning();
m_btn_init_scan->Enable(core_running);
m_btn_next_scan->Enable(core_running && m_scan_is_initialized);
m_label_scan_disabled->Show(!core_running);
Layout(); // Label shown/hidden may require layout adjustment
}
void CheatSearchTab::OnNewScanClicked(wxCommandEvent& WXUNUSED(event))
{
if (!Core::IsRunningAndStarted())
@ -136,6 +167,7 @@ void CheatSearchTab::OnNewScanClicked(wxCommandEvent& WXUNUSED(event))
m_search_results.reserve(Memory::RAM_SIZE / m_search_type_size);
// Enable the "Next Scan" button.
m_scan_is_initialized = true;
m_btn_next_scan->Enable();
CheatSearchResult r;
@ -183,6 +215,21 @@ void CheatSearchTab::OnCreateARCodeClicked(wxCommandEvent&)
arcode_dlg.ShowModal();
}
void CheatSearchTab::OnListViewItemActivated(wxListEvent&)
{
if (!m_btn_create_code->IsEnabled())
return;
wxCommandEvent fake(wxEVT_BUTTON, m_btn_create_code->GetId());
m_btn_create_code->GetEventHandler()->ProcessEvent(fake);
}
void CheatSearchTab::OnListViewItemSelected(wxListEvent&)
{
// Toggle "Create AR Code" Button
m_btn_create_code->Enable(m_lview_search_results->GetSelectedItemCount() > 0);
}
void CheatSearchTab::OnTimerUpdate(wxTimerEvent&)
{
if (Core::GetState() != Core::CORE_RUN)
@ -190,8 +237,8 @@ void CheatSearchTab::OnTimerUpdate(wxTimerEvent&)
// Only update the currently visible list rows.
long first = m_lview_search_results->GetTopItem();
long last =
std::min(m_lview_search_results->GetItemCount(), m_lview_search_results->GetCountPerPage());
long last = std::min<long>(m_lview_search_results->GetItemCount(),
first + m_lview_search_results->GetCountPerPage());
m_lview_search_results->Freeze();
@ -207,8 +254,8 @@ void CheatSearchTab::OnTimerUpdate(wxTimerEvent&)
void CheatSearchTab::UpdateCheatSearchResultsList()
{
m_update_timer.Stop();
m_lview_search_results->ClearAll();
ResetListViewColumns();
m_lview_search_results->DeleteAllItems();
m_btn_create_code->Disable();
wxString count_label = wxString::Format(_("Count: %lu"), (unsigned long)m_search_results.size());
if (m_search_results.size() > MAX_CHEAT_SEARCH_RESULTS_DISPLAY)
@ -312,14 +359,6 @@ void CheatSearchTab::FilterCheatSearchResults(u32 value, bool prev)
m_search_results.swap(filtered_results);
}
void CheatSearchTab::ResetListViewColumns()
{
m_lview_search_results->AppendColumn(_("Address"));
m_lview_search_results->AppendColumn(_("Value"));
m_lview_search_results->AppendColumn(_("Value (float)"));
m_lview_search_results->AppendColumn(_("Value (double)"));
}
bool CheatSearchTab::ParseUserEnteredValue(u32* out) const
{
unsigned long parsed_x_val = 0;

View File

@ -11,6 +11,7 @@
class wxButton;
class wxChoice;
class wxFocusEvent;
class wxListEvent;
class wxListView;
class wxRadioBox;
class wxRadioButton;
@ -22,6 +23,8 @@ class CheatSearchTab final : public wxPanel
public:
CheatSearchTab(wxWindow* const parent);
void UpdateGUI();
private:
class CheatSearchResult final
{
@ -34,25 +37,29 @@ private:
void UpdateCheatSearchResultsList();
void UpdateCheatSearchResultItem(long index);
void FilterCheatSearchResults(u32 value, bool prev);
void ResetListViewColumns();
bool ParseUserEnteredValue(u32* out) const;
u32 SwapValue(u32 value) const;
void OnNewScanClicked(wxCommandEvent&);
void OnNextScanClicked(wxCommandEvent&);
void OnCreateARCodeClicked(wxCommandEvent&);
void OnListViewItemActivated(wxListEvent&);
void OnListViewItemSelected(wxListEvent&);
void OnTimerUpdate(wxTimerEvent&);
std::vector<CheatSearchResult> m_search_results;
unsigned int m_search_type_size;
bool m_scan_is_initialized = false;
wxChoice* m_search_type;
wxListView* m_lview_search_results;
wxStaticText* m_label_results_count;
wxTextCtrl* m_textctrl_value_x;
wxButton* m_btn_create_code;
wxButton* m_btn_init_scan;
wxButton* m_btn_next_scan;
wxStaticText* m_label_scan_disabled;
wxRadioBox* m_data_sizes;

View File

@ -55,13 +55,15 @@ wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
wxDIALOG_NO_PARENT)
{
// Create the GUI controls
Init_ChildControls();
CreateGUI();
// load codes
UpdateGUI();
wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &wxCheatsWindow::OnLocalGameIniModified, this);
SetSize(wxSize(-1, 600));
SetIcons(WxUtils::GetDolphinIconBundle());
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
Center();
Show();
}
@ -71,8 +73,11 @@ wxCheatsWindow::~wxCheatsWindow()
main_frame->g_CheatsWindow = nullptr;
}
void wxCheatsWindow::Init_ChildControls()
void wxCheatsWindow::CreateGUI()
{
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
// Main Notebook
m_notebook_main = new wxNotebook(this, wxID_ANY);
@ -84,13 +89,15 @@ void wxCheatsWindow::Init_ChildControls()
new ActionReplayCodesPanel(tab_cheats, ActionReplayCodesPanel::STYLE_SIDE_PANEL |
ActionReplayCodesPanel::STYLE_MODIFY_BUTTONS);
wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxHORIZONTAL);
sizer_tab_cheats->Add(m_ar_codes_panel, 1, wxEXPAND | wxALL, 5);
wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxVERTICAL);
sizer_tab_cheats->AddSpacer(space5);
sizer_tab_cheats->Add(m_ar_codes_panel, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer_tab_cheats->AddSpacer(space5);
tab_cheats->SetSizerAndFit(sizer_tab_cheats);
// Cheat Search Tab
wxPanel* const tab_cheat_search = new CheatSearchTab(m_notebook_main);
m_tab_cheat_search = new CheatSearchTab(m_notebook_main);
// Log Tab
m_tab_log = new wxPanel(m_notebook_main, wxID_ANY);
@ -105,25 +112,30 @@ void wxCheatsWindow::Init_ChildControls()
&wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange, this);
m_checkbox_log_ar->SetValue(ActionReplay::IsSelfLogging());
m_textctrl_log = new wxTextCtrl(m_tab_log, wxID_ANY, "", wxDefaultPosition, wxSize(100, -1),
wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
m_textctrl_log = new wxTextCtrl(m_tab_log, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
wxBoxSizer* HStrip1 = new wxBoxSizer(wxHORIZONTAL);
HStrip1->Add(m_checkbox_log_ar, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
HStrip1->Add(button_updatelog, 0, wxALL, 5);
HStrip1->Add(button_clearlog, 0, wxALL, 5);
wxBoxSizer* log_control_sizer = new wxBoxSizer(wxHORIZONTAL);
log_control_sizer->Add(m_checkbox_log_ar, 0, wxALIGN_CENTER_VERTICAL);
log_control_sizer->Add(button_updatelog, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space10);
log_control_sizer->Add(button_clearlog, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space10);
wxBoxSizer* sTabLog = new wxBoxSizer(wxVERTICAL);
sTabLog->Add(HStrip1, 0, wxALL, 5);
sTabLog->Add(m_textctrl_log, 1, wxALL | wxEXPAND, 5);
sTabLog->AddSpacer(space5);
sTabLog->Add(log_control_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space10);
sTabLog->AddSpacer(space5);
sTabLog->Add(m_textctrl_log, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sTabLog->AddSpacer(space5);
m_tab_log->SetSizerAndFit(sTabLog);
// Gecko tab
m_geckocode_panel = new Gecko::CodeConfigPanel(m_notebook_main);
// Add Tabs to Notebook
m_notebook_main->AddPage(tab_cheats, _("AR Codes"));
m_geckocode_panel = new Gecko::CodeConfigPanel(m_notebook_main);
m_notebook_main->AddPage(m_geckocode_panel, _("Gecko Codes"));
m_notebook_main->AddPage(tab_cheat_search, _("Cheat Search"));
m_notebook_main->AddPage(m_tab_cheat_search, _("Cheat Search"));
m_notebook_main->AddPage(m_tab_log, _("Logging"));
Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ApplyChanges_Press, this, wxID_APPLY);
@ -137,18 +149,23 @@ void wxCheatsWindow::Init_ChildControls()
SetAffirmativeId(wxID_CANCEL);
wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
sMain->Add(m_notebook_main, 1, wxEXPAND | wxALL, 5);
sMain->Add(sButtons, 0, wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 5);
sMain->AddSpacer(space5);
sMain->Add(m_notebook_main, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->AddSpacer(space5);
sMain->Add(sButtons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->AddSpacer(space5);
sMain->SetMinSize(FromDIP(wxSize(-1, 600)));
SetSizerAndFit(sMain);
}
void wxCheatsWindow::OnEvent_ButtonClose_Press(wxCommandEvent& WXUNUSED(event))
void wxCheatsWindow::OnEvent_ButtonClose_Press(wxCommandEvent&)
{
Close();
}
void wxCheatsWindow::OnEvent_Close(wxCloseEvent& ev)
void wxCheatsWindow::OnEvent_Close(wxCloseEvent&)
{
// This dialog is created on the heap instead of the stack so we have to destroy ourself.
Destroy();
}
@ -164,6 +181,7 @@ void wxCheatsWindow::UpdateGUI()
m_gameini_local_path = File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini";
Load_ARCodes();
Load_GeckoCodes();
m_tab_cheat_search->UpdateGUI();
// enable controls
m_button_apply->Enable(Core::IsRunning());
@ -194,8 +212,7 @@ void wxCheatsWindow::Load_ARCodes()
void wxCheatsWindow::Load_GeckoCodes()
{
m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local,
SConfig::GetInstance().GetUniqueID(), true);
m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, m_game_id, true);
}
void wxCheatsWindow::OnNewARCodeCreated(wxCommandEvent& ev)
@ -243,7 +260,7 @@ void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev)
ev.Skip();
}
void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent& WXUNUSED(event))
void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent&)
{
wxBeginBusyCursor();
m_textctrl_log->Freeze();
@ -284,7 +301,7 @@ void wxCheatsWindow::OnClearActionReplayLog(wxCommandEvent& event)
OnEvent_ButtonUpdateLog_Press(event);
}
void wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& WXUNUSED(event))
void wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent&)
{
ActionReplay::EnableSelfLogging(m_checkbox_log_ar->IsChecked());
}

View File

@ -7,13 +7,13 @@
#include <cstddef>
#include <string>
#include <vector>
#include <wx/arrstr.h>
#include <wx/dialog.h>
#include <wx/panel.h>
#include "Common/CommonTypes.h"
#include "Common/IniFile.h"
class CheatSearchTab;
class wxButton;
class wxCheckBox;
class wxNotebook;
@ -41,6 +41,7 @@ private:
wxButton* m_button_apply;
wxNotebook* m_notebook_main;
CheatSearchTab* m_tab_cheat_search;
wxPanel* m_tab_log;
wxCheckBox* m_checkbox_log_ar;
@ -57,7 +58,7 @@ private:
bool m_ignore_ini_callback = false;
void Init_ChildControls();
void CreateGUI();
void Load_ARCodes();
void Load_GeckoCodes();

View File

@ -19,8 +19,8 @@ CreateCodeDialog::CreateCodeDialog(wxWindow* const parent, const u32 address)
: wxDialog(parent, wxID_ANY, _("Create AR Code")), m_code_address(address)
{
wxStaticText* const label_name = new wxStaticText(this, wxID_ANY, _("Name: "));
m_textctrl_name =
new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(256, -1));
m_textctrl_name = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDLG_UNIT(this, wxSize(180, -1)));
wxStaticText* const label_code = new wxStaticText(this, wxID_ANY, _("Code: "));
m_textctrl_code = new wxTextCtrl(this, wxID_ANY, wxString::Format("0x%08x", address));
@ -33,22 +33,31 @@ CreateCodeDialog::CreateCodeDialog(wxWindow* const parent, const u32 address)
m_checkbox_use_hex->SetValue(true);
wxBoxSizer* const sizer_value_label = new wxBoxSizer(wxHORIZONTAL);
sizer_value_label->Add(label_value, 0, wxRIGHT, 5);
sizer_value_label->Add(m_checkbox_use_hex);
const int space5 = FromDIP(5);
sizer_value_label->Add(label_value);
sizer_value_label->Add(m_checkbox_use_hex, 0, wxLEFT, space5);
// main sizer
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
sizer_main->Add(label_name, 0, wxALL, 5);
sizer_main->Add(m_textctrl_name, 0, wxALL, 5);
sizer_main->Add(label_code, 0, wxALL, 5);
sizer_main->Add(m_textctrl_code, 0, wxALL, 5);
sizer_main->Add(sizer_value_label, 0, wxALL, 5);
sizer_main->Add(m_textctrl_value, 0, wxALL, 5);
sizer_main->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxALL, 5);
sizer_main->AddSpacer(space5);
sizer_main->Add(label_name, 0, wxLEFT | wxRIGHT, space5);
sizer_main->AddSpacer(space5);
sizer_main->Add(m_textctrl_name, 0, wxLEFT | wxRIGHT, space5);
sizer_main->AddSpacer(space5);
sizer_main->Add(label_code, 0, wxLEFT | wxRIGHT, space5);
sizer_main->AddSpacer(space5);
sizer_main->Add(m_textctrl_code, 0, wxLEFT | wxRIGHT, space5);
sizer_main->AddSpacer(space5);
sizer_main->Add(sizer_value_label, 0, wxLEFT | wxRIGHT, space5);
sizer_main->AddSpacer(space5);
sizer_main->Add(m_textctrl_value, 0, wxLEFT | wxRIGHT, space5);
sizer_main->AddSpacer(space5);
sizer_main->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT,
space5);
sizer_main->AddSpacer(space5);
// NOTE: Use default wxCANCEL handling.
Bind(wxEVT_BUTTON, &CreateCodeDialog::PressOK, this, wxID_OK);
Bind(wxEVT_BUTTON, &CreateCodeDialog::PressCancel, this, wxID_CANCEL);
Bind(wxEVT_CLOSE_WINDOW, &CreateCodeDialog::OnEvent_Close, this);
SetSizerAndFit(sizer_main);
SetFocus();
@ -82,15 +91,6 @@ void CreateCodeDialog::PressOK(wxCommandEvent& ev)
add_event.SetClientData(&new_cheat);
GetParent()->GetEventHandler()->ProcessEvent(add_event);
Close();
}
void CreateCodeDialog::PressCancel(wxCommandEvent& ev)
{
Close();
}
void CreateCodeDialog::OnEvent_Close(wxCloseEvent& ev)
{
Destroy();
// Allow base class to process. wxDialog will set the return code and hide the window.
ev.Skip();
}

View File

@ -26,6 +26,4 @@ private:
wxCheckBox* m_checkbox_use_hex;
void PressOK(wxCommandEvent&);
void PressCancel(wxCommandEvent&);
void OnEvent_Close(wxCloseEvent& ev);
};

View File

@ -27,8 +27,9 @@ wxDEFINE_EVENT(DOLPHIN_EVT_GECKOCODE_TOGGLED, wxCommandEvent);
namespace Gecko
{
static const wxString wxstr_name(wxTRANSLATE("Name: ")), wxstr_notes(wxTRANSLATE("Notes: ")),
wxstr_creator(wxTRANSLATE("Creator: "));
static const char str_name[] = wxTRANSLATE("Name: ");
static const char str_notes[] = wxTRANSLATE("Notes: ");
static const char str_creator[] = wxTRANSLATE("Creator: ");
CodeConfigPanel::CodeConfigPanel(wxWindow* const parent) : wxPanel(parent)
{
@ -36,40 +37,41 @@ CodeConfigPanel::CodeConfigPanel(wxWindow* const parent) : wxPanel(parent)
m_listbox_gcodes->Bind(wxEVT_LISTBOX, &CodeConfigPanel::UpdateInfoBox, this);
m_listbox_gcodes->Bind(wxEVT_CHECKLISTBOX, &CodeConfigPanel::ToggleCode, this);
m_infobox.label_name = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_name));
m_infobox.label_creator = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_creator));
m_infobox.label_notes = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_notes));
m_infobox.label_name = new wxStaticText(this, wxID_ANY, wxGetTranslation(str_name));
m_infobox.label_creator = new wxStaticText(this, wxID_ANY, wxGetTranslation(str_creator));
m_infobox.label_notes = new wxStaticText(this, wxID_ANY, wxGetTranslation(str_notes));
m_infobox.textctrl_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxSize(64, -1), wxTE_MULTILINE | wxTE_READONLY);
m_infobox.listbox_codes = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 64));
wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);
m_infobox.listbox_codes =
new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(-1, 48)));
// TODO: buttons to add/edit codes
// sizers
const int space5 = FromDIP(5);
wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL);
sizer_infobox->Add(m_infobox.label_name, 0, wxBOTTOM, 5);
sizer_infobox->Add(m_infobox.label_creator, 0, wxBOTTOM, 5);
sizer_infobox->Add(m_infobox.label_notes, 0, wxBOTTOM, 5);
sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxBOTTOM | wxEXPAND, 5);
sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND, 5);
sizer_infobox->Add(m_infobox.label_name);
sizer_infobox->Add(m_infobox.label_creator, 0, wxTOP, space5);
sizer_infobox->Add(m_infobox.label_notes, 0, wxTOP, space5);
sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxEXPAND | wxTOP, space5);
sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND | wxTOP, space5);
// button sizer
wxBoxSizer* const sizer_buttons = new wxBoxSizer(wxHORIZONTAL);
btn_download = new wxButton(this, wxID_ANY, _("Download Codes (WiiRD Database)"),
wxDefaultPosition, wxSize(128, -1));
btn_download = new wxButton(this, wxID_ANY, _("Download Codes (WiiRD Database)"));
btn_download->Disable();
btn_download->Bind(wxEVT_BUTTON, &CodeConfigPanel::DownloadCodes, this);
sizer_buttons->AddStretchSpacer(1);
sizer_buttons->Add(btn_download, 1, wxEXPAND);
// horizontal sizer
wxBoxSizer* const sizer_vert = new wxBoxSizer(wxVERTICAL);
sizer_vert->Add(sizer_infobox, 1, wxEXPAND);
sizer_vert->Add(sizer_buttons, 0, wxEXPAND | wxTOP, 5);
sizer_buttons->Add(WxUtils::GiveMinSizeDIP(btn_download, wxSize(128, -1)), 1, wxEXPAND);
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5);
sizer_main->Add(sizer_vert, 0, wxALL | wxEXPAND, 5);
sizer_main->AddSpacer(space5);
sizer_main->Add(m_listbox_gcodes, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer_main->AddSpacer(space5);
sizer_main->Add(sizer_infobox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer_main->AddSpacer(space5);
sizer_main->Add(sizer_buttons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer_main->AddSpacer(space5);
SetSizerAndFit(sizer_main);
}
@ -83,7 +85,7 @@ void CodeConfigPanel::UpdateCodeList(bool checkRunning)
// add the codes to the listbox
for (const GeckoCode& code : m_gcodes)
{
m_listbox_gcodes->Append(StrToWxStr(code.name));
m_listbox_gcodes->Append(m_listbox_gcodes->EscapeMnemonics(StrToWxStr(code.name)));
if (code.enabled)
{
m_listbox_gcodes->Check(m_listbox_gcodes->GetCount() - 1, true);
@ -126,7 +128,7 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
if (sel > -1)
{
m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + StrToWxStr(m_gcodes[sel].name));
m_infobox.label_name->SetLabel(wxGetTranslation(str_name) + StrToWxStr(m_gcodes[sel].name));
// notes textctrl
m_infobox.textctrl_notes->Clear();
@ -136,7 +138,7 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
}
m_infobox.textctrl_notes->ScrollLines(-99); // silly
m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) +
m_infobox.label_creator->SetLabel(wxGetTranslation(str_creator) +
StrToWxStr(m_gcodes[sel].creator));
// add codes to info listbox
@ -147,9 +149,9 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
}
else
{
m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name));
m_infobox.label_name->SetLabel(wxGetTranslation(str_name));
m_infobox.textctrl_notes->Clear();
m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator));
m_infobox.label_creator->SetLabel(wxGetTranslation(str_creator));
}
}

View File

@ -7,9 +7,7 @@
#include <wx/checkbox.h>
#include <wx/datectrl.h>
#include <wx/dateevt.h>
#include <wx/gbsizer.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/stattext.h>
#include <wx/time.h>
#include <wx/timectrl.h>
@ -17,6 +15,7 @@
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "DolphinWX/Config/AdvancedConfigPane.h"
#include "DolphinWX/DolphinSlider.h"
AdvancedConfigPane::AdvancedConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
{
@ -29,7 +28,7 @@ void AdvancedConfigPane::InitializeGUI()
{
m_clock_override_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable CPU Clock Override"));
m_clock_override_slider =
new wxSlider(this, wxID_ANY, 100, 0, 150, wxDefaultPosition, wxSize(200, -1));
new DolphinSlider(this, wxID_ANY, 100, 0, 150, wxDefaultPosition, FromDIP(wxSize(200, -1)));
m_clock_override_text = new wxStaticText(this, wxID_ANY, "");
m_clock_override_checkbox->Bind(wxEVT_CHECKBOX,
@ -67,47 +66,47 @@ void AdvancedConfigPane::InitializeGUI()
clock_override_description->Wrap(550);
custom_rtc_description->Wrap(550);
#else
clock_override_description->Wrap(400);
custom_rtc_description->Wrap(400);
clock_override_description->Wrap(FromDIP(400));
custom_rtc_description->Wrap(FromDIP(400));
#endif
wxBoxSizer* const clock_override_checkbox_sizer = new wxBoxSizer(wxHORIZONTAL);
clock_override_checkbox_sizer->Add(m_clock_override_checkbox, 1, wxALL, 5);
const int space5 = FromDIP(5);
wxBoxSizer* const clock_override_slider_sizer = new wxBoxSizer(wxHORIZONTAL);
clock_override_slider_sizer->Add(m_clock_override_slider, 1, wxALL, 5);
clock_override_slider_sizer->Add(m_clock_override_text, 1, wxALL, 5);
wxBoxSizer* const clock_override_description_sizer = new wxBoxSizer(wxHORIZONTAL);
clock_override_description_sizer->Add(clock_override_description, 1, wxALL, 5);
clock_override_slider_sizer->Add(m_clock_override_slider, 1);
clock_override_slider_sizer->Add(m_clock_override_text, 1, wxLEFT, space5);
wxStaticBoxSizer* const cpu_options_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("CPU Options"));
cpu_options_sizer->Add(clock_override_checkbox_sizer);
cpu_options_sizer->Add(clock_override_slider_sizer);
cpu_options_sizer->Add(clock_override_description_sizer);
cpu_options_sizer->AddSpacer(space5);
cpu_options_sizer->Add(m_clock_override_checkbox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
cpu_options_sizer->AddSpacer(space5);
cpu_options_sizer->Add(clock_override_slider_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
cpu_options_sizer->AddSpacer(space5);
cpu_options_sizer->Add(clock_override_description, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
cpu_options_sizer->AddSpacer(space5);
wxBoxSizer* const custom_rtc_checkbox_sizer = new wxBoxSizer(wxHORIZONTAL);
custom_rtc_checkbox_sizer->Add(m_custom_rtc_checkbox, 1, wxALL, 5);
wxGridBagSizer* const custom_rtc_date_time_sizer = new wxGridBagSizer();
custom_rtc_date_time_sizer->Add(m_custom_rtc_date_picker, wxGBPosition(0, 0), wxDefaultSpan,
wxEXPAND | wxALL, 5);
custom_rtc_date_time_sizer->Add(m_custom_rtc_time_picker, wxGBPosition(0, 1), wxDefaultSpan,
wxEXPAND | wxALL, 5);
wxBoxSizer* const custom_rtc_description_sizer = new wxBoxSizer(wxHORIZONTAL);
custom_rtc_description_sizer->Add(custom_rtc_description, 1, wxALL, 5);
wxFlexGridSizer* const custom_rtc_date_time_sizer =
new wxFlexGridSizer(2, wxSize(space5, space5));
custom_rtc_date_time_sizer->Add(m_custom_rtc_date_picker, 0, wxEXPAND);
custom_rtc_date_time_sizer->Add(m_custom_rtc_time_picker, 0, wxEXPAND);
wxStaticBoxSizer* const custom_rtc_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Custom RTC Options"));
custom_rtc_sizer->Add(custom_rtc_checkbox_sizer);
custom_rtc_sizer->Add(custom_rtc_date_time_sizer);
custom_rtc_sizer->Add(custom_rtc_description_sizer);
custom_rtc_sizer->AddSpacer(space5);
custom_rtc_sizer->Add(m_custom_rtc_checkbox, 0, wxLEFT | wxRIGHT, space5);
custom_rtc_sizer->AddSpacer(space5);
custom_rtc_sizer->Add(custom_rtc_date_time_sizer, 0, wxLEFT | wxRIGHT, space5);
custom_rtc_sizer->AddSpacer(space5);
custom_rtc_sizer->Add(custom_rtc_description, 0, wxLEFT | wxRIGHT, space5);
custom_rtc_sizer->AddSpacer(space5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(cpu_options_sizer, 0, wxEXPAND | wxALL, 5);
main_sizer->Add(custom_rtc_sizer, 0, wxEXPAND | wxALL, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(cpu_options_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(custom_rtc_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
SetSizer(main_sizer);
}

View File

@ -6,9 +6,9 @@
#include <wx/panel.h>
class DolphinSlider;
class wxCheckBox;
class wxDatePickerCtrl;
class wxSlider;
class wxStaticText;
class wxTimePickerCtrl;
@ -37,7 +37,7 @@ private:
u32 m_temp_time;
wxCheckBox* m_clock_override_checkbox;
wxSlider* m_clock_override_slider;
DolphinSlider* m_clock_override_slider;
wxStaticText* m_clock_override_text;
wxCheckBox* m_custom_rtc_checkbox;
wxDatePickerCtrl* m_custom_rtc_date_picker;

View File

@ -9,7 +9,6 @@
#include <wx/gbsizer.h>
#include <wx/radiobox.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/spinctrl.h>
#include <wx/stattext.h>
@ -18,6 +17,7 @@
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "DolphinWX/Config/AudioConfigPane.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/WxUtils.h"
AudioConfigPane::AudioConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
@ -37,8 +37,8 @@ void AudioConfigPane::InitializeGUI()
new wxRadioBox(this, wxID_ANY, _("DSP Emulator Engine"), wxDefaultPosition, wxDefaultSize,
m_dsp_engine_strings, 0, wxRA_SPECIFY_ROWS);
m_dpl2_decoder_checkbox = new wxCheckBox(this, wxID_ANY, _("Dolby Pro Logic II decoder"));
m_volume_slider = new wxSlider(this, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize,
wxSL_VERTICAL | wxSL_INVERSE);
m_volume_slider = new DolphinSlider(this, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize,
wxSL_VERTICAL | wxSL_INVERSE);
m_volume_text = new wxStaticText(this, wxID_ANY, "");
m_audio_backend_choice =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_audio_backend_strings);
@ -64,34 +64,51 @@ void AudioConfigPane::InitializeGUI()
_("Enables Dolby Pro Logic II emulation using 5.1 surround. OpenAL or Pulse backends only."));
#endif
const int space5 = FromDIP(5);
wxStaticBoxSizer* const dsp_engine_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Sound Settings"));
dsp_engine_sizer->Add(m_dsp_engine_radiobox, 0, wxALL | wxEXPAND, 5);
dsp_engine_sizer->Add(m_dpl2_decoder_checkbox, 0, wxALL, 5);
dsp_engine_sizer->Add(m_dsp_engine_radiobox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
dsp_engine_sizer->AddSpacer(space5);
dsp_engine_sizer->AddStretchSpacer();
dsp_engine_sizer->Add(m_dpl2_decoder_checkbox, 0, wxLEFT | wxRIGHT, space5);
dsp_engine_sizer->AddStretchSpacer();
dsp_engine_sizer->AddSpacer(space5);
wxStaticBoxSizer* const volume_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Volume"));
volume_sizer->Add(m_volume_slider, 1, wxLEFT | wxRIGHT, 13);
volume_sizer->Add(m_volume_text, 0, wxALIGN_CENTER | wxALL, 5);
volume_sizer->Add(m_volume_slider, 1, wxALIGN_CENTER_HORIZONTAL);
volume_sizer->Add(m_volume_text, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space5);
volume_sizer->AddSpacer(space5);
wxGridBagSizer* const backend_grid_sizer = new wxGridBagSizer();
wxGridBagSizer* const backend_grid_sizer = new wxGridBagSizer(space5, space5);
backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Audio Backend:")), wxGBPosition(0, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
backend_grid_sizer->Add(m_audio_backend_choice, wxGBPosition(0, 1), wxDefaultSpan, wxALL, 5);
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
backend_grid_sizer->Add(m_audio_backend_choice, wxGBPosition(0, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Latency:")), wxGBPosition(1, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
backend_grid_sizer->Add(m_audio_latency_spinctrl, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5);
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
backend_grid_sizer->Add(m_audio_latency_spinctrl, wxGBPosition(1, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
wxStaticBoxSizer* const backend_static_box_sizer =
new wxStaticBoxSizer(wxHORIZONTAL, this, _("Backend Settings"));
backend_static_box_sizer->Add(backend_grid_sizer, 0, wxEXPAND);
new wxStaticBoxSizer(wxVERTICAL, this, _("Backend Settings"));
backend_static_box_sizer->AddSpacer(space5);
backend_static_box_sizer->Add(backend_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
backend_static_box_sizer->AddSpacer(space5);
wxBoxSizer* const dsp_audio_sizer = new wxBoxSizer(wxHORIZONTAL);
dsp_audio_sizer->Add(dsp_engine_sizer, 1, wxEXPAND | wxALL, 5);
dsp_audio_sizer->Add(volume_sizer, 0, wxEXPAND | wxALL, 5);
dsp_audio_sizer->AddSpacer(space5);
dsp_audio_sizer->Add(dsp_engine_sizer, 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
dsp_audio_sizer->AddSpacer(space5);
dsp_audio_sizer->Add(volume_sizer, 0, wxEXPAND | wxTOP | wxBOTTOM, space5);
dsp_audio_sizer->AddSpacer(space5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(dsp_audio_sizer, 0, wxALL | wxEXPAND);
main_sizer->Add(backend_static_box_sizer, 0, wxALL | wxEXPAND, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(dsp_audio_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(backend_static_box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
SetSizerAndFit(main_sizer);
}
@ -180,10 +197,10 @@ void AudioConfigPane::PopulateBackendChoiceBox()
for (const std::string& backend : AudioCommon::GetSoundBackends())
{
m_audio_backend_choice->Append(wxGetTranslation(StrToWxStr(backend)));
int num = m_audio_backend_choice->FindString(StrToWxStr(SConfig::GetInstance().sBackend));
m_audio_backend_choice->SetSelection(num);
}
int num = m_audio_backend_choice->FindString(StrToWxStr(SConfig::GetInstance().sBackend));
m_audio_backend_choice->SetSelection(num);
}
bool AudioConfigPane::SupportsVolumeChanges(const std::string& backend)

View File

@ -8,10 +8,10 @@
#include <wx/arrstr.h>
#include <wx/panel.h>
class DolphinSlider;
class wxCheckBox;
class wxChoice;
class wxRadioBox;
class wxSlider;
class wxSpinCtrl;
class wxStaticText;
@ -39,7 +39,7 @@ private:
wxRadioBox* m_dsp_engine_radiobox;
wxCheckBox* m_dpl2_decoder_checkbox;
wxSlider* m_volume_slider;
DolphinSlider* m_volume_slider;
wxStaticText* m_volume_text;
wxChoice* m_audio_backend_choice;
wxSpinCtrl* m_audio_latency_spinctrl;

View File

@ -76,16 +76,23 @@ void CConfigMain::CreateGUIControls()
Notebook->AddPage(path_pane, _("Paths"));
Notebook->AddPage(advanced_pane, _("Advanced"));
const int space5 = FromDIP(5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(Notebook, 1, wxEXPAND | wxALL, 5);
main_sizer->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(Notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
#ifdef __APPLE__
main_sizer->SetMinSize(550, 0);
#else
main_sizer->SetMinSize(400, 0);
main_sizer->SetMinSize(FromDIP(400), 0);
#endif
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(main_sizer);
Center();
SetFocus();

View File

@ -15,10 +15,8 @@ wxDEFINE_EVENT(wxEVT_ADAPTER_UPDATE, wxCommandEvent);
GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString& name,
const int tab_num)
: wxDialog(parent, wxID_ANY, name, wxPoint(128, -1)), m_pad_id(tab_num)
: wxDialog(parent, wxID_ANY, name), m_pad_id(tab_num)
{
wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Rumble"));
gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble[m_pad_id]);
gamecube_rumble->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterRumble, this);
@ -43,12 +41,16 @@ GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString&
}
GCAdapter::SetAdapterCallback(std::bind(&GCAdapterConfigDiag::ScheduleAdapterUpdate, this));
const int space5 = FromDIP(5);
wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
szr->Add(m_adapter_status, 0, wxEXPAND);
szr->Add(gamecube_rumble, 0, wxEXPAND);
szr->Add(gamecube_konga, 0, wxEXPAND);
szr->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxALL, 5);
szr->AddSpacer(space5);
szr->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr->AddSpacer(space5);
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetSizerAndFit(szr);
Center();

View File

@ -100,42 +100,51 @@ void GameCubeConfigPane::InitializeGUI()
new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
m_memcard_path[1]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotBButtonClick, this);
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
// Populate the GameCube page
wxGridBagSizer* const sGamecubeIPLSettings = new wxGridBagSizer();
sGamecubeIPLSettings->Add(m_skip_bios_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2), wxALL, 5);
wxGridBagSizer* const sGamecubeIPLSettings = new wxGridBagSizer(space5, space5);
sGamecubeIPLSettings->Add(m_skip_bios_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2));
sGamecubeIPLSettings->Add(new wxStaticText(this, wxID_ANY, _("System Language:")),
wxGBPosition(1, 0), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, 5);
wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
sGamecubeIPLSettings->Add(m_system_lang_choice, wxGBPosition(1, 1), wxDefaultSpan,
wxLEFT | wxRIGHT | wxBOTTOM, 5);
sGamecubeIPLSettings->Add(m_override_lang_checkbox, wxGBPosition(2, 0), wxGBSpan(1, 2), wxALL, 5);
wxALIGN_CENTER_VERTICAL);
sGamecubeIPLSettings->Add(m_override_lang_checkbox, wxGBPosition(2, 0), wxGBSpan(1, 2));
wxStaticBoxSizer* const sbGamecubeIPLSettings =
new wxStaticBoxSizer(wxVERTICAL, this, _("IPL Settings"));
sbGamecubeIPLSettings->Add(sGamecubeIPLSettings);
sbGamecubeIPLSettings->AddSpacer(space5);
sbGamecubeIPLSettings->Add(sGamecubeIPLSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbGamecubeIPLSettings->AddSpacer(space5);
wxStaticBoxSizer* const sbGamecubeDeviceSettings =
new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings"));
wxGridBagSizer* const sbGamecubeEXIDevSettings = new wxGridBagSizer(10, 10);
wxGridBagSizer* const gamecube_EXIDev_sizer = new wxGridBagSizer(space10, space10);
for (int i = 0; i < 3; ++i)
{
sbGamecubeEXIDevSettings->Add(GCEXIDeviceText[i], wxGBPosition(i, 0), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
sbGamecubeEXIDevSettings->Add(m_exi_devices[i], wxGBPosition(i, 1),
wxGBSpan(1, (i < 2) ? 1 : 2), wxALIGN_CENTER_VERTICAL);
gamecube_EXIDev_sizer->Add(GCEXIDeviceText[i], wxGBPosition(i, 0), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
gamecube_EXIDev_sizer->Add(m_exi_devices[i], wxGBPosition(i, 1), wxGBSpan(1, (i < 2) ? 1 : 2),
wxALIGN_CENTER_VERTICAL);
if (i < 2)
sbGamecubeEXIDevSettings->Add(m_memcard_path[i], wxGBPosition(i, 2), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
gamecube_EXIDev_sizer->Add(m_memcard_path[i], wxGBPosition(i, 2), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
if (NetPlay::IsNetPlayRunning())
m_exi_devices[i]->Disable();
}
sbGamecubeDeviceSettings->Add(sbGamecubeEXIDevSettings, 0, wxALL, 5);
sbGamecubeDeviceSettings->AddSpacer(space5);
sbGamecubeDeviceSettings->Add(gamecube_EXIDev_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbGamecubeDeviceSettings->AddSpacer(space5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(sbGamecubeIPLSettings, 0, wxEXPAND | wxALL, 5);
main_sizer->Add(sbGamecubeDeviceSettings, 0, wxEXPAND | wxALL, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(sbGamecubeIPLSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(sbGamecubeDeviceSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
SetSizer(main_sizer);
}

View File

@ -101,32 +101,51 @@ void GeneralConfigPane::InitializeGUI()
m_throttler_choice->Bind(wxEVT_CHOICE, &GeneralConfigPane::OnThrottlerChoiceChanged, this);
m_cpu_engine_radiobox->Bind(wxEVT_RADIOBOX, &GeneralConfigPane::OnCPUEngineRadioBoxChanged, this);
const int space5 = FromDIP(5);
wxBoxSizer* const throttler_sizer = new wxBoxSizer(wxHORIZONTAL);
throttler_sizer->AddSpacer(space5);
throttler_sizer->Add(new wxStaticText(this, wxID_ANY, _("Speed Limit:")), 0,
wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, 5);
throttler_sizer->Add(m_throttler_choice, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
wxALIGN_CENTER_VERTICAL | wxBOTTOM, space5);
throttler_sizer->AddSpacer(space5);
throttler_sizer->Add(m_throttler_choice, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM, space5);
throttler_sizer->AddSpacer(space5);
wxStaticBoxSizer* const basic_settings_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Basic Settings"));
basic_settings_sizer->Add(m_dual_core_checkbox, 0, wxALL, 5);
basic_settings_sizer->Add(m_idle_skip_checkbox, 0, wxALL, 5);
basic_settings_sizer->Add(m_cheats_checkbox, 0, wxALL, 5);
basic_settings_sizer->AddSpacer(space5);
basic_settings_sizer->Add(m_dual_core_checkbox, 0, wxLEFT | wxRIGHT, space5);
basic_settings_sizer->AddSpacer(space5);
basic_settings_sizer->Add(m_idle_skip_checkbox, 0, wxLEFT | wxRIGHT, space5);
basic_settings_sizer->AddSpacer(space5);
basic_settings_sizer->Add(m_cheats_checkbox, 0, wxLEFT | wxRIGHT, space5);
basic_settings_sizer->AddSpacer(space5);
basic_settings_sizer->Add(throttler_sizer);
wxStaticBoxSizer* const analytics_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Usage Statistics Reporting Settings"));
analytics_sizer->Add(m_analytics_checkbox, 0, wxALL, 5);
analytics_sizer->Add(m_analytics_new_id, 0, wxALL, 5);
analytics_sizer->AddSpacer(space5);
analytics_sizer->Add(m_analytics_checkbox, 0, wxLEFT | wxRIGHT, space5);
analytics_sizer->AddSpacer(space5);
analytics_sizer->Add(m_analytics_new_id, 0, wxLEFT | wxRIGHT, space5);
analytics_sizer->AddSpacer(space5);
wxStaticBoxSizer* const advanced_settings_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Advanced Settings"));
advanced_settings_sizer->Add(m_cpu_engine_radiobox, 0, wxALL, 5);
advanced_settings_sizer->Add(m_force_ntscj_checkbox, 0, wxALL, 5);
advanced_settings_sizer->AddSpacer(space5);
advanced_settings_sizer->Add(m_cpu_engine_radiobox, 0, wxLEFT | wxRIGHT, space5);
advanced_settings_sizer->AddSpacer(space5);
advanced_settings_sizer->Add(m_force_ntscj_checkbox, 0, wxLEFT | wxRIGHT, space5);
advanced_settings_sizer->AddSpacer(space5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(basic_settings_sizer, 0, wxEXPAND | wxALL, 5);
main_sizer->Add(analytics_sizer, 0, wxEXPAND | wxALL, 5);
main_sizer->Add(advanced_settings_sizer, 0, wxEXPAND | wxALL, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(basic_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(analytics_sizer, 0, wxEXPAND | wxLEFT | wxLEFT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(advanced_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
SetSizer(main_sizer);
}

View File

@ -11,6 +11,7 @@
#include <wx/choice.h>
#include <wx/gbsizer.h>
#include <wx/language.h>
#include <wx/msgdlg.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
@ -30,7 +31,7 @@
#include "DolphinWX/X11Utils.h"
#endif
static const std::array<std::string, 29> language_ids = {{
static const std::array<std::string, 29> language_ids{{
"",
"ms", "ca", "cs", "da", "de", "en", "es", "fr", "hr", "it", "hu", "nl",
@ -115,27 +116,36 @@ void InterfaceConfigPane::InitializeGUI()
m_interface_lang_choice->SetToolTip(
_("Change the language of the user interface.\nRequires restart."));
wxGridBagSizer* const language_and_theme_grid_sizer = new wxGridBagSizer();
const int space5 = FromDIP(5);
wxGridBagSizer* const language_and_theme_grid_sizer = new wxGridBagSizer(space5, space5);
language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Language:")),
wxGBPosition(0, 0), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL | wxALL, 5);
wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
language_and_theme_grid_sizer->Add(m_interface_lang_choice, wxGBPosition(0, 1), wxDefaultSpan,
wxALL, 5);
wxALIGN_CENTER_VERTICAL);
language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Theme:")),
wxGBPosition(1, 0), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL | wxALL, 5);
language_and_theme_grid_sizer->Add(m_theme_choice, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5);
wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
language_and_theme_grid_sizer->Add(m_theme_choice, wxGBPosition(1, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
wxStaticBoxSizer* const main_static_box_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Interface Settings"));
main_static_box_sizer->Add(m_confirm_stop_checkbox, 0, wxALL, 5);
main_static_box_sizer->Add(m_panic_handlers_checkbox, 0, wxALL, 5);
main_static_box_sizer->Add(m_osd_messages_checkbox, 0, wxALL, 5);
main_static_box_sizer->Add(m_pause_focus_lost_checkbox, 0, wxALL, 5);
main_static_box_sizer->Add(language_and_theme_grid_sizer, 0, wxEXPAND | wxALL, 0);
main_static_box_sizer->AddSpacer(space5);
main_static_box_sizer->Add(m_confirm_stop_checkbox, 0, wxLEFT | wxRIGHT, space5);
main_static_box_sizer->AddSpacer(space5);
main_static_box_sizer->Add(m_panic_handlers_checkbox, 0, wxLEFT | wxRIGHT, space5);
main_static_box_sizer->AddSpacer(space5);
main_static_box_sizer->Add(m_osd_messages_checkbox, 0, wxLEFT | wxRIGHT, space5);
main_static_box_sizer->AddSpacer(space5);
main_static_box_sizer->Add(m_pause_focus_lost_checkbox, 0, wxLEFT | wxRIGHT, space5);
main_static_box_sizer->AddSpacer(space5);
main_static_box_sizer->Add(language_and_theme_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_static_box_sizer->AddSpacer(space5);
wxBoxSizer* const main_box_sizer = new wxBoxSizer(wxVERTICAL);
main_box_sizer->Add(main_static_box_sizer, 0, wxEXPAND | wxALL, 5);
main_box_sizer->AddSpacer(space5);
main_box_sizer->Add(main_static_box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_box_sizer->AddSpacer(space5);
SetSizer(main_box_sizer);
}
@ -212,7 +222,10 @@ void InterfaceConfigPane::OnInterfaceLanguageChoiceChanged(wxCommandEvent& event
{
if (SConfig::GetInstance().m_InterfaceLanguage !=
language_ids[m_interface_lang_choice->GetSelection()])
SuccessAlertT("You must restart Dolphin in order for the change to take effect.");
{
wxMessageBox(_("You must restart Dolphin in order for the change to take effect."),
_("Restart Required"), wxOK | wxICON_INFORMATION, this);
}
SConfig::GetInstance().m_InterfaceLanguage =
language_ids[m_interface_lang_choice->GetSelection()];

View File

@ -77,45 +77,49 @@ void PathConfigPane::InitializeGUI()
m_wii_sdcard_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnSdCardPathChanged,
this);
const int space5 = FromDIP(5);
wxBoxSizer* const iso_button_sizer = new wxBoxSizer(wxHORIZONTAL);
iso_button_sizer->Add(m_recursive_iso_paths_checkbox, 0, wxALL | wxALIGN_CENTER);
iso_button_sizer->Add(m_recursive_iso_paths_checkbox, 0, wxALIGN_CENTER_VERTICAL);
iso_button_sizer->AddStretchSpacer();
iso_button_sizer->Add(m_add_iso_path_button, 0, wxALL);
iso_button_sizer->Add(m_remove_iso_path_button, 0, wxALL);
iso_button_sizer->Add(m_add_iso_path_button, 0, wxALIGN_CENTER_VERTICAL);
iso_button_sizer->Add(m_remove_iso_path_button, 0, wxALIGN_CENTER_VERTICAL);
wxStaticBoxSizer* const iso_listbox_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("ISO Directories"));
iso_listbox_sizer->Add(m_iso_paths_listbox, 1, wxEXPAND | wxALL, 0);
iso_listbox_sizer->Add(iso_button_sizer, 0, wxEXPAND | wxALL, 5);
iso_listbox_sizer->Add(m_iso_paths_listbox, 1, wxEXPAND);
iso_listbox_sizer->AddSpacer(space5);
iso_listbox_sizer->Add(iso_button_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
iso_listbox_sizer->AddSpacer(space5);
wxGridBagSizer* const picker_sizer = new wxGridBagSizer();
wxGridBagSizer* const picker_sizer = new wxGridBagSizer(space5, space5);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Default ISO:")), wxGBPosition(0, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
picker_sizer->Add(m_default_iso_filepicker, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND | wxALL,
5);
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_default_iso_filepicker, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("DVD Root:")), wxGBPosition(1, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
picker_sizer->Add(m_dvd_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND | wxALL, 5);
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_dvd_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Apploader:")), wxGBPosition(2, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
picker_sizer->Add(m_apploader_path_filepicker, wxGBPosition(2, 1), wxDefaultSpan,
wxEXPAND | wxALL, 5);
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_apploader_path_filepicker, wxGBPosition(2, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Wii NAND Root:")), wxGBPosition(3, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND | wxALL, 5);
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Dump Path:")), wxGBPosition(4, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
picker_sizer->Add(m_dump_path_dirpicker, wxGBPosition(4, 1), wxDefaultSpan, wxEXPAND | wxALL, 5);
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_dump_path_dirpicker, wxGBPosition(4, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("SD Card Path:")), wxGBPosition(5, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
picker_sizer->Add(m_wii_sdcard_filepicker, wxGBPosition(5, 1), wxDefaultSpan, wxEXPAND | wxALL,
5);
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_wii_sdcard_filepicker, wxGBPosition(5, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->AddGrowableCol(1);
// Populate the Paths page
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(iso_listbox_sizer, 1, wxEXPAND | wxALL, 5);
main_sizer->Add(picker_sizer, 0, wxEXPAND | wxALL, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(iso_listbox_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(picker_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
SetSizer(main_sizer);
}

View File

@ -14,6 +14,7 @@
#include "Core/IPC_HLE/WII_IPC_HLE.h"
#include "DiscIO/Enums.h"
#include "DolphinWX/Config/WiiConfigPane.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/WxUtils.h"
WiiConfigPane::WiiConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
@ -52,14 +53,10 @@ void WiiConfigPane::InitializeGUI()
m_connect_keyboard_checkbox = new wxCheckBox(this, wxID_ANY, _("Connect USB Keyboard"));
m_bt_sensor_bar_pos =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_bt_sensor_bar_pos_strings);
m_bt_sensor_bar_sens = new wxSlider(this, wxID_ANY, 0, 0, 4);
m_bt_speaker_volume = new wxSlider(this, wxID_ANY, 0, 0, 127);
m_bt_sensor_bar_sens = new DolphinSlider(this, wxID_ANY, 0, 0, 4);
m_bt_speaker_volume = new DolphinSlider(this, wxID_ANY, 0, 0, 127);
m_bt_wiimote_motor = new wxCheckBox(this, wxID_ANY, _("Wiimote Motor"));
// With some GTK themes, no minimum size will be applied - so do this manually here
m_bt_sensor_bar_sens->SetMinSize(wxSize(100, -1));
m_bt_speaker_volume->SetMinSize(wxSize(100, -1));
m_screensaver_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnScreenSaverCheckBoxChanged, this);
m_pal60_mode_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnPAL60CheckBoxChanged, this);
m_aspect_ratio_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnAspectRatioChoiceChanged, this);
@ -79,67 +76,78 @@ void WiiConfigPane::InitializeGUI()
m_sd_card_checkbox->SetToolTip(_("Saved to /Wii/sd.raw (default size is 128mb)"));
m_connect_keyboard_checkbox->SetToolTip(_("May cause slow down in Wii Menu and some games."));
wxGridBagSizer* const misc_settings_grid_sizer = new wxGridBagSizer();
misc_settings_grid_sizer->Add(m_screensaver_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2), wxALL,
5);
misc_settings_grid_sizer->Add(m_pal60_mode_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2), wxALL,
5);
const int space5 = FromDIP(5);
wxGridBagSizer* const misc_settings_grid_sizer = new wxGridBagSizer(space5, space5);
misc_settings_grid_sizer->Add(m_screensaver_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2));
misc_settings_grid_sizer->Add(m_pal60_mode_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2));
misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Aspect Ratio:")),
wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
5);
misc_settings_grid_sizer->Add(m_aspect_ratio_choice, wxGBPosition(2, 1), wxDefaultSpan, wxALL, 5);
wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
misc_settings_grid_sizer->Add(m_aspect_ratio_choice, wxGBPosition(2, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("System Language:")),
wxGBPosition(3, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
5);
misc_settings_grid_sizer->Add(m_system_language_choice, wxGBPosition(3, 1), wxDefaultSpan, wxALL,
5);
wxGBPosition(3, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
misc_settings_grid_sizer->Add(m_system_language_choice, wxGBPosition(3, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
auto* const bt_sensor_bar_pos_sizer = new wxBoxSizer(wxHORIZONTAL);
bt_sensor_bar_pos_sizer->Add(new wxStaticText(this, wxID_ANY, _("Min")), 0,
wxALIGN_CENTER_VERTICAL);
bt_sensor_bar_pos_sizer->Add(m_bt_sensor_bar_sens);
bt_sensor_bar_pos_sizer->Add(m_bt_sensor_bar_sens, 0, wxALIGN_CENTER_VERTICAL);
bt_sensor_bar_pos_sizer->Add(new wxStaticText(this, wxID_ANY, _("Max")), 0,
wxALIGN_CENTER_VERTICAL);
auto* const bt_speaker_volume_sizer = new wxBoxSizer(wxHORIZONTAL);
bt_speaker_volume_sizer->Add(new wxStaticText(this, wxID_ANY, _("Min")), 0,
wxALIGN_CENTER_VERTICAL);
bt_speaker_volume_sizer->Add(m_bt_speaker_volume);
bt_speaker_volume_sizer->Add(m_bt_speaker_volume, 0, wxALIGN_CENTER_VERTICAL);
bt_speaker_volume_sizer->Add(new wxStaticText(this, wxID_ANY, _("Max")), 0,
wxALIGN_CENTER_VERTICAL);
wxGridBagSizer* const bt_settings_grid_sizer = new wxGridBagSizer();
wxGridBagSizer* const bt_settings_grid_sizer = new wxGridBagSizer(space5, space5);
bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Sensor Bar Position:")),
wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
5);
bt_settings_grid_sizer->Add(m_bt_sensor_bar_pos, wxGBPosition(0, 1), wxDefaultSpan, wxALL, 5);
wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
bt_settings_grid_sizer->Add(m_bt_sensor_bar_pos, wxGBPosition(0, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("IR Sensitivity:")),
wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
5);
bt_settings_grid_sizer->Add(bt_sensor_bar_pos_sizer, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5);
wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
bt_settings_grid_sizer->Add(bt_sensor_bar_pos_sizer, wxGBPosition(1, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Speaker Volume:")),
wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
5);
bt_settings_grid_sizer->Add(bt_speaker_volume_sizer, wxGBPosition(2, 1), wxDefaultSpan, wxALL, 5);
bt_settings_grid_sizer->Add(m_bt_wiimote_motor, wxGBPosition(3, 0), wxGBSpan(1, 2), wxALL, 5);
wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
bt_settings_grid_sizer->Add(bt_speaker_volume_sizer, wxGBPosition(2, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
bt_settings_grid_sizer->Add(m_bt_wiimote_motor, wxGBPosition(3, 0), wxGBSpan(1, 2),
wxALIGN_CENTER_VERTICAL);
wxStaticBoxSizer* const misc_settings_static_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Misc Settings"));
misc_settings_static_sizer->Add(misc_settings_grid_sizer);
misc_settings_static_sizer->AddSpacer(space5);
misc_settings_static_sizer->Add(misc_settings_grid_sizer, 0, wxLEFT | wxRIGHT, space5);
misc_settings_static_sizer->AddSpacer(space5);
wxStaticBoxSizer* const device_settings_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings"));
device_settings_sizer->Add(m_sd_card_checkbox, 0, wxALL, 5);
device_settings_sizer->Add(m_connect_keyboard_checkbox, 0, wxALL, 5);
device_settings_sizer->AddSpacer(space5);
device_settings_sizer->Add(m_sd_card_checkbox, 0, wxLEFT | wxRIGHT, space5);
device_settings_sizer->AddSpacer(space5);
device_settings_sizer->Add(m_connect_keyboard_checkbox, 0, wxLEFT | wxRIGHT, space5);
device_settings_sizer->AddSpacer(space5);
auto* const bt_settings_static_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Wii Remote Settings"));
bt_settings_static_sizer->Add(bt_settings_grid_sizer);
bt_settings_static_sizer->AddSpacer(space5);
bt_settings_static_sizer->Add(bt_settings_grid_sizer, 0, wxLEFT | wxRIGHT, space5);
bt_settings_static_sizer->AddSpacer(space5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(misc_settings_static_sizer, 0, wxEXPAND | wxALL, 5);
main_sizer->Add(device_settings_sizer, 0, wxEXPAND | wxALL, 5);
main_sizer->Add(bt_settings_static_sizer, 0, wxEXPAND | wxALL, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(misc_settings_static_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(device_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(bt_settings_static_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
SetSizer(main_sizer);
}

View File

@ -13,6 +13,7 @@ namespace DiscIO
enum class Language;
}
class DolphinSlider;
class wxCheckBox;
class wxChoice;
class wxSlider;
@ -53,7 +54,7 @@ private:
wxChoice* m_aspect_ratio_choice;
wxChoice* m_bt_sensor_bar_pos;
wxSlider* m_bt_sensor_bar_sens;
wxSlider* m_bt_speaker_volume;
DolphinSlider* m_bt_sensor_bar_sens;
DolphinSlider* m_bt_speaker_volume;
wxCheckBox* m_bt_wiimote_motor;
};

View File

@ -13,7 +13,7 @@
#include <wx/msgdlg.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include "Common/CommonTypes.h"
@ -29,11 +29,12 @@
#include "Core/HotkeyManager.h"
#include "Core/IPC_HLE/WII_IPC_HLE.h"
#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h"
#include "Core/Movie.h"
#include "Core/NetPlayProto.h"
#include "DolphinWX/Config/GCAdapterConfigDiag.h"
#include "DolphinWX/ControllerConfigDiag.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/InputConfigDiag.h"
#include "DolphinWX/WxUtils.h"
#include "InputCommon/GCAdapter.h"
#if defined(HAVE_XRANDR) && HAVE_XRANDR
@ -47,15 +48,18 @@ ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent)
_("Steering Wheel"), _("Dance Mat"), _("DK Bongos"), _("GBA"),
_("Keyboard")}};
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
const int space5 = FromDIP(5);
// Combine all UI controls into their own encompassing sizer.
wxBoxSizer* control_sizer = new wxBoxSizer(wxVERTICAL);
control_sizer->Add(CreateGamecubeSizer(), 0, wxEXPAND | wxALL, 5);
control_sizer->Add(CreateWiimoteConfigSizer(), 0, wxEXPAND | wxALL, 5);
main_sizer->Add(control_sizer, 0, wxEXPAND);
main_sizer->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->AddSpacer(space5);
main_sizer->Add(CreateGamecubeSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(CreateWiimoteConfigSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT,
space5);
main_sizer->AddSpacer(space5);
Bind(wxEVT_CLOSE_WINDOW, &ControllerConfigDiag::OnClose, this);
Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnCloseButton, this, wxID_CLOSE);
@ -131,25 +135,31 @@ void ControllerConfigDiag::UpdateUI()
}
}
wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
wxSizer* ControllerConfigDiag::CreateGamecubeSizer()
{
wxStaticBoxSizer* const gamecube_static_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Controllers"));
wxFlexGridSizer* const gamecube_flex_sizer = new wxFlexGridSizer(3, 5, 5);
const int space5 = FromDIP(5);
auto* gamecube_static_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Controllers"));
auto* gamecube_flex_sizer = new wxFlexGridSizer(3, space5, space5);
gamecube_flex_sizer->AddGrowableCol(1);
gamecube_static_sizer->AddSpacer(space5);
gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
gamecube_static_sizer->AddSpacer(space5);
wxStaticText* pad_labels[4];
wxChoice* pad_type_choices[4];
for (int i = 0; i < 4; i++)
{
pad_labels[i] = new wxStaticText(this, wxID_ANY, wxString::Format(_("Port %i"), i + 1));
pad_labels[i] = new wxStaticText(gamecube_static_sizer->GetStaticBox(), wxID_ANY,
wxString::Format(_("Port %i"), i + 1));
// Create an ID for the config button.
const wxWindowID button_id = wxWindow::NewControlId();
m_gc_port_from_config_id.emplace(button_id, i);
m_gc_port_configure_button[i] =
new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, -1));
new wxButton(gamecube_static_sizer->GetStaticBox(), button_id, _("Configure"),
wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
m_gc_port_configure_button[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton,
this);
@ -157,8 +167,9 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
const wxWindowID choice_id = wxWindow::NewControlId();
m_gc_port_from_choice_id.emplace(choice_id, i);
pad_type_choices[i] = new wxChoice(this, choice_id, wxDefaultPosition, wxDefaultSize,
m_gc_pad_type_strs.size(), m_gc_pad_type_strs.data());
pad_type_choices[i] =
new wxChoice(gamecube_static_sizer->GetStaticBox(), choice_id, wxDefaultPosition,
wxDefaultSize, m_gc_pad_type_strs.size(), m_gc_pad_type_strs.data());
pad_type_choices[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnGameCubePortChanged, this);
@ -199,35 +210,38 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
// Add to the sizer
gamecube_flex_sizer->Add(pad_labels[i], 0, wxALIGN_CENTER_VERTICAL);
gamecube_flex_sizer->Add(pad_type_choices[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
gamecube_flex_sizer->Add(m_gc_port_configure_button[i], 1, wxEXPAND);
gamecube_flex_sizer->Add(WxUtils::GiveMinSize(pad_type_choices[i], wxDefaultSize), 0, wxEXPAND);
gamecube_flex_sizer->Add(m_gc_port_configure_button[i], 0, wxEXPAND);
}
gamecube_static_sizer->Add(gamecube_flex_sizer, 0, wxEXPAND | wxALL, 5);
gamecube_static_sizer->AddSpacer(5);
return gamecube_static_sizer;
}
wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
wxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
{
const int space5 = FromDIP(5);
const int space20 = FromDIP(20);
auto* const box = new wxStaticBoxSizer(wxVERTICAL, this, _("Wiimotes"));
m_passthrough_bt_radio = new wxRadioButton(this, wxID_ANY, _("Passthrough a Bluetooth adapter"),
wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
m_passthrough_bt_radio->Bind(wxEVT_RADIOBUTTON, &ControllerConfigDiag::OnBluetoothModeChanged,
this);
box->Add(m_passthrough_bt_radio, 0, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5);
box->Add(CreatePassthroughBTConfigSizer(), 0, wxALL | wxEXPAND, 5);
box->AddSpacer(space5);
box->Add(m_passthrough_bt_radio, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
box->AddSpacer(space5);
box->Add(CreatePassthroughBTConfigSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
box->AddSpacer(10);
box->AddSpacer(space20);
m_emulated_bt_radio = new wxRadioButton(this, wxID_ANY, _("Emulate the Wii's Bluetooth adapter"));
m_emulated_bt_radio->Bind(wxEVT_RADIOBUTTON, &ControllerConfigDiag::OnBluetoothModeChanged, this);
box->Add(m_emulated_bt_radio, 0, wxALL | wxEXPAND, 5);
box->Add(CreateEmulatedBTConfigSizer(), 0, wxALL | wxEXPAND, 5);
box->AddSpacer(5);
box->Add(m_emulated_bt_radio, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
box->AddSpacer(space5);
box->Add(CreateEmulatedBTConfigSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
box->AddSpacer(space5);
if (SConfig::GetInstance().m_bt_passthrough_enabled)
m_passthrough_bt_radio->SetValue(true);
@ -237,46 +251,45 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
return box;
}
wxBoxSizer* ControllerConfigDiag::CreatePassthroughBTConfigSizer()
wxSizer* ControllerConfigDiag::CreatePassthroughBTConfigSizer()
{
auto* const sizer = new wxBoxSizer(wxVERTICAL);
m_passthrough_sync_text = new wxStaticText(this, wxID_ANY, _("Sync real Wiimotes and pair them"));
m_passthrough_sync_btn =
new wxButton(this, wxID_ANY, _("Sync"), wxDefaultPosition, wxSize(100, -1));
new wxButton(this, wxID_ANY, _("Sync"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
m_passthrough_sync_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughScanButton, this);
m_passthrough_reset_text =
new wxStaticText(this, wxID_ANY, _("Reset all saved Wiimote pairings"));
m_passthrough_reset_btn =
new wxButton(this, wxID_ANY, _("Reset"), wxDefaultPosition, wxSize(100, -1));
new wxButton(this, wxID_ANY, _("Reset"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
m_passthrough_reset_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughResetButton,
this);
auto* const sync_sizer = new wxBoxSizer(wxHORIZONTAL);
sync_sizer->Add(m_passthrough_sync_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
sync_sizer->AddStretchSpacer();
sync_sizer->Add(m_passthrough_sync_btn, 0, wxEXPAND);
auto* const reset_sizer = new wxBoxSizer(wxHORIZONTAL);
reset_sizer->Add(m_passthrough_reset_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
reset_sizer->AddStretchSpacer();
reset_sizer->Add(m_passthrough_reset_btn, 0, wxEXPAND);
const int space5 = FromDIP(5);
sizer->Add(sync_sizer, 0, wxEXPAND);
sizer->AddSpacer(5);
sizer->Add(reset_sizer, 0, wxEXPAND);
return sizer;
auto* grid = new wxFlexGridSizer(3, space5, space5);
grid->AddGrowableCol(1);
grid->Add(m_passthrough_sync_text, 0, wxALIGN_CENTER_VERTICAL);
grid->AddSpacer(1);
grid->Add(m_passthrough_sync_btn, 0, wxEXPAND);
grid->Add(m_passthrough_reset_text, 0, wxALIGN_CENTER_VERTICAL);
grid->AddSpacer(1);
grid->Add(m_passthrough_reset_btn, 0, wxEXPAND);
return grid;
}
wxBoxSizer* ControllerConfigDiag::CreateEmulatedBTConfigSizer()
wxSizer* ControllerConfigDiag::CreateEmulatedBTConfigSizer()
{
static const std::array<wxString, 4> src_choices = {
const std::array<wxString, 4> src_choices{
{_("None"), _("Emulated Wiimote"), _("Real Wiimote"), _("Hybrid Wiimote")}};
auto* const sizer = new wxBoxSizer(wxVERTICAL);
const int space5 = FromDIP(5);
// Source selector grid
auto* const grid = new wxFlexGridSizer(3, 5, 5);
auto* const grid = new wxFlexGridSizer(3, space5, space5);
grid->AddGrowableCol(1);
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
@ -296,53 +309,58 @@ wxBoxSizer* ControllerConfigDiag::CreateEmulatedBTConfigSizer()
src_choices.size(), src_choices.data());
m_wiimote_sources[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnWiimoteSourceChanged, this);
m_wiimote_configure_button[i] =
new wxButton(this, config_bt_id, _("Configure"), wxDefaultPosition, wxSize(100, -1));
m_wiimote_configure_button[i] = new wxButton(
this, config_bt_id, _("Configure"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
m_wiimote_configure_button[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteConfigButton,
this);
grid->Add(m_wiimote_labels[i], 0, wxALIGN_CENTER_VERTICAL);
grid->Add(m_wiimote_sources[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
grid->Add(m_wiimote_configure_button[i], 1, wxEXPAND);
grid->Add(WxUtils::GiveMinSize(m_wiimote_sources[i], wxDefaultSize), 0, wxEXPAND);
grid->Add(m_wiimote_configure_button[i], 0, wxEXPAND);
}
sizer->Add(grid, 0, wxEXPAND);
sizer->AddSpacer(5);
// Scanning controls
m_enable_continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning"));
m_enable_continuous_scanning->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnContinuousScanning,
this);
m_enable_continuous_scanning->SetValue(SConfig::GetInstance().m_WiimoteContinuousScanning);
m_refresh_wm_button =
new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition, wxSize(100, -1));
m_refresh_wm_button = new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition,
wxDLG_UNIT(this, wxSize(60, -1)));
m_refresh_wm_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteRefreshButton, this);
m_unsupported_bt_text =
new wxStaticText(this, wxID_ANY, _("A supported Bluetooth device could not be found,\n"
"so you must connect Wiimotes manually."));
m_unsupported_bt_text->Show(!WiimoteReal::g_wiimote_scanner.IsReady());
sizer->Add(m_unsupported_bt_text, 0, wxALIGN_CENTER | wxALL, 5);
auto* const scanning_sizer = new wxBoxSizer(wxHORIZONTAL);
scanning_sizer->Add(m_enable_continuous_scanning, 0, wxALIGN_CENTER_VERTICAL);
scanning_sizer->AddStretchSpacer();
scanning_sizer->Add(m_refresh_wm_button, 0, wxALL | wxEXPAND);
sizer->Add(scanning_sizer, 0, wxEXPAND);
// Balance Board
m_balance_board_checkbox = new wxCheckBox(this, wxID_ANY, _("Real Balance Board"));
m_balance_board_checkbox->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnBalanceBoardChanged,
this);
m_balance_board_checkbox->SetValue(g_wiimote_sources[WIIMOTE_BALANCE_BOARD] == WIIMOTE_SRC_REAL);
sizer->Add(m_balance_board_checkbox);
sizer->AddSpacer(5);
// Speaker data
m_enable_speaker_data = new wxCheckBox(this, wxID_ANY, _("Enable Speaker Data"));
m_enable_speaker_data->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnEnableSpeaker, this);
m_enable_speaker_data->SetValue(SConfig::GetInstance().m_WiimoteEnableSpeaker);
sizer->Add(m_enable_speaker_data);
auto* const checkbox_sizer = new wxBoxSizer(wxVERTICAL);
checkbox_sizer->Add(m_enable_continuous_scanning);
checkbox_sizer->AddSpacer(space5);
checkbox_sizer->Add(m_balance_board_checkbox);
checkbox_sizer->AddSpacer(space5);
checkbox_sizer->Add(m_enable_speaker_data);
auto* const scanning_sizer = new wxBoxSizer(wxHORIZONTAL);
scanning_sizer->Add(checkbox_sizer, 1, wxEXPAND);
scanning_sizer->Add(m_refresh_wm_button, 0, wxALIGN_TOP);
auto* const sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(grid, 0, wxEXPAND);
sizer->AddSpacer(space5);
sizer->Add(m_unsupported_bt_text, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, space5);
sizer->AddSpacer(space5);
sizer->Add(scanning_sizer, 0, wxEXPAND);
return sizer;
}
@ -428,21 +446,21 @@ void ControllerConfigDiag::OnGameCubeConfigButton(wxCommandEvent& event)
if (SConfig::GetInstance().m_SIDevice[port_num] == SIDEVICE_GC_KEYBOARD)
{
InputConfigDialog m_ConfigFrame(this, *key_plugin, _("GameCube Controller Configuration"),
port_num);
m_ConfigFrame.ShowModal();
InputConfigDialog config_diag(this, *key_plugin, _("GameCube Keyboard Configuration"),
port_num);
config_diag.ShowModal();
}
else if (SConfig::GetInstance().m_SIDevice[port_num] == SIDEVICE_WIIU_ADAPTER)
{
GCAdapterConfigDiag m_ConfigFramg(this, _("Wii U Gamecube Controller Adapter Configuration"),
port_num);
m_ConfigFramg.ShowModal();
GCAdapterConfigDiag config_diag(this, _("Wii U Gamecube Controller Adapter Configuration"),
port_num);
config_diag.ShowModal();
}
else
{
InputConfigDialog m_ConfigFrame(this, *pad_plugin, _("GameCube Controller Configuration"),
port_num);
m_ConfigFrame.ShowModal();
InputConfigDialog config_diag(this, *pad_plugin, _("GameCube Controller Configuration"),
port_num);
config_diag.ShowModal();
}
HotkeyManagerEmu::Enable(true);

View File

@ -17,7 +17,6 @@ class InputConfig;
class wxCheckBox;
class wxChoice;
class wxRadioButton;
class wxStaticBoxSizer;
class wxStaticText;
class ControllerConfigDiag final : public wxDialog
@ -28,10 +27,10 @@ public:
private:
void UpdateUI();
wxStaticBoxSizer* CreateGamecubeSizer();
wxStaticBoxSizer* CreateWiimoteConfigSizer();
wxBoxSizer* CreatePassthroughBTConfigSizer();
wxBoxSizer* CreateEmulatedBTConfigSizer();
wxSizer* CreateGamecubeSizer();
wxSizer* CreateWiimoteConfigSizer();
wxSizer* CreatePassthroughBTConfigSizer();
wxSizer* CreateEmulatedBTConfigSizer();
void OnClose(wxCloseEvent& event);
void OnCloseButton(wxCommandEvent& event);

View File

@ -23,11 +23,15 @@ BreakPointDlg::BreakPointDlg(CBreakPointWindow* _Parent)
m_pEditAddress = new wxTextCtrl(this, wxID_ANY, "80000000");
wxBoxSizer* sMainSizer = new wxBoxSizer(wxVERTICAL);
sMainSizer->Add(m_pEditAddress, 0, wxEXPAND | wxALL, 5);
sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALL, 5);
const int space5 = FromDIP(5);
wxBoxSizer* main_szr = new wxBoxSizer(wxVERTICAL);
main_szr->AddSpacer(space5);
main_szr->Add(m_pEditAddress, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
SetSizerAndFit(sMainSizer);
SetSizerAndFit(main_szr);
SetFocus();
}

View File

@ -25,7 +25,7 @@ CBreakPointView::CBreakPointView(wxWindow* parent, const wxWindowID id)
Refresh();
}
void CBreakPointView::Update()
void CBreakPointView::Repopulate()
{
ClearAll();
@ -98,6 +98,6 @@ void CBreakPointView::DeleteCurrentSelection()
u32 Address = (u32)GetItemData(item);
PowerPC::breakpoints.Remove(Address);
PowerPC::memchecks.Remove(Address);
Update();
Repopulate();
}
}

View File

@ -11,6 +11,6 @@ class CBreakPointView : public wxListCtrl
public:
CBreakPointView(wxWindow* parent, const wxWindowID id);
void Update() override;
void Repopulate();
void DeleteCurrentSelection();
};

View File

@ -2,6 +2,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <array>
// clang-format off
#include <wx/bitmap.h>
#include <wx/aui/framemanager.h>
@ -32,11 +34,15 @@ public:
: DolphinAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize,
wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT)
{
SetToolBitmapSize(wxSize(24, 24));
wxSize bitmap_size = FromDIP(wxSize(24, 24));
SetToolBitmapSize(bitmap_size);
m_Bitmaps[Toolbar_Delete] = WxUtils::LoadResourceBitmap("toolbar_debugger_delete");
m_Bitmaps[Toolbar_Add_BP] = WxUtils::LoadResourceBitmap("toolbar_add_breakpoint");
m_Bitmaps[Toolbar_Add_MC] = WxUtils::LoadResourceBitmap("toolbar_add_memorycheck");
static const std::array<const char* const, Num_Bitmaps> image_names{
{"toolbar_debugger_delete", "toolbar_add_breakpoint", "toolbar_add_memorycheck"}};
for (std::size_t i = 0; i < image_names.size(); ++i)
m_Bitmaps[i] =
WxUtils::LoadScaledResourceBitmap(image_names[i], this, bitmap_size, wxDefaultSize,
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
AddTool(ID_DELETE, _("Delete"), m_Bitmaps[Toolbar_Delete]);
Bind(wxEVT_TOOL, &CBreakPointWindow::OnDelete, parent, ID_DELETE);
@ -84,8 +90,6 @@ CBreakPointWindow::CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent
const wxSize& size, long style)
: wxPanel(parent, id, position, size, style, title), m_pCodeWindow(_pCodeWindow)
{
Bind(wxEVT_CLOSE_WINDOW, &CBreakPointWindow::OnClose, this);
m_mgr.SetManagedWindow(this);
m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
@ -108,15 +112,9 @@ CBreakPointWindow::~CBreakPointWindow()
m_mgr.UnInit();
}
void CBreakPointWindow::OnClose(wxCloseEvent& event)
{
SaveAll();
event.Skip();
}
void CBreakPointWindow::NotifyUpdate()
{
m_BreakPointListView->Update();
m_BreakPointListView->Repopulate();
}
void CBreakPointWindow::OnDelete(wxCommandEvent& WXUNUSED(event))

View File

@ -21,21 +21,21 @@ public:
~CBreakPointWindow();
void NotifyUpdate();
void SaveAll();
void LoadAll();
private:
friend class CBreakPointBar;
void OnDelete(wxCommandEvent& WXUNUSED(event));
void OnClear(wxCommandEvent& WXUNUSED(event));
void OnAddBreakPoint(wxCommandEvent& WXUNUSED(event));
void OnAddMemoryCheck(wxCommandEvent& WXUNUSED(event));
void Event_SaveAll(wxCommandEvent& WXUNUSED(event));
void SaveAll();
void Event_LoadAll(wxCommandEvent& WXUNUSED(event));
void LoadAll();
void OnSelectBP(wxListEvent& event);
private:
wxAuiManager m_mgr;
CBreakPointView* m_BreakPointListView;
CCodeWindow* m_pCodeWindow;
void OnClose(wxCloseEvent& event);
void OnSelectBP(wxListEvent& event);
};

View File

@ -53,9 +53,9 @@ CCodeView::CCodeView(DebugInterface* debuginterface, SymbolDB* symboldb, wxWindo
wxWindowID Id)
: wxControl(parent, Id), m_debugger(debuginterface), m_symbol_db(symboldb), m_plain(false),
m_curAddress(debuginterface->GetPC()), m_align(debuginterface->GetInstructionSize(0)),
m_rowHeight(13), m_selection(0), m_oldSelection(0), m_selecting(false), m_lx(-1), m_ly(-1)
m_rowHeight(FromDIP(13)), m_left_col_width(FromDIP(LEFT_COL_WIDTH)), m_selection(0),
m_oldSelection(0), m_selecting(false)
{
Bind(wxEVT_ERASE_BACKGROUND, &CCodeView::OnErase, this);
Bind(wxEVT_PAINT, &CCodeView::OnPaint, this);
Bind(wxEVT_MOUSEWHEEL, &CCodeView::OnScrollWheel, this);
Bind(wxEVT_LEFT_DOWN, &CCodeView::OnMouseDown, this);
@ -65,6 +65,13 @@ CCodeView::CCodeView(DebugInterface* debuginterface, SymbolDB* symboldb, wxWindo
Bind(wxEVT_RIGHT_UP, &CCodeView::OnMouseUpR, this);
Bind(wxEVT_MENU, &CCodeView::OnPopupMenu, this);
Bind(wxEVT_SIZE, &CCodeView::OnResize, this);
// Disable the erase event, the entire window is being painted so the erase
// event will just cause unnecessary flicker.
SetBackgroundStyle(wxBG_STYLE_PAINT);
#if defined(__WXMSW__) || defined(__WXGTK__)
SetDoubleBuffered(true);
#endif
}
int CCodeView::YToAddress(int y)
@ -80,7 +87,7 @@ void CCodeView::OnMouseDown(wxMouseEvent& event)
int x = event.m_x;
int y = event.m_y;
if (x > 16)
if (x > m_left_col_width)
{
m_oldSelection = m_selection;
m_selection = YToAddress(y);
@ -131,7 +138,7 @@ void CCodeView::OnMouseMove(wxMouseEvent& event)
{
wxRect rc = GetClientRect();
if (event.m_leftDown && event.m_x > 16)
if (event.m_leftDown && event.m_x > m_left_col_width)
{
if (event.m_y < 0)
{
@ -162,7 +169,7 @@ void CCodeView::RaiseEvent()
void CCodeView::OnMouseUpL(wxMouseEvent& event)
{
if (event.m_x > 16)
if (event.m_x > m_left_col_width)
{
m_curAddress = YToAddress(event.m_y);
m_selecting = false;
@ -222,10 +229,6 @@ void CCodeView::InsertBlrNop(int Blr)
void CCodeView::OnPopupMenu(wxCommandEvent& event)
{
#if wxUSE_CLIPBOARD
wxTheClipboard->Open();
#endif
switch (event.GetId())
{
case IDM_GOTOINMEMVIEW:
@ -234,11 +237,15 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
#if wxUSE_CLIPBOARD
case IDM_COPYADDRESS:
{
wxClipboardLocker locker;
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", m_selection)));
break;
}
break;
case IDM_COPYCODE:
{
wxClipboardLocker locker;
std::string disasm = m_debugger->Disassemble(m_selection);
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(disasm)));
}
@ -246,8 +253,9 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
case IDM_COPYHEX:
{
std::string temp = StringFromFormat("%08x", m_debugger->ReadInstruction(m_selection));
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
wxClipboardLocker locker;
wxTheClipboard->SetData(
new wxTextDataObject(wxString::Format("%08x", m_debugger->ReadInstruction(m_selection))));
}
break;
@ -266,6 +274,7 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
std::string disasm = m_debugger->Disassemble(addr);
text += StringFromFormat("%08x: ", addr) + disasm + "\r\n";
}
wxClipboardLocker locker;
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(text)));
}
}
@ -283,6 +292,7 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
InsertBlrNop(0);
Refresh();
break;
case IDM_INSERTNOP:
InsertBlrNop(1);
Refresh();
@ -332,12 +342,11 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
case IDM_PATCHALERT:
break;
}
#if wxUSE_CLIPBOARD
wxTheClipboard->Close();
#endif
event.Skip();
default:
event.Skip();
break;
}
}
void CCodeView::OnMouseUpR(wxMouseEvent& event)
@ -363,104 +372,112 @@ void CCodeView::OnMouseUpR(wxMouseEvent& event)
menu.Append(IDM_JITRESULTS, _("PPC vs X86"))->Enable(Core::IsRunning());
menu.Append(IDM_INSERTBLR, _("Insert &blr"))->Enable(Core::IsRunning());
menu.Append(IDM_INSERTNOP, _("Insert &nop"))->Enable(Core::IsRunning());
menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning());
// menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning());
PopupMenu(&menu);
event.Skip();
}
void CCodeView::OnErase(wxEraseEvent& event)
{
}
void CCodeView::OnPaint(wxPaintEvent& event)
{
// -------------------------
// General settings
// -------------------------
std::unique_ptr<wxGraphicsContext> ctx(wxGraphicsContext::Create(wxPaintDC(this)));
wxPaintDC paint_dc(this);
wxRect rc = GetClientRect();
int char_width;
paint_dc.SetFont(DebuggerFont);
{
wxFontMetrics metrics = paint_dc.GetFontMetrics();
char_width = metrics.averageWidth;
if (metrics.height > m_rowHeight)
m_rowHeight = metrics.height;
}
std::unique_ptr<wxGraphicsContext> ctx(wxGraphicsContext::Create(paint_dc));
ctx->DisableOffset(); // Incompatible with matrix transforms
ctx->SetFont(DebuggerFont, *wxBLACK);
wxDouble w, h;
ctx->GetTextExtent("0WJyq", &w, &h);
if (h > m_rowHeight)
m_rowHeight = h;
ctx->GetTextExtent("W", &w, &h);
int charWidth = w;
struct branch
struct Branch
{
int src, dst, srcAddr;
};
branch branches[256];
int numBranches = 0;
// TODO: Add any drawing code here...
int width = rc.width;
int numRows = ((rc.height / m_rowHeight) / 2) + 2;
Branch branches[256];
int num_branches = 0;
const int num_rows = ((rc.height / m_rowHeight) / 2) + 2;
const double scale = FromDIP(1024) / 1024.0;
const int pen_width = static_cast<int>(std::ceil(scale));
const int col_width = rc.width - m_left_col_width;
const int text_col = m_left_col_width + pen_width / 2 + 1; // 1 unscaled pixel
const int bp_offset_x = FromDIP(LEFT_COL_WIDTH / 8);
const wxSize bp_size = FromDIP(wxSize(LEFT_COL_WIDTH * 3 / 4, LEFT_COL_WIDTH * 3 / 4));
const int bp_offset_y = (m_rowHeight - bp_size.GetHeight()) / 2;
// ------------
// -------------------------
// Colors and brushes
// -------------------------
const wxColour bgColor = *wxWHITE;
wxPen nullPen(bgColor);
wxPen currentPen(*wxBLACK_PEN);
wxPen selPen(*wxGREY_PEN);
nullPen.SetStyle(wxPENSTYLE_TRANSPARENT);
currentPen.SetStyle(wxPENSTYLE_SOLID);
wxBrush currentBrush(*wxLIGHT_GREY_BRUSH);
wxBrush pcBrush(*wxGREEN_BRUSH);
wxBrush bpBrush(*wxRED_BRUSH);
wxColour branch_color = wxTheColourDatabase->Find("PURPLE");
wxColour blr_color = wxTheColourDatabase->Find("DARK GREEN");
wxColour instr_color = wxTheColourDatabase->Find("VIOLET");
wxGraphicsPen null_pen = ctx->CreatePen(*wxTRANSPARENT_PEN);
wxGraphicsPen focus_pen = ctx->CreatePen(wxPen(*wxBLACK, pen_width));
wxGraphicsPen selection_pen = ctx->CreatePen(wxPen("GREY", pen_width));
wxGraphicsBrush pc_brush = ctx->CreateBrush(*wxGREEN_BRUSH);
wxGraphicsBrush bp_brush = ctx->CreateBrush(*wxRED_BRUSH);
wxGraphicsBrush back_brush = ctx->CreateBrush(*wxWHITE_BRUSH);
wxGraphicsBrush null_brush = ctx->CreateBrush(*wxTRANSPARENT_BRUSH);
wxBrush bgBrush(bgColor);
wxBrush nullBrush(bgColor);
nullBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
ctx->SetPen(nullPen);
ctx->SetBrush(bgBrush);
ctx->DrawRectangle(0, 0, 16, rc.height);
ctx->DrawRectangle(0, 0, rc.width, 5);
// ------------
// -----------------------------
// Walk through all visible rows
// -----------------------------
for (int i = -numRows; i <= numRows; i++)
for (int i = -num_rows; i <= num_rows; i++)
{
unsigned int address = m_curAddress + (i * m_align);
int rowY1 = (rc.height / 2) + (m_rowHeight * i) - (m_rowHeight / 2);
int rowY2 = (rc.height / 2) + (m_rowHeight * i) + (m_rowHeight / 2);
int row_y = (rc.height / 2) + (m_rowHeight * i) - (m_rowHeight / 2);
wxString temp = wxString::Format("%08x", address);
u32 color = m_debugger->GetColor(address);
wxBrush rowBrush(wxColour(color >> 16, color >> 8, color));
ctx->SetBrush(nullBrush);
ctx->SetPen(nullPen);
ctx->DrawRectangle(0, rowY1, 16, rowY2 - rowY1 + 2);
if (m_selecting && (address == m_selection))
ctx->SetPen(selPen);
else
ctx->SetPen(i == 0 ? currentPen : nullPen);
wxBrush row_brush(wxColour(color >> 16, color >> 8, color));
ctx->SetBrush(back_brush);
ctx->SetPen(null_pen);
ctx->DrawRectangle(0, row_y, m_left_col_width, m_rowHeight);
if (address == m_debugger->GetPC())
ctx->SetBrush(pcBrush);
ctx->SetBrush(pc_brush);
else
ctx->SetBrush(rowBrush);
ctx->SetBrush(row_brush);
ctx->SetPen(null_pen);
ctx->DrawRectangle(m_left_col_width, row_y, col_width, m_rowHeight);
if (i == 0 || (m_selecting && address == m_selection))
{
if (m_selecting && address == m_selection)
ctx->SetPen(selection_pen);
else
ctx->SetPen(focus_pen);
ctx->SetBrush(null_brush);
// In a graphics context, the border of a rectangle is drawn along the edge,
// it does not count towards the width of the rectangle (i.e. drawn right on
// the pixel boundary of the fill area, half inside, half outside. For example
// a rect with a 1px pen at (5,5)->(10,10) will have an actual screen size of
// (4.5,4.5)->(10.5,10.5) with the line being aliased on the half-pixels)
double offset = pen_width / 2.0;
ctx->DrawRectangle(m_left_col_width + offset, row_y + offset, col_width - pen_width,
m_rowHeight - pen_width);
}
ctx->DrawRectangle(16, rowY1, width, rowY2 - rowY1 + 1);
ctx->SetBrush(currentBrush);
if (!m_plain)
{
// the address text is dark red
ctx->SetFont(DebuggerFont, wxColour("#600000"));
ctx->DrawText(temp, 17, rowY1);
ctx->SetFont(DebuggerFont, wxColour(0x60, 0x00, 0x00));
ctx->DrawText(temp, text_col, row_y);
ctx->SetFont(DebuggerFont, *wxBLACK);
}
@ -488,31 +505,32 @@ void CCodeView::OnPaint(wxPaintEvent& event)
{
u32 offs = std::stoul(hex_str, nullptr, 16);
branches[numBranches].src = rowY1 + (m_rowHeight / 2);
branches[numBranches].srcAddr = (address / m_align);
branches[numBranches++].dst =
(int)(rowY1 + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align +
branches[num_branches].src = row_y + (m_rowHeight / 2);
branches[num_branches].srcAddr = (address / m_align);
branches[num_branches++].dst =
(int)(row_y + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align +
m_rowHeight / 2);
desc = StringFromFormat("-->%s", m_debugger->GetDescription(offs).c_str());
// the -> arrow illustrations are purple
ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("PURPLE"));
ctx->SetFont(DebuggerFont, branch_color);
}
else
{
ctx->SetFont(DebuggerFont, *wxBLACK);
}
ctx->DrawText(StrToWxStr(operands), 17 + 17 * charWidth, rowY1);
ctx->DrawText(StrToWxStr(operands), text_col + 17 * char_width, row_y);
// ------------
// Show blr as its' own color
if (opcode == "blr")
ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("DARK GREEN"));
ctx->SetFont(DebuggerFont, blr_color);
else
ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("VIOLET"));
ctx->SetFont(DebuggerFont, instr_color);
ctx->DrawText(StrToWxStr(opcode), 17 + (m_plain ? 1 * charWidth : 9 * charWidth), rowY1);
ctx->DrawText(StrToWxStr(opcode), text_col + (m_plain ? 1 * char_width : 9 * char_width),
row_y);
if (desc.empty())
{
@ -527,15 +545,16 @@ void CCodeView::OnPaint(wxPaintEvent& event)
// UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE);
if (!desc.empty())
{
ctx->DrawText(StrToWxStr(desc), 17 + 35 * charWidth, rowY1);
ctx->DrawText(StrToWxStr(desc), text_col + 45 * char_width, row_y);
}
}
// Show red breakpoint dot
if (m_debugger->IsBreakpoint(address))
{
ctx->SetBrush(bpBrush);
ctx->DrawRectangle(2, rowY1 + 1, 11, 11);
ctx->SetPen(null_pen);
ctx->SetBrush(bp_brush);
ctx->DrawEllipse(bp_offset_x, row_y + bp_offset_y, bp_size.GetWidth(), bp_size.GetHeight());
}
}
} // end of for
@ -544,22 +563,24 @@ void CCodeView::OnPaint(wxPaintEvent& event)
// -------------------------
// Colors and brushes
// -------------------------
ctx->SetPen(currentPen);
ctx->SetPen(focus_pen);
for (int i = 0; i < numBranches; i++)
wxGraphicsPath branch_path = ctx->CreatePath();
for (int i = 0; i < num_branches; ++i)
{
int x = 17 + 49 * charWidth + (branches[i].srcAddr % 9) * 8;
MoveTo(x - 2, branches[i].src);
int x = text_col + 52 * char_width + (branches[i].srcAddr % 9) * 8;
branch_path.MoveToPoint(x - 2 * scale, branches[i].src);
if (branches[i].dst < rc.height + 400 && branches[i].dst > -400)
{
LineTo(ctx, x + 2, branches[i].src);
LineTo(ctx, x + 2, branches[i].dst);
LineTo(ctx, x - 4, branches[i].dst);
branch_path.AddLineToPoint(x + 2 * scale, branches[i].src);
branch_path.AddLineToPoint(x + 2 * scale, branches[i].dst);
branch_path.AddLineToPoint(x - 4 * scale, branches[i].dst);
MoveTo(x, branches[i].dst - 4);
LineTo(ctx, x - 4, branches[i].dst);
LineTo(ctx, x + 1, branches[i].dst + 5);
branch_path.MoveToPoint(x, branches[i].dst - 4 * scale);
branch_path.AddLineToPoint(x - 4 * scale, branches[i].dst);
branch_path.AddLineToPoint(x + 1 * scale, branches[i].dst + 5 * scale);
}
// else
//{
@ -575,18 +596,19 @@ void CCodeView::OnPaint(wxPaintEvent& event)
// LineTo(ctx, x, branches[i].dst+4);
// LineTo(ctx, x-2, branches[i].dst);
}
// If the pen width is odd then we need to offset the path so that lines are drawn in
// the middle of pixels instead of the edge so we don't get aliasing.
if (pen_width & 1)
{
wxGraphicsMatrix matrix = ctx->CreateMatrix();
matrix.Translate(0.5, 0.5);
branch_path.Transform(matrix);
}
ctx->StrokePath(branch_path);
// ------------
}
void CCodeView::LineTo(std::unique_ptr<wxGraphicsContext>& ctx, int x, int y)
{
std::vector<wxPoint2DDouble> points{wxPoint2DDouble(m_lx, m_ly), wxPoint2DDouble(x, y)};
ctx->DrawLines(points.size(), points.data());
m_lx = x;
m_ly = y;
}
void CCodeView::OnResize(wxSizeEvent& event)
{
Refresh();

View File

@ -40,7 +40,6 @@ public:
void SetPlain() { m_plain = true; }
private:
void OnPaint(wxPaintEvent& event);
void OnErase(wxEraseEvent& event);
void OnScrollWheel(wxMouseEvent& event);
void OnMouseDown(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event);
@ -55,14 +54,6 @@ private:
u32 AddrToBranch(u32 addr);
void OnResize(wxSizeEvent& event);
void MoveTo(int x, int y)
{
m_lx = x;
m_ly = y;
}
void LineTo(std::unique_ptr<wxGraphicsContext>& dc, int x, int y);
struct BlrStruct // for IDM_INSERTBLR
{
u32 address;
@ -70,6 +61,8 @@ private:
};
std::vector<BlrStruct> m_blrList;
static constexpr int LEFT_COL_WIDTH = 16;
DebugInterface* m_debugger;
SymbolDB* m_symbol_db;
@ -78,10 +71,9 @@ private:
int m_curAddress;
int m_align;
int m_rowHeight;
int m_left_col_width;
u32 m_selection;
u32 m_oldSelection;
bool m_selecting;
int m_lx, m_ly;
};

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <array>
#include <cstdio>
#include <string>
#include <vector>
@ -43,6 +44,7 @@
#include "DolphinWX/Debugger/CodeWindow.h"
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
#include "DolphinWX/Debugger/JitWindow.h"
#include "DolphinWX/Debugger/MemoryWindow.h"
#include "DolphinWX/Debugger/RegisterWindow.h"
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/AuiToolBar.h"
@ -53,9 +55,8 @@
CCodeWindow::CCodeWindow(const SConfig& _LocalCoreStartupParameter, CFrame* parent, wxWindowID id,
const wxPoint& position, const wxSize& size, long style,
const wxString& name)
: wxPanel(parent, id, position, size, style, name), Parent(parent), m_RegisterWindow(nullptr),
m_WatchWindow(nullptr), m_BreakpointWindow(nullptr), m_MemoryWindow(nullptr),
m_JitWindow(nullptr), m_SoundWindow(nullptr), m_VideoWindow(nullptr), codeview(nullptr)
: wxPanel(parent, id, position, size, style, name), m_sibling_panels(), Parent(parent),
codeview(nullptr)
{
InitBitmaps();
@ -87,21 +88,31 @@ CCodeWindow::CCodeWindow(const SConfig& _LocalCoreStartupParameter, CFrame* pare
m_aui_manager.SetManagedWindow(this);
m_aui_manager.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
m_aui_manager.AddPane(m_aui_toolbar,
wxAuiPaneInfo().MinSize(150, -1).ToolbarPane().Top().Floatable(false));
m_aui_manager.AddPane(
callstack,
wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(
_("Callstack")));
m_aui_manager.AddPane(
symbols, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(
_("Symbols")));
m_aui_manager.AddPane(
calls, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(
_("Function calls")));
m_aui_manager.AddPane(
callers, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(
_("Function callers")));
m_aui_manager.AddPane(m_aui_toolbar, wxAuiPaneInfo().ToolbarPane().Top().Floatable(false));
m_aui_manager.AddPane(callstack, wxAuiPaneInfo()
.MinSize(FromDIP(wxSize(150, 100)))
.Left()
.CloseButton(false)
.Floatable(false)
.Caption(_("Callstack")));
m_aui_manager.AddPane(symbols, wxAuiPaneInfo()
.MinSize(FromDIP(wxSize(150, 100)))
.Left()
.CloseButton(false)
.Floatable(false)
.Caption(_("Symbols")));
m_aui_manager.AddPane(calls, wxAuiPaneInfo()
.MinSize(FromDIP(wxSize(150, 100)))
.Left()
.CloseButton(false)
.Floatable(false)
.Caption(_("Function calls")));
m_aui_manager.AddPane(callers, wxAuiPaneInfo()
.MinSize(FromDIP(wxSize(150, 100)))
.Left()
.CloseButton(false)
.Floatable(false)
.Caption(_("Function callers")));
m_aui_manager.AddPane(codeview, wxAuiPaneInfo().CenterPane().CloseButton(false).Floatable(false));
m_aui_manager.Update();
@ -143,30 +154,30 @@ void CCodeWindow::OnHostMessage(wxCommandEvent& event)
{
case IDM_NOTIFY_MAP_LOADED:
NotifyMapLoaded();
if (m_BreakpointWindow)
m_BreakpointWindow->NotifyUpdate();
if (HasPanel<CBreakPointWindow>())
GetPanel<CBreakPointWindow>()->NotifyUpdate();
break;
case IDM_UPDATE_DISASM_DIALOG:
Update();
if (CPU::IsStepping())
Parent->UpdateGUI();
if (m_RegisterWindow)
m_RegisterWindow->NotifyUpdate();
if (m_WatchWindow)
m_WatchWindow->NotifyUpdate();
Repopulate();
if (HasPanel<CRegisterWindow>())
GetPanel<CRegisterWindow>()->NotifyUpdate();
if (HasPanel<CWatchWindow>())
GetPanel<CWatchWindow>()->NotifyUpdate();
if (HasPanel<CMemoryWindow>())
GetPanel<CMemoryWindow>()->Refresh();
break;
case IDM_UPDATE_BREAKPOINTS:
if (m_BreakpointWindow)
m_BreakpointWindow->NotifyUpdate();
Repopulate();
if (HasPanel<CBreakPointWindow>())
GetPanel<CBreakPointWindow>()->NotifyUpdate();
if (HasPanel<CMemoryWindow>())
GetPanel<CMemoryWindow>()->Refresh();
break;
case IDM_UPDATE_JIT_PANE:
// Check if the JIT pane is in the AUI notebook. If not, add it and switch to it.
if (!m_JitWindow)
ToggleJitWindow(true);
m_JitWindow->ViewAddr(codeview->GetSelection());
RequirePanel<CJitWindow>()->ViewAddr(codeview->GetSelection());
break;
}
}
@ -194,12 +205,12 @@ void CCodeWindow::OnCodeStep(wxCommandEvent& event)
case IDM_SKIP:
PC += 4;
Update();
Repopulate();
break;
case IDM_SETPC:
PC = codeview->GetSelection();
Update();
Repopulate();
break;
case IDM_GOTOPC:
@ -372,8 +383,12 @@ void CCodeWindow::StepOut()
PowerPC::SetMode(old_mode);
CPU::PauseAndLock(false, false);
Host_UpdateDisasmDialog();
UpdateButtonStates();
JumpToAddress(PC);
{
wxCommandEvent ev(wxEVT_HOST_COMMAND, IDM_UPDATE_DISASM_DIALOG);
GetEventHandler()->ProcessEvent(ev);
}
// Update all toolbars in the aui manager
Parent->UpdateGUI();
}
@ -385,7 +400,7 @@ void CCodeWindow::ToggleBreakpoint()
{
if (codeview)
codeview->ToggleBreakpoint(codeview->GetSelection());
Update();
Repopulate();
}
}
@ -666,19 +681,18 @@ bool CCodeWindow::JITNoBlockLinking()
// Toolbar
void CCodeWindow::InitBitmaps()
{
m_Bitmaps[Toolbar_Step] = WxUtils::LoadResourceBitmap("toolbar_debugger_step");
m_Bitmaps[Toolbar_StepOver] = WxUtils::LoadResourceBitmap("toolbar_debugger_step_over");
m_Bitmaps[Toolbar_StepOut] = WxUtils::LoadResourceBitmap("toolbar_debugger_step_out");
m_Bitmaps[Toolbar_Skip] = WxUtils::LoadResourceBitmap("toolbar_debugger_skip");
m_Bitmaps[Toolbar_GotoPC] = WxUtils::LoadResourceBitmap("toolbar_debugger_goto_pc");
m_Bitmaps[Toolbar_SetPC] = WxUtils::LoadResourceBitmap("toolbar_debugger_set_pc");
static constexpr std::array<const char* const, Toolbar_Debug_Bitmap_Max> s_image_names{
{"toolbar_debugger_step", "toolbar_debugger_step_over", "toolbar_debugger_step_out",
"toolbar_debugger_skip", "toolbar_debugger_goto_pc", "toolbar_debugger_set_pc"}};
const wxSize tool_size = Parent->GetToolbarBitmapSize();
for (std::size_t i = 0; i < s_image_names.size(); ++i)
m_Bitmaps[i] =
WxUtils::LoadScaledResourceBitmap(s_image_names[i], Parent, tool_size, wxDefaultSize,
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
}
void CCodeWindow::PopulateToolbar(wxToolBar* toolBar)
{
int w = m_Bitmaps[0].GetWidth(), h = m_Bitmaps[0].GetHeight();
toolBar->SetToolBitmapSize(wxSize(w, h));
WxUtils::AddToolbarButton(toolBar, IDM_STEP, _("Step"), m_Bitmaps[Toolbar_Step],
_("Step into the next instruction"));
WxUtils::AddToolbarButton(toolBar, IDM_STEPOVER, _("Step Over"), m_Bitmaps[Toolbar_StepOver],
@ -695,7 +709,7 @@ void CCodeWindow::PopulateToolbar(wxToolBar* toolBar)
}
// Update GUI
void CCodeWindow::Update()
void CCodeWindow::Repopulate()
{
if (!codeview)
return;
@ -714,41 +728,28 @@ void CCodeWindow::UpdateButtonStates()
bool Initialized = (Core::GetState() != Core::CORE_UNINITIALIZED);
bool Pause = (Core::GetState() == Core::CORE_PAUSE);
bool Stepping = CPU::IsStepping();
bool can_step = Initialized && Stepping;
wxToolBar* ToolBar = GetToolBar();
// Toolbar
if (!ToolBar)
return;
if (!Initialized)
{
ToolBar->EnableTool(IDM_STEPOVER, false);
ToolBar->EnableTool(IDM_STEPOUT, false);
ToolBar->EnableTool(IDM_SKIP, false);
}
else
{
if (!Stepping)
{
ToolBar->EnableTool(IDM_STEPOVER, false);
ToolBar->EnableTool(IDM_STEPOUT, false);
ToolBar->EnableTool(IDM_SKIP, false);
}
else
{
ToolBar->EnableTool(IDM_STEPOVER, true);
ToolBar->EnableTool(IDM_STEPOUT, true);
ToolBar->EnableTool(IDM_SKIP, true);
}
}
ToolBar->EnableTool(IDM_STEP, Initialized && Stepping);
ToolBar->EnableTool(IDM_STEP, can_step);
ToolBar->EnableTool(IDM_STEPOVER, can_step);
ToolBar->EnableTool(IDM_STEPOUT, can_step);
ToolBar->EnableTool(IDM_SKIP, can_step);
ToolBar->EnableTool(IDM_SETPC, Pause);
ToolBar->Realize();
// Menu bar
// ------------------
GetMenuBar()->Enable(IDM_INTERPRETER, Pause); // CPU Mode
GetMenuBar()->Enable(IDM_STEP, can_step);
GetMenuBar()->Enable(IDM_STEPOVER, can_step);
GetMenuBar()->Enable(IDM_STEPOUT, can_step);
GetMenuBar()->Enable(IDM_JIT_NO_BLOCK_CACHE, !Initialized);
GetMenuBar()->Enable(IDM_JIT_OFF, Pause);

View File

@ -4,6 +4,8 @@
#pragma once
#include <array>
#include <wx/aui/framemanager.h>
#include <wx/bitmap.h>
#include <wx/panel.h>
@ -12,16 +14,16 @@
#include "Common/Event.h"
#include "DolphinWX/Globals.h"
class CCodeView;
class CFrame;
struct SConfig;
class CBreakPointWindow;
class CRegisterWindow;
class CWatchWindow;
class CBreakPointWindow;
class CMemoryWindow;
class CJitWindow;
class CCodeView;
class DSPDebuggerLLE;
class GFXDebuggerPanel;
struct SConfig;
class DolphinAuiToolBar;
class wxListBox;
@ -29,6 +31,48 @@ class wxMenu;
class wxMenuBar;
class wxToolBar;
namespace Details
{
template <class T>
struct DebugPanelToID;
template <>
struct DebugPanelToID<CBreakPointWindow>
{
static constexpr int ID = IDM_BREAKPOINT_WINDOW;
};
template <>
struct DebugPanelToID<CRegisterWindow>
{
static constexpr int ID = IDM_REGISTER_WINDOW;
};
template <>
struct DebugPanelToID<CWatchWindow>
{
static constexpr int ID = IDM_WATCH_WINDOW;
};
template <>
struct DebugPanelToID<CMemoryWindow>
{
static constexpr int ID = IDM_MEMORY_WINDOW;
};
template <>
struct DebugPanelToID<CJitWindow>
{
static constexpr int ID = IDM_JIT_WINDOW;
};
template <>
struct DebugPanelToID<DSPDebuggerLLE>
{
static constexpr int ID = IDM_SOUND_WINDOW;
};
template <>
struct DebugPanelToID<GFXDebuggerPanel>
{
static constexpr int ID = IDM_VIDEO_WINDOW;
};
}
class CCodeWindow : public wxPanel
{
public:
@ -41,10 +85,8 @@ public:
void Save();
// Parent interaction
CFrame* Parent;
wxMenuBar* GetMenuBar();
wxToolBar* GetToolBar();
wxBitmap m_Bitmaps[Toolbar_Debug_Bitmap_Max];
bool UseInterpreter();
bool BootToPause();
@ -53,7 +95,7 @@ public:
bool JITNoBlockLinking();
bool JumpToAddress(u32 address);
void Update() override;
void Repopulate();
void NotifyMapLoaded();
void CreateMenu(const SConfig& _LocalCoreStartupParameter, wxMenuBar* pMenuBar);
void CreateMenuOptions(wxMenu* pMenu);
@ -63,29 +105,35 @@ public:
void OpenPages();
// Menu bar
void ToggleCodeWindow(bool bShow);
void ToggleRegisterWindow(bool bShow);
void ToggleWatchWindow(bool bShow);
void ToggleBreakPointWindow(bool bShow);
void ToggleMemoryWindow(bool bShow);
void ToggleJitWindow(bool bShow);
void ToggleSoundWindow(bool bShow);
void ToggleVideoWindow(bool bShow);
// FIXME: This belongs in a separate class.
void TogglePanel(int id, bool show);
wxPanel* GetUntypedPanel(int id) const;
bool HasUntypedPanel(int id) const { return GetUntypedPanel(id) != nullptr; }
template <class T>
T* GetPanel() const
{
return static_cast<T*>(GetUntypedPanel(Details::DebugPanelToID<T>::ID));
}
template <class T>
bool HasPanel() const
{
return HasUntypedPanel(Details::DebugPanelToID<T>::ID);
}
template <class T>
T* RequirePanel()
{
if (T* p = GetPanel<T>())
return p;
// Sub dialogs
CRegisterWindow* m_RegisterWindow;
CWatchWindow* m_WatchWindow;
CBreakPointWindow* m_BreakpointWindow;
CMemoryWindow* m_MemoryWindow;
CJitWindow* m_JitWindow;
DSPDebuggerLLE* m_SoundWindow;
GFXDebuggerPanel* m_VideoWindow;
TogglePanel(Details::DebugPanelToID<T>::ID, true);
return GetPanel<T>();
}
// Settings
bool bAutomaticStart;
bool bBootToPause;
bool bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW + 1];
int iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW + 1];
bool bShowOnStart[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START];
int iNbAffiliation[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START];
private:
void OnCPUMode(wxCommandEvent& event);
@ -99,7 +147,6 @@ private:
void OnProfilerMenu(wxCommandEvent& event);
void OnSymbolListChange(wxCommandEvent& event);
void OnSymbolListContextMenu(wxContextMenuEvent& event);
void OnCallstackListChange(wxCommandEvent& event);
void OnCallersListChange(wxCommandEvent& event);
void OnCallsListChange(wxCommandEvent& event);
@ -116,7 +163,15 @@ private:
void UpdateCallstack();
void InitBitmaps();
wxPanel* CreateSiblingPanel(int id);
wxBitmap m_Bitmaps[Toolbar_Debug_Bitmap_Max];
// Sibling debugger panels
// FIXME: This obviously belongs in some manager class above this one.
std::array<wxPanel*, IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START> m_sibling_panels;
CFrame* Parent;
CCodeView* codeview;
wxListBox* callstack;
wxListBox* symbols;

View File

@ -453,7 +453,7 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event)
break;
case IDM_PATCH_HLE_FUNCTIONS:
HLE::PatchFunctions();
Update();
Repopulate();
break;
}
}
@ -464,7 +464,6 @@ void CCodeWindow::NotifyMapLoaded()
return;
g_symbolDB.FillInCallers();
// symbols->Show(false); // hide it for faster filling
symbols->Freeze(); // HyperIris: wx style fast filling
symbols->Clear();
for (const auto& symbol : g_symbolDB.Symbols())
@ -473,8 +472,7 @@ void CCodeWindow::NotifyMapLoaded()
symbols->SetClientData(idx, (void*)&symbol.second);
}
symbols->Thaw();
// symbols->Show(true);
Update();
Repopulate();
}
void CCodeWindow::OnSymbolListChange(wxCommandEvent& event)
@ -487,8 +485,9 @@ void CCodeWindow::OnSymbolListChange(wxCommandEvent& event)
{
if (pSymbol->type == Symbol::Type::Data)
{
if (m_MemoryWindow) // && m_MemoryWindow->IsVisible())
m_MemoryWindow->JumpToAddress(pSymbol->address);
CMemoryWindow* memory = GetPanel<CMemoryWindow>();
if (memory)
memory->JumpToAddress(pSymbol->address);
}
else
{
@ -498,10 +497,6 @@ void CCodeWindow::OnSymbolListChange(wxCommandEvent& event)
}
}
void CCodeWindow::OnSymbolListContextMenu(wxContextMenuEvent& event)
{
}
// Change the global DebuggerFont
void CCodeWindow::OnChangeFont(wxCommandEvent& event)
{
@ -511,157 +506,104 @@ void CCodeWindow::OnChangeFont(wxCommandEvent& event)
wxFontDialog dialog(this, data);
if (dialog.ShowModal() == wxID_OK)
DebuggerFont = dialog.GetFontData().GetChosenFont();
// TODO: Send event to all panels that tells them to reload the font when it changes.
}
// Toggle windows
wxPanel* CCodeWindow::GetUntypedPanel(int id) const
{
wxASSERT_MSG(id >= IDM_DEBUG_WINDOW_LIST_START && id < IDM_DEBUG_WINDOW_LIST_END,
"ID out of range");
wxASSERT_MSG(id != IDM_LOG_WINDOW && id != IDM_LOG_CONFIG_WINDOW,
"Log windows are managed separately");
return m_sibling_panels.at(id - IDM_DEBUG_WINDOW_LIST_START);
}
void CCodeWindow::TogglePanel(int id, bool show)
{
wxPanel* panel = GetUntypedPanel(id);
// Not all the panels (i.e. CodeWindow) have corresponding menu options.
wxMenuItem* item = GetMenuBar()->FindItem(id);
if (item)
item->Check(show);
if (show)
{
if (!panel)
{
panel = CreateSiblingPanel(id);
}
Parent->DoAddPage(panel, iNbAffiliation[id - IDM_DEBUG_WINDOW_LIST_START],
Parent->bFloatWindow[id - IDM_DEBUG_WINDOW_LIST_START]);
}
else if (panel) // Close
{
Parent->DoRemovePage(panel, panel == this);
m_sibling_panels[id - IDM_DEBUG_WINDOW_LIST_START] = nullptr;
}
}
wxPanel* CCodeWindow::CreateSiblingPanel(int id)
{
// Includes range check inside the get call
wxASSERT_MSG(!GetUntypedPanel(id), "Panel must not already exist");
wxPanel* panel = nullptr;
switch (id)
{
// case IDM_LOG_WINDOW: // These exist separately in CFrame.
// case IDM_LOG_CONFIG_WINDOW:
case IDM_REGISTER_WINDOW:
panel = new CRegisterWindow(Parent, IDM_REGISTER_WINDOW);
break;
case IDM_WATCH_WINDOW:
panel = new CWatchWindow(Parent, IDM_WATCH_WINDOW);
break;
case IDM_BREAKPOINT_WINDOW:
panel = new CBreakPointWindow(this, Parent, IDM_BREAKPOINT_WINDOW);
break;
case IDM_MEMORY_WINDOW:
panel = new CMemoryWindow(Parent, IDM_MEMORY_WINDOW);
break;
case IDM_JIT_WINDOW:
panel = new CJitWindow(Parent, IDM_JIT_WINDOW);
break;
case IDM_SOUND_WINDOW:
panel = new DSPDebuggerLLE(Parent, IDM_SOUND_WINDOW);
break;
case IDM_VIDEO_WINDOW:
panel = new GFXDebuggerPanel(Parent, IDM_VIDEO_WINDOW);
break;
case IDM_CODE_WINDOW:
panel = this;
break;
default:
wxTrap();
break;
}
m_sibling_panels[id - IDM_DEBUG_WINDOW_LIST_START] = panel;
return panel;
}
void CCodeWindow::OpenPages()
{
ToggleCodeWindow(true);
if (bShowOnStart[0])
// This is forced, and should always be placed as the first tab in the notebook.
TogglePanel(IDM_CODE_WINDOW, true);
// These panels are managed separately by CFrame
if (bShowOnStart[IDM_LOG_WINDOW - IDM_DEBUG_WINDOW_LIST_START])
Parent->ToggleLogWindow(true);
if (bShowOnStart[IDM_LOG_CONFIG_WINDOW - IDM_LOG_WINDOW])
if (bShowOnStart[IDM_LOG_CONFIG_WINDOW - IDM_DEBUG_WINDOW_LIST_START])
Parent->ToggleLogConfigWindow(true);
if (bShowOnStart[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW])
ToggleRegisterWindow(true);
if (bShowOnStart[IDM_WATCH_WINDOW - IDM_LOG_WINDOW])
ToggleWatchWindow(true);
if (bShowOnStart[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW])
ToggleBreakPointWindow(true);
if (bShowOnStart[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW])
ToggleMemoryWindow(true);
if (bShowOnStart[IDM_JIT_WINDOW - IDM_LOG_WINDOW])
ToggleJitWindow(true);
if (bShowOnStart[IDM_SOUND_WINDOW - IDM_LOG_WINDOW])
ToggleSoundWindow(true);
if (bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW])
ToggleVideoWindow(true);
}
void CCodeWindow::ToggleCodeWindow(bool bShow)
{
if (bShow)
Parent->DoAddPage(this, iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_CODE_WINDOW - IDM_LOG_WINDOW]);
else // Hide
Parent->DoRemovePage(this);
}
void CCodeWindow::ToggleRegisterWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_REGISTER_WINDOW)->Check(bShow);
if (bShow)
// Iterate normal panels that don't have weird rules.
for (int i = IDM_REGISTER_WINDOW; i < IDM_CODE_WINDOW; ++i)
{
if (!m_RegisterWindow)
m_RegisterWindow = new CRegisterWindow(Parent, IDM_REGISTER_WINDOW);
Parent->DoAddPage(m_RegisterWindow, iNbAffiliation[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_RegisterWindow, false);
m_RegisterWindow = nullptr;
}
}
void CCodeWindow::ToggleWatchWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_WATCH_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_WatchWindow)
m_WatchWindow = new CWatchWindow(Parent, IDM_WATCH_WINDOW);
Parent->DoAddPage(m_WatchWindow, iNbAffiliation[IDM_WATCH_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_WATCH_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_WatchWindow, false);
m_WatchWindow = nullptr;
}
}
void CCodeWindow::ToggleBreakPointWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_BREAKPOINT_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_BreakpointWindow)
m_BreakpointWindow = new CBreakPointWindow(this, Parent, IDM_BREAKPOINT_WINDOW);
Parent->DoAddPage(m_BreakpointWindow, iNbAffiliation[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_BreakpointWindow, false);
m_BreakpointWindow = nullptr;
}
}
void CCodeWindow::ToggleMemoryWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_MEMORY_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_MemoryWindow)
m_MemoryWindow = new CMemoryWindow(this, Parent, IDM_MEMORY_WINDOW);
Parent->DoAddPage(m_MemoryWindow, iNbAffiliation[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_MemoryWindow, false);
m_MemoryWindow = nullptr;
}
}
void CCodeWindow::ToggleJitWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_JIT_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_JitWindow)
m_JitWindow = new CJitWindow(Parent, IDM_JIT_WINDOW);
Parent->DoAddPage(m_JitWindow, iNbAffiliation[IDM_JIT_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_JIT_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_JitWindow, false);
m_JitWindow = nullptr;
}
}
void CCodeWindow::ToggleSoundWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_SOUND_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_SoundWindow)
m_SoundWindow = new DSPDebuggerLLE(Parent, IDM_SOUND_WINDOW);
Parent->DoAddPage(m_SoundWindow, iNbAffiliation[IDM_SOUND_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_SOUND_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_SoundWindow, false);
m_SoundWindow = nullptr;
}
}
void CCodeWindow::ToggleVideoWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_VIDEO_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_VideoWindow)
m_VideoWindow = new GFXDebuggerPanel(Parent, IDM_VIDEO_WINDOW);
Parent->DoAddPage(m_VideoWindow, iNbAffiliation[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_VideoWindow, false);
m_VideoWindow = nullptr;
if (bShowOnStart[i - IDM_DEBUG_WINDOW_LIST_START])
TogglePanel(i, true);
}
}

View File

@ -32,9 +32,8 @@ static DSPDebuggerLLE* m_DebuggerFrame = nullptr;
DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
: wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _("DSP LLE Debugger")),
m_CachedStepCounter(-1)
m_CachedStepCounter(-1), m_toolbar_item_size(FromDIP(wxSize(16, 16)))
{
Bind(wxEVT_CLOSE_WINDOW, &DSPDebuggerLLE::OnClose, this);
Bind(wxEVT_MENU, &DSPDebuggerLLE::OnChangeState, this, ID_RUNTOOL, ID_SHOWPCTOOL);
m_DebuggerFrame = this;
@ -46,11 +45,12 @@ DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
m_Toolbar =
new DolphinAuiToolBar(this, ID_TOOLBAR, wxDefaultPosition, wxDefaultSize, wxAUI_TB_HORZ_TEXT);
m_Toolbar->AddTool(ID_RUNTOOL, _("Pause"),
wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, wxSize(10, 10)));
wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->AddTool(ID_STEPTOOL, _("Step"),
wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_OTHER, wxSize(10, 10)));
m_Toolbar->AddTool(ID_SHOWPCTOOL, _("Show PC"),
wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_OTHER, wxSize(10, 10)));
wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->AddTool(
ID_SHOWPCTOOL, _("Show PC"),
wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->AddSeparator();
m_addr_txtctrl = new wxTextCtrl(m_Toolbar, wxID_ANY, wxEmptyString, wxDefaultPosition,
@ -60,8 +60,8 @@ DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
m_Toolbar->AddControl(m_addr_txtctrl);
m_Toolbar->Realize();
m_SymbolList =
new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(140, 100), 0, nullptr, wxLB_SORT);
m_SymbolList = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(100, 80)),
0, nullptr, wxLB_SORT);
m_SymbolList->Bind(wxEVT_LISTBOX, &DSPDebuggerLLE::OnSymbolListChange, this);
m_MainNotebook = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
@ -71,15 +71,14 @@ DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
wxBoxSizer* code_sizer = new wxBoxSizer(wxVERTICAL);
m_CodeView = new CCodeView(&debug_interface, &DSPSymbols::g_dsp_symbol_db, code_panel);
m_CodeView->SetPlain();
code_sizer->Add(m_CodeView, 1, wxALL | wxEXPAND);
code_sizer->Add(m_CodeView, 1, wxEXPAND);
code_panel->SetSizer(code_sizer);
m_MainNotebook->AddPage(code_panel, _("Disassembly"), true);
wxPanel* mem_panel = new wxPanel(m_MainNotebook, wxID_ANY);
wxBoxSizer* mem_sizer = new wxBoxSizer(wxVERTICAL);
// TODO insert memViewer class
m_MemView = new CMemoryView(&debug_interface, mem_panel);
mem_sizer->Add(m_MemView, 1, wxALL | wxEXPAND);
mem_sizer->Add(m_MemView, 1, wxEXPAND);
mem_panel->SetSizer(mem_sizer);
m_MainNotebook->AddPage(mem_panel, _("Memory"));
@ -111,11 +110,6 @@ DSPDebuggerLLE::~DSPDebuggerLLE()
m_DebuggerFrame = nullptr;
}
void DSPDebuggerLLE::OnClose(wxCloseEvent& event)
{
event.Skip();
}
void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
{
if (DSPCore_GetState() == DSPCORE_STOP)
@ -134,7 +128,7 @@ void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
if (DSPCore_GetState() == DSPCORE_STEPPING)
{
DSPCore_Step();
Update();
Repopulate();
}
break;
@ -149,24 +143,24 @@ void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
void Host_RefreshDSPDebuggerWindow()
{
// FIXME: This should use QueueEvent to post the update request to the UI thread.
// Need to check if this can safely be performed asynchronously or if it races.
// FIXME: This probably belongs in Main.cpp with the other host functions.
// NOTE: The DSP never tells us when it shuts down. It probably should.
if (m_DebuggerFrame)
m_DebuggerFrame->Update();
m_DebuggerFrame->Repopulate();
}
void DSPDebuggerLLE::Update()
void DSPDebuggerLLE::Repopulate()
{
#if defined __WXGTK__
if (!wxIsMainThread())
wxMutexGuiEnter();
#endif
UpdateSymbolMap();
UpdateDisAsmListView();
UpdateRegisterFlags();
UpdateState();
#if defined __WXGTK__
if (!wxIsMainThread())
wxMutexGuiLeave();
#endif
}
void DSPDebuggerLLE::FocusOnPC()
@ -180,14 +174,14 @@ void DSPDebuggerLLE::UpdateState()
{
m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Pause"));
m_Toolbar->SetToolBitmap(
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, wxSize(10, 10)));
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->EnableTool(ID_STEPTOOL, false);
}
else
{
m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Run"));
m_Toolbar->SetToolBitmap(
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_OTHER, wxSize(10, 10)));
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->EnableTool(ID_STEPTOOL, true);
}
m_Toolbar->Realize();
@ -201,7 +195,7 @@ void DSPDebuggerLLE::UpdateDisAsmListView()
// show PC
FocusOnPC();
m_CachedStepCounter = g_dsp.step_counter;
m_Regs->Update();
m_Regs->Repopulate();
}
void DSPDebuggerLLE::UpdateSymbolMap()

View File

@ -23,7 +23,7 @@ public:
DSPDebuggerLLE(wxWindow* parent, wxWindowID id = wxID_ANY);
virtual ~DSPDebuggerLLE();
void Update() override;
void Repopulate();
private:
enum
@ -52,8 +52,8 @@ private:
wxListBox* m_SymbolList;
wxTextCtrl* m_addr_txtctrl;
wxAuiNotebook* m_MainNotebook;
wxSize m_toolbar_item_size;
void OnClose(wxCloseEvent& event);
void OnChangeState(wxCommandEvent& event);
// void OnRightClick(wxListEvent& event);
// void OnDoubleClick(wxListEvent& event);

View File

@ -71,7 +71,7 @@ wxGridCellAttr* CDSPRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKi
}
DSPRegisterView::DSPRegisterView(wxWindow* parent, wxWindowID id)
: wxGrid(parent, id, wxDefaultPosition, wxSize(130, 120))
: wxGrid(parent, id, wxDefaultPosition, wxDLG_UNIT(parent, wxSize(100, 80)))
{
m_register_table = new CDSPRegTable();
@ -83,7 +83,7 @@ DSPRegisterView::DSPRegisterView(wxWindow* parent, wxWindowID id)
AutoSizeColumns();
}
void DSPRegisterView::Update()
void DSPRegisterView::Repopulate()
{
m_register_table->UpdateCachedRegs();
ForceRefresh();

View File

@ -38,7 +38,7 @@ class DSPRegisterView : public wxGrid
{
public:
DSPRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY);
void Update() override;
void Repopulate();
private:
// Owned by wx. Deleted implicitly upon destruction.

View File

@ -11,6 +11,7 @@
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include "Common/CommonFuncs.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Core/ConfigManager.h"
@ -26,10 +27,6 @@ GFXDebuggerPanel::GFXDebuggerPanel(wxWindow* parent, wxWindowID id, const wxPoin
g_pdebugger = this;
CreateGUIControls();
Bind(wxEVT_CLOSE_WINDOW, &GFXDebuggerPanel::OnClose, this);
LoadSettings();
}
GFXDebuggerPanel::~GFXDebuggerPanel()
@ -38,55 +35,6 @@ GFXDebuggerPanel::~GFXDebuggerPanel()
GFXDebuggerPauseFlag = false;
}
void GFXDebuggerPanel::OnClose(wxCloseEvent& event)
{
// save the window position when we hide the window
SaveSettings();
event.Skip();
}
void GFXDebuggerPanel::SaveSettings() const
{
IniFile file;
file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
// TODO: make this work when we close the entire program too, currently on total close we get
// weird values, perhaps because of some conflict with the rendering window
// TODO: get the screen resolution and make limits from that
if (GetPosition().x < 1000 && GetPosition().y < 1000 && GetSize().GetWidth() < 1000 &&
GetSize().GetHeight() < 1000)
{
IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow");
video_window->Set("x", GetPosition().x);
video_window->Set("y", GetPosition().y);
video_window->Set("w", GetSize().GetWidth());
video_window->Set("h", GetSize().GetHeight());
}
file.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
}
void GFXDebuggerPanel::LoadSettings()
{
IniFile file;
file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
int x = 100;
int y = 100;
int w = 100;
int h = 100;
IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow");
video_window->Get("x", &x, GetPosition().x);
video_window->Get("y", &y, GetPosition().y);
video_window->Get("w", &w, GetSize().GetWidth());
video_window->Get("h", &h, GetSize().GetHeight());
SetSize(x, y, w, h);
}
struct PauseEventMap
{
PauseEvent event;
@ -118,10 +66,9 @@ void GFXDebuggerPanel::CreateGUIControls()
{NEXT_ERROR, _("Error")}};
pauseEventMap = map;
const int numPauseEventMap = sizeof(map) / sizeof(PauseEventMap);
static constexpr int numPauseEventMap = ArraySize(map);
// Basic settings
CenterOnParent();
const int space3 = FromDIP(3);
m_pButtonPause = new wxButton(this, wxID_ANY, _("Pause"), wxDefaultPosition, wxDefaultSize, 0,
wxDefaultValidator, _("Pause"));
@ -139,10 +86,11 @@ void GFXDebuggerPanel::CreateGUIControls()
wxDefaultValidator, _("Continue"));
m_pButtonCont->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnContButton, this);
m_pCount = new wxTextCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxSize(50, 25), wxTE_RIGHT,
m_pCount = new wxTextCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxDefaultSize, wxTE_RIGHT,
wxDefaultValidator, _("Count"));
m_pCount->SetMinSize(WxUtils::GetTextWidgetMinSize(m_pCount, 10000));
m_pPauseAtList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(100, 25), 0, nullptr, 0,
m_pPauseAtList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, 0,
wxDefaultValidator, _("PauseAtList"));
for (int i = 0; i < numPauseEventMap; i++)
{
@ -180,7 +128,7 @@ void GFXDebuggerPanel::CreateGUIControls()
m_pButtonClearPixelShaderCache->Bind(wxEVT_BUTTON,
&GFXDebuggerPanel::OnClearPixelShaderCacheButton, this);
m_pDumpList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(120, 25), 0, nullptr, 0,
m_pDumpList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, 0,
wxDefaultValidator, _("DumpList"));
m_pDumpList->Insert(_("Pixel Shader"), 0);
m_pDumpList->Append(_("Vertex Shader"));
@ -196,31 +144,40 @@ void GFXDebuggerPanel::CreateGUIControls()
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control"));
wxBoxSizer* const pPauseAtNextSzr = new wxBoxSizer(wxHORIZONTAL);
pFlowCtrlBox->Add(m_pButtonPause);
pPauseAtNextSzr->Add(m_pButtonPauseAtNext);
pPauseAtNextSzr->Add(m_pCount);
pPauseAtNextSzr->Add(m_pPauseAtList);
pFlowCtrlBox->Add(pPauseAtNextSzr);
pFlowCtrlBox->Add(m_pButtonPauseAtNextFrame);
pFlowCtrlBox->Add(m_pButtonCont);
pPauseAtNextSzr->Add(m_pCount, 0, wxALIGN_CENTER_VERTICAL);
pPauseAtNextSzr->Add(m_pPauseAtList, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
wxFlexGridSizer* const flow_szr = new wxFlexGridSizer(2, space3, space3);
flow_szr->Add(m_pButtonPause, 0, wxEXPAND);
flow_szr->AddSpacer(1);
flow_szr->Add(m_pButtonPauseAtNext, 0, wxEXPAND);
flow_szr->Add(pPauseAtNextSzr, 0, wxEXPAND);
flow_szr->Add(m_pButtonPauseAtNextFrame, 0, wxEXPAND);
flow_szr->AddSpacer(1);
flow_szr->Add(m_pButtonCont, 0, wxEXPAND);
flow_szr->AddSpacer(1);
wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control"));
pFlowCtrlBox->Add(flow_szr, 1, wxEXPAND);
wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL);
pDumpSzr->Add(m_pButtonDump, 0, wxALIGN_CENTER_VERTICAL);
pDumpSzr->Add(m_pDumpList, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
wxGridSizer* const pDbgGrid = new wxGridSizer(2, space3, space3);
pDbgGrid->Add(m_pButtonUpdateScreen, 0, wxEXPAND);
pDbgGrid->Add(m_pButtonClearScreen, 0, wxEXPAND);
pDbgGrid->Add(m_pButtonClearTextureCache, 0, wxEXPAND);
pDbgGrid->Add(m_pButtonClearVertexShaderCache, 0, wxEXPAND);
pDbgGrid->Add(m_pButtonClearPixelShaderCache, 0, wxEXPAND);
wxStaticBoxSizer* const pDebugBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Debugging"));
wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL);
pDumpSzr->Add(m_pButtonDump);
pDumpSzr->Add(m_pDumpList);
pDebugBox->Add(pDumpSzr);
wxGridSizer* const pDbgGrid = new wxGridSizer(2, 5, 5);
pDbgGrid->Add(m_pButtonUpdateScreen);
pDbgGrid->Add(m_pButtonClearScreen);
pDbgGrid->Add(m_pButtonClearTextureCache);
pDbgGrid->Add(m_pButtonClearVertexShaderCache);
pDbgGrid->Add(m_pButtonClearPixelShaderCache);
pDebugBox->Add(pDbgGrid);
pDebugBox->Add(pDumpSzr, 0, wxEXPAND);
pDebugBox->Add(pDbgGrid, 1, wxTOP, space3);
sMain->Add(pFlowCtrlBox, 0, 0, 5);
sMain->Add(pDebugBox, 0, 0, 5);
sMain->Add(pFlowCtrlBox);
sMain->Add(pDebugBox);
SetSizerAndFit(sMain);
OnContinue();
@ -248,12 +205,6 @@ void GFXDebuggerPanel::OnContinue()
m_pButtonClearPixelShaderCache->Disable();
}
// General settings
void GFXDebuggerPanel::GeneralSettings(wxCommandEvent& event)
{
SaveSettings();
}
void GFXDebuggerPanel::OnPauseButton(wxCommandEvent& event)
{
GFXDebuggerPauseFlag = true;

View File

@ -20,9 +20,6 @@ public:
virtual ~GFXDebuggerPanel();
void SaveSettings() const;
void LoadSettings();
bool bInfoLog;
bool bPrimLog;
bool bSaveTextures;
@ -49,11 +46,8 @@ private:
wxButton* m_pButtonClearPixelShaderCache;
wxTextCtrl* m_pCount;
void OnClose(wxCloseEvent& event);
void CreateGUIControls();
void GeneralSettings(wxCommandEvent& event);
// These set GFXDebuggerPauseFlag to true (either immediately or once the specified event has
// occurred)
void OnPauseButton(wxCommandEvent& event);

View File

@ -34,7 +34,8 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, cons
sizerSplit->Add(x86_box = new wxTextCtrl(this, wxID_ANY, "(x86)", wxDefaultPosition,
wxDefaultSize, wxTE_MULTILINE),
1, wxEXPAND);
sizerBig->Add(block_list = new JitBlockList(this, wxID_ANY, wxDefaultPosition, wxSize(100, 140),
sizerBig->Add(block_list = new JitBlockList(this, wxID_ANY, wxDefaultPosition,
wxDLG_UNIT(this, wxSize(80, 96)),
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT |
wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING),
0, wxEXPAND);
@ -43,10 +44,7 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, cons
sizerBig->Add(button_refresh = new wxButton(this, wxID_ANY, _("&Refresh")));
button_refresh->Bind(wxEVT_BUTTON, &CJitWindow::OnRefresh, this);
SetSizer(sizerBig);
sizerSplit->Fit(this);
sizerBig->Fit(this);
SetSizerAndFit(sizerBig);
#if defined(_M_X86)
m_disassembler.reset(GetNewDisassembler("x86"));
@ -59,7 +57,7 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, cons
void CJitWindow::OnRefresh(wxCommandEvent& /*event*/)
{
block_list->Update();
block_list->Repopulate();
}
void CJitWindow::ViewAddr(u32 em_address)
@ -135,7 +133,7 @@ void CJitWindow::Compare(u32 em_address)
}
}
void CJitWindow::Update()
void CJitWindow::Repopulate()
{
}
@ -181,6 +179,6 @@ void JitBlockList::Init()
InsertColumn(COLUMN_COST, _("Cost"));
}
void JitBlockList::Update()
void JitBlockList::Repopulate()
{
}

View File

@ -22,7 +22,7 @@ public:
JitBlockList(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size,
long style);
void Init();
void Update() override;
void Repopulate();
};
class CJitWindow : public wxPanel
@ -33,7 +33,7 @@ public:
const wxString& name = _("JIT Block Viewer"));
void ViewAddr(u32 em_address);
void Update() override;
void Repopulate();
private:
void OnRefresh(wxCommandEvent& /*event*/);

View File

@ -22,6 +22,8 @@ MemoryCheckDlg::MemoryCheckDlg(CBreakPointWindow* parent)
Bind(wxEVT_BUTTON, &MemoryCheckDlg::OnOK, this, wxID_OK);
Bind(wxEVT_RADIOBUTTON, &MemoryCheckDlg::OnRadioButtonClick, this);
const int space5 = FromDIP(5);
m_textAddress = new wxStaticText(this, wxID_ANY, _("Address"));
m_textStartAddress = new wxStaticText(this, wxID_ANY, _("Start"));
m_textStartAddress->Disable();
@ -46,14 +48,22 @@ MemoryCheckDlg::MemoryCheckDlg(CBreakPointWindow* parent)
m_radioBreakLog->SetValue(true);
auto* sAddressBox = new wxBoxSizer(wxHORIZONTAL);
sAddressBox->Add(m_textAddress, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
sAddressBox->Add(m_pEditAddress, 1, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, 10);
sAddressBox->AddSpacer(space5);
sAddressBox->Add(m_textAddress, 0, wxALIGN_CENTER_VERTICAL);
sAddressBox->AddSpacer(space5);
sAddressBox->Add(m_pEditAddress, 1, wxALIGN_CENTER_VERTICAL);
sAddressBox->AddSpacer(space5);
auto* sAddressRangeBox = new wxBoxSizer(wxHORIZONTAL);
sAddressRangeBox->Add(m_textStartAddress, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
sAddressRangeBox->Add(m_pEditStartAddress, 1, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, 10);
sAddressRangeBox->Add(m_textEndAddress, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
sAddressRangeBox->Add(m_pEditEndAddress, 1, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, 5);
sAddressRangeBox->AddSpacer(space5);
sAddressRangeBox->Add(m_textStartAddress, 0, wxALIGN_CENTER_VERTICAL);
sAddressRangeBox->AddSpacer(space5);
sAddressRangeBox->Add(m_pEditStartAddress, 1, wxALIGN_CENTER_VERTICAL);
sAddressRangeBox->AddSpacer(space5);
sAddressRangeBox->Add(m_textEndAddress, 0, wxALIGN_CENTER_VERTICAL);
sAddressRangeBox->AddSpacer(space5);
sAddressRangeBox->Add(m_pEditEndAddress, 1, wxALIGN_CENTER_VERTICAL);
sAddressRangeBox->AddSpacer(space5);
auto* sActions = new wxStaticBoxSizer(wxVERTICAL, this, _("Action"));
sActions->Add(m_radioRead, 0, wxEXPAND);
@ -67,19 +77,26 @@ MemoryCheckDlg::MemoryCheckDlg(CBreakPointWindow* parent)
sFlags->Add(m_radioBreakLog);
auto* sOptionsBox = new wxBoxSizer(wxHORIZONTAL);
sOptionsBox->Add(sActions, 1, wxEXPAND | wxRIGHT | wxTOP | wxBOTTOM, 5);
sOptionsBox->Add(sFlags, 1, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 5);
sOptionsBox->Add(sActions, 1, wxEXPAND, space5);
sOptionsBox->Add(sFlags, 1, wxEXPAND | wxLEFT, space5);
auto* sControls = new wxBoxSizer(wxVERTICAL);
sControls->Add(m_radioAddress, 0, wxEXPAND);
sControls->AddSpacer(5);
sControls->Add(sAddressBox, 0, wxEXPAND);
sControls->AddSpacer(5);
sControls->Add(m_radioRange, 0, wxEXPAND);
sControls->AddSpacer(5);
sControls->Add(sAddressRangeBox, 0, wxEXPAND);
sControls->AddSpacer(5);
sControls->Add(sOptionsBox, 0, wxEXPAND);
auto* sMainSizer = new wxBoxSizer(wxVERTICAL);
sMainSizer->Add(sControls, 0, wxEXPAND | wxTOP | wxRIGHT | wxLEFT, 5);
sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
sMainSizer->AddSpacer(space5);
sMainSizer->Add(sControls, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMainSizer->AddSpacer(space5);
sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMainSizer->AddSpacer(space5);
SetSizerAndFit(sMainSizer);
SetFocus();

View File

@ -2,6 +2,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <cctype>
#include <cmath>
#include <string>
#include <wx/brush.h>
@ -17,6 +19,7 @@
#include "Common/CommonTypes.h"
#include "Common/DebugInterface.h"
#include "Common/StringUtil.h"
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/CodeWindow.h"
@ -25,6 +28,7 @@
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/Main.h"
#include "DolphinWX/WxUtils.h"
enum
@ -42,11 +46,12 @@ enum
IDM_VIEWASHEX,
};
wxDEFINE_EVENT(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, wxCommandEvent);
CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent)
: wxControl(parent, wxID_ANY), debugger(debuginterface),
align(debuginterface->GetInstructionSize(0)), rowHeight(13), selection(0), oldSelection(0),
selecting(false), memory(0), curAddress(debuginterface->GetPC()),
dataType(MemoryDataType::U8), viewAsType(VIEWAS_FP)
: wxControl(parent, wxID_ANY), debugger(debuginterface), align(0), rowHeight(FromDIP(13)),
m_left_col_width(FromDIP(LEFT_COL_WIDTH)), selection(0), oldSelection(0), selecting(false),
memory(0), curAddress(debuginterface->GetPC()), m_data_type(MemoryDataType::U8)
{
Bind(wxEVT_PAINT, &CMemoryView::OnPaint, this);
Bind(wxEVT_LEFT_DOWN, &CMemoryView::OnMouseDownL, this);
@ -56,6 +61,38 @@ CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent)
Bind(wxEVT_MOUSEWHEEL, &CMemoryView::OnScrollWheel, this);
Bind(wxEVT_MENU, &CMemoryView::OnPopupMenu, this);
Bind(wxEVT_SIZE, &CMemoryView::OnResize, this);
SetDataType(MemoryDataType::FloatingPoint);
// Every pixel will be drawn over in the paint event so erasing will just cause flickering.
SetBackgroundStyle(wxBG_STYLE_PAINT);
#if defined(__WXMSW__) || defined(__WXGTK__)
SetDoubleBuffered(true);
#endif
}
void CMemoryView::SetDataType(MemoryDataType data_type)
{
if (m_data_type == data_type)
return;
m_data_type = data_type;
switch (data_type)
{
case MemoryDataType::FloatingPoint:
case MemoryDataType::ASCII:
align = 4;
break;
default:
align = 16;
m_last_hex_type = data_type;
break;
}
Refresh();
wxCommandEvent ev(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, GetId());
ev.SetInt(static_cast<int>(data_type));
GetEventHandler()->ProcessEvent(ev);
}
int CMemoryView::YToAddress(int y)
@ -68,10 +105,10 @@ int CMemoryView::YToAddress(int y)
void CMemoryView::OnMouseDownL(wxMouseEvent& event)
{
int x = event.m_x;
int y = event.m_y;
int x = event.GetX();
int y = event.GetY();
if (x > 16)
if (x > m_left_col_width)
{
oldSelection = selection;
selection = YToAddress(y);
@ -99,7 +136,7 @@ void CMemoryView::OnMouseMove(wxMouseEvent& event)
{
wxRect rc = GetClientRect();
if (event.m_leftDown && event.m_x > 16)
if (event.m_leftDown && event.m_x > m_left_col_width)
{
if (event.m_y < 0)
{
@ -120,7 +157,7 @@ void CMemoryView::OnMouseMove(wxMouseEvent& event)
void CMemoryView::OnMouseUpL(wxMouseEvent& event)
{
if (event.m_x > 16)
if (event.m_x > m_left_col_width)
{
curAddress = YToAddress(event.m_y);
selecting = false;
@ -137,11 +174,11 @@ void CMemoryView::OnScrollWheel(wxMouseEvent& event)
if (scroll_down)
{
curAddress += num_lines * 4;
curAddress += num_lines * align;
}
else
{
curAddress -= num_lines * 4;
curAddress -= num_lines * align;
}
Refresh();
@ -150,25 +187,26 @@ void CMemoryView::OnScrollWheel(wxMouseEvent& event)
void CMemoryView::OnPopupMenu(wxCommandEvent& event)
{
CFrame* main_frame = static_cast<CFrame*>(GetGrandParent()->GetParent());
CCodeWindow* code_window = main_frame->g_pCodeWindow;
CWatchWindow* watch_window = code_window->m_WatchWindow;
#if wxUSE_CLIPBOARD
wxTheClipboard->Open();
#endif
// FIXME: This is terrible. Generate events instead.
CFrame* cframe = wxGetApp().GetCFrame();
CCodeWindow* code_window = cframe->g_pCodeWindow;
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
switch (event.GetId())
{
#if wxUSE_CLIPBOARD
case IDM_COPYADDRESS:
{
wxClipboardLocker clipboard_lock;
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", selection)));
break;
}
break;
case IDM_COPYHEX:
{
std::string temp = StringFromFormat("%08x", debugger->ReadExtraMemory(memory, selection));
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
wxClipboardLocker clipboard_lock;
wxTheClipboard->SetData(new wxTextDataObject(
wxString::Format("%08x", debugger->ReadExtraMemory(memory, selection))));
}
break;
#endif
@ -186,24 +224,21 @@ void CMemoryView::OnPopupMenu(wxCommandEvent& event)
break;
case IDM_VIEWASFP:
viewAsType = VIEWAS_FP;
Refresh();
SetDataType(MemoryDataType::FloatingPoint);
break;
case IDM_VIEWASASCII:
viewAsType = VIEWAS_ASCII;
Refresh();
SetDataType(MemoryDataType::ASCII);
break;
case IDM_VIEWASHEX:
viewAsType = VIEWAS_HEX;
Refresh();
SetDataType(m_last_hex_type);
break;
default:
event.Skip();
break;
}
#if wxUSE_CLIPBOARD
wxTheClipboard->Close();
#endif
event.Skip();
}
void CMemoryView::OnMouseDownR(wxMouseEvent& event)
@ -216,12 +251,14 @@ void CMemoryView::OnMouseDownR(wxMouseEvent& event)
menu.Append(IDM_COPYHEX, _("Copy &hex"));
#endif
menu.Append(IDM_WATCHADDRESS, _("Add to &watch"));
menu.Append(IDM_TOGGLEMEMORY, _("Toggle &memory"));
menu.AppendCheckItem(IDM_TOGGLEMEMORY, _("Toggle &memory"))->Check(memory != 0);
wxMenu* viewAsSubMenu = new wxMenu;
viewAsSubMenu->Append(IDM_VIEWASFP, _("FP value"));
viewAsSubMenu->Append(IDM_VIEWASASCII, "ASCII");
viewAsSubMenu->Append(IDM_VIEWASHEX, _("Hex"));
viewAsSubMenu->AppendRadioItem(IDM_VIEWASFP, _("FP value"))
->Check(m_data_type == MemoryDataType::FloatingPoint);
viewAsSubMenu->AppendRadioItem(IDM_VIEWASASCII, "ASCII")
->Check(m_data_type == MemoryDataType::ASCII);
viewAsSubMenu->AppendRadioItem(IDM_VIEWASHEX, _("Hex"))->Check(IsHexMode());
menu.AppendSubMenu(viewAsSubMenu, _("View As:"));
PopupMenu(&menu);
@ -231,176 +268,160 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
wxRect rc = GetClientRect();
wxFont hFont("Courier");
hFont.SetFamily(wxFONTFAMILY_TELETYPE);
wxCoord w, h;
dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &hFont);
if (h > rowHeight)
rowHeight = h;
dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &DebuggerFont);
if (h > rowHeight)
rowHeight = h;
if (viewAsType == VIEWAS_HEX)
dc.SetFont(hFont);
else
if (DebuggerFont.IsFixedWidth())
{
dc.SetFont(DebuggerFont);
}
else
{
dc.SetFont(wxFont(DebuggerFont.GetPointSize(), wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
wxFONTWEIGHT_NORMAL, false, "Courier"));
}
dc.GetTextExtent("W", &w, &h);
int fontSize = w;
int textPlacement = 17 + 9 * fontSize;
int font_width;
{
wxFontMetrics metrics = dc.GetFontMetrics();
font_width = metrics.averageWidth;
if (metrics.height > rowHeight)
rowHeight = metrics.height;
}
// TODO: Add any drawing code here...
int width = rc.width;
int numRows = (rc.height / rowHeight) / 2 + 2;
dc.SetBackgroundMode(wxPENSTYLE_TRANSPARENT);
const wxColour bgColor = *wxWHITE;
wxPen nullPen(bgColor);
wxPen currentPen(*wxBLACK_PEN);
wxPen selPen(*wxGREY_PEN);
nullPen.SetStyle(wxPENSTYLE_TRANSPARENT);
const int row_start_x = m_left_col_width + 1;
const int mchk_x = FromDIP(LEFT_COL_WIDTH / 8);
const wxSize mchk_size = FromDIP(wxSize(LEFT_COL_WIDTH * 3 / 4, LEFT_COL_WIDTH * 3 / 4));
const int mchk_offset_y = (rowHeight - mchk_size.GetHeight()) / 2;
wxBrush currentBrush(*wxLIGHT_GREY_BRUSH);
wxBrush pcBrush(*wxGREEN_BRUSH);
wxBrush mcBrush(*wxBLUE_BRUSH);
wxBrush bgBrush(bgColor);
wxBrush nullBrush(bgColor);
nullBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
int col_width = rc.width - m_left_col_width;
int num_rows = (rc.height / rowHeight) / 2 + 2;
const wxColour navy_color = wxTheColourDatabase->Find("NAVY");
dc.SetPen(nullPen);
dc.SetBrush(bgBrush);
dc.DrawRectangle(0, 0, 16, rc.height);
dc.DrawRectangle(0, 0, rc.width, 5 + 8);
const int pen_width = FromDIP(1);
wxPen focus_pen(*wxBLACK, pen_width);
wxPen selection_pen(*wxLIGHT_GREY, pen_width);
wxBrush pc_brush(*wxGREEN_BRUSH);
wxBrush mc_brush(*wxBLUE_BRUSH);
wxBrush bg_brush(*wxWHITE_BRUSH);
// TODO - clean up this freaking mess!!!!!
for (int row = -numRows; row <= numRows; row++)
for (int row = -num_rows; row <= num_rows; ++row)
{
unsigned int address = curAddress + row * align;
u32 address = curAddress + row * align;
int rowY1 = rc.height / 2 + rowHeight * row - rowHeight / 2;
int rowY2 = rc.height / 2 + rowHeight * row + rowHeight / 2;
int row_y = rc.height / 2 + rowHeight * row - rowHeight / 2;
int row_x = row_start_x;
auto draw_text = [&](const wxString& s, int offset_chars = 0, int min_length = 0) -> void {
dc.DrawText(s, row_x + font_width * offset_chars, row_y);
row_x += font_width * (std::max(static_cast<int>(s.size()), min_length) + offset_chars);
};
wxString temp = wxString::Format("%08x", address);
u32 col = debugger->GetColor(address);
wxBrush rowBrush(wxColour(col >> 16, col >> 8, col));
dc.SetBrush(nullBrush);
dc.SetPen(nullPen);
dc.DrawRectangle(0, rowY1, 16, rowY2);
dc.SetBrush(bg_brush);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(0, row_y, m_left_col_width, rowHeight);
if (selecting && (address == selection))
dc.SetPen(selPen);
dc.SetPen(selection_pen);
else
dc.SetPen(row == 0 ? currentPen : nullPen);
dc.SetPen(row == 0 ? focus_pen : *wxTRANSPARENT_PEN);
if (address == debugger->GetPC())
dc.SetBrush(pcBrush);
dc.SetBrush(pc_brush);
else
dc.SetBrush(rowBrush);
dc.DrawRectangle(16, rowY1, width, rowY2 - 1);
dc.SetBrush(currentBrush);
dc.SetTextForeground("#600000"); // Dark red
dc.DrawText(temp, 17, rowY1);
dc.DrawRectangle(m_left_col_width, row_y, col_width, rowHeight);
dc.SetTextForeground(wxColour(0x60, 0x00, 0x00)); // Dark red
draw_text(temp);
if (viewAsType != VIEWAS_HEX)
if (!IsHexMode())
{
char mem[256];
debugger->GetRawMemoryString(memory, address, mem, 256);
dc.SetTextForeground(wxTheColourDatabase->Find("NAVY"));
dc.DrawText(StrToWxStr(mem), 17 + fontSize * (8), rowY1);
dc.SetTextForeground(*wxBLACK);
dc.SetTextForeground(navy_color);
draw_text(StrToWxStr(mem), 2);
}
dc.SetTextForeground(*wxBLACK);
// NOTE: We can trigger a segfault inside HostIsRAMAddress (nullptr) during shutdown
// because we still get paint events even though the core is being deleted so we
// need to make sure the Memory still exists.
// FIXME: This isn't relevant to the DSP Memory View
if (!debugger->IsAlive() || !Memory::IsInitialized() || !PowerPC::HostIsRAMAddress(address))
continue;
std::string dis;
// FIXME: This doesn't work with the DSP Debugger
u32 mem_data = debugger->ReadExtraMemory(memory, address);
if (m_data_type == MemoryDataType::FloatingPoint)
{
float& flt = reinterpret_cast<float&>(mem_data);
dis = StringFromFormat("f: %f", flt);
}
else if (m_data_type == MemoryDataType::ASCII)
{
dis.reserve(4);
for (unsigned int i = 0; i < 4; ++i)
{
u8 byte = static_cast<u8>(mem_data >> (24 - i * 8));
if (std::isprint(byte))
dis += static_cast<char>(byte);
else
dis += ' ';
}
Symbol* sym = g_symbolDB.GetSymbolFromAddr(mem_data);
if (sym)
{
dis += StringFromFormat(" # -> %s", sym->name.c_str());
}
}
else
{
dis.reserve(48);
for (unsigned int i = 0; i < align; i += sizeof(u32))
{
if (!PowerPC::HostIsRAMAddress(address + i))
break;
u32 word = debugger->ReadExtraMemory(memory, address + i);
switch (m_data_type)
{
case MemoryDataType::U8:
default:
dis += StringFromFormat(" %02X %02X %02X %02X", (word >> 24) & 0xFF, (word >> 16) & 0xFF,
(word >> 8) & 0xFF, word & 0xFF);
break;
case MemoryDataType::U16:
dis += StringFromFormat(" %04X %04X", (word >> 16) & 0xFFFF, word & 0xFFFF);
break;
case MemoryDataType::U32:
dis += StringFromFormat(" %08X", word);
break;
}
}
}
if (debugger->IsAlive())
// Pad to a minimum of 48 characters for full fixed point float width
draw_text(StrToWxStr(dis), 2, 48);
dc.SetTextForeground(*wxBLUE);
std::string desc = debugger->GetDescription(address);
if (!desc.empty())
draw_text(StrToWxStr(desc), 2);
// Show blue memory check dot
if (debugger->IsMemCheck(address))
{
if (!PowerPC::HostIsRAMAddress(address))
continue;
std::string dis;
u32 mem_data = debugger->ReadExtraMemory(memory, address);
if (viewAsType == VIEWAS_FP)
{
float flt = *(float*)(&mem_data);
dis = StringFromFormat("f: %f", flt);
}
else if (viewAsType == VIEWAS_ASCII)
{
u32 a[4] = {(mem_data & 0xff000000) >> 24, (mem_data & 0xff0000) >> 16,
(mem_data & 0xff00) >> 8, (mem_data & 0xff)};
for (auto& word : a)
{
if (word == '\0')
word = ' ';
}
Symbol* sym = g_symbolDB.GetSymbolFromAddr(mem_data);
if (sym == nullptr)
dis = StringFromFormat("%c%c%c%c", a[0], a[1], a[2], a[3]);
else
dis = StringFromFormat("# -> %s", sym->name.c_str());
}
else if (viewAsType == VIEWAS_HEX)
{
u32 mema[8] = {debugger->ReadExtraMemory(memory, address),
debugger->ReadExtraMemory(memory, address + 4),
debugger->ReadExtraMemory(memory, address + 8),
debugger->ReadExtraMemory(memory, address + 12),
debugger->ReadExtraMemory(memory, address + 16),
debugger->ReadExtraMemory(memory, address + 20),
debugger->ReadExtraMemory(memory, address + 24),
debugger->ReadExtraMemory(memory, address + 28)};
for (auto& word : mema)
{
switch (dataType)
{
case MemoryDataType::U8:
dis += StringFromFormat(" %02X %02X %02X %02X", ((word & 0xff000000) >> 24) & 0xFF,
((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF,
word & 0xff);
break;
case MemoryDataType::U16:
dis += StringFromFormat(" %02X%02X %02X%02X", ((word & 0xff000000) >> 24) & 0xFF,
((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF,
word & 0xff);
break;
case MemoryDataType::U32:
dis += StringFromFormat(" %02X%02X%02X%02X", ((word & 0xff000000) >> 24) & 0xFF,
((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF,
word & 0xff);
break;
}
}
}
else
{
dis = "INVALID VIEWAS TYPE";
}
if (viewAsType != VIEWAS_HEX)
dc.DrawText(StrToWxStr(dis), textPlacement + fontSize * (8 + 8), rowY1);
else
dc.DrawText(StrToWxStr(dis), textPlacement, rowY1);
dc.SetTextForeground(*wxBLUE);
std::string desc = debugger->GetDescription(address);
if (!desc.empty())
dc.DrawText(StrToWxStr(desc), 17 + fontSize * ((8 + 8 + 8 + 30) * 2), rowY1);
// Show blue memory check dot
if (debugger->IsMemCheck(address))
{
dc.SetBrush(mcBrush);
dc.DrawRectangle(8, rowY1 + 1, 11, 11);
}
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(mc_brush);
dc.DrawEllipse(mchk_x, row_y + mchk_offset_y, mchk_size.GetWidth(), mchk_size.GetHeight());
}
}
dc.SetPen(currentPen);
}
void CMemoryView::OnResize(wxSizeEvent& event)

View File

@ -13,9 +13,13 @@ enum class MemoryDataType
{
U8,
U16,
U32
U32,
ASCII,
FloatingPoint
};
wxDECLARE_EVENT(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, wxCommandEvent);
class CMemoryView : public wxControl
{
public:
@ -29,12 +33,8 @@ public:
Refresh();
}
void SetDataType(MemoryDataType data_type)
{
dataType = data_type;
Refresh();
}
void SetDataType(MemoryDataType data_type);
MemoryDataType GetDataType() const { return m_data_type; }
void SetMemCheckOptions(bool read, bool write, bool log)
{
memCheckRead = read;
@ -43,6 +43,12 @@ public:
}
private:
int YToAddress(int y);
bool IsHexMode() const
{
return m_data_type != MemoryDataType::ASCII && m_data_type != MemoryDataType::FloatingPoint;
}
void OnPaint(wxPaintEvent& event);
void OnMouseDownL(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event);
@ -50,14 +56,15 @@ private:
void OnMouseDownR(wxMouseEvent& event);
void OnScrollWheel(wxMouseEvent& event);
void OnPopupMenu(wxCommandEvent& event);
int YToAddress(int y);
void OnResize(wxSizeEvent& event);
static constexpr int LEFT_COL_WIDTH = 16;
DebugInterface* debugger;
int align;
unsigned int align;
int rowHeight;
int m_left_col_width;
u32 selection;
u32 oldSelection;
@ -65,18 +72,11 @@ private:
int memory;
int curAddress;
MemoryDataType dataType;
bool memCheckRead;
bool memCheckWrite;
bool memCheckLog;
enum EViewAsType
{
VIEWAS_ASCII = 0,
VIEWAS_FP,
VIEWAS_HEX,
};
EViewAsType viewAsType;
MemoryDataType m_data_type;
MemoryDataType m_last_hex_type = MemoryDataType::U8;
};

View File

@ -2,9 +2,10 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <wx/button.h>
@ -12,10 +13,13 @@
#include <wx/listbox.h>
#include <wx/msgdlg.h>
#include <wx/panel.h>
#include <wx/radiobox.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/srchctrl.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/utils.h>
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
@ -43,9 +47,7 @@ enum
IDM_DUMP_MEM2,
IDM_DUMP_FAKEVMEM,
IDM_VALBOX,
IDM_U8,
IDM_U16,
IDM_U32,
IDM_DATA_TYPE_RBOX,
IDM_SEARCH,
IDM_ASCII,
IDM_HEX,
@ -53,30 +55,24 @@ enum
};
BEGIN_EVENT_TABLE(CMemoryWindow, wxPanel)
EVT_LISTBOX(IDM_SYMBOLLIST, CMemoryWindow::OnSymbolListChange)
EVT_HOST_COMMAND(wxID_ANY, CMemoryWindow::OnHostMessage)
EVT_BUTTON(IDM_SETVALBUTTON, CMemoryWindow::SetMemoryValue)
EVT_BUTTON(IDM_DUMP_MEMORY, CMemoryWindow::OnDumpMemory)
EVT_BUTTON(IDM_DUMP_MEM2, CMemoryWindow::OnDumpMem2)
EVT_BUTTON(IDM_DUMP_FAKEVMEM, CMemoryWindow::OnDumpFakeVMEM)
EVT_CHECKBOX(IDM_U8, CMemoryWindow::U8)
EVT_CHECKBOX(IDM_U16, CMemoryWindow::U16)
EVT_CHECKBOX(IDM_U32, CMemoryWindow::U32)
EVT_BUTTON(IDM_SEARCH, CMemoryWindow::onSearch)
EVT_CHECKBOX(IDM_ASCII, CMemoryWindow::onAscii)
EVT_CHECKBOX(IDM_HEX, CMemoryWindow::onHex)
EVT_RADIOBUTTON(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::onMemCheckOptionChange)
EVT_CHECKBOX(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::onMemCheckOptionChange)
EVT_RADIOBOX(IDM_DATA_TYPE_RBOX, CMemoryWindow::OnDataTypeChanged)
EVT_BUTTON(IDM_SEARCH, CMemoryWindow::OnSearch)
EVT_RADIOBUTTON(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::OnMemCheckOptionChange)
EVT_CHECKBOX(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::OnMemCheckOptionChange)
END_EVENT_TABLE()
CMemoryWindow::CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindowID id,
const wxPoint& pos, const wxSize& size, long style,
const wxString& name)
: wxPanel(parent, id, pos, size, style, name), m_code_window(code_window)
CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
const wxSize& size, long style, const wxString& name)
: wxPanel(parent, id, pos, size, style, name)
{
DebugInterface* di = &PowerPC::debug_interface;
memview = new CMemoryView(di, this);
memview->Bind(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, &CMemoryWindow::OnDataTypeChanged, this);
addrbox = new wxSearchCtrl(this, IDM_MEM_ADDRBOX);
addrbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnAddrBoxChange, this);
@ -85,13 +81,17 @@ CMemoryWindow::CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindo
valbox =
new wxTextCtrl(this, IDM_VALBOX, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
valbox->Bind(wxEVT_TEXT_ENTER, &CMemoryWindow::SetMemoryValueFromValBox, this);
valbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnValueChanged, this);
wxGridSizer* const search_sizer = new wxGridSizer(1);
search_sizer->Add(addrbox);
const int space3 = FromDIP(3);
const int space5 = FromDIP(5);
wxBoxSizer* const search_sizer = new wxBoxSizer(wxVERTICAL);
search_sizer->Add(addrbox, 0, wxEXPAND);
search_sizer->Add(valbox, 0, wxEXPAND);
search_sizer->Add(new wxButton(this, IDM_SETVALBUTTON, _("Set Value")));
wxGridSizer* const dump_sizer = new wxGridSizer(1);
wxBoxSizer* const dump_sizer = new wxBoxSizer(wxVERTICAL);
dump_sizer->Add(new wxButton(this, IDM_DUMP_MEMORY, _("Dump MRAM")), 0, wxEXPAND);
dump_sizer->Add(new wxButton(this, IDM_DUMP_MEM2, _("Dump EXRAM")), 0, wxEXPAND);
if (!SConfig::GetInstance().bMMU)
@ -99,73 +99,57 @@ CMemoryWindow::CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindo
wxStaticBoxSizer* const sizerSearchType = new wxStaticBoxSizer(wxVERTICAL, this, _("Search"));
sizerSearchType->Add(btnSearch = new wxButton(this, IDM_SEARCH, _("Search")));
sizerSearchType->Add(chkAscii = new wxCheckBox(this, IDM_ASCII, "Ascii "));
sizerSearchType->Add(chkHex = new wxCheckBox(this, IDM_HEX, _("Hex")));
sizerSearchType->Add(m_rb_ascii = new wxRadioButton(this, IDM_ASCII, "Ascii", wxDefaultPosition,
wxDefaultSize, wxRB_GROUP));
sizerSearchType->Add(m_rb_hex = new wxRadioButton(this, IDM_HEX, _("Hex")));
m_search_result_msg =
new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxST_NO_AUTORESIZE | wxALIGN_CENTER_HORIZONTAL);
sizerSearchType->Add(m_search_result_msg, 0, wxEXPAND);
wxStaticBoxSizer* const sizerDataTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Data Type"));
sizerDataTypes->SetMinSize(74, 40);
sizerDataTypes->Add(chk8 = new wxCheckBox(this, IDM_U8, "U8"));
sizerDataTypes->Add(chk16 = new wxCheckBox(this, IDM_U16, "U16"));
sizerDataTypes->Add(chk32 = new wxCheckBox(this, IDM_U32, "U32"));
wxArrayString data_type_options;
data_type_options.Add("U8");
data_type_options.Add("U16");
data_type_options.Add("U32");
data_type_options.Add("ASCII");
data_type_options.Add("Float32");
m_rbox_data_type = new wxRadioBox(this, IDM_DATA_TYPE_RBOX, _("Data Type"), wxDefaultPosition,
wxDefaultSize, data_type_options, 1);
wxStaticBoxSizer* const sizerMemCheckOptions =
wxStaticBoxSizer* const memcheck_options_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, "Memory check options");
sizerMemCheckOptions->Add(rdbReadWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE,
"Read and Write", wxDefaultPosition,
wxDefaultSize, wxRB_GROUP));
sizerMemCheckOptions->Add(rdbRead =
new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Read only"));
sizerMemCheckOptions->Add(rdbWrite =
new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Write only"));
sizerMemCheckOptions->Add(chkLog = new wxCheckBox(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Log"));
memcheck_options_sizer->Add(rdbReadWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE,
"Read and Write", wxDefaultPosition,
wxDefaultSize, wxRB_GROUP));
memcheck_options_sizer->Add(
rdbRead = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Read only"));
memcheck_options_sizer->Add(
rdbWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Write only"));
memcheck_options_sizer->Add(chkLog = new wxCheckBox(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Log"));
wxBoxSizer* const sizerRight = new wxBoxSizer(wxVERTICAL);
sizerRight->Add(search_sizer);
sizerRight->AddSpacer(5);
sizerRight->Add(dump_sizer);
sizerRight->Add(sizerSearchType);
sizerRight->Add(sizerDataTypes);
sizerRight->Add(sizerMemCheckOptions);
sizerRight->AddSpacer(space5);
sizerRight->Add(dump_sizer, 0, wxEXPAND);
sizerRight->Add(sizerSearchType, 0, wxEXPAND);
sizerRight->Add(m_rbox_data_type, 0, wxEXPAND);
sizerRight->Add(memcheck_options_sizer, 0, wxEXPAND);
wxBoxSizer* const sizerBig = new wxBoxSizer(wxHORIZONTAL);
sizerBig->Add(memview, 20, wxEXPAND);
sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3);
sizerBig->AddSpacer(space3);
sizerBig->Add(sizerRight, 0, wxEXPAND | wxTOP | wxBOTTOM, space3);
sizerBig->AddSpacer(space3);
SetSizer(sizerBig);
chkHex->SetValue(1); // Set defaults
chk8->SetValue(1);
chkLog->SetValue(1);
m_rb_hex->SetValue(true); // Set defaults
chkLog->SetValue(true);
m_rbox_data_type->SetSelection(static_cast<int>(memview->GetDataType()));
sizerRight->Fit(this);
sizerBig->Fit(this);
}
void CMemoryWindow::Save(IniFile& ini) const
{
// Prevent these bad values that can happen after a crash or hanging
if (GetPosition().x != -32000 && GetPosition().y != -32000)
{
IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow");
mem_window->Set("x", GetPosition().x);
mem_window->Set("y", GetPosition().y);
mem_window->Set("w", GetSize().GetWidth());
mem_window->Set("h", GetSize().GetHeight());
}
}
void CMemoryWindow::Load(IniFile& ini)
{
int x, y, w, h;
IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow");
mem_window->Get("x", &x, GetPosition().x);
mem_window->Get("y", &y, GetPosition().y);
mem_window->Get("w", &w, GetSize().GetWidth());
mem_window->Get("h", &h, GetSize().GetHeight());
SetSize(x, y, w, h);
}
void CMemoryWindow::JumpToAddress(u32 _Address)
{
memview->Center(_Address);
@ -219,55 +203,14 @@ void CMemoryWindow::OnAddrBoxChange(wxCommandEvent& event)
event.Skip();
}
void CMemoryWindow::Update()
void CMemoryWindow::Repopulate()
{
memview->Refresh();
memview->Center(PC);
}
void CMemoryWindow::NotifyMapLoaded()
void CMemoryWindow::OnValueChanged(wxCommandEvent&)
{
symbols->Show(false); // hide it for faster filling
symbols->Clear();
#if 0
#ifdef _WIN32
const FunctionDB::XFuncMap &syms = g_symbolDB.Symbols();
for (FuntionDB::XFuncMap::iterator iter = syms.begin(); iter != syms.end(); ++iter)
{
int idx = symbols->Append(iter->second.name.c_str());
symbols->SetClientData(idx, (void*)&iter->second);
}
#endif
#endif
symbols->Show(true);
Update();
}
void CMemoryWindow::OnSymbolListChange(wxCommandEvent& event)
{
int index = symbols->GetSelection();
if (index >= 0)
{
Symbol* pSymbol = static_cast<Symbol*>(symbols->GetClientData(index));
if (pSymbol != nullptr)
{
memview->Center(pSymbol->address);
}
}
}
void CMemoryWindow::OnHostMessage(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_NOTIFY_MAP_LOADED:
NotifyMapLoaded();
break;
case IDM_UPDATE_BREAKPOINTS:
if (m_code_window->m_BreakpointWindow)
m_code_window->m_BreakpointWindow->NotifyUpdate();
break;
}
m_continue_search = false;
}
static void DumpArray(const std::string& filename, const u8* data, size_t length)
@ -304,39 +247,40 @@ void CMemoryWindow::OnDumpFakeVMEM(wxCommandEvent& event)
DumpArray(File::GetUserPath(F_FAKEVMEMDUMP_IDX), Memory::m_pFakeVMEM, Memory::FAKEVMEM_SIZE);
}
void CMemoryWindow::U8(wxCommandEvent& event)
void CMemoryWindow::OnDataTypeChanged(wxCommandEvent& ev)
{
chk16->SetValue(0);
chk32->SetValue(0);
memview->SetDataType(MemoryDataType::U8);
static constexpr std::array<MemoryDataType, 5> map{{MemoryDataType::U8, MemoryDataType::U16,
MemoryDataType::U32, MemoryDataType::ASCII,
MemoryDataType::FloatingPoint}};
if (ev.GetId() == IDM_DATA_TYPE_RBOX)
{
memview->SetDataType(map.at(ev.GetSelection()));
}
else
{
// Event from the CMemoryView indicating type was changed.
auto itr = std::find(map.begin(), map.end(), static_cast<MemoryDataType>(ev.GetInt()));
int idx = -1;
if (itr != map.end())
idx = static_cast<int>(itr - map.begin());
m_rbox_data_type->SetSelection(idx);
}
}
void CMemoryWindow::U16(wxCommandEvent& event)
void CMemoryWindow::OnSearch(wxCommandEvent& event)
{
chk8->SetValue(0);
chk32->SetValue(0);
memview->SetDataType(MemoryDataType::U16);
}
void CMemoryWindow::U32(wxCommandEvent& event)
{
chk16->SetValue(0);
chk8->SetValue(0);
memview->SetDataType(MemoryDataType::U32);
}
void CMemoryWindow::onSearch(wxCommandEvent& event)
{
u8* TheRAM = nullptr;
u32 szRAM = 0;
wxBusyCursor hourglass_cursor;
u8* ram_ptr = nullptr;
u32 ram_size = 0;
// NOTE: We're assuming the base address is zero.
switch (memview->GetMemoryType())
{
case 0:
default:
if (Memory::m_pRAM)
{
TheRAM = Memory::m_pRAM;
szRAM = Memory::REALRAM_SIZE;
ram_ptr = Memory::m_pRAM;
ram_size = Memory::REALRAM_SIZE;
}
break;
case 1:
@ -344,131 +288,115 @@ void CMemoryWindow::onSearch(wxCommandEvent& event)
u8* aram = DSP::GetARAMPtr();
if (aram)
{
TheRAM = aram;
szRAM = DSP::ARAM_SIZE;
ram_ptr = aram;
ram_size = DSP::ARAM_SIZE;
}
}
break;
}
// Now we have memory to look in
// Are we looking for ASCII string, or hex?
// memview->cu
wxString rawData = valbox->GetValue();
std::vector<u8> Dest; // May need a better name
u32 size = 0;
int pad = rawData.size() % 2; // If it's uneven
unsigned int i = 0;
long count = 0;
char copy[3] = {0};
long newsize = 0;
unsigned char* tmp2 = nullptr;
char* tmpstr = nullptr;
if (chkHex->GetValue())
if (!ram_ptr)
{
// We are looking for hex
// If it's uneven
size = (rawData.size() / 2) + pad;
Dest.resize(size + 32);
newsize = rawData.size();
m_search_result_msg->SetLabel(_("Memory Not Ready"));
return;
}
if (pad)
std::vector<u8> search_bytes;
wxString search_val = valbox->GetValue();
if (m_rb_hex->GetValue())
{
search_val.Trim(true).Trim(false);
// If there's a trailing nybble, stick a zero in front to make it a byte
if (search_val.size() & 1)
search_val.insert(0, 1, '0');
search_bytes.reserve(search_val.size() / 2);
wxString conversion_buffer(2, ' ');
for (std::size_t i = 0; i < search_val.size(); i += 2)
{
tmpstr = new char[newsize + 2];
memset(tmpstr, 0, newsize + 2);
tmpstr[0] = '0';
unsigned long byte = 0;
conversion_buffer[0] = search_val[i];
conversion_buffer[1] = search_val[i + 1];
if (!conversion_buffer.ToULong(&byte, 16))
{
m_search_result_msg->SetLabel(_("Not Valid Hex"));
return;
}
search_bytes.push_back(static_cast<u8>(byte));
}
else
{
tmpstr = new char[newsize + 1];
memset(tmpstr, 0, newsize + 1);
}
strcat(tmpstr, WxStrToStr(rawData).c_str());
tmp2 = &Dest.front();
count = 0;
for (i = 0; i < strlen(tmpstr); i++)
{
copy[0] = tmpstr[i];
copy[1] = tmpstr[i + 1];
copy[2] = 0;
int tmpint;
sscanf(copy, "%02x", &tmpint);
tmp2[count++] = tmpint;
// Dest[count] should now be the hex of what the two chars were!
// Also should add a check to make sure it's A-F only
// sscanf(copy, "%02x", &tmp2[count++]);
i += 1;
}
delete[] tmpstr;
}
else
{
// Looking for an ascii string
size = rawData.size();
Dest.resize(size + 1);
tmpstr = new char[size + 1];
tmp2 = &Dest.front();
sprintf(tmpstr, "%s", WxStrToStr(rawData).c_str());
for (i = 0; i < size; i++)
tmp2[i] = tmpstr[i];
delete[] tmpstr;
const auto& bytes = search_val.ToUTF8();
search_bytes.assign(bytes.data(), bytes.data() + bytes.length());
}
search_val.Clear();
if (size)
// For completeness
if (search_bytes.size() > ram_size)
{
unsigned char* pnt = &Dest.front();
unsigned int k = 0;
// grab
wxString txt = addrbox->GetValue();
u32 addr = 0;
if (txt.size())
m_search_result_msg->SetLabel(_("Value Too Large"));
return;
}
if (search_bytes.empty())
{
m_search_result_msg->SetLabel(_("No Value Given"));
return;
}
// Search starting from specified address if there is one.
u32 addr = 0; // Base address
{
wxString addr_val = addrbox->GetValue();
addr_val.Trim(true).Trim(false);
if (!addr_val.empty())
{
sscanf(WxStrToStr(txt).c_str(), "%08x", &addr);
}
i = addr + 4;
for (; i < szRAM; ++i)
{
for (k = 0; k < size; ++k)
unsigned long addr_ul = 0;
if (addr_val.ToULong(&addr_ul, 16))
{
if (i + k > szRAM)
break;
if (k > size)
break;
if (pnt[k] != TheRAM[i + k])
{
k = 0;
break;
}
}
if (k == size)
{
// Match was found
wxMessageBox(_("A match was found. Placing viewer at the offset."));
addrbox->SetValue(wxString::Format("%08x", i));
// memview->curAddress = i;
// memview->Refresh();
OnAddrBoxChange(event);
return;
addr = static_cast<u32>(addr_ul);
// Don't find the result we're already looking at
if (m_continue_search && addr == m_last_search_address)
addr += 1;
}
}
wxMessageBox(_("No match was found."));
}
// If the current address doesn't leave enough bytes to search then we're done.
if (addr >= ram_size - search_bytes.size())
{
m_search_result_msg->SetLabel(_("Address Out of Range"));
return;
}
u8* end = &ram_ptr[ram_size - search_bytes.size() + 1];
u8* ptr = &ram_ptr[addr];
while (true)
{
ptr = std::find(ptr, end, search_bytes[0]);
if (ptr == end)
{
m_search_result_msg->SetLabel(_("No Match"));
break;
}
if (std::equal(search_bytes.begin(), search_bytes.end(), ptr))
{
m_search_result_msg->SetLabel(_("Match Found"));
u32 offset = static_cast<u32>(ptr - ram_ptr);
// NOTE: SetValue() generates a synthetic wxEVT_TEXT
addrbox->SetValue(wxString::Format("%08x", offset));
m_last_search_address = offset;
m_continue_search = true;
break;
}
++ptr;
}
}
void CMemoryWindow::onAscii(wxCommandEvent& event)
{
chkHex->SetValue(0);
}
void CMemoryWindow::onHex(wxCommandEvent& event)
{
chkAscii->SetValue(0);
}
void CMemoryWindow::onMemCheckOptionChange(wxCommandEvent& event)
void CMemoryWindow::OnMemCheckOptionChange(wxCommandEvent& event)
{
if (rdbReadWrite->GetValue())
memview->SetMemCheckOptions(true, true, chkLog->GetValue());

View File

@ -12,51 +12,46 @@ class CCodeWindow;
class IniFile;
class wxButton;
class wxCheckBox;
class wxRadioBox;
class wxRadioButton;
class wxListBox;
class wxSearchCtrl;
class wxStaticText;
class wxTextCtrl;
class wxRadioButton;
class CMemoryWindow : public wxPanel
{
public:
CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL | wxBORDER_NONE, const wxString& name = _("Memory"));
CMemoryWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxBORDER_NONE,
const wxString& name = _("Memory"));
void Save(IniFile& _IniFile) const;
void Load(IniFile& _IniFile);
void Update() override;
void NotifyMapLoaded();
void Repopulate();
void JumpToAddress(u32 _Address);
private:
DECLARE_EVENT_TABLE()
void U8(wxCommandEvent& event);
void U16(wxCommandEvent& event);
void U32(wxCommandEvent& event);
void onSearch(wxCommandEvent& event);
void onAscii(wxCommandEvent& event);
void onHex(wxCommandEvent& event);
void OnSymbolListChange(wxCommandEvent& event);
void OnDataTypeChanged(wxCommandEvent& event);
void OnSearch(wxCommandEvent& event);
void OnAddrBoxChange(wxCommandEvent& event);
void OnHostMessage(wxCommandEvent& event);
void OnValueChanged(wxCommandEvent&);
void SetMemoryValueFromValBox(wxCommandEvent& event);
void SetMemoryValue(wxCommandEvent& event);
void OnDumpMemory(wxCommandEvent& event);
void OnDumpMem2(wxCommandEvent& event);
void OnDumpFakeVMEM(wxCommandEvent& event);
void onMemCheckOptionChange(wxCommandEvent& event);
void OnMemCheckOptionChange(wxCommandEvent& event);
wxCheckBox* chk8;
wxCheckBox* chk16;
wxCheckBox* chk32;
wxButton* btnSearch;
wxCheckBox* chkAscii;
wxCheckBox* chkHex;
wxRadioButton* m_rb_ascii;
wxRadioButton* m_rb_hex;
wxRadioBox* m_rbox_data_type;
wxStaticText* m_search_result_msg;
wxCheckBox* chkLog;
wxRadioButton* rdbRead;
wxRadioButton* rdbWrite;
@ -65,8 +60,10 @@ private:
CCodeWindow* m_code_window;
CMemoryView* memview;
wxListBox* symbols;
wxSearchCtrl* addrbox;
wxTextCtrl* valbox;
u32 m_last_search_address = 0;
bool m_continue_search = false;
};

View File

@ -19,6 +19,7 @@
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/Main.h"
#include "DolphinWX/WxUtils.h"
// F-zero 80005e60 wtf??
@ -466,7 +467,7 @@ CRegisterView::CRegisterView(wxWindow* parent, wxWindowID id) : wxGrid(parent, i
AutoSizeColumns();
}
void CRegisterView::Update()
void CRegisterView::Repopulate()
{
m_register_table->UpdateCachedRegs();
ForceRefresh();
@ -507,10 +508,11 @@ void CRegisterView::OnMouseDownR(wxGridEvent& event)
void CRegisterView::OnPopupMenu(wxCommandEvent& event)
{
CFrame* main_frame = static_cast<CFrame*>(GetGrandParent()->GetParent());
CCodeWindow* code_window = main_frame->g_pCodeWindow;
CWatchWindow* watch_window = code_window->m_WatchWindow;
CMemoryWindow* memory_window = code_window->m_MemoryWindow;
// FIXME: This is terrible. Generate events instead.
CFrame* cframe = wxGetApp().GetCFrame();
CCodeWindow* code_window = cframe->g_pCodeWindow;
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
switch (event.GetId())
{

View File

@ -51,7 +51,7 @@ public:
void UpdateCachedRegs();
private:
static constexpr size_t NUM_SPECIALS = 14;
static constexpr int NUM_SPECIALS = 14;
std::array<u32, 32> m_CachedRegs{};
std::array<u32, NUM_SPECIALS> m_CachedSpecialRegs{};
@ -72,7 +72,7 @@ class CRegisterView : public wxGrid
{
public:
CRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY);
void Update() override;
void Repopulate();
private:
void OnMouseDownR(wxGridEvent& event);

View File

@ -21,7 +21,7 @@ void CRegisterWindow::CreateGUIControls()
{
wxBoxSizer* sGrid = new wxBoxSizer(wxVERTICAL);
m_GPRGridView = new CRegisterView(this);
sGrid->Add(m_GPRGridView, 1, wxGROW);
sGrid->Add(m_GPRGridView, 1, wxEXPAND);
SetSizer(sGrid);
NotifyUpdate();
@ -30,5 +30,5 @@ void CRegisterWindow::CreateGUIControls()
void CRegisterWindow::NotifyUpdate()
{
if (m_GPRGridView != nullptr)
m_GPRGridView->Update();
m_GPRGridView->Repopulate();
}

View File

@ -18,6 +18,7 @@
#include "DolphinWX/Debugger/WatchView.h"
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Main.h"
#include "DolphinWX/WxUtils.h"
enum
@ -232,7 +233,7 @@ CWatchView::CWatchView(wxWindow* parent, wxWindowID id) : wxGrid(parent, id)
Bind(wxEVT_MENU, &CWatchView::OnPopupMenu, this);
}
void CWatchView::Update()
void CWatchView::Repopulate()
{
if (Core::IsRunning())
{
@ -269,11 +270,12 @@ void CWatchView::OnMouseDownR(wxGridEvent& event)
void CWatchView::OnPopupMenu(wxCommandEvent& event)
{
CFrame* main_frame = static_cast<CFrame*>(GetGrandParent()->GetParent());
CCodeWindow* code_window = main_frame->g_pCodeWindow;
CWatchWindow* watch_window = code_window->m_WatchWindow;
CMemoryWindow* memory_window = code_window->m_MemoryWindow;
CBreakPointWindow* breakpoint_window = code_window->m_BreakpointWindow;
// FIXME: This is terrible. Generate events instead.
CFrame* cframe = wxGetApp().GetCFrame();
CCodeWindow* code_window = cframe->g_pCodeWindow;
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
CBreakPointWindow* breakpoint_window = code_window->GetPanel<CBreakPointWindow>();
wxString strNewVal;
TMemCheck MemCheck;

View File

@ -37,7 +37,7 @@ class CWatchView : public wxGrid
{
public:
CWatchView(wxWindow* parent, wxWindowID id = wxID_ANY);
void Update() override;
void Repopulate();
private:
void OnMouseDownR(wxGridEvent& event);

View File

@ -25,9 +25,12 @@ public:
: DolphinAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize,
wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT)
{
SetToolBitmapSize(wxSize(16, 16));
wxSize bitmap_size = FromDIP(wxSize(16, 16));
SetToolBitmapSize(bitmap_size);
m_Bitmaps[Toolbar_File] = WxUtils::LoadResourceBitmap("toolbar_debugger_delete");
m_Bitmaps[Toolbar_File] = WxUtils::LoadScaledResourceBitmap(
"toolbar_debugger_delete", this, bitmap_size, wxDefaultSize,
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_File]);
Bind(wxEVT_TOOL, &CWatchWindow::Event_LoadAll, parent, ID_LOAD);
@ -80,7 +83,7 @@ CWatchWindow::~CWatchWindow()
void CWatchWindow::NotifyUpdate()
{
if (m_GPRGridView != nullptr)
m_GPRGridView->Update();
m_GPRGridView->Repopulate();
}
void CWatchWindow::Event_SaveAll(wxCommandEvent& WXUNUSED(event))

View File

@ -0,0 +1,126 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <wx/utils.h>
#include "DolphinWX/DolphinSlider.h"
#ifdef __WXMSW__
#define WIN32_LEAN_AND_MEAN 1
// clang-format off
#include <Windows.h>
#include <CommCtrl.h>
// clang-format on
#endif
static constexpr int SLIDER_MIN_LENGTH = 100;
DolphinSlider::DolphinSlider() = default;
DolphinSlider::~DolphinSlider() = default;
bool DolphinSlider::Create(wxWindow* parent, wxWindowID id, int value, int min_val, int max_val,
const wxPoint& pos, const wxSize& size, long style,
const wxValidator& validator, const wxString& name)
{
// Sanitize the style flags.
// We don't want any label flags because those break DPI scaling on wxMSW,
// wxWidgets will internally lock the height of the slider to 32 pixels.
style &= ~wxSL_LABELS;
return wxSlider::Create(parent, id, value, min_val, max_val, pos, size, style, validator, name);
}
wxSize DolphinSlider::DoGetBestClientSize() const
{
#ifdef __WXMSW__
int ticks = 0;
int default_length = FromDIP(SLIDER_MIN_LENGTH);
if (HasFlag(wxSL_TICKS))
{
// NOTE: Ticks do not scale at all (on Win7)
default_length += 4;
ticks = 6;
}
int metric = 0;
{
// We need to determine the maximum thumb size because unfortunately the thumb size
// is controlled by the theme so may have a varying maximum size limit.
// NOTE: We can't use ourself because we're const so we can't change our size.
// NOTE: This is less inefficient then it seems, DoGetBestSize() is only called once
// per instance and cached until InvalidateBestSize() is called.
wxSlider* helper = new wxSlider(GetParent(), wxID_ANY, GetValue(), GetMin(), GetMax(),
wxDefaultPosition, FromDIP(wxSize(100, 100)), GetWindowStyle());
::RECT r{};
::SendMessageW(reinterpret_cast<HWND>(helper->GetHWND()), TBM_GETTHUMBRECT, 0,
reinterpret_cast<LPARAM>(&r));
helper->Destroy();
// Breakdown metrics
int computed_size;
int scroll_size;
if (HasFlag(wxSL_VERTICAL))
{
// Trackbar thumb does not directly touch the edge, we add the padding
// a second time to pad the other edge to make it symmetric.
computed_size = static_cast<int>(r.right + r.left);
scroll_size = ::GetSystemMetrics(SM_CXVSCROLL);
}
else
{
computed_size = static_cast<int>(r.bottom + r.top);
scroll_size = ::GetSystemMetrics(SM_CYHSCROLL);
}
// This is based on how Microsoft calculates trackbar sizes in the .Net Framework
// when using automatic sizing in WinForms.
int max = scroll_size * 2;
metric = wxClip(computed_size, scroll_size, max);
}
if (HasFlag(wxSL_VERTICAL))
return wxSize(metric + ticks, default_length);
return wxSize(default_length, metric + ticks);
#else
wxSize base_size = wxSlider::DoGetBestClientSize();
// If the base class is not using DoGetBestClientSize(), fallback to DoGetBestSize()
if (base_size == wxDefaultSize)
return wxDefaultSize;
return CorrectMinSize(base_size);
#endif
}
wxSize DolphinSlider::DoGetBestSize() const
{
return CorrectMinSize(wxSlider::DoGetBestSize());
}
wxSize DolphinSlider::CorrectMinSize(wxSize size) const
{
wxSize default_length = FromDIP(wxSize(SLIDER_MIN_LENGTH, SLIDER_MIN_LENGTH));
// GTK Styles sometimes don't return a default length.
// NOTE: Vertical is the dominant flag if both are set.
if (HasFlag(wxSL_VERTICAL))
{
if (size.GetHeight() < default_length.GetHeight())
{
size.SetHeight(default_length.GetHeight());
}
}
else if (size.GetWidth() < default_length.GetWidth())
{
size.SetWidth(default_length.GetWidth());
}
return size;
}
#ifdef __WXMSW__
WXLRESULT DolphinSlider::MSWWindowProc(WXUINT msg, WXWPARAM wp, WXLPARAM lp)
{
if (msg == WM_THEMECHANGED)
InvalidateBestSize();
return wxSlider::MSWWindowProc(msg, wp, lp);
}
#endif

View File

@ -0,0 +1,51 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/slider.h>
// wxSlider has several bugs, including not scaling with DPI.
// This extended slider class tries to paper over the flaws.
// NOTE: wxSL_LABELS is not supported because it doesn't work correctly.
class DolphinSlider : public wxSlider
{
public:
DolphinSlider();
~DolphinSlider() override;
DolphinSlider(const DolphinSlider&) = delete;
DolphinSlider(wxWindow* parent, wxWindowID id, int value, int min_value, int max_value,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxSL_HORIZONTAL, const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxSliderNameStr)
{
Create(parent, id, value, min_value, max_value, pos, size, style, validator, name);
}
DolphinSlider& operator=(const DolphinSlider&) = delete;
bool Create(wxWindow* parent, wxWindowID id, int value, int min_value, int max_value,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxSL_HORIZONTAL, const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxSliderNameStr);
#ifdef __WXMSW__
// For WM_THEMECHANGED to regenerate metrics
WXLRESULT MSWWindowProc(WXUINT msg, WXWPARAM wp, WXLPARAM lp) override;
#endif
protected:
// DoGetBestSize() in wxMSW::wxSlider is borked.
// This is called by GetEffectiveMinSize() which is used by
// wxSizers to decide the size of the widget for generating layout.
wxSize DoGetBestClientSize() const override;
// GTK Themes sometimes don't provide a default min size.
// Make other platforms consistent with Windows (i.e. min length = 100px)
wxSize DoGetBestSize() const override;
private:
wxSize CorrectMinSize(wxSize size) const;
};

View File

@ -89,6 +89,7 @@
<ClCompile Include="Debugger\RegisterWindow.cpp" />
<ClCompile Include="Debugger\WatchView.cpp" />
<ClCompile Include="Debugger\WatchWindow.cpp" />
<ClCompile Include="DolphinSlider.cpp" />
<ClCompile Include="NetPlay\ChangeGameDialog.cpp" />
<ClCompile Include="NetPlay\MD5Dialog.cpp" />
<ClCompile Include="NetPlay\NetPlayLauncher.cpp" />
@ -131,6 +132,7 @@
<ClInclude Include="Config\InterfaceConfigPane.h" />
<ClInclude Include="Config\PathConfigPane.h" />
<ClInclude Include="Config\WiiConfigPane.h" />
<ClInclude Include="DolphinSlider.h" />
<ClInclude Include="NetPlay\ChangeGameDialog.h" />
<ClInclude Include="NetPlay\MD5Dialog.h" />
<ClInclude Include="NetPlay\NetPlayLauncher.h" />

View File

@ -28,6 +28,9 @@
<Filter Include="GUI\Config">
<UniqueIdentifier>{9d8b4144-f335-4fa4-b995-852533298474}</UniqueIdentifier>
</Filter>
<Filter Include="GUI\Widgets">
<UniqueIdentifier>{a894e2e3-e577-4b65-8572-055699f23a49}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Main.cpp" />
@ -208,6 +211,9 @@
<ClCompile Include="NetPlay\NetPlayLauncher.cpp">
<Filter>GUI\NetPlay</Filter>
</ClCompile>
<ClCompile Include="DolphinSlider.cpp">
<Filter>GUI\Widgets</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Main.h" />
@ -381,6 +387,9 @@
<ClInclude Include="NetPlay\NetPlayLauncher.h">
<Filter>GUI\NetPlay</Filter>
</ClInclude>
<ClInclude Include="DolphinSlider.h">
<Filter>GUI\Widgets</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
@ -393,4 +402,4 @@
<ItemGroup>
<Image Include="$(CoreDir)..\..\Installer\Dolphin.ico" />
</ItemGroup>
</Project>
</Project>

View File

@ -66,149 +66,139 @@ FifoPlayerDlg::~FifoPlayerDlg()
void FifoPlayerDlg::CreateGUIControls()
{
wxBoxSizer* sMain;
sMain = new wxBoxSizer(wxVERTICAL);
const int space5 = FromDIP(5);
m_Notebook = new wxNotebook(this, wxID_ANY);
{
m_PlayPage =
new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
wxBoxSizer* sPlayPage;
sPlayPage = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer* sPlayInfo;
sPlayInfo =
new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("File Info")), wxVERTICAL);
// File Info
m_NumFramesLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString);
m_NumFramesLabel->Wrap(-1);
sPlayInfo->Add(m_NumFramesLabel, 0, wxALL, 5);
m_CurrentFrameLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString);
m_CurrentFrameLabel->Wrap(-1);
sPlayInfo->Add(m_CurrentFrameLabel, 0, wxALL, 5);
m_NumObjectsLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString);
m_NumObjectsLabel->Wrap(-1);
sPlayInfo->Add(m_NumObjectsLabel, 0, wxALL, 5);
sPlayPage->Add(sPlayInfo, 1, wxEXPAND, 5);
wxStaticBoxSizer* sFrameRange;
sFrameRange =
new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("Frame Range")), wxHORIZONTAL);
// Frame Range
m_FrameFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From"));
m_FrameFromLabel->Wrap(-1);
sFrameRange->Add(m_FrameFromLabel, 0, wxALL, 5);
m_FrameFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0);
sFrameRange->Add(m_FrameFromCtrl, 0, wxALL, 5);
m_FrameToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To"));
m_FrameToLabel->Wrap(-1);
sFrameRange->Add(m_FrameToLabel, 0, wxALL, 5);
m_FrameToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxSize(-1, -1), wxSP_ARROW_KEYS, 0, 10, 0);
sFrameRange->Add(m_FrameToCtrl, 0, wxALL, 5);
sPlayPage->Add(sFrameRange, 0, wxEXPAND, 5);
wxStaticBoxSizer* sObjectRange;
sObjectRange = new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("Object Range")),
wxHORIZONTAL);
wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0);
// Object Range
m_ObjectFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From"));
m_ObjectFromLabel->Wrap(-1);
sObjectRange->Add(m_ObjectFromLabel, 0, wxALL, 5);
m_ObjectFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0);
sObjectRange->Add(m_ObjectFromCtrl, 0, wxALL, 5);
m_ObjectToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To"));
m_ObjectToLabel->Wrap(-1);
sObjectRange->Add(m_ObjectToLabel, 0, wxALL, 5);
m_ObjectToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0);
sObjectRange->Add(m_ObjectToCtrl, 0, wxALL, 5);
sPlayPage->Add(sObjectRange, 0, wxEXPAND, 5);
wxStaticBoxSizer* sPlayOptions;
sPlayOptions = new wxStaticBoxSizer(
new wxStaticBox(m_PlayPage, wxID_ANY, _("Playback Options")), wxVERTICAL);
// Playback Options
m_EarlyMemoryUpdates = new wxCheckBox(m_PlayPage, wxID_ANY, _("Early Memory Updates"));
sPlayOptions->Add(m_EarlyMemoryUpdates, 0, wxALL, 5);
sPlayPage->Add(sPlayOptions, 0, wxEXPAND, 5);
wxStaticBoxSizer* sPlayInfo = new wxStaticBoxSizer(wxVERTICAL, m_PlayPage, _("File Info"));
sPlayInfo->AddSpacer(space5);
sPlayInfo->Add(m_NumFramesLabel, 0, wxLEFT | wxRIGHT, space5);
sPlayInfo->AddSpacer(space5);
sPlayInfo->Add(m_CurrentFrameLabel, 0, wxLEFT | wxRIGHT, space5);
sPlayInfo->AddSpacer(space5);
sPlayInfo->Add(m_NumObjectsLabel, 0, wxLEFT | wxRIGHT, space5);
sPlayInfo->AddSpacer(space5);
wxStaticBoxSizer* sFrameRange =
new wxStaticBoxSizer(wxHORIZONTAL, m_PlayPage, _("Frame Range"));
sFrameRange->AddSpacer(space5);
sFrameRange->Add(m_FrameFromLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
sFrameRange->AddSpacer(space5);
sFrameRange->Add(m_FrameFromCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
sFrameRange->AddSpacer(space5);
sFrameRange->Add(m_FrameToLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
sFrameRange->AddSpacer(space5);
sFrameRange->Add(m_FrameToCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
sFrameRange->AddSpacer(space5);
wxStaticBoxSizer* sObjectRange =
new wxStaticBoxSizer(wxHORIZONTAL, m_PlayPage, _("Object Range"));
sObjectRange->AddSpacer(space5);
sObjectRange->Add(m_ObjectFromLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
sObjectRange->AddSpacer(space5);
sObjectRange->Add(m_ObjectFromCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
sObjectRange->AddSpacer(space5);
sObjectRange->Add(m_ObjectToLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
sObjectRange->AddSpacer(space5);
sObjectRange->Add(m_ObjectToCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
sObjectRange->AddSpacer(space5);
wxStaticBoxSizer* sPlayOptions =
new wxStaticBoxSizer(wxVERTICAL, m_PlayPage, _("Playback Options"));
sPlayOptions->AddSpacer(space5);
sPlayOptions->Add(m_EarlyMemoryUpdates, 0, wxLEFT | wxRIGHT, space5);
sPlayOptions->AddSpacer(space5);
wxBoxSizer* sPlayPage = new wxBoxSizer(wxVERTICAL);
sPlayPage->Add(sPlayInfo, 1, wxEXPAND);
sPlayPage->Add(sFrameRange, 0, wxEXPAND);
sPlayPage->Add(sObjectRange, 0, wxEXPAND);
sPlayPage->Add(sPlayOptions, 0, wxEXPAND);
sPlayPage->AddStretchSpacer();
m_PlayPage->SetSizer(sPlayPage);
m_PlayPage->Layout();
sPlayPage->Fit(m_PlayPage);
m_Notebook->AddPage(m_PlayPage, _("Play"), true);
}
{
m_RecordPage =
new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
wxBoxSizer* sRecordPage;
sRecordPage = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer* sRecordInfo;
sRecordInfo = new wxStaticBoxSizer(new wxStaticBox(m_RecordPage, wxID_ANY, _("Recording Info")),
wxVERTICAL);
// Recording Info
m_RecordingFifoSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString);
m_RecordingFifoSizeLabel->Wrap(-1);
sRecordInfo->Add(m_RecordingFifoSizeLabel, 0, wxALL, 5);
m_RecordingMemSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString);
m_RecordingMemSizeLabel->Wrap(-1);
sRecordInfo->Add(m_RecordingMemSizeLabel, 0, wxALL, 5);
m_RecordingFramesLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString);
m_RecordingFramesLabel->Wrap(-1);
sRecordInfo->Add(m_RecordingFramesLabel, 0, wxALL, 5);
sRecordPage->Add(sRecordInfo, 0, wxEXPAND, 5);
wxBoxSizer* sRecordButtons;
sRecordButtons = new wxBoxSizer(wxHORIZONTAL);
// Recording Buttons
m_RecordStop = new wxButton(m_RecordPage, wxID_ANY, _("Record"));
sRecordButtons->Add(m_RecordStop, 0, wxALL, 5);
m_Save = new wxButton(m_RecordPage, wxID_ANY, _("Save"));
sRecordButtons->Add(m_Save, 0, wxALL, 5);
sRecordPage->Add(sRecordButtons, 0, wxEXPAND, 5);
wxStaticBoxSizer* sRecordingOptions;
sRecordingOptions = new wxStaticBoxSizer(
new wxStaticBox(m_RecordPage, wxID_ANY, _("Recording Options")), wxHORIZONTAL);
// Recording Options
m_FramesToRecordLabel = new wxStaticText(m_RecordPage, wxID_ANY, _("Frames To Record"));
m_FramesToRecordLabel->Wrap(-1);
sRecordingOptions->Add(m_FramesToRecordLabel, 0, wxALL, 5);
m_FramesToRecordCtrl =
new wxSpinCtrl(m_RecordPage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxSP_ARROW_KEYS, 0, 10000, m_FramesToRecord);
wxString initialNum = wxString::Format("%d", m_FramesToRecord);
m_FramesToRecordCtrl = new wxSpinCtrl(m_RecordPage, wxID_ANY, initialNum, wxDefaultPosition,
wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 1);
sRecordingOptions->Add(m_FramesToRecordCtrl, 0, wxALL, 5);
wxStaticBoxSizer* sRecordInfo =
new wxStaticBoxSizer(wxVERTICAL, m_RecordPage, _("Recording Info"));
sRecordInfo->AddSpacer(space5);
sRecordInfo->Add(m_RecordingFifoSizeLabel, 0, wxLEFT | wxRIGHT, space5);
sRecordInfo->AddSpacer(space5);
sRecordInfo->Add(m_RecordingMemSizeLabel, 0, wxLEFT | wxRIGHT, space5);
sRecordInfo->AddSpacer(space5);
sRecordInfo->Add(m_RecordingFramesLabel, 0, wxLEFT | wxRIGHT, space5);
sRecordInfo->AddSpacer(space5);
sRecordPage->Add(sRecordingOptions, 0, wxEXPAND, 5);
sRecordPage->AddStretchSpacer();
wxBoxSizer* sRecordButtons = new wxBoxSizer(wxHORIZONTAL);
sRecordButtons->Add(m_RecordStop);
sRecordButtons->Add(m_Save, 0, wxLEFT, space5);
wxStaticBoxSizer* sRecordingOptions =
new wxStaticBoxSizer(wxHORIZONTAL, m_RecordPage, _("Recording Options"));
sRecordingOptions->AddSpacer(space5);
sRecordingOptions->Add(m_FramesToRecordLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM,
space5);
sRecordingOptions->AddSpacer(space5);
sRecordingOptions->Add(m_FramesToRecordCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM,
space5);
sRecordingOptions->AddSpacer(space5);
wxBoxSizer* sRecordPage = new wxBoxSizer(wxVERTICAL);
sRecordPage->Add(sRecordInfo, 0, wxEXPAND);
sRecordPage->AddSpacer(space5);
sRecordPage->Add(sRecordButtons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sRecordPage->AddSpacer(space5);
sRecordPage->Add(sRecordingOptions, 0, wxEXPAND);
m_RecordPage->SetSizer(sRecordPage);
m_RecordPage->Layout();
sRecordPage->Fit(m_RecordPage);
m_Notebook->AddPage(m_RecordPage, _("Record"), false);
}
@ -216,81 +206,86 @@ void FifoPlayerDlg::CreateGUIControls()
{
m_AnalyzePage =
new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
wxBoxSizer* sAnalyzePage;
sAnalyzePage = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer* sFrameInfoSizer;
sFrameInfoSizer =
new wxStaticBoxSizer(new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Frame Info")), wxVERTICAL);
// FIFO Content Lists
m_framesList = new wxListBox(m_AnalyzePage, wxID_ANY, wxDefaultPosition,
wxDLG_UNIT(this, wxSize(72, 185)));
m_objectsList = new wxListBox(m_AnalyzePage, wxID_ANY, wxDefaultPosition,
wxDLG_UNIT(this, wxSize(72, 185)));
m_objectCmdList =
new wxListBox(m_AnalyzePage, wxID_ANY, wxDefaultPosition,
wxDLG_UNIT(this, wxSize(144, 185)), wxArrayString(), wxLB_HSCROLL);
wxBoxSizer* sListsSizer = new wxBoxSizer(wxHORIZONTAL);
// Selected command breakdown
m_objectCmdInfo = new wxStaticText(m_AnalyzePage, wxID_ANY, wxEmptyString);
m_framesList = new wxListBox(m_AnalyzePage, wxID_ANY);
m_framesList->SetMinSize(wxSize(100, 250));
sListsSizer->Add(m_framesList, 0, wxALL, 5);
m_objectsList = new wxListBox(m_AnalyzePage, wxID_ANY);
m_objectsList->SetMinSize(wxSize(110, 250));
sListsSizer->Add(m_objectsList, 0, wxALL, 5);
m_objectCmdList = new wxListBox(m_AnalyzePage, wxID_ANY);
m_objectCmdList->SetMinSize(wxSize(175, 250));
sListsSizer->Add(m_objectCmdList, 0, wxALL, 5);
sFrameInfoSizer->Add(sListsSizer, 0, wxALL, 5);
m_objectCmdInfo = new wxStaticText(m_AnalyzePage, wxID_ANY, wxString());
sFrameInfoSizer->Add(m_objectCmdInfo, 0, wxALL, 5);
sAnalyzePage->Add(sFrameInfoSizer, 0, wxEXPAND, 5);
wxStaticBoxSizer* sSearchSizer = new wxStaticBoxSizer(
new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Search current Object")), wxVERTICAL);
wxBoxSizer* sSearchField = new wxBoxSizer(wxHORIZONTAL);
sSearchField->Add(new wxStaticText(m_AnalyzePage, wxID_ANY, _("Search for hex Value:")), 0,
wxALIGN_CENTER_VERTICAL, 5);
// Search box
wxStaticText* search_label =
new wxStaticText(m_AnalyzePage, wxID_ANY, _("Search for hex Value:"));
// TODO: ugh, wxValidator sucks - but we should use it anyway.
m_searchField = new wxTextCtrl(m_AnalyzePage, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxTE_PROCESS_ENTER);
m_numResultsText = new wxStaticText(m_AnalyzePage, wxID_ANY, wxEmptyString);
sSearchField->Add(m_searchField, 0, wxALL, 5);
sSearchField->Add(m_numResultsText, 0, wxALIGN_CENTER_VERTICAL, 5);
wxBoxSizer* sSearchButtons = new wxBoxSizer(wxHORIZONTAL);
// Search buttons
m_beginSearch = new wxButton(m_AnalyzePage, wxID_ANY, _("Search"));
m_findNext = new wxButton(m_AnalyzePage, wxID_ANY, _("Find next"));
m_findPrevious = new wxButton(m_AnalyzePage, wxID_ANY, _("Find previous"));
ResetSearch();
sSearchButtons->Add(m_beginSearch, 0, wxALL, 5);
sSearchButtons->Add(m_findNext, 0, wxALL, 5);
sSearchButtons->Add(m_findPrevious, 0, wxALL, 5);
wxBoxSizer* sListsSizer = new wxBoxSizer(wxHORIZONTAL);
sListsSizer->Add(m_framesList);
sListsSizer->Add(m_objectsList, 0, wxLEFT, space5);
sListsSizer->Add(m_objectCmdList, 1, wxLEFT, space5);
sSearchSizer->Add(sSearchField, 0, wxEXPAND, 5);
sSearchSizer->Add(sSearchButtons, 0, wxEXPAND, 5);
wxStaticBoxSizer* sFrameInfoSizer =
new wxStaticBoxSizer(wxVERTICAL, m_AnalyzePage, _("Frame Info"));
sFrameInfoSizer->AddSpacer(space5);
sFrameInfoSizer->Add(sListsSizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sFrameInfoSizer->AddSpacer(space5);
sFrameInfoSizer->Add(m_objectCmdInfo, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sFrameInfoSizer->AddSpacer(space5);
sAnalyzePage->Add(sSearchSizer, 0, wxEXPAND, 5);
sAnalyzePage->AddStretchSpacer();
wxBoxSizer* sSearchField = new wxBoxSizer(wxHORIZONTAL);
sSearchField->Add(search_label, 0, wxALIGN_CENTER_VERTICAL);
sSearchField->Add(m_searchField, 0, wxLEFT, space5);
sSearchField->Add(m_numResultsText, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
wxBoxSizer* sSearchButtons = new wxBoxSizer(wxHORIZONTAL);
sSearchButtons->Add(m_beginSearch);
sSearchButtons->Add(m_findNext, 0, wxLEFT, space5);
sSearchButtons->Add(m_findPrevious, 0, wxLEFT, space5);
wxStaticBoxSizer* sSearchSizer =
new wxStaticBoxSizer(wxVERTICAL, m_AnalyzePage, _("Search current Object"));
sSearchSizer->Add(sSearchField, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sSearchSizer->AddSpacer(space5);
sSearchSizer->Add(sSearchButtons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sSearchSizer->AddSpacer(space5);
wxBoxSizer* sAnalyzePage = new wxBoxSizer(wxVERTICAL);
sAnalyzePage->Add(sFrameInfoSizer, 0, wxEXPAND);
sAnalyzePage->Add(sSearchSizer, 0, wxEXPAND);
m_AnalyzePage->SetSizer(sAnalyzePage);
m_AnalyzePage->Layout();
sAnalyzePage->Fit(m_AnalyzePage);
m_Notebook->AddPage(m_AnalyzePage, _("Analyze"), false);
}
sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5);
sMain->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
wxStdDialogButtonSizer* close_btn_sizer = CreateStdDialogButtonSizer(wxCLOSE);
close_btn_sizer->GetCancelButton()->SetLabel(_("Close"));
SetSizer(sMain);
Layout();
sMain->Fit(this);
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
sMain->AddSpacer(space5);
sMain->Add(m_Notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->AddSpacer(space5);
sMain->Add(close_btn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->AddSpacer(space5);
Center(wxBOTH);
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(sMain);
Center();
// Connect Events
Bind(wxEVT_PAINT, &FifoPlayerDlg::OnPaint, this);
@ -302,7 +297,6 @@ void FifoPlayerDlg::CreateGUIControls()
m_RecordStop->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnRecordStop, this);
m_Save->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnSaveFile, this);
m_FramesToRecordCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnNumFramesToRecord, this);
Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnCloseClick, this);
m_framesList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnFrameListSelectionChanged, this);
m_objectsList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnObjectListSelectionChanged, this);
@ -808,11 +802,6 @@ void FifoPlayerDlg::OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event)
}
}
void FifoPlayerDlg::OnCloseClick(wxCommandEvent& WXUNUSED(event))
{
Hide();
}
void FifoPlayerDlg::OnRecordingFinished(wxEvent&)
{
m_RecordStop->SetLabel(_("Record"));

View File

@ -39,7 +39,6 @@ private:
void OnRecordStop(wxCommandEvent& event);
void OnSaveFile(wxCommandEvent& event);
void OnNumFramesToRecord(wxSpinEvent& event);
void OnCloseClick(wxCommandEvent& event);
void OnBeginSearch(wxCommandEvent& event);
void OnFindNextClick(wxCommandEvent& event);

View File

@ -85,9 +85,7 @@ CRenderFrame::CRenderFrame(wxFrame* parent, wxWindowID id, const wxString& title
: wxFrame(parent, id, title, pos, size, style)
{
// Give it an icon
wxIcon IconTemp;
IconTemp.CopyFromBitmap(WxUtils::LoadResourceBitmap("Dolphin"));
SetIcon(IconTemp);
SetIcons(WxUtils::GetDolphinIconBundle());
DragAcceptFiles(true);
Bind(wxEVT_DROP_FILES, &CRenderFrame::OnDropFiles, this);
@ -323,14 +321,9 @@ EVT_MOVE(CFrame::OnMove)
EVT_HOST_COMMAND(wxID_ANY, CFrame::OnHostMessage)
EVT_AUI_PANE_CLOSE(CFrame::OnPaneClose)
EVT_AUINOTEBOOK_PAGE_CLOSE(wxID_ANY, CFrame::OnNotebookPageClose)
EVT_AUINOTEBOOK_ALLOW_DND(wxID_ANY, CFrame::OnAllowNotebookDnD)
EVT_AUINOTEBOOK_PAGE_CHANGED(wxID_ANY, CFrame::OnNotebookPageChanged)
EVT_AUINOTEBOOK_TAB_RIGHT_UP(wxID_ANY, CFrame::OnTab)
// Post events to child panels
EVT_MENU_RANGE(IDM_INTERPRETER, IDM_ADDRBOX, CFrame::PostEvent)
EVT_TEXT(IDM_ADDRBOX, CFrame::PostEvent)
END_EVENT_TABLE()
@ -381,22 +374,18 @@ static BOOL WINAPI s_ctrl_handler(DWORD fdwCtrlType)
}
#endif
CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, const wxPoint& pos,
const wxSize& size, bool _UseDebugger, bool _BatchMode, bool ShowLogWindow,
long style)
: CRenderFrame(parent, id, title, pos, size, style), UseDebugger(_UseDebugger),
m_bBatchMode(_BatchMode)
CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, wxRect geometry,
bool use_debugger, bool batch_mode, bool show_log_window, long style)
: CRenderFrame(parent, id, title, wxDefaultPosition, wxSize(800, 600), style),
UseDebugger(use_debugger), m_bBatchMode(batch_mode),
m_toolbar_bitmap_size(FromDIP(wxSize(32, 32)))
{
for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++)
bFloatWindow[i] = false;
if (ShowLogWindow)
if (show_log_window)
SConfig::GetInstance().m_InterfaceLogWindow = true;
// Start debugging maximized
if (UseDebugger)
this->Maximize(true);
// Debugger class
if (UseDebugger)
{
@ -487,15 +476,23 @@ CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, const wxPo
ToggleLogConfigWindow(true);
}
// Set the size of the window after the UI has been built, but before we show it
SetSize(size);
// Setup the window size.
// This has to be done here instead of in Main because the Show() happens here.
SetMinSize(FromDIP(wxSize(400, 300)));
WxUtils::SetWindowSizeAndFitToScreen(this, geometry.GetPosition(), geometry.GetSize(),
FromDIP(wxSize(800, 600)));
// Show window
Show();
// Start debugging maximized (Must be after the window has been positioned)
if (UseDebugger)
Maximize(true);
// Commit
m_Mgr->Update();
// The window must be shown for m_XRRConfig to be created (wxGTK will not allocate X11
// resources until the window is shown for the first time).
Show();
#ifdef _WIN32
SetToolTip("");
GetToolTip()->SetAutoPop(25000);
@ -639,11 +636,10 @@ void CFrame::OnClose(wxCloseEvent& event)
}
else
{
// Close the log window now so that its settings are saved
if (m_LogWindow)
m_LogWindow->Close();
m_LogWindow = nullptr;
m_LogWindow->SaveSettings();
}
if (m_LogWindow)
m_LogWindow->RemoveAllListeners();
// Uninit
m_Mgr->UnInit();
@ -680,7 +676,8 @@ void CFrame::OnResize(wxSizeEvent& event)
{
event.Skip();
if (!IsMaximized() && !(SConfig::GetInstance().bRenderToMain && RendererIsFullscreen()) &&
if (!IsMaximized() && !IsIconized() &&
!(SConfig::GetInstance().bRenderToMain && RendererIsFullscreen()) &&
!(Core::GetState() != Core::CORE_UNINITIALIZED && SConfig::GetInstance().bRenderToMain &&
SConfig::GetInstance().bRenderWindowAutoSize))
{
@ -740,6 +737,11 @@ void CFrame::OnHostMessage(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_UPDATE_DISASM_DIALOG: // For breakpoints causing pausing
if (!g_pCodeWindow || Core::GetState() != Core::CORE_PAUSE)
return;
// fallthrough
case IDM_UPDATE_GUI:
UpdateGUI();
break;
@ -821,33 +823,29 @@ void CFrame::OnHostMessage(wxCommandEvent& event)
void CFrame::OnRenderWindowSizeRequest(int width, int height)
{
if (!Core::IsRunning() || !SConfig::GetInstance().bRenderWindowAutoSize ||
if (!SConfig::GetInstance().bRenderWindowAutoSize || !Core::IsRunning() ||
RendererIsFullscreen() || m_RenderFrame->IsMaximized())
return;
int old_width, old_height, log_width = 0, log_height = 0;
m_RenderFrame->GetClientSize(&old_width, &old_height);
wxSize requested_size(width, height);
// Convert to window pixels, since the size is from the backend it will be in framebuffer px.
requested_size *= 1.0 / m_RenderFrame->GetContentScaleFactor();
wxSize old_size;
// Add space for the log/console/debugger window
if (SConfig::GetInstance().bRenderToMain && (SConfig::GetInstance().m_InterfaceLogWindow ||
SConfig::GetInstance().m_InterfaceLogConfigWindow) &&
!m_Mgr->GetPane("Pane 1").IsFloating())
if (!SConfig::GetInstance().bRenderToMain)
{
switch (m_Mgr->GetPane("Pane 1").dock_direction)
{
case wxAUI_DOCK_LEFT:
case wxAUI_DOCK_RIGHT:
log_width = m_Mgr->GetPane("Pane 1").rect.GetWidth();
break;
case wxAUI_DOCK_TOP:
case wxAUI_DOCK_BOTTOM:
log_height = m_Mgr->GetPane("Pane 1").rect.GetHeight();
break;
}
old_size = m_RenderFrame->GetClientSize();
}
else
{
// Resize for the render panel only, this implicitly retains space for everything else
// (i.e. log panel, toolbar, statusbar, etc) without needing to compute for them.
old_size = m_RenderParent->GetSize();
}
if (old_width != width + log_width || old_height != height + log_height)
m_RenderFrame->SetClientSize(width + log_width, height + log_height);
wxSize diff = requested_size - old_size;
if (diff != wxSize())
m_RenderFrame->SetSize(m_RenderFrame->GetSize() + diff);
}
bool CFrame::RendererHasFocus()
@ -930,7 +928,7 @@ void CFrame::OnGameListCtrlItemActivated(wxListEvent& WXUNUSED(event))
GetMenuBar()->FindItem(IDM_LIST_WORLD)->Check(true);
GetMenuBar()->FindItem(IDM_LIST_UNKNOWN)->Check(true);
m_GameListCtrl->Update();
UpdateGameList();
}
else if (!m_GameListCtrl->GetISO(0))
{

View File

@ -46,7 +46,7 @@ class CRenderFrame : public wxFrame
public:
CRenderFrame(wxFrame* parent, wxWindowID id = wxID_ANY, const wxString& title = "Dolphin",
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
long style = wxDEFAULT_FRAME_STYLE);
bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL) override;
@ -63,8 +63,8 @@ class CFrame : public CRenderFrame
{
public:
CFrame(wxFrame* parent, wxWindowID id = wxID_ANY, const wxString& title = "Dolphin",
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
bool _UseDebugger = false, bool _BatchMode = false, bool ShowLogWindow = false,
wxRect geometry = wxDefaultSize, bool use_debugger = false, bool batch_mode = false,
bool show_log_window = false,
long style = wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
virtual ~CFrame();
@ -113,6 +113,7 @@ public:
const CGameListCtrl* GetGameListCtrl() const;
wxMenuBar* GetMenuBar() const override;
const wxSize& GetToolbarBitmapSize() const; // Needed before the toolbar exists
#ifdef __WXGTK__
Common::Event panic_event;
@ -129,7 +130,7 @@ public:
wxToolBar* m_ToolBar = nullptr;
// AUI
wxAuiManager* m_Mgr = nullptr;
bool bFloatWindow[IDM_CODE_WINDOW - IDM_LOG_WINDOW + 1];
bool bFloatWindow[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START] = {};
// Perspectives (Should find a way to make all of this private)
void DoAddPage(wxWindow* Win, int i, bool Float);
@ -191,6 +192,7 @@ private:
wxTimer m_poll_hotkey_timer;
wxTimer m_handle_signal_timer;
wxSize m_toolbar_bitmap_size;
wxBitmap m_Bitmaps[EToolbar_Max];
wxMenuBar* m_menubar_shadow = nullptr;
@ -209,12 +211,12 @@ private:
// Perspectives
void AddRemoveBlankPage();
void OnNotebookPageClose(wxAuiNotebookEvent& event);
void OnAllowNotebookDnD(wxAuiNotebookEvent& event);
void OnNotebookAllowDnD(wxAuiNotebookEvent& event);
void OnNotebookPageChanged(wxAuiNotebookEvent& event);
void OnNotebookPageClose(wxAuiNotebookEvent& event);
void OnNotebookTabRightUp(wxAuiNotebookEvent& event);
void OnFloatWindow(wxCommandEvent& event);
void ToggleFloatWindow(int Id);
void OnTab(wxAuiNotebookEvent& event);
int GetNotebookAffiliation(wxWindowID Id);
void ClosePages();
void CloseAllNotebooks();
@ -226,7 +228,6 @@ private:
// Float window
void DoUnfloatPage(int Id);
void OnFloatingPageClosed(wxCloseEvent& event);
void OnFloatingPageSize(wxSizeEvent& event);
void DoFloatNotebookPage(wxWindowID Id);
wxFrame* CreateParentFrame(wxWindowID Id = wxID_ANY, const wxString& title = "",
wxWindow* = nullptr);

View File

@ -152,41 +152,22 @@ void CFrame::ToggleLogConfigWindow(bool bShow)
void CFrame::OnToggleWindow(wxCommandEvent& event)
{
bool bShow = GetMenuBar()->IsChecked(event.GetId());
bool show = GetMenuBar()->IsChecked(event.GetId());
switch (event.GetId())
{
case IDM_LOG_WINDOW:
if (!g_pCodeWindow)
SConfig::GetInstance().m_InterfaceLogWindow = bShow;
ToggleLogWindow(bShow);
SConfig::GetInstance().m_InterfaceLogWindow = show;
ToggleLogWindow(show);
break;
case IDM_LOG_CONFIG_WINDOW:
if (!g_pCodeWindow)
SConfig::GetInstance().m_InterfaceLogConfigWindow = bShow;
ToggleLogConfigWindow(bShow);
break;
case IDM_REGISTER_WINDOW:
g_pCodeWindow->ToggleRegisterWindow(bShow);
break;
case IDM_WATCH_WINDOW:
g_pCodeWindow->ToggleWatchWindow(bShow);
break;
case IDM_BREAKPOINT_WINDOW:
g_pCodeWindow->ToggleBreakPointWindow(bShow);
break;
case IDM_MEMORY_WINDOW:
g_pCodeWindow->ToggleMemoryWindow(bShow);
break;
case IDM_JIT_WINDOW:
g_pCodeWindow->ToggleJitWindow(bShow);
break;
case IDM_SOUND_WINDOW:
g_pCodeWindow->ToggleSoundWindow(bShow);
break;
case IDM_VIDEO_WINDOW:
g_pCodeWindow->ToggleVideoWindow(bShow);
SConfig::GetInstance().m_InterfaceLogConfigWindow = show;
ToggleLogConfigWindow(show);
break;
default:
g_pCodeWindow->TogglePanel(event.GetId(), show);
}
}
@ -199,20 +180,21 @@ void CFrame::ClosePages()
if (g_pCodeWindow)
{
g_pCodeWindow->ToggleCodeWindow(false);
g_pCodeWindow->ToggleRegisterWindow(false);
g_pCodeWindow->ToggleWatchWindow(false);
g_pCodeWindow->ToggleBreakPointWindow(false);
g_pCodeWindow->ToggleMemoryWindow(false);
g_pCodeWindow->ToggleJitWindow(false);
g_pCodeWindow->ToggleSoundWindow(false);
g_pCodeWindow->ToggleVideoWindow(false);
for (int i = IDM_REGISTER_WINDOW; i < IDM_DEBUG_WINDOW_LIST_END; ++i)
{
g_pCodeWindow->TogglePanel(i, false);
}
}
}
void CFrame::OnNotebookPageChanged(wxAuiNotebookEvent& event)
{
event.Skip();
// Event is intended for someone else
if (event.GetPropagatedFrom() != nullptr)
{
event.Skip();
return;
}
if (!g_pCodeWindow)
return;
@ -230,39 +212,45 @@ void CFrame::OnNotebookPageChanged(wxAuiNotebookEvent& event)
void CFrame::OnNotebookPageClose(wxAuiNotebookEvent& event)
{
// Event is intended for someone else
if (event.GetPropagatedFrom() != nullptr)
{
event.Skip();
return;
}
// Override event
event.Veto();
wxAuiNotebook* Ctrl = (wxAuiNotebook*)event.GetEventObject();
wxAuiNotebook* nb = static_cast<wxAuiNotebook*>(event.GetEventObject());
int page_id = nb->GetPage(event.GetSelection())->GetId();
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_WINDOW)
ToggleLogWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_CONFIG_WINDOW)
ToggleLogConfigWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_REGISTER_WINDOW)
g_pCodeWindow->ToggleRegisterWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_WATCH_WINDOW)
g_pCodeWindow->ToggleWatchWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_BREAKPOINT_WINDOW)
g_pCodeWindow->ToggleBreakPointWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_JIT_WINDOW)
g_pCodeWindow->ToggleJitWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_MEMORY_WINDOW)
g_pCodeWindow->ToggleMemoryWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_SOUND_WINDOW)
g_pCodeWindow->ToggleSoundWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_VIDEO_WINDOW)
g_pCodeWindow->ToggleVideoWindow(false);
switch (page_id)
{
case IDM_LOG_WINDOW:
case IDM_LOG_CONFIG_WINDOW:
{
GetMenuBar()->Check(page_id, !GetMenuBar()->IsChecked(page_id));
wxCommandEvent ev(wxEVT_MENU, page_id);
OnToggleWindow(ev);
break;
}
case IDM_CODE_WINDOW:
break; // Code Window is not allowed to be closed
default:
// Check for the magic empty panel.
if (nb->GetPageText(event.GetSelection()).IsSameAs("<>"))
break;
g_pCodeWindow->TogglePanel(page_id, false);
}
}
void CFrame::OnFloatingPageClosed(wxCloseEvent& event)
{
ToggleFloatWindow(event.GetId() - IDM_LOG_WINDOW_PARENT + IDM_FLOAT_LOG_WINDOW);
}
// TODO: This is a good place to save the window size and position to an INI
void CFrame::OnFloatingPageSize(wxSizeEvent& event)
{
event.Skip();
ToggleFloatWindow(event.GetId() - IDM_LOG_WINDOW_PARENT + IDM_FLOAT_LOG_WINDOW);
}
void CFrame::OnFloatWindow(wxCommandEvent& event)
@ -320,9 +308,15 @@ void CFrame::DoUnfloatPage(int Id)
Win->Destroy();
}
void CFrame::OnTab(wxAuiNotebookEvent& event)
void CFrame::OnNotebookTabRightUp(wxAuiNotebookEvent& event)
{
event.Skip();
// Event is intended for someone else
if (event.GetPropagatedFrom() != nullptr)
{
event.Skip();
return;
}
if (!g_pCodeWindow)
return;
@ -354,10 +348,21 @@ void CFrame::OnTab(wxAuiNotebookEvent& event)
PopupMenu(&MenuPopup, Pt);
}
void CFrame::OnAllowNotebookDnD(wxAuiNotebookEvent& event)
void CFrame::OnNotebookAllowDnD(wxAuiNotebookEvent& event)
{
event.Skip();
event.Allow();
// NOTE: This event was sent FROM the source notebook TO the destination notebook so
// all the member variables are related to the source, we can't get the drop target.
// NOTE: This function is "part of the internal interface" but there's no clean alternative.
if (event.GetPropagatedFrom() != nullptr)
{
// Drop target was one of the notebook's children, we don't care about this event.
event.Skip();
return;
}
// Since the destination is one of our own notebooks, make sure the source is as well.
// If the source is some other panel, leave the event in the default reject state.
if (m_Mgr->GetPane(event.GetDragSource()).window)
event.Allow();
}
void CFrame::ShowResizePane()
@ -391,12 +396,7 @@ void CFrame::ShowResizePane()
void CFrame::TogglePane()
{
// Get the first notebook
wxAuiNotebook* NB = nullptr;
for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++)
{
if (m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook)))
NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window;
}
wxAuiNotebook* NB = GetNotebookFromId(0);
if (NB)
{
@ -450,6 +450,7 @@ void CFrame::DoRemovePage(wxWindow* Win, bool bHide)
{
Win->Destroy();
}
break;
}
}
}
@ -468,13 +469,17 @@ void CFrame::DoAddPage(wxWindow* Win, int i, bool Float)
i = 0;
// The page was already previously added, no need to add it again.
if (Win && GetNotebookFromId(i)->GetPageIndex(Win) != wxNOT_FOUND)
if (GetNotebookFromId(i)->GetPageIndex(Win) != wxNOT_FOUND)
return;
if (!Float)
{
GetNotebookFromId(i)->AddPage(Win, Win->GetName(), true);
}
else
{
CreateParentFrame(Win->GetId() + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW, Win->GetName(), Win);
}
}
void CFrame::PopulateSavedPerspectives()
@ -664,8 +669,7 @@ void CFrame::SetPaneSize()
if (Perspectives.size() <= ActivePerspective)
return;
int iClientX = GetSize().GetX();
int iClientY = GetSize().GetY();
wxSize client_size = GetClientSize();
for (u32 i = 0, j = 0; i < m_Mgr->GetAllPanes().GetCount(); i++)
{
@ -687,8 +691,8 @@ void CFrame::SetPaneSize()
H = MathUtil::Clamp<u32>(H, 5, 95);
// Convert percentages to pixel lengths
W = (W * iClientX) / 100;
H = (H * iClientY) / 100;
W = (W * client_size.GetWidth()) / 100;
H = (H * client_size.GetHeight()) / 100;
m_Mgr->GetAllPanes()[i].BestSize(W, H).MinSize(W, H);
j++;
@ -815,7 +819,7 @@ void CFrame::UpdateCurrentPerspective()
current->Perspective = m_Mgr->SavePerspective();
// Get client size
int iClientX = GetSize().GetX(), iClientY = GetSize().GetY();
wxSize client_size = GetClientSize();
current->Width.clear();
current->Height.clear();
for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++)
@ -823,10 +827,10 @@ void CFrame::UpdateCurrentPerspective()
if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiToolBar)))
{
// Save width and height as a percentage of the client width and height
current->Width.push_back((m_Mgr->GetAllPanes()[i].window->GetClientSize().GetX() * 100) /
iClientX);
current->Height.push_back((m_Mgr->GetAllPanes()[i].window->GetClientSize().GetY() * 100) /
iClientY);
current->Width.push_back((m_Mgr->GetAllPanes()[i].window->GetSize().GetX() * 100) /
client_size.GetWidth());
current->Height.push_back((m_Mgr->GetAllPanes()[i].window->GetSize().GetY() * 100) /
client_size.GetHeight());
}
}
}
@ -952,23 +956,40 @@ wxFrame* CFrame::CreateParentFrame(wxWindowID Id, const wxString& Title, wxWindo
m_MainSizer->Add(Child, 1, wxEXPAND);
// If the tab is not the one currently being shown to the user then it will
// be hidden. Make sure it is being shown.
Child->Show();
Frame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnFloatingPageClosed, this);
// TODO: This is a good place to load window position and size settings from an INI
// Main sizer
Frame->SetSizer(m_MainSizer);
// Minimum frame size
Frame->SetMinSize(wxSize(200, 200));
Frame->SetSizerAndFit(m_MainSizer);
Frame->Show();
return Frame;
}
wxAuiNotebook* CFrame::CreateEmptyNotebook()
{
const long NOTEBOOK_STYLE = wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE |
wxAUI_NB_TAB_EXTERNAL_MOVE | wxAUI_NB_SCROLL_BUTTONS |
wxAUI_NB_WINDOWLIST_BUTTON | wxNO_BORDER;
static constexpr long NOTEBOOK_STYLE = wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE |
wxAUI_NB_CLOSE_BUTTON | wxAUI_NB_TAB_EXTERNAL_MOVE |
wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_WINDOWLIST_BUTTON |
wxNO_BORDER;
return new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, NOTEBOOK_STYLE);
auto* nb = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, NOTEBOOK_STYLE);
// wxAuiNotebookEvent is derived from wxCommandEvent so they bubble up from child panels.
// This is a problem if the panels contain their own AUI Notebooks like DSPDebuggerLLE
// since we receive its events as though they came from our own children which we do
// not want to deal with. Binding directly to our notebooks and ignoring any event that
// has been propagated from somewhere else resolves it.
nb->Bind(wxEVT_AUINOTEBOOK_ALLOW_DND, &CFrame::OnNotebookAllowDnD, this);
nb->Bind(wxEVT_AUINOTEBOOK_PAGE_CHANGED, &CFrame::OnNotebookPageChanged, this);
nb->Bind(wxEVT_AUINOTEBOOK_PAGE_CLOSE, &CFrame::OnNotebookPageClose, this);
nb->Bind(wxEVT_AUINOTEBOOK_TAB_RIGHT_UP, &CFrame::OnNotebookTabRightUp, this);
return nb;
}
void CFrame::AddRemoveBlankPage()

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <array>
#include <cstdarg>
#include <cstdio>
#include <mutex>
@ -77,21 +78,6 @@
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
#ifdef _WIN32
#ifndef SM_XVIRTUALSCREEN
#define SM_XVIRTUALSCREEN 76
#endif
#ifndef SM_YVIRTUALSCREEN
#define SM_YVIRTUALSCREEN 77
#endif
#ifndef SM_CXVIRTUALSCREEN
#define SM_CXVIRTUALSCREEN 78
#endif
#ifndef SM_CYVIRTUALSCREEN
#define SM_CYVIRTUALSCREEN 79
#endif
#endif
class InputConfig;
class wxFrame;
@ -108,6 +94,11 @@ wxMenuBar* CFrame::GetMenuBar() const
}
}
const wxSize& CFrame::GetToolbarBitmapSize() const
{
return m_toolbar_bitmap_size;
}
// Create menu items
// ---------------------
wxMenuBar* CFrame::CreateMenu()
@ -528,9 +519,6 @@ wxString CFrame::GetMenuLabel(int Id)
// ---------------------
void CFrame::PopulateToolbar(wxToolBar* ToolBar)
{
int w = m_Bitmaps[Toolbar_FileOpen].GetWidth(), h = m_Bitmaps[Toolbar_FileOpen].GetHeight();
ToolBar->SetToolBitmapSize(wxSize(w, h));
WxUtils::AddToolbarButton(ToolBar, wxID_OPEN, _("Open"), m_Bitmaps[Toolbar_FileOpen],
_("Open file..."));
WxUtils::AddToolbarButton(ToolBar, wxID_REFRESH, _("Refresh"), m_Bitmaps[Toolbar_Refresh],
@ -554,7 +542,7 @@ void CFrame::PopulateToolbar(wxToolBar* ToolBar)
// Delete and recreate the toolbar
void CFrame::RecreateToolbar()
{
static const long TOOLBAR_STYLE = wxTB_DEFAULT_STYLE | wxTB_TEXT | wxTB_FLAT;
static constexpr long TOOLBAR_STYLE = wxTB_DEFAULT_STYLE | wxTB_TEXT | wxTB_FLAT;
if (m_ToolBar != nullptr)
{
@ -563,6 +551,7 @@ void CFrame::RecreateToolbar()
}
m_ToolBar = CreateToolBar(TOOLBAR_STYLE, wxID_ANY);
m_ToolBar->SetToolBitmapSize(m_toolbar_bitmap_size);
if (g_pCodeWindow)
{
@ -580,18 +569,11 @@ void CFrame::RecreateToolbar()
void CFrame::InitBitmaps()
{
auto const dir = StrToWxStr(File::GetThemeDir(SConfig::GetInstance().theme_name));
m_Bitmaps[Toolbar_FileOpen].LoadFile(dir + "open.png", wxBITMAP_TYPE_PNG);
m_Bitmaps[Toolbar_Refresh].LoadFile(dir + "refresh.png", wxBITMAP_TYPE_PNG);
m_Bitmaps[Toolbar_Play].LoadFile(dir + "play.png", wxBITMAP_TYPE_PNG);
m_Bitmaps[Toolbar_Stop].LoadFile(dir + "stop.png", wxBITMAP_TYPE_PNG);
m_Bitmaps[Toolbar_Pause].LoadFile(dir + "pause.png", wxBITMAP_TYPE_PNG);
m_Bitmaps[Toolbar_ConfigMain].LoadFile(dir + "config.png", wxBITMAP_TYPE_PNG);
m_Bitmaps[Toolbar_ConfigGFX].LoadFile(dir + "graphics.png", wxBITMAP_TYPE_PNG);
m_Bitmaps[Toolbar_Controller].LoadFile(dir + "classic.png", wxBITMAP_TYPE_PNG);
m_Bitmaps[Toolbar_Screenshot].LoadFile(dir + "screenshot.png", wxBITMAP_TYPE_PNG);
m_Bitmaps[Toolbar_FullScreen].LoadFile(dir + "fullscreen.png", wxBITMAP_TYPE_PNG);
static constexpr std::array<const char* const, EToolbar_Max> s_image_names{
{"open", "refresh", "play", "stop", "pause", "screenshot", "fullscreen", "config", "graphics",
"classic"}};
for (std::size_t i = 0; i < s_image_names.size(); ++i)
m_Bitmaps[i] = WxUtils::LoadScaledThemeBitmap(s_image_names[i], this, m_toolbar_bitmap_size);
// Update in case the bitmap has been updated
if (m_ToolBar != nullptr)
@ -606,7 +588,7 @@ void CFrame::OpenGeneralConfiguration(int tab)
HotkeyManagerEmu::Enable(false);
if (config_main.ShowModal() == wxID_OK)
m_GameListCtrl->Update();
UpdateGameList();
HotkeyManagerEmu::Enable(true);
UpdateGUI();
@ -660,10 +642,10 @@ void CFrame::BootGame(const std::string& filename)
StartGame(bootfile);
if (UseDebugger && g_pCodeWindow)
{
if (g_pCodeWindow->m_WatchWindow)
g_pCodeWindow->m_WatchWindow->LoadAll();
if (g_pCodeWindow->m_BreakpointWindow)
g_pCodeWindow->m_BreakpointWindow->LoadAll();
if (g_pCodeWindow->HasPanel<CWatchWindow>())
g_pCodeWindow->GetPanel<CWatchWindow>()->LoadAll();
if (g_pCodeWindow->HasPanel<CBreakPointWindow>())
g_pCodeWindow->GetPanel<CBreakPointWindow>()->LoadAll();
}
}
}
@ -860,7 +842,7 @@ void CFrame::OnPlay(wxCommandEvent& WXUNUSED(event))
wxThread::Sleep(20);
g_pCodeWindow->JumpToAddress(PC);
g_pCodeWindow->Update();
g_pCodeWindow->Repopulate();
// Update toolbar with Play/Pause status
UpdateGUI();
}
@ -987,36 +969,29 @@ void CFrame::StartGame(const std::string& filename)
}
else
{
wxPoint position(SConfig::GetInstance().iRenderWindowXPos,
SConfig::GetInstance().iRenderWindowYPos);
#ifdef __APPLE__
// On OS X, the render window's title bar is not visible,
// and the window therefore not easily moved, when the
// position is 0,0. Weed out the 0's from existing configs.
if (position == wxPoint(0, 0))
position = wxDefaultPosition;
#endif
wxRect window_geometry(
SConfig::GetInstance().iRenderWindowXPos, SConfig::GetInstance().iRenderWindowYPos,
SConfig::GetInstance().iRenderWindowWidth, SConfig::GetInstance().iRenderWindowHeight);
// Set window size in framebuffer pixels since the 3D rendering will be operating at
// that level.
wxSize default_size{wxSize(640, 480) * (1.0 / GetContentScaleFactor())};
m_RenderFrame = new CRenderFrame(this, wxID_ANY, _("Dolphin"), wxDefaultPosition, default_size);
// Convert ClientSize coordinates to frame sizes.
wxSize decoration_fudge = m_RenderFrame->GetSize() - m_RenderFrame->GetClientSize();
default_size += decoration_fudge;
if (!window_geometry.IsEmpty())
window_geometry.SetSize(window_geometry.GetSize() + decoration_fudge);
WxUtils::SetWindowSizeAndFitToScreen(m_RenderFrame, window_geometry.GetPosition(),
window_geometry.GetSize(), default_size);
wxSize size(SConfig::GetInstance().iRenderWindowWidth,
SConfig::GetInstance().iRenderWindowHeight);
#ifdef _WIN32
// Out of desktop check
int leftPos = GetSystemMetrics(SM_XVIRTUALSCREEN);
int topPos = GetSystemMetrics(SM_YVIRTUALSCREEN);
int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
if ((leftPos + width) < (position.x + size.GetWidth()) || leftPos > position.x ||
(topPos + height) < (position.y + size.GetHeight()) || topPos > position.y)
position.x = position.y = wxDefaultCoord;
#endif
m_RenderFrame = new CRenderFrame((wxFrame*)this, wxID_ANY, _("Dolphin"), position);
if (SConfig::GetInstance().bKeepWindowOnTop)
m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP);
else
m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP);
m_RenderFrame->SetBackgroundColour(*wxBLACK);
m_RenderFrame->SetClientSize(size.GetWidth(), size.GetHeight());
m_RenderFrame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnRenderParentClose, this);
m_RenderFrame->Bind(wxEVT_ACTIVATE, &CFrame::OnActive, this);
m_RenderFrame->Bind(wxEVT_MOVE, &CFrame::OnRenderParentMove, this);
@ -1035,7 +1010,7 @@ void CFrame::StartGame(const std::string& filename)
m_RenderFrame->EnableFullScreenView(true);
#endif
wxBeginBusyCursor();
wxBusyCursor hourglass;
DoFullscreen(SConfig::GetInstance().bFullscreen);
@ -1045,6 +1020,7 @@ void CFrame::StartGame(const std::string& filename)
// Destroy the renderer frame when not rendering to main
if (!SConfig::GetInstance().bRenderToMain)
m_RenderFrame->Destroy();
m_RenderFrame = nullptr;
m_RenderParent = nullptr;
m_bGameLoading = false;
UpdateGUI();
@ -1076,8 +1052,6 @@ void CFrame::StartGame(const std::string& filename)
wxTheApp->Bind(wxEVT_KILL_FOCUS, &CFrame::OnFocusChange, this);
m_RenderParent->Bind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this);
}
wxEndBusyCursor();
}
void CFrame::OnBootDrive(wxCommandEvent& event)
@ -1088,10 +1062,7 @@ void CFrame::OnBootDrive(wxCommandEvent& event)
// Refresh the file list and browse for a favorites directory
void CFrame::OnRefresh(wxCommandEvent& WXUNUSED(event))
{
if (m_GameListCtrl)
{
m_GameListCtrl->Update();
}
UpdateGameList();
}
// Create screenshot
@ -1194,18 +1165,15 @@ void CFrame::DoStop()
if (UseDebugger && g_pCodeWindow)
{
if (g_pCodeWindow->m_WatchWindow)
{
g_pCodeWindow->m_WatchWindow->SaveAll();
PowerPC::watches.Clear();
}
if (g_pCodeWindow->m_BreakpointWindow)
{
g_pCodeWindow->m_BreakpointWindow->SaveAll();
PowerPC::breakpoints.Clear();
PowerPC::memchecks.Clear();
g_pCodeWindow->m_BreakpointWindow->NotifyUpdate();
}
if (g_pCodeWindow->HasPanel<CWatchWindow>())
g_pCodeWindow->GetPanel<CWatchWindow>()->SaveAll();
PowerPC::watches.Clear();
if (g_pCodeWindow->HasPanel<CBreakPointWindow>())
g_pCodeWindow->GetPanel<CBreakPointWindow>()->SaveAll();
PowerPC::breakpoints.Clear();
PowerPC::memchecks.Clear();
if (g_pCodeWindow->HasPanel<CBreakPointWindow>())
g_pCodeWindow->GetPanel<CBreakPointWindow>()->NotifyUpdate();
g_symbolDB.Clear();
Host_NotifyMapLoaded();
}
@ -1912,7 +1880,8 @@ void CFrame::UpdateGUI()
void CFrame::UpdateGameList()
{
m_GameListCtrl->Update();
if (m_GameListCtrl)
m_GameListCtrl->ReloadList();
}
void CFrame::GameListChanged(wxCommandEvent& event)
@ -1987,11 +1956,7 @@ void CFrame::GameListChanged(wxCommandEvent& event)
break;
}
// Update gamelist
if (m_GameListCtrl)
{
m_GameListCtrl->Update();
}
UpdateGameList();
}
// Enable and disable the toolbar
@ -2047,6 +2012,6 @@ void CFrame::OnChangeColumnsVisible(wxCommandEvent& event)
default:
return;
}
m_GameListCtrl->Update();
UpdateGameList();
SConfig::GetInstance().SaveSettings();
}

View File

@ -11,6 +11,7 @@
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <wx/app.h>
#include <wx/bitmap.h>
@ -187,47 +188,73 @@ CGameListCtrl::~CGameListCtrl()
}
template <typename T>
static void InitBitmap(wxImageList* img_list, std::vector<int>* vector, T index,
const std::string& name)
static void InitBitmap(wxImageList* img_list, std::vector<int>* vector, wxWindow* context,
const wxSize& usable_size, T index, const std::string& name)
{
wxSize size(96, 32);
(*vector)[static_cast<size_t>(index)] = img_list->Add(WxUtils::LoadResourceBitmap(name, size));
wxSize size = img_list->GetSize();
(*vector)[static_cast<size_t>(index)] = img_list->Add(WxUtils::LoadScaledResourceBitmap(
name, context, size, usable_size, WxUtils::LSI_SCALE | WxUtils::LSI_ALIGN_VCENTER));
}
void CGameListCtrl::InitBitmaps()
{
wxImageList* img_list = new wxImageList(96, 32);
const wxSize size = FromDIP(wxSize(96, 32));
const wxSize flag_bmp_size = FromDIP(wxSize(32, 32));
const wxSize platform_bmp_size = flag_bmp_size;
const wxSize rating_bmp_size = FromDIP(wxSize(48, 32));
wxImageList* img_list = new wxImageList(size.GetWidth(), size.GetHeight());
AssignImageList(img_list, wxIMAGE_LIST_SMALL);
m_FlagImageIndex.resize(static_cast<size_t>(DiscIO::Country::NUMBER_OF_COUNTRIES));
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_JAPAN, "Flag_Japan");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_EUROPE, "Flag_Europe");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_USA, "Flag_USA");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_AUSTRALIA, "Flag_Australia");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_FRANCE, "Flag_France");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_GERMANY, "Flag_Germany");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_ITALY, "Flag_Italy");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_KOREA, "Flag_Korea");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_NETHERLANDS, "Flag_Netherlands");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_RUSSIA, "Flag_Russia");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_SPAIN, "Flag_Spain");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_TAIWAN, "Flag_Taiwan");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_WORLD, "Flag_International");
InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_UNKNOWN, "Flag_Unknown");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_JAPAN,
"Flag_Japan");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_EUROPE,
"Flag_Europe");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_USA,
"Flag_USA");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_AUSTRALIA,
"Flag_Australia");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_FRANCE,
"Flag_France");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_GERMANY,
"Flag_Germany");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_ITALY,
"Flag_Italy");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_KOREA,
"Flag_Korea");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_NETHERLANDS,
"Flag_Netherlands");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_RUSSIA,
"Flag_Russia");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_SPAIN,
"Flag_Spain");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_TAIWAN,
"Flag_Taiwan");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_WORLD,
"Flag_International");
InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_UNKNOWN,
"Flag_Unknown");
m_PlatformImageIndex.resize(static_cast<size_t>(DiscIO::Platform::NUMBER_OF_PLATFORMS));
InitBitmap(img_list, &m_PlatformImageIndex, DiscIO::Platform::GAMECUBE_DISC, "Platform_Gamecube");
InitBitmap(img_list, &m_PlatformImageIndex, DiscIO::Platform::WII_DISC, "Platform_Wii");
InitBitmap(img_list, &m_PlatformImageIndex, DiscIO::Platform::WII_WAD, "Platform_Wad");
InitBitmap(img_list, &m_PlatformImageIndex, DiscIO::Platform::ELF_DOL, "Platform_File");
InitBitmap(img_list, &m_PlatformImageIndex, this, platform_bmp_size,
DiscIO::Platform::GAMECUBE_DISC, "Platform_Gamecube");
InitBitmap(img_list, &m_PlatformImageIndex, this, platform_bmp_size, DiscIO::Platform::WII_DISC,
"Platform_Wii");
InitBitmap(img_list, &m_PlatformImageIndex, this, platform_bmp_size, DiscIO::Platform::WII_WAD,
"Platform_Wad");
InitBitmap(img_list, &m_PlatformImageIndex, this, platform_bmp_size, DiscIO::Platform::ELF_DOL,
"Platform_File");
m_EmuStateImageIndex.resize(6);
InitBitmap(img_list, &m_EmuStateImageIndex, 0, "rating0");
InitBitmap(img_list, &m_EmuStateImageIndex, 1, "rating1");
InitBitmap(img_list, &m_EmuStateImageIndex, 2, "rating2");
InitBitmap(img_list, &m_EmuStateImageIndex, 3, "rating3");
InitBitmap(img_list, &m_EmuStateImageIndex, 4, "rating4");
InitBitmap(img_list, &m_EmuStateImageIndex, 5, "rating5");
InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 0, "rating0");
InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 1, "rating1");
InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 2, "rating2");
InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 3, "rating3");
InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 4, "rating4");
InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 5, "rating5");
m_utility_game_banners.resize(1);
InitBitmap(img_list, &m_utility_game_banners, this, size, 0, "nobanner");
}
void CGameListCtrl::BrowseForDirectory()
@ -252,11 +279,11 @@ void CGameListCtrl::BrowseForDirectory()
SConfig::GetInstance().SaveSettings();
}
Update();
ReloadList();
}
}
void CGameListCtrl::Update()
void CGameListCtrl::ReloadList()
{
int scrollPos = wxWindow::GetScrollPos(wxVERTICAL);
// Don't let the user refresh it while a game is running
@ -297,20 +324,22 @@ void CGameListCtrl::Update()
// set initial sizes for columns
SetColumnWidth(COLUMN_DUMMY, 0);
SetColumnWidth(COLUMN_PLATFORM, SConfig::GetInstance().m_showSystemColumn ?
32 + platform_icon_padding + platform_padding :
FromDIP(32 + platform_icon_padding + platform_padding) :
0);
SetColumnWidth(COLUMN_BANNER,
SConfig::GetInstance().m_showBannerColumn ? 96 + platform_padding : 0);
SetColumnWidth(COLUMN_TITLE, 175 + platform_padding);
SConfig::GetInstance().m_showBannerColumn ? FromDIP(96 + platform_padding) : 0);
SetColumnWidth(COLUMN_TITLE, FromDIP(175 + platform_padding));
SetColumnWidth(COLUMN_MAKER,
SConfig::GetInstance().m_showMakerColumn ? 150 + platform_padding : 0);
SetColumnWidth(COLUMN_FILENAME,
SConfig::GetInstance().m_showFileNameColumn ? 100 + platform_padding : 0);
SetColumnWidth(COLUMN_ID, SConfig::GetInstance().m_showIDColumn ? 75 + platform_padding : 0);
SConfig::GetInstance().m_showMakerColumn ? FromDIP(150 + platform_padding) : 0);
SetColumnWidth(COLUMN_FILENAME, SConfig::GetInstance().m_showFileNameColumn ?
FromDIP(100 + platform_padding) :
0);
SetColumnWidth(COLUMN_ID,
SConfig::GetInstance().m_showIDColumn ? FromDIP(75 + platform_padding) : 0);
SetColumnWidth(COLUMN_COUNTRY,
SConfig::GetInstance().m_showRegionColumn ? 32 + platform_padding : 0);
SConfig::GetInstance().m_showRegionColumn ? FromDIP(32 + platform_padding) : 0);
SetColumnWidth(COLUMN_EMULATION_STATE,
SConfig::GetInstance().m_showStateColumn ? 48 + platform_padding : 0);
SConfig::GetInstance().m_showStateColumn ? FromDIP(48 + platform_padding) : 0);
// add all items
for (int i = 0; i < (int)m_ISOFiles.size(); i++)
@ -405,10 +434,14 @@ void CGameListCtrl::UpdateItemAtColumn(long _Index, int column)
}
case COLUMN_BANNER:
{
int ImageIndex = -1;
int ImageIndex = m_utility_game_banners[0]; // nobanner
if (rISOFile.GetBitmap().IsOk())
ImageIndex = GetImageList(wxIMAGE_LIST_SMALL)->Add(rISOFile.GetBitmap());
if (rISOFile.GetBannerImage().IsOk())
{
wxImageList* img_list = GetImageList(wxIMAGE_LIST_SMALL);
ImageIndex = img_list->Add(
WxUtils::ScaleImageToBitmap(rISOFile.GetBannerImage(), this, img_list->GetSize()));
}
SetItemColumnImage(_Index, COLUMN_BANNER, ImageIndex);
break;
@ -502,7 +535,7 @@ void CGameListCtrl::SetBackgroundColor()
void CGameListCtrl::ScanForISOs()
{
ClearIsoFiles();
m_ISOFiles.clear();
// Load custom game titles from titles.txt
// http://www.gametdb.com/Wii/Downloads
@ -1098,7 +1131,7 @@ void CGameListCtrl::OnDeleteISO(wxCommandEvent& WXUNUSED(event))
{
for (const GameListItem* iso : GetAllSelectedISOs())
File::Delete(iso->GetFileName());
Update();
ReloadList();
}
}
@ -1269,7 +1302,7 @@ void CGameListCtrl::CompressSelection(bool _compress)
if (!all_good)
WxUtils::ShowErrorDialog(_("Dolphin was unable to complete the requested action."));
Update();
ReloadList();
}
bool CGameListCtrl::CompressCB(const std::string& text, float percent, void* arg)
@ -1342,7 +1375,7 @@ void CGameListCtrl::OnCompressISO(wxCommandEvent& WXUNUSED(event))
if (!all_good)
WxUtils::ShowErrorDialog(_("Dolphin was unable to complete the requested action."));
Update();
ReloadList();
}
void CGameListCtrl::OnChangeDisc(wxCommandEvent& WXUNUSED(event))

View File

@ -38,7 +38,7 @@ public:
long style);
~CGameListCtrl();
void Update() override;
void ReloadList();
void BrowseForDirectory();
const GameListItem* GetISO(size_t index) const;
@ -70,6 +70,7 @@ private:
std::vector<int> m_FlagImageIndex;
std::vector<int> m_PlatformImageIndex;
std::vector<int> m_EmuStateImageIndex;
std::vector<int> m_utility_game_banners;
std::vector<std::unique_ptr<GameListItem>> m_ISOFiles;
void ClearIsoFiles() { m_ISOFiles.clear(); }

View File

@ -163,7 +163,9 @@ enum
IDM_CONFIG_LOGGER,
// Views
IDM_LOG_WINDOW,
// IMPORTANT: Make sure IDM_FLOAT_xxx and IDM_xxx_PARENT are kept in sync!
IDM_DEBUG_WINDOW_LIST_START, // Bookend for doing array lookups
IDM_LOG_WINDOW = IDM_DEBUG_WINDOW_LIST_START,
IDM_LOG_CONFIG_WINDOW,
IDM_REGISTER_WINDOW,
IDM_WATCH_WINDOW,
@ -173,9 +175,10 @@ enum
IDM_SOUND_WINDOW,
IDM_VIDEO_WINDOW,
IDM_CODE_WINDOW,
IDM_DEBUG_WINDOW_LIST_END, // Bookend for doing array lookups
// List Column Title Toggles
IDM_SHOW_SYSTEM,
IDM_SHOW_SYSTEM = IDM_DEBUG_WINDOW_LIST_END,
IDM_SHOW_BANNER,
IDM_SHOW_MAKER,
IDM_SHOW_FILENAME,
@ -345,6 +348,7 @@ enum
// custom message macro
#define EVT_HOST_COMMAND(id, fn) EVT_COMMAND(id, wxEVT_HOST_COMMAND, fn)
// FIXME: This should be changed to wxThreadEvent
wxDECLARE_EVENT(wxEVT_HOST_COMMAND, wxCommandEvent);
// Sent to wxTheApp

View File

@ -38,9 +38,6 @@
static const u32 CACHE_REVISION = 0x127; // Last changed in PR 3309
#define DVD_BANNER_WIDTH 96
#define DVD_BANNER_HEIGHT 32
static std::string GetLanguageString(DiscIO::Language language,
std::map<DiscIO::Language, std::string> strings)
{
@ -165,13 +162,12 @@ GameListItem::GameListItem(const std::string& _rFileName,
// Volume banner. Typical for everything that isn't a DOL or ELF.
if (!m_pImage.empty())
{
wxImage image(m_ImageWidth, m_ImageHeight, &m_pImage[0], true);
m_Bitmap = ScaleBanner(&image);
// Need to make explicit copy as wxImage uses reference counting for copies combined with only
// taking a pointer, not the content, when given a buffer to its constructor.
m_image.Create(m_ImageWidth, m_ImageHeight, false);
std::memcpy(m_image.GetData(), m_pImage.data(), m_pImage.size());
return;
}
// Fallback in case no banner is available.
ReadPNGBanner(File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP + "nobanner.png");
}
GameListItem::~GameListItem()
@ -277,25 +273,11 @@ bool GameListItem::ReadPNGBanner(const std::string& path)
return false;
wxImage image(StrToWxStr(path), wxBITMAP_TYPE_PNG);
m_Bitmap = ScaleBanner(&image);
return true;
}
if (!image.IsOk())
return false;
wxBitmap GameListItem::ScaleBanner(wxImage* image)
{
const double gui_scale = wxTheApp->GetTopWindow()->GetContentScaleFactor();
const double target_width = DVD_BANNER_WIDTH * gui_scale;
const double target_height = DVD_BANNER_HEIGHT * gui_scale;
const double banner_scale =
std::min(target_width / image->GetWidth(), target_height / image->GetHeight());
image->Rescale(image->GetWidth() * banner_scale, image->GetHeight() * banner_scale,
wxIMAGE_QUALITY_HIGH);
image->Resize(wxSize(target_width, target_height), wxPoint(), 0xFF, 0xFF, 0xFF);
#ifdef __APPLE__
return wxBitmap(*image, -1, gui_scale);
#else
return wxBitmap(*image, -1);
#endif
m_image = image;
return true;
}
std::string GameListItem::GetDescription(DiscIO::Language language) const

View File

@ -59,7 +59,9 @@ public:
// 0 is the first disc, 1 is the second disc
u8 GetDiscNumber() const { return m_disc_number; }
#if defined(HAVE_WX) && HAVE_WX
const wxBitmap& GetBitmap() const { return m_Bitmap; }
// NOTE: Banner image is at the original resolution, use WxUtils::ScaleImageToBitmap
// to display it
const wxImage& GetBannerImage() const { return m_image; }
#endif
void DoState(PointerWrap& p);
@ -86,7 +88,7 @@ private:
u16 m_Revision;
#if defined(HAVE_WX) && HAVE_WX
wxBitmap m_Bitmap;
wxImage m_image;
#endif
bool m_Valid;
std::vector<u8> m_pImage;
@ -107,6 +109,4 @@ private:
void ReadVolumeBanner(const std::vector<u32>& buffer, int width, int height);
// Outputs to m_Bitmap
bool ReadPNGBanner(const std::string& path);
static wxBitmap ScaleBanner(wxImage* image);
};

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <array>
#include <cinttypes>
#include <cstddef>
#include <cstdio>
@ -33,7 +34,6 @@
#include <wx/panel.h>
#include <wx/progdlg.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/spinctrl.h>
#include <wx/statbmp.h>
#include <wx/stattext.h>
@ -63,6 +63,7 @@
#include "DiscIO/VolumeCreator.h"
#include "DolphinWX/Cheats/ActionReplayCodesPanel.h"
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/ISOFile.h"
@ -110,6 +111,9 @@ private:
void CreateGUI()
{
int space10 = FromDIP(10);
int space15 = FromDIP(15);
wxStaticBitmap* icon =
new wxStaticBitmap(this, wxID_ANY, wxArtProvider::GetMessageBoxIcon(wxICON_WARNING));
m_message = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
@ -119,10 +123,10 @@ private:
m_btn_configure->Bind(wxEVT_BUTTON, &CheatWarningMessage::OnConfigureClicked, this);
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 15);
sizer->Add(m_message, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 15);
sizer->Add(m_btn_configure, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 10);
sizer->AddSpacer(10);
sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space15);
sizer->Add(m_message, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, space15);
sizer->Add(m_btn_configure, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space10);
sizer->AddSpacer(space10);
SetSizer(sizer);
}
@ -286,8 +290,17 @@ CISOProperties::CISOProperties(const GameListItem& game_list_item, wxWindow* par
bool wii = m_open_iso->GetVolumeType() != DiscIO::Platform::GAMECUBE_DISC;
ChangeBannerDetails(SConfig::GetInstance().GetCurrentLanguage(wii));
m_Banner->SetBitmap(OpenGameListItem.GetBitmap());
m_Banner->Bind(wxEVT_RIGHT_DOWN, &CISOProperties::RightClickOnBanner, this);
if (OpenGameListItem.GetBannerImage().IsOk())
{
m_Banner->SetBitmap(WxUtils::ScaleImageToBitmap(OpenGameListItem.GetBannerImage(), this,
m_Banner->GetMinSize()));
m_Banner->Bind(wxEVT_RIGHT_DOWN, &CISOProperties::RightClickOnBanner, this);
}
else
{
m_Banner->SetBitmap(
WxUtils::LoadScaledResourceBitmap("nobanner", this, m_Banner->GetMinSize()));
}
// Filesystem browser/dumper
// TODO : Should we add a way to browse the wad file ?
@ -410,6 +423,9 @@ long CISOProperties::GetElementStyle(const char* section, const char* key)
void CISOProperties::CreateGUIControls()
{
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
wxButton* const EditConfig = new wxButton(this, ID_EDITCONFIG, _("Edit Config"));
EditConfig->SetToolTip(_("This will let you manually edit the INI config file."));
@ -473,8 +489,8 @@ void CISOProperties::CreateGUIControls()
arrayStringFor_GPUDeterminism.Add(_("fake-completion"));
GPUDeterminism = new wxChoice(m_GameConfig, ID_GPUDETERMINISM, wxDefaultPosition, wxDefaultSize,
arrayStringFor_GPUDeterminism);
sGPUDeterminism->Add(GPUDeterminismText);
sGPUDeterminism->Add(GPUDeterminism);
sGPUDeterminism->Add(GPUDeterminismText, 0, wxALIGN_CENTER_VERTICAL);
sGPUDeterminism->Add(GPUDeterminism, 0, wxALIGN_CENTER_VERTICAL);
// Wii Console
EnableWideScreen =
@ -485,7 +501,7 @@ void CISOProperties::CreateGUIControls()
wxBoxSizer* const sDepthPercentage = new wxBoxSizer(wxHORIZONTAL);
wxStaticText* const DepthPercentageText =
new wxStaticText(m_GameConfig, wxID_ANY, _("Depth Percentage: "));
DepthPercentage = new wxSlider(m_GameConfig, ID_DEPTHPERCENTAGE, 100, 0, 200);
DepthPercentage = new DolphinSlider(m_GameConfig, ID_DEPTHPERCENTAGE, 100, 0, 200);
DepthPercentage->SetToolTip(
_("This value is multiplied with the depth set in the graphics configuration."));
sDepthPercentage->Add(DepthPercentageText);
@ -518,19 +534,23 @@ void CISOProperties::CreateGUIControls()
EmuState = new wxChoice(m_GameConfig, ID_EMUSTATE, wxDefaultPosition, wxDefaultSize,
arrayStringFor_EmuState);
EmuIssues = new wxTextCtrl(m_GameConfig, ID_EMU_ISSUES, wxEmptyString);
sEmuState->Add(EmuStateText, 0, wxALIGN_CENTER_VERTICAL);
sEmuState->Add(EmuState, 0, wxALIGN_CENTER_VERTICAL);
sEmuState->Add(EmuIssues, 1, wxEXPAND);
wxBoxSizer* const sConfigPage = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer* const sbCoreOverrides =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Core"));
sbCoreOverrides->Add(CPUThread, 0, wxLEFT, 5);
sbCoreOverrides->Add(SkipIdle, 0, wxLEFT, 5);
sbCoreOverrides->Add(MMU, 0, wxLEFT, 5);
sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT, 5);
sbCoreOverrides->Add(FPRF, 0, wxLEFT, 5);
sbCoreOverrides->Add(SyncGPU, 0, wxLEFT, 5);
sbCoreOverrides->Add(FastDiscSpeed, 0, wxLEFT, 5);
sbCoreOverrides->Add(DSPHLE, 0, wxLEFT, 5);
sbCoreOverrides->Add(sGPUDeterminism, 0, wxEXPAND | wxALL, 5);
sbCoreOverrides->Add(CPUThread, 0, wxLEFT | wxRIGHT, space5);
sbCoreOverrides->Add(SkipIdle, 0, wxLEFT | wxRIGHT, space5);
sbCoreOverrides->Add(MMU, 0, wxLEFT | wxRIGHT, space5);
sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT | wxRIGHT, space5);
sbCoreOverrides->Add(FPRF, 0, wxLEFT | wxRIGHT, space5);
sbCoreOverrides->Add(SyncGPU, 0, wxLEFT | wxRIGHT, space5);
sbCoreOverrides->Add(FastDiscSpeed, 0, wxLEFT | wxRIGHT, space5);
sbCoreOverrides->Add(DSPHLE, 0, wxLEFT | wxRIGHT, space5);
sbCoreOverrides->AddSpacer(space5);
sbCoreOverrides->Add(sGPUDeterminism, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbCoreOverrides->AddSpacer(space5);
wxStaticBoxSizer* const sbWiiOverrides =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Wii Console"));
@ -539,7 +559,7 @@ void CISOProperties::CreateGUIControls()
sbWiiOverrides->ShowItems(false);
EnableWideScreen->Hide();
}
sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, 5);
sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, space5);
wxStaticBoxSizer* const sbStereoOverrides =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Stereoscopy"));
@ -549,15 +569,19 @@ void CISOProperties::CreateGUIControls()
wxStaticBoxSizer* const sbGameConfig =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Game-Specific Settings"));
sbGameConfig->Add(OverrideText, 0, wxEXPAND | wxALL, 5);
sbGameConfig->AddSpacer(space5);
sbGameConfig->Add(OverrideText, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbGameConfig->AddSpacer(space5);
sbGameConfig->Add(sbCoreOverrides, 0, wxEXPAND);
sbGameConfig->Add(sbWiiOverrides, 0, wxEXPAND);
sbGameConfig->Add(sbStereoOverrides, 0, wxEXPAND);
sConfigPage->Add(sbGameConfig, 0, wxEXPAND | wxALL, 5);
sEmuState->Add(EmuStateText, 0, wxALIGN_CENTER_VERTICAL);
sEmuState->Add(EmuState, 0, wxEXPAND);
sEmuState->Add(EmuIssues, 1, wxEXPAND);
sConfigPage->Add(sEmuState, 0, wxEXPAND | wxALL, 5);
wxBoxSizer* const sConfigPage = new wxBoxSizer(wxVERTICAL);
sConfigPage->AddSpacer(space5);
sConfigPage->Add(sbGameConfig, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sConfigPage->AddSpacer(space5);
sConfigPage->Add(sEmuState, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sConfigPage->AddSpacer(space5);
m_GameConfig->SetSizer(sConfigPage);
// Patches
@ -572,13 +596,15 @@ void CISOProperties::CreateGUIControls()
RemovePatch->Disable();
wxBoxSizer* sPatchPage = new wxBoxSizer(wxVERTICAL);
sPatches->Add(Patches, 1, wxEXPAND | wxALL, 0);
sPatchButtons->Add(EditPatch, 0, wxEXPAND | wxALL, 0);
sPatches->Add(Patches, 1, wxEXPAND);
sPatchButtons->Add(EditPatch, 0, wxEXPAND);
sPatchButtons->AddStretchSpacer();
sPatchButtons->Add(AddPatch, 0, wxEXPAND | wxALL, 0);
sPatchButtons->Add(RemovePatch, 0, wxEXPAND | wxALL, 0);
sPatches->Add(sPatchButtons, 0, wxEXPAND | wxALL, 0);
sPatchPage->Add(sPatches, 1, wxEXPAND | wxALL, 5);
sPatchButtons->Add(AddPatch, 0, wxEXPAND);
sPatchButtons->Add(RemovePatch, 0, wxEXPAND);
sPatches->Add(sPatchButtons, 0, wxEXPAND);
sPatchPage->AddSpacer(space5);
sPatchPage->Add(sPatches, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sPatchPage->AddSpacer(space5);
m_PatchPage->SetSizer(sPatchPage);
// Action Replay Cheats
@ -589,8 +615,8 @@ void CISOProperties::CreateGUIControls()
m_ar_code_panel->Bind(DOLPHIN_EVT_ARCODE_TOGGLED, &CISOProperties::OnCheatCodeToggled, this);
wxBoxSizer* const sCheatPage = new wxBoxSizer(wxVERTICAL);
sCheatPage->Add(m_cheats_disabled_ar, 0, wxEXPAND | wxTOP, 5);
sCheatPage->Add(m_ar_code_panel, 1, wxEXPAND | wxALL, 5);
sCheatPage->Add(m_cheats_disabled_ar, 0, wxEXPAND | wxTOP, space5);
sCheatPage->Add(m_ar_code_panel, 1, wxEXPAND | wxALL, space5);
m_CheatPage->SetSizer(sCheatPage);
// Gecko Cheats
@ -600,7 +626,7 @@ void CISOProperties::CreateGUIControls()
m_geckocode_panel->Bind(DOLPHIN_EVT_GECKOCODE_TOGGLED, &CISOProperties::OnCheatCodeToggled, this);
wxBoxSizer* gecko_layout = new wxBoxSizer(wxVERTICAL);
gecko_layout->Add(m_cheats_disabled_gecko, 0, wxEXPAND | wxTOP, 5);
gecko_layout->Add(m_cheats_disabled_gecko, 0, wxEXPAND | wxTOP, space5);
gecko_layout->Add(m_geckocode_panel, 1, wxEXPAND);
gecko_cheat_page->SetSizer(gecko_layout);
@ -698,67 +724,63 @@ void CISOProperties::CreateGUIControls()
m_Comment = new wxTextCtrl(m_Information, ID_COMMENT, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);
wxStaticText* const m_BannerText = new wxStaticText(m_Information, wxID_ANY, _("Banner:"));
m_Banner =
new wxStaticBitmap(m_Information, ID_BANNER, wxNullBitmap, wxDefaultPosition, wxSize(96, 32));
m_Banner = new wxStaticBitmap(m_Information, ID_BANNER, wxNullBitmap, wxDefaultPosition,
FromDIP(wxSize(96, 32)));
// ISO Details
wxGridBagSizer* const sISODetails = new wxGridBagSizer(0, 0);
sISODetails->Add(m_InternalNameText, wxGBPosition(0, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sISODetails->Add(m_InternalName, wxGBPosition(0, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
sISODetails->Add(m_GameIDText, wxGBPosition(1, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sISODetails->Add(m_GameID, wxGBPosition(1, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
sISODetails->Add(m_CountryText, wxGBPosition(2, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sISODetails->Add(m_Country, wxGBPosition(2, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
sISODetails->Add(m_MakerIDText, wxGBPosition(3, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sISODetails->Add(m_MakerID, wxGBPosition(3, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
sISODetails->Add(m_RevisionText, wxGBPosition(4, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sISODetails->Add(m_Revision, wxGBPosition(4, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
sISODetails->Add(m_DateText, wxGBPosition(5, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxALL,
5);
sISODetails->Add(m_Date, wxGBPosition(5, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
sISODetails->Add(m_FSTText, wxGBPosition(6, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxALL,
5);
sISODetails->Add(m_FST, wxGBPosition(6, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
sISODetails->Add(m_MD5SumText, wxGBPosition(7, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sISODetails->Add(m_MD5Sum, wxGBPosition(7, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
wxSizer* sMD5SumButtonSizer = CreateButtonSizer(wxNO_DEFAULT);
sMD5SumButtonSizer->Add(m_MD5SumCompute);
sISODetails->Add(sMD5SumButtonSizer, wxGBPosition(7, 2), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
wxGridBagSizer* const sISODetails = new wxGridBagSizer(space10, space10);
sISODetails->Add(m_InternalNameText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sISODetails->Add(m_InternalName, wxGBPosition(0, 1), wxGBSpan(1, 2), wxEXPAND);
sISODetails->Add(m_GameIDText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sISODetails->Add(m_GameID, wxGBPosition(1, 1), wxGBSpan(1, 2), wxEXPAND);
sISODetails->Add(m_CountryText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sISODetails->Add(m_Country, wxGBPosition(2, 1), wxGBSpan(1, 2), wxEXPAND);
sISODetails->Add(m_MakerIDText, wxGBPosition(3, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sISODetails->Add(m_MakerID, wxGBPosition(3, 1), wxGBSpan(1, 2), wxEXPAND);
sISODetails->Add(m_RevisionText, wxGBPosition(4, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sISODetails->Add(m_Revision, wxGBPosition(4, 1), wxGBSpan(1, 2), wxEXPAND);
sISODetails->Add(m_DateText, wxGBPosition(5, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sISODetails->Add(m_Date, wxGBPosition(5, 1), wxGBSpan(1, 2), wxEXPAND);
sISODetails->Add(m_FSTText, wxGBPosition(6, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sISODetails->Add(m_FST, wxGBPosition(6, 1), wxGBSpan(1, 2), wxEXPAND);
sISODetails->Add(m_MD5SumText, wxGBPosition(7, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sISODetails->Add(m_MD5Sum, wxGBPosition(7, 1), wxGBSpan(1, 1), wxEXPAND);
sISODetails->Add(m_MD5SumCompute, wxGBPosition(7, 2), wxGBSpan(1, 1), wxEXPAND);
sISODetails->AddGrowableCol(1);
wxStaticBoxSizer* const sbISODetails =
new wxStaticBoxSizer(wxVERTICAL, m_Information, _("ISO Details"));
sbISODetails->Add(sISODetails, 0, wxEXPAND, 5);
sbISODetails->AddSpacer(space5);
sbISODetails->Add(sISODetails, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbISODetails->AddSpacer(space5);
// Banner Details
wxGridBagSizer* const sBannerDetails = new wxGridBagSizer(0, 0);
sBannerDetails->Add(m_LangText, wxGBPosition(0, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sBannerDetails->Add(m_Lang, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
sBannerDetails->Add(m_NameText, wxGBPosition(1, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sBannerDetails->Add(m_Name, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
sBannerDetails->Add(m_MakerText, wxGBPosition(2, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sBannerDetails->Add(m_Maker, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
sBannerDetails->Add(m_CommentText, wxGBPosition(3, 0), wxGBSpan(1, 1), wxALL, 5);
sBannerDetails->Add(m_Comment, wxGBPosition(3, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
sBannerDetails->Add(m_BannerText, wxGBPosition(4, 0), wxGBSpan(1, 1), wxALL, 5);
sBannerDetails->Add(m_Banner, wxGBPosition(4, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
wxGridBagSizer* const sBannerDetails = new wxGridBagSizer(space10, space10);
sBannerDetails->Add(m_LangText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
// Comboboxes cannot be safely stretched vertically on Windows.
sBannerDetails->Add(WxUtils::GiveMinSize(m_Lang, wxDefaultSize), wxGBPosition(0, 1),
wxGBSpan(1, 1), wxEXPAND);
sBannerDetails->Add(m_NameText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sBannerDetails->Add(m_Name, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND);
sBannerDetails->Add(m_MakerText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sBannerDetails->Add(m_Maker, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND);
sBannerDetails->Add(m_CommentText, wxGBPosition(3, 0), wxGBSpan(1, 1));
sBannerDetails->Add(m_Comment, wxGBPosition(3, 1), wxGBSpan(1, 1), wxEXPAND);
sBannerDetails->Add(m_BannerText, wxGBPosition(4, 0), wxGBSpan(1, 1));
sBannerDetails->Add(m_Banner, wxGBPosition(4, 1), wxGBSpan(1, 1), wxEXPAND);
sBannerDetails->AddGrowableCol(1);
wxStaticBoxSizer* const sbBannerDetails =
new wxStaticBoxSizer(wxVERTICAL, m_Information, _("Banner Details"));
sbBannerDetails->Add(sBannerDetails, 0, wxEXPAND, 5);
sbBannerDetails->AddSpacer(space5);
sbBannerDetails->Add(sBannerDetails, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbBannerDetails->AddSpacer(space5);
wxBoxSizer* const sInfoPage = new wxBoxSizer(wxVERTICAL);
sInfoPage->Add(sbISODetails, 0, wxEXPAND | wxALL, 5);
sInfoPage->Add(sbBannerDetails, 0, wxEXPAND | wxALL, 5);
sInfoPage->AddSpacer(space5);
sInfoPage->Add(sbISODetails, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sInfoPage->AddSpacer(space5);
sInfoPage->Add(sbBannerDetails, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sInfoPage->AddSpacer(space5);
m_Information->SetSizer(sInfoPage);
if (m_open_iso->GetVolumeType() != DiscIO::Platform::WII_WAD)
@ -767,10 +789,14 @@ void CISOProperties::CreateGUIControls()
m_Notebook->AddPage(filesystem_panel, _("Filesystem"));
// Filesystem icons
wxImageList* const m_iconList = new wxImageList(16, 16);
m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_disc")); // 0
m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_folder")); // 1
m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_file")); // 2
wxSize icon_size = FromDIP(wxSize(16, 16));
wxImageList* const m_iconList = new wxImageList(icon_size.GetWidth(), icon_size.GetHeight());
static const std::array<const char* const, 3> s_icon_names{
{"isoproperties_disc", "isoproperties_folder", "isoproperties_file"}};
for (const auto& name : s_icon_names)
m_iconList->Add(
WxUtils::LoadScaledResourceBitmap(name, this, icon_size, wxDefaultSize,
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER));
// Filesystem tree
m_Treectrl = new wxTreeCtrl(filesystem_panel, ID_TREECTRL);
@ -778,14 +804,16 @@ void CISOProperties::CreateGUIControls()
RootId = m_Treectrl->AddRoot(_("Disc"), 0, 0, nullptr);
wxBoxSizer* sTreePage = new wxBoxSizer(wxVERTICAL);
sTreePage->Add(m_Treectrl, 1, wxEXPAND | wxALL, 5);
sTreePage->AddSpacer(space5);
sTreePage->Add(m_Treectrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sTreePage->AddSpacer(space5);
filesystem_panel->SetSizer(sTreePage);
}
wxSizer* sButtons = CreateButtonSizer(wxNO_DEFAULT);
wxStdDialogButtonSizer* sButtons = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
sButtons->Prepend(EditConfigDefault);
sButtons->Prepend(EditConfig);
sButtons->Add(new wxButton(this, wxID_OK, _("Close")));
sButtons->GetAffirmativeButton()->SetLabel(_("Close"));
// If there is no default gameini, disable the button.
bool game_ini_exists = false;
@ -803,10 +831,15 @@ void CISOProperties::CreateGUIControls()
// Add notebook and buttons to the dialog
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5);
sMain->Add(sButtons, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
sMain->SetMinSize(wxSize(500, -1));
sMain->AddSpacer(space5);
sMain->Add(m_Notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->AddSpacer(space5);
sMain->Add(sButtons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->AddSpacer(space5);
sMain->SetMinSize(FromDIP(wxSize(500, -1)));
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(sMain);
Center();
SetFocus();
@ -842,7 +875,7 @@ void CISOProperties::OnBannerImageSave(wxCommandEvent& WXUNUSED(event))
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (dialog.ShowModal() == wxID_OK)
{
m_Banner->GetBitmap().ConvertToImage().SaveFile(dialog.GetPath());
OpenGameListItem.GetBannerImage().SaveFile(dialog.GetPath());
}
Raise();
}

View File

@ -19,11 +19,11 @@
#include "DolphinWX/ISOFile.h"
#include "DolphinWX/PatchAddEdit.h"
class DolphinSlider;
class wxButton;
class wxCheckBox;
class wxCheckListBox;
class wxChoice;
class wxSlider;
class wxSpinCtrl;
class wxStaticBitmap;
class wxTextCtrl;
@ -90,7 +90,7 @@ private:
wxCheckBox* EnableWideScreen;
// Stereoscopy
wxSlider* DepthPercentage;
DolphinSlider* DepthPercentage;
wxSpinCtrl* Convergence;
wxCheckBox* MonoDepth;

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cctype>
#include <cstddef>
#include <memory>
@ -16,6 +17,7 @@
#include <wx/choice.h>
#include <wx/combobox.h>
#include <wx/control.h>
#include <wx/dcclient.h>
#include <wx/dcmemory.h>
#include <wx/dialog.h>
#include <wx/event.h>
@ -25,9 +27,9 @@
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/spinctrl.h>
#include <wx/statbmp.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/timer.h>
@ -41,6 +43,7 @@
#include "Core/HW/GCPad.h"
#include "Core/HW/Wiimote.h"
#include "Core/HotkeyManager.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/InputConfigDiag.h"
#include "DolphinWX/WxUtils.h"
#include "InputCommon/ControllerEmu.h"
@ -66,8 +69,10 @@ void GamepadPage::ConfigExtension(wxCommandEvent& event)
ControlGroupsSizer* const szr = new ControlGroupsSizer(
ex->attachments[ex->switch_extension].get(), &dlg, this, &control_groups);
main_szr->Add(szr, 0, wxLEFT, 5);
main_szr->Add(dlg.CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
const int space5 = FromDIP(5);
main_szr->Add(szr, 0, wxLEFT, space5);
main_szr->Add(dlg.CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
dlg.SetSizerAndFit(main_szr);
dlg.Center();
@ -122,6 +127,19 @@ void PadSettingCheckBox::UpdateValue()
setting->SetValue(((wxCheckBox*)wxcontrol)->GetValue());
}
PadSettingSpin::PadSettingSpin(wxWindow* const parent,
ControllerEmu::ControlGroup::NumericSetting* const settings)
: PadSetting(new wxSpinCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxSP_ARROW_KEYS, settings->m_low, settings->m_high,
(int)(settings->m_value * 100))),
setting(settings)
{
// Compute how wide the control needs to be to fit the maximum value in it.
// This accounts for borders, margins and the spinner buttons.
wxcontrol->SetMinSize(WxUtils::GetTextWidgetMinSize(static_cast<wxSpinCtrl*>(wxcontrol)));
wxcontrol->SetLabelText(setting->m_name);
}
void PadSettingSpin::UpdateGUI()
{
((wxSpinCtrl*)wxcontrol)->SetValue((int)(setting->GetValue() * 100));
@ -139,13 +157,12 @@ ControlDialog::ControlDialog(GamepadPage* const parent, InputConfig& config,
control_reference(ref), m_config(config), m_parent(parent)
{
m_devq = m_parent->controller->default_device;
const int space5 = FromDIP(5);
// GetStrings() sounds slow :/
// device_cbox = new wxComboBox(this, wxID_ANY, StrToWxStr(ref->device_qualifier.ToString()),
// wxDefaultPosition, wxSize(256,-1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER);
device_cbox =
new wxComboBox(this, wxID_ANY, StrToWxStr(m_devq.ToString()), wxDefaultPosition,
wxSize(256, -1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER);
device_cbox = new wxComboBox(this, wxID_ANY, StrToWxStr(m_devq.ToString()), wxDefaultPosition,
wxDLG_UNIT(this, wxSize(180, -1)), parent->device_cbox->GetStrings(),
wxTE_PROCESS_ENTER);
device_cbox->Bind(wxEVT_COMBOBOX, &ControlDialog::SetDevice, this);
device_cbox->Bind(wxEVT_TEXT_ENTER, &ControlDialog::SetDevice, this);
@ -153,12 +170,19 @@ ControlDialog::ControlDialog(GamepadPage* const parent, InputConfig& config,
wxStaticBoxSizer* const control_chooser = CreateControlChooser(parent);
wxStaticBoxSizer* const d_szr = new wxStaticBoxSizer(wxVERTICAL, this, _("Device"));
d_szr->Add(device_cbox, 0, wxEXPAND | wxALL, 5);
d_szr->AddSpacer(space5);
d_szr->Add(device_cbox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
d_szr->AddSpacer(space5);
wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
szr->Add(d_szr, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5);
szr->Add(control_chooser, 1, wxEXPAND | wxALL, 5);
szr->AddSpacer(space5);
szr->Add(d_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr->AddSpacer(space5);
szr->Add(control_chooser, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr->AddSpacer(space5);
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(szr); // needed
UpdateGUI();
@ -169,15 +193,26 @@ ControlButton::ControlButton(wxWindow* const parent,
ControllerInterface::ControlReference* const _ref,
const std::string& name, const unsigned int width,
const std::string& label)
: wxButton(parent, wxID_ANY, "", wxDefaultPosition, wxSize(width, 20)), control_reference(_ref),
m_name(name)
: wxButton(parent, wxID_ANY), control_reference(_ref), m_name(name),
m_configured_width(FromDIP(width))
{
if (label.empty())
SetLabel(StrToWxStr(_ref->expression));
SetLabelText(StrToWxStr(_ref->expression));
else
SetLabel(StrToWxStr(label));
}
wxSize ControlButton::DoGetBestSize() const
{
if (m_configured_width == wxDefaultCoord)
return wxButton::DoGetBestSize();
static constexpr int PADDING_HEIGHT = 4;
wxClientDC dc(const_cast<ControlButton*>(this));
wxFontMetrics metrics = dc.GetFontMetrics();
return {m_configured_width, metrics.height + FromDIP(PADDING_HEIGHT * 2)};
}
void InputConfigDialog::UpdateProfileComboBox()
{
std::string pname(File::GetUserPath(D_CONFIG_IDX));
@ -222,7 +257,7 @@ void InputConfigDialog::OnCloseButton(wxCommandEvent& event)
int ControlDialog::GetRangeSliderValue() const
{
return range_slider->GetValue();
return m_range_slider->GetValue();
}
void ControlDialog::UpdateListContents()
@ -288,9 +323,7 @@ void GamepadPage::UpdateGUI()
{
for (ControlButton* button : cgBox->control_buttons)
{
wxString expr = StrToWxStr(button->control_reference->expression);
expr.Replace("&", "&&");
button->SetLabel(expr);
button->SetLabelText(StrToWxStr(button->control_reference->expression));
}
for (PadSetting* padSetting : cgBox->options)
@ -503,6 +536,23 @@ void GamepadPage::EnableControlButton(const std::string& group_name, const std::
(*it)->Enable(enabled);
}
void ControlDialog::OnRangeSlide(wxScrollEvent& event)
{
m_range_spinner->SetValue(event.GetPosition());
control_reference->range = static_cast<ControlState>(event.GetPosition()) / SLIDER_TICK_COUNT;
}
void ControlDialog::OnRangeSpin(wxSpinEvent& event)
{
m_range_slider->SetValue(event.GetValue());
control_reference->range = static_cast<ControlState>(event.GetValue()) / SLIDER_TICK_COUNT;
}
void ControlDialog::OnRangeThumbtrack(wxScrollEvent& event)
{
m_range_spinner->SetValue(event.GetPosition());
}
void GamepadPage::AdjustSetting(wxCommandEvent& event)
{
const auto* const control = static_cast<wxControl*>(event.GetEventObject());
@ -528,12 +578,6 @@ void GamepadPage::AdjustBooleanSetting(wxCommandEvent& event)
}
}
void GamepadPage::AdjustControlOption(wxCommandEvent&)
{
m_control_dialog->control_reference->range =
(ControlState)(m_control_dialog->GetRangeSliderValue()) / SLIDER_TICK_COUNT;
}
void GamepadPage::ConfigControl(wxEvent& event)
{
m_control_dialog = new ControlDialog(this, m_config,
@ -647,9 +691,10 @@ wxStaticBoxSizer* ControlDialog::CreateControlChooser(GamepadPage* const parent)
{
wxStaticBoxSizer* const main_szr = new wxStaticBoxSizer(
wxVERTICAL, this, control_reference->is_input ? _("Input") : _("Output"));
const int space5 = FromDIP(5);
textctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, 48),
wxTE_MULTILINE | wxTE_RICH2);
textctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDLG_UNIT(this, wxSize(-1, 32)), wxTE_MULTILINE | wxTE_RICH2);
wxFont font = textctrl->GetFont();
font.SetFamily(wxFONTFAMILY_MODERN);
textctrl->SetFont(font);
@ -665,12 +710,12 @@ wxStaticBoxSizer* ControlDialog::CreateControlChooser(GamepadPage* const parent)
wxButton* const or_button = new wxButton(this, wxID_ANY, _("| OR"));
or_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this);
control_lbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 64));
control_lbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(-1, 48)));
wxBoxSizer* const button_sizer = new wxBoxSizer(wxVERTICAL);
button_sizer->Add(detect_button, 1, 0, 5);
button_sizer->Add(select_button, 1, 0, 5);
button_sizer->Add(or_button, 1, 0, 5);
button_sizer->Add(detect_button, 1);
button_sizer->Add(select_button, 1);
button_sizer->Add(or_button, 1);
if (control_reference->is_input)
{
@ -683,43 +728,57 @@ wxStaticBoxSizer* ControlDialog::CreateControlChooser(GamepadPage* const parent)
not_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this);
add_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this);
button_sizer->Add(and_button, 1, 0, 5);
button_sizer->Add(not_button, 1, 0, 5);
button_sizer->Add(add_button, 1, 0, 5);
button_sizer->Add(and_button, 1);
button_sizer->Add(not_button, 1);
button_sizer->Add(add_button, 1);
}
range_slider =
new wxSlider(this, wxID_ANY, SLIDER_TICK_COUNT, -SLIDER_TICK_COUNT * 5, SLIDER_TICK_COUNT * 5,
wxDefaultPosition, wxDefaultSize, wxSL_TOP | wxSL_LABELS /*| wxSL_AUTOTICKS*/);
range_slider->SetValue((int)(control_reference->range * SLIDER_TICK_COUNT));
m_range_slider = new DolphinSlider(
this, wxID_ANY, static_cast<int>(control_reference->range * SLIDER_TICK_COUNT),
-SLIDER_TICK_COUNT * 5, SLIDER_TICK_COUNT * 5, wxDefaultPosition, wxDefaultSize, wxSL_TOP);
m_range_spinner = new wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDLG_UNIT(this, wxSize(32, -1)),
wxSP_ARROW_KEYS | wxALIGN_RIGHT, m_range_slider->GetMin(),
m_range_slider->GetMax(), m_range_slider->GetValue());
detect_button->Bind(wxEVT_BUTTON, &ControlDialog::DetectControl, this);
clear_button->Bind(wxEVT_BUTTON, &ControlDialog::ClearControl, this);
range_slider->Bind(wxEVT_SCROLL_CHANGED, &GamepadPage::AdjustControlOption, parent);
wxStaticText* const range_label = new wxStaticText(this, wxID_ANY, _("Range"));
m_range_slider->Bind(wxEVT_SCROLL_CHANGED, &ControlDialog::OnRangeSlide, this);
m_range_slider->Bind(wxEVT_SCROLL_THUMBTRACK, &ControlDialog::OnRangeThumbtrack, this);
m_range_spinner->Bind(wxEVT_SPINCTRL, &ControlDialog::OnRangeSpin, this);
m_bound_label = new wxStaticText(this, wxID_ANY, "");
m_error_label = new wxStaticText(this, wxID_ANY, "");
wxBoxSizer* const range_sizer = new wxBoxSizer(wxHORIZONTAL);
range_sizer->Add(range_label, 0, wxCENTER | wxLEFT, 5);
range_sizer->Add(range_slider, 1, wxEXPAND | wxLEFT, 5);
range_sizer->Add(new wxStaticText(this, wxID_ANY, _("Range")), 0, wxALIGN_CENTER_VERTICAL);
range_sizer->Add(
new wxStaticText(this, wxID_ANY, wxString::Format("%d", m_range_slider->GetMin())), 0,
wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
range_sizer->Add(m_range_slider, 1, wxEXPAND);
range_sizer->Add(
new wxStaticText(this, wxID_ANY, wxString::Format("%d", m_range_slider->GetMax())), 0,
wxALIGN_CENTER_VERTICAL);
range_sizer->Add(m_range_spinner, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
wxBoxSizer* const ctrls_sizer = new wxBoxSizer(wxHORIZONTAL);
ctrls_sizer->Add(control_lbox, 1, wxEXPAND, 0);
ctrls_sizer->Add(button_sizer, 0, wxEXPAND, 0);
ctrls_sizer->Add(control_lbox, 1, wxEXPAND);
ctrls_sizer->Add(button_sizer, 0, wxEXPAND);
wxSizer* const bottom_btns_sizer = CreateButtonSizer(wxOK | wxAPPLY);
bottom_btns_sizer->Prepend(clear_button, 0, wxLEFT, 5);
bottom_btns_sizer->Prepend(clear_button, 0, wxLEFT, space5);
main_szr->Add(range_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
main_szr->Add(ctrls_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
main_szr->Add(textctrl, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
main_szr->Add(bottom_btns_sizer, 0, wxEXPAND | wxBOTTOM | wxRIGHT, 5);
main_szr->Add(m_bound_label, 0, wxCENTER, 0);
main_szr->Add(m_error_label, 0, wxCENTER, 0);
main_szr->Add(range_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(ctrls_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(textctrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(bottom_btns_sizer, 0, wxEXPAND | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(m_bound_label, 0, wxALIGN_CENTER_HORIZONTAL);
main_szr->Add(m_error_label, 0, wxALIGN_CENTER_HORIZONTAL);
UpdateListContents();
@ -839,22 +898,25 @@ ControlGroupBox::~ControlGroupBox()
ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWindow* const parent,
GamepadPage* const eventsink)
: wxBoxSizer(wxVERTICAL), control_group(group)
: wxBoxSizer(wxVERTICAL), control_group(group), static_bitmap(nullptr), m_scale(1)
{
static_bitmap = nullptr;
const std::vector<std::string> exclude_buttons = {"Mic", "Modifier"};
const std::vector<std::string> exclude_groups = {"IR", "Swing", "Tilt", "Shake",
"UDP Wiimote", "Extension", "Rumble"};
static constexpr std::array<const char* const, 2> exclude_buttons{{"Mic", "Modifier"}};
static constexpr std::array<const char* const, 7> exclude_groups{
{"IR", "Swing", "Tilt", "Shake", "UDP Wiimote", "Extension", "Rumble"}};
wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
for (auto& control : group->controls)
wxFont small_font(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
const int space3 = parent->FromDIP(3);
wxFlexGridSizer* control_grid = new wxFlexGridSizer(2, 0, space3);
control_grid->AddGrowableCol(0);
for (const auto& control : group->controls)
{
wxStaticText* const label =
new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(control->name)));
ControlButton* const control_button =
new ControlButton(parent, control->control_ref.get(), control->name, 80);
control_button->SetFont(m_SmallFont);
control_button->SetFont(small_font);
control_buttons.push_back(control_button);
if (std::find(exclude_groups.begin(), exclude_groups.end(), control_group->name) ==
@ -878,15 +940,10 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
control_button->Bind(wxEVT_MIDDLE_DOWN, &GamepadPage::ClearControl, eventsink);
control_button->Bind(wxEVT_RIGHT_UP, &GamepadPage::ConfigControl, eventsink);
wxBoxSizer* const control_sizer = new wxBoxSizer(wxHORIZONTAL);
control_sizer->AddStretchSpacer(1);
control_sizer->Add(label, 0, wxCENTER | wxRIGHT, 3);
control_sizer->Add(control_button, 0, 0, 0);
Add(control_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 3);
control_grid->Add(label, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
control_grid->Add(control_button, 0, wxALIGN_CENTER_VERTICAL);
}
wxMemoryDC dc;
Add(control_grid, 0, wxEXPAND | wxLEFT | wxRIGHT, space3);
switch (group->type)
{
@ -895,9 +952,15 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
case GROUP_TYPE_CURSOR:
case GROUP_TYPE_FORCE:
{
wxBitmap bitmap(64, 64);
dc.SelectObject(bitmap);
wxSize bitmap_size = parent->FromDIP(wxSize(64, 64));
m_scale = bitmap_size.GetWidth() / 64.0;
wxBitmap bitmap;
bitmap.CreateScaled(bitmap_size.GetWidth(), bitmap_size.GetHeight(), wxBITMAP_SCREEN_DEPTH,
parent->GetContentScaleFactor());
wxMemoryDC dc(bitmap);
dc.Clear();
dc.SelectObject(wxNullBitmap);
static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize,
wxBITMAP_TYPE_BMP);
@ -909,21 +972,23 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
options.push_back(setting);
szr->Add(
new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->m_name))));
szr->Add(setting->wxcontrol, 0, wxLEFT, 0);
szr->Add(setting->wxcontrol);
}
for (auto& groupSetting : group->boolean_settings)
{
auto* checkbox = new PadSettingCheckBox(parent, groupSetting.get());
checkbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustBooleanSetting, eventsink);
options.push_back(checkbox);
Add(checkbox->wxcontrol, 0, wxALL | wxLEFT, 5);
Add(checkbox->wxcontrol, 0, wxALL | wxLEFT, space3);
}
wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL);
h_szr->Add(szr, 1, 0, 5);
h_szr->Add(static_bitmap, 0, wxALL | wxCENTER, 3);
h_szr->Add(szr, 1, wxEXPAND | wxTOP | wxBOTTOM, space3);
h_szr->AddSpacer(space3);
h_szr->Add(static_bitmap, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space3);
Add(h_szr, 0, wxEXPAND | wxLEFT | wxCENTER | wxTOP, 3);
AddSpacer(space3);
Add(h_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space3);
}
break;
case GROUP_TYPE_BUTTONS:
@ -931,10 +996,16 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
// Draw buttons in rows of 8
unsigned int button_cols = group->controls.size() > 8 ? 8 : group->controls.size();
unsigned int button_rows = ceil((float)group->controls.size() / 8.0f);
wxBitmap bitmap(int(12 * button_cols + 1), (11 * button_rows) + 1);
wxSize bitmap_size(12 * button_cols + 1, 11 * button_rows + 1);
wxSize bitmap_scaled_size = parent->FromDIP(bitmap_size);
m_scale = static_cast<double>(bitmap_scaled_size.GetWidth()) / bitmap_size.GetWidth();
dc.SelectObject(bitmap);
wxBitmap bitmap;
bitmap.CreateScaled(bitmap_scaled_size.GetWidth(), bitmap_scaled_size.GetHeight(),
wxBITMAP_SCREEN_DEPTH, parent->GetContentScaleFactor());
wxMemoryDC dc(bitmap);
dc.Clear();
dc.SelectObject(wxNullBitmap);
static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize,
wxBITMAP_TYPE_BMP);
@ -949,11 +1020,13 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
szr->Add(new wxStaticText(parent, wxID_ANY,
wxGetTranslation(StrToWxStr(group->numeric_settings[0]->m_name))),
0, wxCENTER | wxRIGHT, 3);
szr->Add(threshold_cbox->wxcontrol, 0, wxRIGHT, 3);
0, wxALIGN_CENTER_VERTICAL | wxRIGHT, space3);
szr->Add(threshold_cbox->wxcontrol, 0, wxRIGHT, space3);
Add(szr, 0, wxALL | wxCENTER, 3);
Add(static_bitmap, 0, wxALL | wxCENTER, 3);
AddSpacer(space3);
Add(szr, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space3);
AddSpacer(space3);
Add(static_bitmap, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space3);
}
break;
case GROUP_TYPE_MIXED_TRIGGERS:
@ -968,10 +1041,16 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
if (GROUP_TYPE_TRIGGERS != group->type)
height /= 2;
height += 1;
wxBitmap bitmap(width, height + 1);
dc.SelectObject(bitmap);
wxSize bitmap_size = parent->FromDIP(wxSize(width, height));
m_scale = static_cast<double>(bitmap_size.GetWidth()) / width;
wxBitmap bitmap;
bitmap.CreateScaled(bitmap_size.GetWidth(), bitmap_size.GetHeight(), wxBITMAP_SCREEN_DEPTH,
parent->GetContentScaleFactor());
wxMemoryDC dc(bitmap);
dc.Clear();
dc.SelectObject(wxNullBitmap);
static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize,
wxBITMAP_TYPE_BMP);
@ -983,12 +1062,15 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
szr->Add(
new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->m_name))), 0,
wxCENTER | wxRIGHT, 3);
szr->Add(setting->wxcontrol, 0, wxRIGHT, 3);
Add(szr, 0, wxALL | wxCENTER, 3);
wxALIGN_CENTER_VERTICAL);
szr->Add(setting->wxcontrol, 0, wxLEFT, space3);
AddSpacer(space3);
Add(szr, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space3);
}
Add(static_bitmap, 0, wxALL | wxCENTER, 3);
AddSpacer(space3);
Add(static_bitmap, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space3);
}
break;
case GROUP_TYPE_EXTENSION:
@ -1002,8 +1084,10 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
attachments->wxcontrol->Bind(wxEVT_CHOICE, &GamepadPage::AdjustSetting, eventsink);
configure_btn->Bind(wxEVT_BUTTON, &GamepadPage::ConfigExtension, eventsink);
Add(attachments->wxcontrol, 0, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, 3);
Add(configure_btn, 0, wxALL | wxEXPAND, 3);
AddSpacer(space3);
Add(attachments->wxcontrol, 0, wxEXPAND | wxLEFT | wxRIGHT, space3);
AddSpacer(space3);
Add(configure_btn, 0, wxEXPAND | wxLEFT | wxRIGHT, space3);
}
break;
default:
@ -1016,7 +1100,8 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
if (groupSetting->m_name == "Iterative Input")
groupSetting->SetValue(false);
options.push_back(setting_cbox);
Add(setting_cbox->wxcontrol, 0, wxALL | wxLEFT, 5);
AddSpacer(space3);
Add(setting_cbox->wxcontrol, 0, wxLEFT | wxRIGHT, space3);
}
for (auto& groupSetting : group->numeric_settings)
{
@ -1026,17 +1111,15 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
szr->Add(
new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->m_name))), 0,
wxCENTER | wxRIGHT, 3);
szr->Add(setting->wxcontrol, 0, wxRIGHT, 3);
Add(szr, 0, wxALL | wxCENTER, 3);
wxALIGN_CENTER_VERTICAL, space3);
szr->Add(setting->wxcontrol, 0, wxLEFT, space3);
AddSpacer(space3);
Add(szr, 0, wxLEFT | wxRIGHT, space3);
}
break;
}
break;
}
dc.SelectObject(wxNullBitmap);
// AddStretchSpacer(0);
AddSpacer(space3);
}
ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow* const parent,
@ -1044,15 +1127,17 @@ ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow
std::vector<ControlGroupBox*>* groups)
: wxBoxSizer(wxHORIZONTAL)
{
const int space5 = parent->FromDIP(5);
size_t col_size = 0;
wxBoxSizer* stacked_groups = nullptr;
for (auto& group : controller->groups)
{
ControlGroupBox* control_group_box = new ControlGroupBox(group.get(), parent, eventsink);
wxStaticBoxSizer* control_group =
new wxStaticBoxSizer(wxVERTICAL, parent, wxGetTranslation(StrToWxStr(group->ui_name)));
control_group->Add(control_group_box);
ControlGroupBox* control_group_box =
new ControlGroupBox(group.get(), control_group->GetStaticBox(), eventsink);
control_group->Add(control_group_box, 0, wxEXPAND);
const size_t grp_size =
group->controls.size() + group->numeric_settings.size() + group->boolean_settings.size();
@ -1060,7 +1145,10 @@ ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow
if (col_size > 8 || nullptr == stacked_groups)
{
if (stacked_groups)
Add(stacked_groups, 0, /*wxEXPAND|*/ wxBOTTOM | wxRIGHT, 5);
{
Add(stacked_groups, 0, wxBOTTOM, space5);
AddSpacer(space5);
}
stacked_groups = new wxBoxSizer(wxVERTICAL);
stacked_groups->Add(control_group, 0, wxEXPAND);
@ -1077,7 +1165,7 @@ ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow
}
if (stacked_groups)
Add(stacked_groups, 0, /*wxEXPAND|*/ wxBOTTOM | wxRIGHT, 5);
Add(stacked_groups, 0, wxBOTTOM, space5);
}
GamepadPage::GamepadPage(wxWindow* parent, InputConfig& config, const int pad_num,
@ -1086,65 +1174,81 @@ GamepadPage::GamepadPage(wxWindow* parent, InputConfig& config, const int pad_nu
m_config_dialog(config_dialog), m_config(config)
{
wxBoxSizer* control_group_sizer = new ControlGroupsSizer(controller, this, this, &control_groups);
wxStaticBoxSizer* profile_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Profile"));
const int space3 = FromDIP(3);
const int space5 = FromDIP(5);
// device chooser
wxStaticBoxSizer* const device_sbox = new wxStaticBoxSizer(wxVERTICAL, this, _("Device"));
wxStaticBoxSizer* const device_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Device"));
device_cbox = new wxComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(64, -1));
device_cbox = new wxComboBox(device_sbox->GetStaticBox(), wxID_ANY, "");
device_cbox->ToggleWindowStyle(wxTE_PROCESS_ENTER);
wxButton* refresh_button =
new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxButton* refresh_button = new wxButton(device_sbox->GetStaticBox(), wxID_ANY, _("Refresh"),
wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
device_cbox->Bind(wxEVT_COMBOBOX, &GamepadPage::SetDevice, this);
device_cbox->Bind(wxEVT_TEXT_ENTER, &GamepadPage::SetDevice, this);
refresh_button->Bind(wxEVT_BUTTON, &GamepadPage::RefreshDevices, this);
device_sbox->Add(device_cbox, 1, wxLEFT | wxRIGHT, 3);
device_sbox->Add(refresh_button, 0, wxRIGHT | wxBOTTOM, 3);
wxBoxSizer* const device_sbox_in = new wxBoxSizer(wxHORIZONTAL);
device_sbox_in->Add(WxUtils::GiveMinSizeDIP(device_cbox, wxSize(64, -1)), 1,
wxALIGN_CENTER_VERTICAL);
device_sbox_in->Add(refresh_button, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
device_sbox->Add(device_sbox_in, 1, wxEXPAND | wxLEFT | wxRIGHT, space3);
device_sbox->AddSpacer(space3);
wxButton* const default_button =
new wxButton(this, wxID_ANY, _("Default"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxButton* const clearall_button =
new wxButton(this, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
// Clear / Reset buttons
wxStaticBoxSizer* const clear_sbox = new wxStaticBoxSizer(wxVERTICAL, this, _("Reset"));
wxStaticBoxSizer* const clear_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Reset"));
clear_sbox->Add(default_button, 1, wxLEFT, 3);
clear_sbox->Add(clearall_button, 1, wxRIGHT, 3);
wxButton* const default_button = new wxButton(clear_sbox->GetStaticBox(), wxID_ANY, _("Default"),
wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxButton* const clearall_button = new wxButton(clear_sbox->GetStaticBox(), wxID_ANY, _("Clear"),
wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxBoxSizer* clear_sbox_in = new wxBoxSizer(wxHORIZONTAL);
clear_sbox_in->Add(default_button, 1, wxALIGN_CENTER_VERTICAL);
clear_sbox_in->Add(clearall_button, 1, wxALIGN_CENTER_VERTICAL);
clear_sbox->Add(clear_sbox_in, 1, wxEXPAND | wxLEFT | wxRIGHT, space3);
clear_sbox->AddSpacer(space3);
clearall_button->Bind(wxEVT_BUTTON, &GamepadPage::ClearAll, this);
default_button->Bind(wxEVT_BUTTON, &GamepadPage::LoadDefaults, this);
profile_cbox = new wxComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(64, -1));
// Profile selector
wxStaticBoxSizer* profile_sbox = new wxStaticBoxSizer(wxVERTICAL, this, _("Profile"));
profile_cbox = new wxComboBox(profile_sbox->GetStaticBox(), wxID_ANY, "");
wxButton* const pload_btn =
new wxButton(this, wxID_ANY, _("Load"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxButton* const psave_btn =
new wxButton(this, wxID_ANY, _("Save"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxButton* const pdelete_btn =
new wxButton(this, wxID_ANY, _("Delete"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxButton* const pload_btn = new wxButton(profile_sbox->GetStaticBox(), wxID_ANY, _("Load"),
wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxButton* const psave_btn = new wxButton(profile_sbox->GetStaticBox(), wxID_ANY, _("Save"),
wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxButton* const pdelete_btn = new wxButton(profile_sbox->GetStaticBox(), wxID_ANY, _("Delete"),
wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
pload_btn->Bind(wxEVT_BUTTON, &GamepadPage::LoadProfile, this);
psave_btn->Bind(wxEVT_BUTTON, &GamepadPage::SaveProfile, this);
pdelete_btn->Bind(wxEVT_BUTTON, &GamepadPage::DeleteProfile, this);
profile_sbox->Add(profile_cbox, 1, wxLEFT, 3);
profile_sbox->Add(pload_btn, 0, wxLEFT, 3);
profile_sbox->Add(psave_btn, 0, 0, 3);
profile_sbox->Add(pdelete_btn, 0, wxRIGHT | wxBOTTOM, 3);
wxBoxSizer* profile_sbox_in = new wxBoxSizer(wxHORIZONTAL);
profile_sbox_in->Add(WxUtils::GiveMinSizeDIP(profile_cbox, wxSize(64, -1)), 1,
wxALIGN_CENTER_VERTICAL);
profile_sbox_in->AddSpacer(space3);
profile_sbox_in->Add(pload_btn, 0, wxALIGN_CENTER_VERTICAL);
profile_sbox_in->Add(psave_btn, 0, wxALIGN_CENTER_VERTICAL);
profile_sbox_in->Add(pdelete_btn, 0, wxALIGN_CENTER_VERTICAL);
profile_sbox->Add(profile_sbox_in, 1, wxEXPAND | wxLEFT | wxRIGHT, space3);
profile_sbox->AddSpacer(space3);
wxBoxSizer* const dio = new wxBoxSizer(wxHORIZONTAL);
dio->Add(device_sbox, 1, wxEXPAND | wxRIGHT, 5);
dio->Add(clear_sbox, 0, wxEXPAND | wxRIGHT, 5);
dio->Add(profile_sbox, 1, wxEXPAND | wxRIGHT, 5);
dio->Add(device_sbox, 1, wxEXPAND);
dio->Add(clear_sbox, 0, wxEXPAND | wxLEFT, space5);
dio->Add(profile_sbox, 1, wxEXPAND | wxLEFT, space5);
wxBoxSizer* const mapping = new wxBoxSizer(wxVERTICAL);
mapping->Add(dio, 1, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 5);
mapping->Add(control_group_sizer, 0, wxLEFT | wxEXPAND, 5);
mapping->AddSpacer(space5);
mapping->Add(dio, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
mapping->AddSpacer(space5);
mapping->Add(control_group_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
UpdateGUI();
@ -1154,9 +1258,9 @@ GamepadPage::GamepadPage(wxWindow* parent, InputConfig& config, const int pad_nu
InputConfigDialog::InputConfigDialog(wxWindow* const parent, InputConfig& config,
const wxString& name, const int tab_num)
: wxDialog(parent, wxID_ANY, name, wxPoint(128, -1)), m_config(config)
: wxDialog(parent, wxID_ANY, name), m_config(config)
{
m_pad_notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_DEFAULT);
m_pad_notebook = new wxNotebook(this, wxID_ANY);
GamepadPage* gp = new GamepadPage(m_pad_notebook, m_config, tab_num, this);
m_padpages.push_back(gp);
m_pad_notebook->AddPage(gp, wxString::Format("%s [%u]",
@ -1172,10 +1276,15 @@ InputConfigDialog::InputConfigDialog(wxWindow* const parent, InputConfig& config
Bind(wxEVT_BUTTON, &InputConfigDialog::OnCloseButton, this, wxID_CLOSE);
wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
szr->Add(m_pad_notebook, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5);
szr->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxALL, 5);
const int space5 = FromDIP(5);
szr->AddSpacer(space5);
szr->Add(m_pad_notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr->AddSpacer(space5);
szr->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr->AddSpacer(space5);
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(szr);
Center();

View File

@ -27,11 +27,11 @@
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/ControllerInterface/Device.h"
class DolphinSlider;
class InputConfig;
class wxComboBox;
class wxListBox;
class wxNotebook;
class wxSlider;
class wxStaticBitmap;
class wxStaticText;
class wxTextCtrl;
@ -62,15 +62,7 @@ class PadSettingSpin : public PadSetting
{
public:
PadSettingSpin(wxWindow* const parent,
ControllerEmu::ControlGroup::NumericSetting* const _setting)
: PadSetting(new wxSpinCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxSize(54, -1), 0, _setting->m_low, _setting->m_high,
(int)(_setting->GetValue() * 100))),
setting(_setting)
{
wxcontrol->SetLabel(setting->m_name);
}
ControllerEmu::ControlGroup::NumericSetting* const setting);
void UpdateGUI() override;
void UpdateValue() override;
@ -136,6 +128,9 @@ private:
void SetSelectedControl(wxCommandEvent& event);
void AppendControl(wxCommandEvent& event);
void OnRangeSlide(wxScrollEvent&);
void OnRangeSpin(wxSpinEvent&);
void OnRangeThumbtrack(wxScrollEvent&);
bool GetExpressionForSelectedControl(wxString& expr);
@ -143,7 +138,8 @@ private:
wxComboBox* device_cbox;
wxTextCtrl* textctrl;
wxListBox* control_lbox;
wxSlider* range_slider;
DolphinSlider* m_range_slider;
wxSpinCtrl* m_range_spinner;
wxStaticText* m_bound_label;
wxStaticText* m_error_label;
InputEventFilter m_event_filter;
@ -165,10 +161,15 @@ class ControlButton : public wxButton
{
public:
ControlButton(wxWindow* const parent, ControllerInterface::ControlReference* const _ref,
const std::string& name, const unsigned int width, const std::string& label = "");
const std::string& name, const unsigned int width, const std::string& label = {});
ControllerInterface::ControlReference* const control_reference;
const std::string m_name;
protected:
wxSize DoGetBestSize() const override;
int m_configured_width = wxDefaultCoord;
};
class ControlGroupBox : public wxBoxSizer
@ -178,11 +179,18 @@ public:
GamepadPage* const eventsink);
~ControlGroupBox();
bool HasBitmapHeading() const
{
return control_group->type == GROUP_TYPE_STICK || control_group->type == GROUP_TYPE_TILT ||
control_group->type == GROUP_TYPE_CURSOR || control_group->type == GROUP_TYPE_FORCE;
}
std::vector<PadSetting*> options;
ControllerEmu::ControlGroup* const control_group;
wxStaticBitmap* static_bitmap;
std::vector<ControlButton*> control_buttons;
double m_scale;
};
class ControlGroupsSizer : public wxBoxSizer

View File

@ -2,6 +2,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <cmath>
#include <cstring>
#include <memory>
#include <string>
@ -11,8 +13,10 @@
#include <wx/colour.h>
#include <wx/dcmemory.h>
#include <wx/font.h>
#include <wx/graphics.h>
#include <wx/notebook.h>
#include <wx/pen.h>
#include <wx/settings.h>
#include <wx/statbmp.h>
#include "DolphinWX/InputConfigDiag.h"
@ -36,69 +40,64 @@ struct ShapePosition
};
// regular octagon
static void DrawOctagon(wxDC* dc, ShapePosition p)
static void DrawOctagon(wxGraphicsContext* gc, ShapePosition p)
{
const int vertices = 8;
static constexpr int vertices = 8;
double radius = p.max;
wxPoint point[vertices];
wxGraphicsPath path = gc->CreatePath();
double angle = 2.0 * M_PI / vertices;
for (int i = 0; i < vertices; i++)
{
double a = (angle * i);
double a = angle * i;
double x = radius * cos(a);
double y = radius * sin(a);
point[i].x = x;
point[i].y = y;
if (i == 0)
path.MoveToPoint(x, y);
else
path.AddLineToPoint(x, y);
}
path.CloseSubpath();
dc->DrawPolygon(vertices, point, p.offset, p.offset);
wxGraphicsMatrix matrix = gc->CreateMatrix();
matrix.Translate(p.offset, p.offset);
path.Transform(matrix);
gc->DrawPath(path);
}
// irregular dodecagon
static void DrawDodecagon(wxDC* dc, ShapePosition p)
static void DrawDodecagon(wxGraphicsContext* gc, ShapePosition p)
{
const int vertices = 12;
wxGraphicsPath path = gc->CreatePath();
path.MoveToPoint(p.dz, p.max);
path.AddLineToPoint(p.diag, p.diag);
path.AddLineToPoint(p.max, p.dz);
path.AddLineToPoint(p.max, -p.dz);
path.AddLineToPoint(p.diag, -p.diag);
path.AddLineToPoint(p.dz, -p.max);
path.AddLineToPoint(-p.dz, -p.max);
path.AddLineToPoint(-p.diag, -p.diag);
path.AddLineToPoint(-p.max, -p.dz);
path.AddLineToPoint(-p.max, p.dz);
path.AddLineToPoint(-p.diag, p.diag);
path.AddLineToPoint(-p.dz, p.max);
path.CloseSubpath();
wxPoint point[vertices];
point[0].x = p.dz;
point[0].y = p.max;
point[1].x = p.diag;
point[1].y = p.diag;
point[2].x = p.max;
point[2].y = p.dz;
wxGraphicsMatrix matrix = gc->CreateMatrix();
matrix.Translate(p.offset, p.offset);
path.Transform(matrix);
point[3].x = p.max;
point[3].y = -p.dz;
point[4].x = p.diag;
point[4].y = -p.diag;
point[5].x = p.dz;
point[5].y = -p.max;
point[6].x = -p.dz;
point[6].y = -p.max;
point[7].x = -p.diag;
point[7].y = -p.diag;
point[8].x = -p.max;
point[8].y = -p.dz;
point[9].x = -p.max;
point[9].y = p.dz;
point[10].x = -p.diag;
point[10].y = p.diag;
point[11].x = -p.dz;
point[11].y = p.max;
dc->DrawPolygon(vertices, point, p.offset, p.offset);
gc->DrawPath(path);
}
static void DrawCenteredRectangle(wxDC& dc, int x, int y, int w, int h)
static void DrawCenteredRectangle(wxGraphicsContext* gc, double x, double y, double w, double h)
{
x -= w / 2;
y -= h / 2;
dc.DrawRectangle(x, y, w, h);
gc->DrawRectangle(x, y, w, h);
}
#define VIS_BITMAP_SIZE 64
@ -108,37 +107,47 @@ static void DrawCenteredRectangle(wxDC& dc, int x, int y, int w, int h)
#define COORD_VIS_SIZE 4
static void DrawCoordinate(wxDC& dc, ControlState x, ControlState y)
static void DrawCoordinate(wxGraphicsContext* gc, ControlState x, ControlState y)
{
int xc = VIS_COORD(x);
int yc = VIS_COORD(y);
DrawCenteredRectangle(dc, xc, yc, COORD_VIS_SIZE, COORD_VIS_SIZE);
double xc = VIS_COORD(x);
double yc = VIS_COORD(y);
DrawCenteredRectangle(gc, xc, yc, COORD_VIS_SIZE, COORD_VIS_SIZE);
}
static void DrawButton(unsigned int* const bitmasks, unsigned int buttons, unsigned int n, wxDC& dc,
ControlGroupBox* g, unsigned int row)
static void DrawButton(const std::vector<unsigned int>& bitmasks, unsigned int buttons,
unsigned int n, wxGraphicsContext* gc, ControlGroupBox* g, unsigned int row,
const wxGraphicsMatrix& null_matrix)
{
if (buttons & bitmasks[(row * 8) + n])
{
dc.SetBrush(*wxRED_BRUSH);
gc->SetBrush(*wxRED_BRUSH);
}
else
{
auto lock = ControllerEmu::GetStateLock();
unsigned char amt = 255 - g->control_group->controls[(row * 8) + n]->control_ref->State() * 128;
dc.SetBrush(wxBrush(wxColour(amt, amt, amt)));
gc->SetBrush(wxBrush(wxColour(amt, amt, amt)));
}
dc.DrawRectangle(n * 12, (row == 0) ? 0 : (row * 11), 14, 12);
gc->DrawRectangle(n * 12, (row == 0) ? 0 : (row * 11), 14, 12);
// text
const std::string name = g->control_group->controls[(row * 8) + n]->name;
// Matrix transformation needs to be disabled so we don't draw scaled/zoomed text.
wxGraphicsMatrix old_matrix = gc->GetTransform();
gc->SetTransform(null_matrix);
// bit of hax so ZL, ZR show up as L, R
dc.DrawText(StrToWxStr(std::string(1, (name[1] && name[1] < 'a') ? name[1] : name[0])),
n * 12 + 2, 1 + ((row == 0) ? 0 : (row * 11)));
gc->DrawText(wxUniChar((name[1] && name[1] < 'a') ? name[1] : name[0]), (n * 12 + 2) * g->m_scale,
(1 + (row == 0 ? 0 : row * 11)) * g->m_scale);
gc->SetTransform(old_matrix);
}
static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
static void DrawControlGroupBox(wxGraphicsContext* gc, ControlGroupBox* g)
{
wxGraphicsMatrix null_matrix = gc->GetTransform();
wxGraphicsMatrix scale_matrix = null_matrix;
scale_matrix.Scale(g->m_scale, g->m_scale);
gc->SetTransform(scale_matrix);
switch (g->control_group->type)
{
case GROUP_TYPE_TILT:
@ -165,29 +174,17 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
// ir cursor forward movement
if (GROUP_TYPE_CURSOR == g->control_group->type)
{
if (z)
{
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
}
else
{
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxGREY_BRUSH);
}
dc.DrawRectangle(0, 31 - z * 31, 64, 2);
gc->SetBrush(z ? *wxRED_BRUSH : *wxGREY_BRUSH);
wxGraphicsPath path = gc->CreatePath();
path.AddRectangle(0, 31 - z * 31, 64, 2);
gc->FillPath(path);
}
// input zone
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
gc->SetPen(*wxLIGHT_GREY_PEN);
if (GROUP_TYPE_STICK == g->control_group->type)
{
// outline and fill colors
wxBrush LightGrayBrush("#dddddd");
wxPen LightGrayPen("#bfbfbf");
dc.SetBrush(LightGrayBrush);
dc.SetPen(LightGrayPen);
gc->SetBrush(wxColour(0xDDDDDD)); // Light Gray
ShapePosition p;
p.box = 64;
@ -215,20 +212,25 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
}
if (octagon)
DrawOctagon(&dc, p);
DrawOctagon(gc, p);
else
DrawDodecagon(&dc, p);
DrawDodecagon(gc, p);
}
else
{
dc.DrawRectangle(16, 16, 32, 32);
gc->SetBrush(*wxWHITE_BRUSH);
gc->DrawRectangle(16, 16, 32, 32);
}
if (GROUP_TYPE_CURSOR != g->control_group->type)
{
// deadzone circle
dc.SetBrush(*wxLIGHT_GREY_BRUSH);
dc.DrawCircle(32, 32, g->control_group->numeric_settings[SETTING_DEADZONE]->GetValue() * 32);
int deadzone_idx = g->control_group->type == GROUP_TYPE_STICK ? SETTING_DEADZONE : 0;
wxGraphicsPath path = gc->CreatePath();
path.AddCircle(VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2,
g->control_group->numeric_settings[deadzone_idx]->GetValue() *
VIS_BITMAP_SIZE / 2);
gc->SetBrush(*wxLIGHT_GREY_BRUSH);
gc->FillPath(path);
}
// raw dot
@ -238,21 +240,21 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
yy = g->control_group->controls[1]->control_ref->State();
yy -= g->control_group->controls[0]->control_ref->State();
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxGREY_BRUSH);
DrawCoordinate(dc, xx, yy);
gc->SetPen(*wxTRANSPARENT_PEN);
gc->SetBrush(*wxGREY_BRUSH);
DrawCoordinate(gc, xx, yy);
// adjusted dot
if (x != 0 || y != 0)
{
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
gc->SetBrush(*wxRED_BRUSH);
// XXX: The adjusted values flip the Y axis to be in the format
// the Wii expects. Should this be in WiimoteEmu.cpp instead?
DrawCoordinate(dc, x, -y);
DrawCoordinate(gc, x, -y);
}
}
break;
case GROUP_TYPE_FORCE:
{
ControlState raw_dot[3];
@ -270,69 +272,67 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
}
// deadzone rect for forward/backward visual
dc.SetBrush(*wxLIGHT_GREY_BRUSH);
dc.SetPen(*wxLIGHT_GREY_PEN);
gc->SetPen(*wxTRANSPARENT_PEN);
gc->SetBrush(*wxLIGHT_GREY_BRUSH);
int deadzone_height = deadzone * VIS_BITMAP_SIZE;
DrawCenteredRectangle(dc, 0, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE, deadzone_height);
DrawCenteredRectangle(gc, 0, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE, deadzone_height);
#define LINE_HEIGHT 2
int line_y;
// raw forward/background line
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxGREY_BRUSH);
gc->SetBrush(*wxGREY_BRUSH);
line_y = VIS_COORD(raw_dot[2]);
DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
// adjusted forward/background line
if (adj_dot[2] != 0.0)
{
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
gc->SetBrush(*wxRED_BRUSH);
line_y = VIS_COORD(adj_dot[2]);
DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
}
#define DEADZONE_RECT_SIZE 32
// empty deadzone square
dc.SetBrush(*wxWHITE_BRUSH);
dc.SetPen(*wxLIGHT_GREY_PEN);
DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, DEADZONE_RECT_SIZE,
gc->SetPen(*wxLIGHT_GREY_PEN);
gc->SetBrush(*wxWHITE_BRUSH);
DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, DEADZONE_RECT_SIZE,
DEADZONE_RECT_SIZE);
// deadzone square
dc.SetBrush(*wxLIGHT_GREY_BRUSH);
gc->SetPen(*wxTRANSPARENT_PEN);
gc->SetBrush(*wxLIGHT_GREY_BRUSH);
int dz_size = (deadzone * DEADZONE_RECT_SIZE);
DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, dz_size, dz_size);
DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, dz_size, dz_size);
// raw dot
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxGREY_BRUSH);
DrawCoordinate(dc, raw_dot[1], raw_dot[0]);
gc->SetBrush(*wxGREY_BRUSH);
DrawCoordinate(gc, raw_dot[1], raw_dot[0]);
// adjusted dot
if (adj_dot[1] != 0 && adj_dot[0] != 0)
{
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
DrawCoordinate(dc, adj_dot[1], adj_dot[0]);
gc->SetBrush(*wxRED_BRUSH);
DrawCoordinate(gc, adj_dot[1], adj_dot[0]);
}
}
break;
case GROUP_TYPE_BUTTONS:
{
unsigned int button_count = ((unsigned int)g->control_group->controls.size());
const unsigned int button_count = static_cast<unsigned int>(g->control_group->controls.size());
std::vector<unsigned int> bitmasks(button_count);
// draw the shit
dc.SetPen(*wxGREY_PEN);
gc->SetPen(*wxGREY_PEN);
unsigned int* const bitmasks = new unsigned int[button_count];
for (unsigned int n = 0; n < button_count; ++n)
bitmasks[n] = (1 << n);
unsigned int buttons = 0;
((ControllerEmu::Buttons*)g->control_group)->GetState(&buttons, bitmasks);
((ControllerEmu::Buttons*)g->control_group)->GetState(&buttons, bitmasks.data());
// Draw buttons in rows of 8
for (unsigned int row = 0; row < ceil((float)button_count / 8.0f); row++)
@ -343,155 +343,200 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
for (unsigned int n = 0; n < buttons_to_draw; ++n)
{
DrawButton(bitmasks, buttons, n, dc, g, row);
DrawButton(bitmasks, buttons, n, gc, g, row, null_matrix);
}
}
delete[] bitmasks;
}
break;
case GROUP_TYPE_TRIGGERS:
{
const unsigned int trigger_count = ((unsigned int)(g->control_group->controls.size()));
const unsigned int trigger_count = static_cast<unsigned int>(g->control_group->controls.size());
std::vector<ControlState> trigs(trigger_count);
// draw the shit
dc.SetPen(*wxGREY_PEN);
ControlState deadzone = g->control_group->numeric_settings[0]->GetValue();
gc->SetPen(*wxGREY_PEN);
ControlState* const trigs = new ControlState[trigger_count];
((ControllerEmu::Triggers*)g->control_group)->GetState(trigs);
ControlState deadzone = g->control_group->numeric_settings[0]->GetValue();
((ControllerEmu::Triggers*)g->control_group)->GetState(trigs.data());
for (unsigned int n = 0; n < trigger_count; ++n)
{
ControlState trig_r = g->control_group->controls[n]->control_ref->State();
// outline
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle(0, n * 12, 64, 14);
gc->SetBrush(*wxWHITE_BRUSH);
gc->DrawRectangle(0, n * 12, 64, 14);
// raw
dc.SetBrush(*wxGREY_BRUSH);
dc.DrawRectangle(0, n * 12, trig_r * 64, 14);
gc->SetBrush(*wxGREY_BRUSH);
gc->DrawRectangle(0, n * 12, trig_r * 64, 14);
// deadzone affected
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle(0, n * 12, trigs[n] * 64, 14);
gc->SetBrush(*wxRED_BRUSH);
gc->DrawRectangle(0, n * 12, trigs[n] * 64, 14);
// text
dc.DrawText(StrToWxStr(g->control_group->controls[n]->name), 3, n * 12 + 1);
// We don't want the text to be scaled/zoomed
gc->SetTransform(null_matrix);
gc->DrawText(StrToWxStr(g->control_group->controls[n]->name), 3 * g->m_scale,
(n * 12 + 1) * g->m_scale);
gc->SetTransform(scale_matrix);
}
delete[] trigs;
// deadzone box
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, deadzone * 64, trigger_count * 14);
gc->SetPen(*wxLIGHT_GREY_PEN);
gc->SetBrush(*wxTRANSPARENT_BRUSH);
gc->DrawRectangle(0, 0, deadzone * 64, trigger_count * 14);
}
break;
case GROUP_TYPE_MIXED_TRIGGERS:
{
const unsigned int trigger_count = ((unsigned int)(g->control_group->controls.size() / 2));
// draw the shit
dc.SetPen(*wxGREY_PEN);
gc->SetPen(*wxGREY_PEN);
ControlState thresh = g->control_group->numeric_settings[0]->GetValue();
for (unsigned int n = 0; n < trigger_count; ++n)
{
dc.SetBrush(*wxRED_BRUSH);
gc->SetBrush(*wxRED_BRUSH);
ControlState trig_d = g->control_group->controls[n]->control_ref->State();
ControlState trig_a =
trig_d > thresh ? 1 : g->control_group->controls[n + trigger_count]->control_ref->State();
dc.DrawRectangle(0, n * 12, 64 + 20, 14);
gc->DrawRectangle(0, n * 12, 64 + 20, 14);
if (trig_d <= thresh)
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle(trig_a * 64, n * 12, 64 + 20, 14);
dc.DrawRectangle(64, n * 12, 32, 14);
gc->SetBrush(*wxWHITE_BRUSH);
gc->DrawRectangle(trig_a * 64, n * 12, 64 + 20, 14);
gc->DrawRectangle(64, n * 12, 32, 14);
// text
dc.DrawText(StrToWxStr(g->control_group->controls[n + trigger_count]->name), 3, n * 12 + 1);
dc.DrawText(StrToWxStr(std::string(1, g->control_group->controls[n]->name[0])), 64 + 3,
n * 12 + 1);
// We don't want the text to be scaled/zoomed
gc->SetTransform(null_matrix);
gc->DrawText(StrToWxStr(g->control_group->controls[n + trigger_count]->name), 3 * g->m_scale,
(n * 12 + 1) * g->m_scale);
gc->DrawText(StrToWxStr(std::string(1, g->control_group->controls[n]->name[0])),
(64 + 3) * g->m_scale, (n * 12 + 1) * g->m_scale);
gc->SetTransform(scale_matrix);
}
// threshold box
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(thresh * 64, 0, 128, trigger_count * 14);
gc->SetPen(*wxLIGHT_GREY_PEN);
gc->SetBrush(*wxTRANSPARENT_BRUSH);
gc->DrawRectangle(thresh * 64, 0, 128, trigger_count * 14);
}
break;
case GROUP_TYPE_SLIDER:
{
const ControlState deadzone = g->control_group->numeric_settings[0]->GetValue();
ControlState state = g->control_group->controls[1]->control_ref->State() -
g->control_group->controls[0]->control_ref->State();
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxGREY_BRUSH);
dc.DrawRectangle(31 + state * 30, 0, 2, 14);
gc->SetPen(*wxTRANSPARENT_PEN);
gc->SetBrush(*wxGREY_BRUSH);
gc->DrawRectangle(31 + state * 30, 0, 2, 14);
ControlState adj_state;
((ControllerEmu::Slider*)g->control_group)->GetState(&adj_state);
if (state)
{
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle(31 + adj_state * 30, 0, 2, 14);
gc->SetBrush(*wxRED_BRUSH);
gc->DrawRectangle(31 + adj_state * 30, 0, 2, 14);
}
// deadzone box
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(32 - deadzone * 32, 0, deadzone * 64, 14);
gc->SetPen(*wxLIGHT_GREY_PEN);
gc->SetBrush(*wxTRANSPARENT_BRUSH);
gc->DrawRectangle(32 - deadzone * 32, 0, deadzone * 64, 14);
}
break;
default:
break;
}
gc->SetTransform(null_matrix);
}
static void DrawBorder(wxGraphicsContext* gc, double scale)
{
double pen_width = std::round(scale); // Pen width = 1px * scale
// Use the window caption bar color as a safe accent color.
wxPen border_pen(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION),
static_cast<int>(pen_width));
border_pen.SetCap(wxCAP_PROJECTING);
double width, height;
gc->GetSize(&width, &height);
wxGraphicsPath path = gc->CreatePath();
path.AddRectangle(pen_width / 2, pen_width / 2, width - pen_width, height - pen_width);
gc->SetPen(border_pen);
gc->StrokePath(path);
}
void InputConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event))
{
wxFont small_font(6, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
const wxColour font_color{0xB8B8B8};
g_controller_interface.UpdateInput();
GamepadPage* const current_page =
(GamepadPage*)m_pad_notebook->GetPage(m_pad_notebook->GetSelection());
static_cast<GamepadPage*>(m_pad_notebook->GetPage(m_pad_notebook->GetSelection()));
wxMemoryDC dc;
auto lock = ControllerEmu::GetStateLock();
for (ControlGroupBox* g : current_page->control_groups)
{
// if this control group has a bitmap
if (g->static_bitmap)
// Only if this control group has a bitmap
if (!g->static_bitmap)
continue;
wxBitmap bitmap(g->static_bitmap->GetBitmap());
// NOTE: Selecting the bitmap inherits the bitmap's ScaleFactor onto the DC as well.
dc.SelectObject(bitmap);
dc.SetBackground(*wxWHITE_BRUSH);
dc.Clear();
#ifdef __WXGTK20__
int dc_height = 0;
dc.SetFont(small_font);
dc.GetTextExtent(g->control_group->name, nullptr, &dc_height);
#endif
std::unique_ptr<wxGraphicsContext> gc{wxGraphicsContext::Create(dc)};
gc->DisableOffset();
gc->SetFont(small_font, font_color);
#ifdef __WXGTK20__
double gc_height = 0;
gc->GetTextExtent(g->control_group->name, nullptr, &gc_height);
// On GTK2, wx creates a new empty Cairo/Pango context for the graphics context instead
// of reusing the wxMemoryDC one, this causes it to forget the screen DPI so fonts stop
// scaling, we need to scale it manually instead.
if (std::ceil(gc_height) < dc_height)
{
wxMemoryDC dc;
wxBitmap bitmap(g->static_bitmap->GetBitmap());
dc.SelectObject(bitmap);
dc.Clear();
dc.SetFont(small_font);
dc.SetTextForeground(0xC0C0C0);
DrawControlGroupBox(dc, g);
// box outline
// Windows XP color
dc.SetPen(wxPen("#7f9db9"));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, bitmap.GetWidth(), bitmap.GetHeight());
// label for sticks and stuff
if (64 == bitmap.GetHeight())
dc.DrawText(StrToWxStr(g->control_group->name).Upper(), 4, 2);
dc.SelectObject(wxNullBitmap);
g->static_bitmap->SetBitmap(bitmap);
wxFont fixed_font(small_font);
fixed_font.SetPointSize(static_cast<int>(fixed_font.GetPointSize() * g->m_scale));
gc->SetFont(fixed_font, font_color);
}
#endif
DrawControlGroupBox(gc.get(), g);
DrawBorder(gc.get(), g->m_scale);
// label for sticks and stuff
if (g->HasBitmapHeading())
gc->DrawText(StrToWxStr(g->control_group->name).Upper(), 4 * g->m_scale, 2 * g->m_scale);
gc.reset();
dc.SelectObject(wxNullBitmap);
g->static_bitmap->SetBitmap(bitmap);
}
}

View File

@ -25,18 +25,11 @@ LogConfigWindow::LogConfigWindow(wxWindow* parent, wxWindowID id)
_("Log Configuration")),
enableAll(true)
{
Bind(wxEVT_CLOSE_WINDOW, &LogConfigWindow::OnClose, this);
SetMinSize(wxSize(100, 100));
m_LogManager = LogManager::GetInstance();
CreateGUIControls();
LoadSettings();
}
void LogConfigWindow::OnClose(wxCloseEvent& event)
{
SaveSettings();
}
void LogConfigWindow::CreateGUIControls()
{
// Verbosity
@ -68,23 +61,26 @@ void LogConfigWindow::CreateGUIControls()
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
m_checks->Append(StrToWxStr(m_LogManager->GetFullName((LogTypes::LOG_TYPE)i)));
const int space1 = FromDIP(1);
const int space5 = FromDIP(5);
// Sizers
wxStaticBoxSizer* sbOutputs = new wxStaticBoxSizer(wxVERTICAL, this, _("Logger Outputs"));
sbOutputs->Add(m_writeFileCB, 0, wxDOWN, 1);
sbOutputs->Add(m_writeConsoleCB, 0, wxDOWN, 1);
sbOutputs->Add(m_writeWindowCB, 0);
sbOutputs->Add(m_writeFileCB, 0);
sbOutputs->Add(m_writeConsoleCB, 0, wxTOP, space1);
sbOutputs->Add(m_writeWindowCB, 0, wxTOP, space1);
wxStaticBoxSizer* sbLogTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Log Types"));
sbLogTypes->Add(m_checks, 1, wxEXPAND);
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
sMain->Add(m_verbosity, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
sMain->Add(sbOutputs, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
sMain->Add(btn_toggle_all, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
sMain->Add(sbLogTypes, 1, wxEXPAND | wxLEFT | wxRIGHT, 5);
sMain->Add(m_verbosity, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->Add(sbOutputs, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->Add(btn_toggle_all, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->Add(sbLogTypes, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
SetSizer(sMain);
Layout();
sMain->SetMinSize(FromDIP(wxSize(100, 100)));
SetSizerAndFit(sMain);
}
void LogConfigWindow::LoadSettings()

View File

@ -31,7 +31,6 @@ private:
void CreateGUIControls();
void OnVerbosityChange(wxCommandEvent& event);
void OnClose(wxCloseEvent& event);
void OnWriteFileChecked(wxCommandEvent& event);
void OnWriteConsoleChecked(wxCommandEvent& event);
void OnWriteWindowChecked(wxCommandEvent& event);

View File

@ -39,7 +39,6 @@ CLogWindow::CLogWindow(CFrame* parent, wxWindowID id, const wxPoint& pos, const
: wxPanel(parent, id, pos, size, style, name), x(0), y(0), winpos(0), Parent(parent),
m_LogAccess(true), m_Log(nullptr), m_cmdline(nullptr), m_FontChoice(nullptr)
{
Bind(wxEVT_CLOSE_WINDOW, &CLogWindow::OnClose, this);
Bind(wxEVT_TIMER, &CLogWindow::OnLogTimer, this);
m_LogManager = LogManager::GetInstance();
@ -94,6 +93,7 @@ void CLogWindow::CreateGUIControls()
m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)(verbosity));
}
m_has_listeners = true;
// Font
m_FontChoice = new wxChoice(this, wxID_ANY);
@ -132,11 +132,13 @@ void CLogWindow::CreateGUIControls()
new wxButton(this, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
m_clear_log_btn->Bind(wxEVT_BUTTON, &CLogWindow::OnClear, this);
const int space3 = FromDIP(3);
// Sizers
wxBoxSizer* sTop = new wxBoxSizer(wxHORIZONTAL);
sTop->Add(m_clear_log_btn);
sTop->Add(m_FontChoice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 3);
sTop->Add(m_WrapLine, 0, wxALIGN_CENTER_VERTICAL);
sTop->Add(m_clear_log_btn, 0, wxALIGN_CENTER_VERTICAL);
sTop->Add(m_FontChoice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
sTop->Add(m_WrapLine, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
sBottom = new wxBoxSizer(wxVERTICAL);
PopulateBottom();
@ -149,15 +151,17 @@ void CLogWindow::CreateGUIControls()
m_cmdline->SetFocus();
}
void CLogWindow::OnClose(wxCloseEvent& event)
CLogWindow::~CLogWindow()
{
SaveSettings();
event.Skip();
RemoveAllListeners();
}
void CLogWindow::RemoveAllListeners()
{
if (!m_has_listeners)
return;
m_has_listeners = false;
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
m_LogManager->RemoveListener(static_cast<LogTypes::LOG_TYPE>(i),

View File

@ -28,7 +28,11 @@ public:
CLogWindow(CFrame* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL,
const wxString& name = _("Log"));
~CLogWindow() override;
// Listeners must be removed explicitly before the window is closed to prevent crashes on OS X
// when closing via the Dock. (The Core is probably being shutdown before the window)
void RemoveAllListeners();
void SaveSettings();
void Log(LogTypes::LOG_LEVELS, const char* text) override;
@ -42,6 +46,7 @@ private:
LogManager* m_LogManager;
std::queue<std::pair<u8, wxString>> msgQueue;
bool m_writeFile, m_writeWindow, m_LogAccess;
bool m_has_listeners = false;
// Controls
wxBoxSizer* sBottom;
@ -57,11 +62,9 @@ private:
void CreateGUIControls();
void PopulateBottom();
void UnPopulateBottom();
void OnClose(wxCloseEvent& event);
void OnFontChange(wxCommandEvent& event);
void OnWrapLineCheck(wxCommandEvent& event);
void OnClear(wxCommandEvent& event);
void OnLogTimer(wxTimerEvent& WXUNUSED(event));
void RemoveAllListeners();
void UpdateLog();
};

View File

@ -53,25 +53,6 @@
#include <X11/Xlib.h>
#endif
#ifdef _WIN32
#ifndef SM_XVIRTUALSCREEN
#define SM_XVIRTUALSCREEN 76
#endif
#ifndef SM_YVIRTUALSCREEN
#define SM_YVIRTUALSCREEN 77
#endif
#ifndef SM_CXVIRTUALSCREEN
#define SM_CXVIRTUALSCREEN 78
#endif
#ifndef SM_CYVIRTUALSCREEN
#define SM_CYVIRTUALSCREEN 79
#endif
#endif
class wxFrame;
// ------------
// Main window
@ -130,31 +111,14 @@ bool DolphinApp::OnInit()
// Enable the PNG image handler for screenshots
wxImage::AddHandler(new wxPNGHandler);
int x = SConfig::GetInstance().iPosX;
int y = SConfig::GetInstance().iPosY;
int w = SConfig::GetInstance().iWidth;
int h = SConfig::GetInstance().iHeight;
// The following is not needed with X11, where window managers
// do not allow windows to be created off the desktop.
#ifdef _WIN32
// Out of desktop check
int leftPos = GetSystemMetrics(SM_XVIRTUALSCREEN);
int topPos = GetSystemMetrics(SM_YVIRTUALSCREEN);
int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
if ((leftPos + width) < (x + w) || leftPos > x || (topPos + height) < (y + h) || topPos > y)
x = y = wxDefaultCoord;
#elif defined __APPLE__
if (y < 1)
y = wxDefaultCoord;
#endif
main_frame = new CFrame(nullptr, wxID_ANY, StrToWxStr(scm_rev_str), wxPoint(x, y), wxSize(w, h),
// We have to copy the size and position out of SConfig now because CFrame's OnMove
// handler will corrupt them during window creation (various APIs like SetMenuBar cause
// event dispatch including WM_MOVE/WM_SIZE)
wxRect window_geometry(SConfig::GetInstance().iPosX, SConfig::GetInstance().iPosY,
SConfig::GetInstance().iWidth, SConfig::GetInstance().iHeight);
main_frame = new CFrame(nullptr, wxID_ANY, StrToWxStr(scm_rev_str), window_geometry,
m_use_debugger, m_batch_mode, m_use_logger);
SetTopWindow(main_frame);
main_frame->SetMinSize(wxSize(400, 300));
AfterInit();

View File

@ -17,7 +17,6 @@
#include <wx/listbase.h>
#include <wx/menu.h>
#include <wx/msgdlg.h>
#include <wx/mstream.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
@ -34,37 +33,24 @@
#define FIRSTPAGE 0
#define ARROWS slot ? "" : ARROW[slot], slot ? ARROW[slot] : ""
static wxBitmap wxBitmapFromMemoryRGBA(const unsigned char* data, u32 width, u32 height)
static wxImage wxImageFromMemoryRGBA(const u32* data, u32 width, u32 height)
{
static const std::array<u8, 54> header = {
{0x42, 0x4D, 0x38, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00,
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // Width
0x20, 0x00, 0x00, 0x00, // Height
0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, // Data size
0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}};
u32 stride = (4 * width);
u32 bytes = (stride * height) + header.size();
bytes = (bytes + 3) & ~3;
u32 data_length = bytes - header.size();
std::vector<u8> pdata(bytes);
std::copy(header.begin(), header.end(), pdata.begin());
u8* const pixelData = &pdata[header.size()];
for (u32 y = 0; y < height; y++)
std::memcpy(&pixelData[y * stride], &data[(height - y - 1) * stride], stride);
std::memcpy(&pdata[18], &width, sizeof(u32));
std::memcpy(&pdata[22], &height, sizeof(u32));
std::memcpy(&pdata[34], &data_length, sizeof(u32));
wxMemoryInputStream is(pdata.data(), bytes);
return wxBitmap(wxImage(is, wxBITMAP_TYPE_BMP));
wxImage image(width, height, false);
image.InitAlpha();
u8* rgb = image.GetData();
u8* alpha = image.GetAlpha();
for (u32 y = 0; y < height; ++y)
{
for (u32 x = 0; x < width; ++x)
{
u32 pixel = data[y * width + x];
*rgb++ = (pixel & 0x00FF0000) >> 16; // Red
*rgb++ = (pixel & 0x0000FF00) >> 8; // Green
*rgb++ = (pixel & 0x000000FF) >> 0; // Blue
*alpha++ = (pixel & 0xFF000000) >> 24;
}
}
return image;
}
BEGIN_EVENT_TABLE(CMemcardManager, wxDialog)
@ -94,7 +80,8 @@ END_EVENT_TABLE()
CMemcardManager::CMemcardManager(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Memory Card Manager"), wxDefaultPosition, wxDefaultSize,
wxCAPTION | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxCLOSE_BOX | wxRESIZE_BORDER |
wxMAXIMIZE_BOX)
wxMAXIMIZE_BOX),
m_image_list_size(FromDIP(wxSize(96, 32)))
{
memoryCard[SLOT_A] = nullptr;
memoryCard[SLOT_B] = nullptr;
@ -179,6 +166,7 @@ bool CMemcardManager::SaveSettings()
void CMemcardManager::CreateGUIControls()
{
// Create the controls for both memcards
const int space5 = FromDIP(5);
const char* ARROW[2] = {"<-", "->"};
@ -203,11 +191,11 @@ void CMemcardManager::CreateGUIControls()
t_Status[slot] = new wxStaticText(this, 0, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0,
wxEmptyString);
wxBoxSizer* const sPages = new wxBoxSizer(wxHORIZONTAL);
sPages->Add(m_PrevPage[slot], 0, wxEXPAND | wxALL, 1);
sPages->Add(t_Status[slot], 0, wxEXPAND | wxALL, 5);
sPages->Add(0, 0, 1, wxEXPAND | wxALL, 0);
sPages->Add(m_NextPage[slot], 0, wxEXPAND | wxALL, 1);
wxFlexGridSizer* const paging_sizer = new wxFlexGridSizer(3, wxSize(space5, space5));
paging_sizer->AddGrowableCol(1);
paging_sizer->Add(m_PrevPage[slot], 0, wxEXPAND);
paging_sizer->Add(t_Status[slot], 0, wxALIGN_CENTER);
paging_sizer->Add(m_NextPage[slot], 0, wxEXPAND);
m_MemcardPath[slot] = new wxFilePickerCtrl(
this, ID_MEMCARDPATH_A + slot, StrToWxStr(File::GetUserPath(D_GCUSER_IDX)),
@ -216,41 +204,51 @@ void CMemcardManager::CreateGUIControls()
wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN);
m_MemcardList[slot] = new CMemcardListCtrl(
this, ID_MEMCARDLIST_A + slot, wxDefaultPosition, wxSize(350, 400),
this, ID_MEMCARDLIST_A + slot, wxDefaultPosition, FromDIP(wxSize(350, 400)),
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL, mcmSettings);
m_MemcardList[slot]->AssignImageList(new wxImageList(96, 32), wxIMAGE_LIST_SMALL);
m_MemcardList[slot]->AssignImageList(
new wxImageList(m_image_list_size.GetWidth(), m_image_list_size.GetHeight()),
wxIMAGE_LIST_SMALL);
sMemcard[slot] = new wxStaticBoxSizer(wxVERTICAL, this,
_("Memory Card") + wxString::Format(" %c", 'A' + slot));
sMemcard[slot]->Add(m_MemcardPath[slot], 0, wxEXPAND | wxALL, 5);
sMemcard[slot]->Add(m_MemcardList[slot], 1, wxEXPAND | wxALL, 5);
sMemcard[slot]->Add(sPages, 0, wxEXPAND | wxALL, 1);
sMemcard[slot]->AddSpacer(space5);
sMemcard[slot]->Add(m_MemcardPath[slot], 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMemcard[slot]->AddSpacer(space5);
sMemcard[slot]->Add(m_MemcardList[slot], 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMemcard[slot]->AddSpacer(space5);
sMemcard[slot]->Add(paging_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMemcard[slot]->AddSpacer(space5);
}
wxBoxSizer* const sButtons = new wxBoxSizer(wxVERTICAL);
sButtons->AddStretchSpacer(2);
sButtons->Add(m_CopyFrom[SLOT_B], 0, wxEXPAND, 5);
sButtons->Add(m_CopyFrom[SLOT_A], 0, wxEXPAND, 5);
sButtons->AddStretchSpacer(1);
sButtons->Add(m_SaveImport[SLOT_A], 0, wxEXPAND, 5);
sButtons->Add(m_SaveExport[SLOT_A], 0, wxEXPAND, 5);
sButtons->AddStretchSpacer(1);
sButtons->Add(m_ConvertToGci, 0, wxEXPAND, 5);
sButtons->AddStretchSpacer(1);
sButtons->Add(m_SaveImport[SLOT_B], 0, wxEXPAND, 5);
sButtons->Add(m_SaveExport[SLOT_B], 0, wxEXPAND, 5);
sButtons->AddStretchSpacer(1);
sButtons->Add(m_Delete[SLOT_A], 0, wxEXPAND, 5);
sButtons->Add(m_Delete[SLOT_B], 0, wxEXPAND, 5);
sButtons->Add(m_CopyFrom[SLOT_B], 0, wxEXPAND);
sButtons->Add(m_CopyFrom[SLOT_A], 0, wxEXPAND);
sButtons->AddStretchSpacer();
sButtons->Add(new wxButton(this, wxID_OK, _("Close")), 0, wxEXPAND, 5);
sButtons->Add(m_SaveImport[SLOT_A], 0, wxEXPAND);
sButtons->Add(m_SaveExport[SLOT_A], 0, wxEXPAND);
sButtons->AddStretchSpacer();
sButtons->Add(m_ConvertToGci, 0, wxEXPAND);
sButtons->AddStretchSpacer();
sButtons->Add(m_SaveImport[SLOT_B], 0, wxEXPAND);
sButtons->Add(m_SaveExport[SLOT_B], 0, wxEXPAND);
sButtons->AddStretchSpacer();
sButtons->Add(m_Delete[SLOT_A], 0, wxEXPAND);
sButtons->Add(m_Delete[SLOT_B], 0, wxEXPAND);
sButtons->AddStretchSpacer();
sButtons->Add(new wxButton(this, wxID_OK, _("Close")), 0, wxEXPAND);
sButtons->AddStretchSpacer();
wxBoxSizer* const sMain = new wxBoxSizer(wxHORIZONTAL);
sMain->Add(sMemcard[SLOT_A], 1, wxEXPAND | wxALL, 5);
sMain->Add(sButtons, 0, wxEXPAND, 0);
sMain->Add(sMemcard[SLOT_B], 1, wxEXPAND | wxALL, 5);
sMain->AddSpacer(space5);
sMain->Add(sMemcard[SLOT_A], 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
sMain->AddSpacer(space5);
sMain->Add(sButtons, 0, wxEXPAND | wxTOP | wxBOTTOM, space5);
sMain->AddSpacer(space5);
sMain->Add(sMemcard[SLOT_B], 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
sMain->AddSpacer(space5);
SetSizerAndFit(sMain);
Center();
@ -653,57 +651,73 @@ bool CMemcardManager::ReloadMemcard(const std::string& fileName, int card)
u8 nFiles = memoryCard[card]->GetNumFiles();
std::vector<int> images(nFiles * 2);
static constexpr unsigned int BANNER_WIDTH = 96;
static constexpr unsigned int ANIM_FRAME_WIDTH = 32;
static constexpr unsigned int IMAGE_HEIGHT = 32;
static constexpr unsigned int ANIM_MAX_FRAMES = 8;
std::vector<u32> pxdata(BANNER_WIDTH * IMAGE_HEIGHT);
std::vector<u8> anim_delay(ANIM_MAX_FRAMES);
std::vector<u32> anim_data(ANIM_FRAME_WIDTH * IMAGE_HEIGHT * ANIM_MAX_FRAMES);
for (u8 i = 0; i < nFiles; i++)
{
static u32 pxdata[96 * 32];
static u8 animDelay[8];
static u32 animData[32 * 32 * 8];
u8 file_index = memoryCard[card]->GetFileIndex(i);
u32 num_frames =
memoryCard[card]->ReadAnimRGBA8(file_index, anim_data.data(), anim_delay.data());
u8 fileIndex = memoryCard[card]->GetFileIndex(i);
int numFrames = memoryCard[card]->ReadAnimRGBA8(fileIndex, animData, animDelay);
if (!memoryCard[card]->ReadBannerRGBA8(fileIndex, pxdata))
// Decode Save File Animation
wxImage anim_img_strip;
if (num_frames > 0)
{
memset(pxdata, 0, 96 * 32 * 4);
unsigned int frames = BANNER_WIDTH / ANIM_FRAME_WIDTH;
if (numFrames > 0) // Just use the first one
if (num_frames < frames)
{
u32* icdata = animData;
frames = num_frames;
for (int y = 0; y < 32; y++)
// Clear unused frame's pixels from the buffer.
std::fill(pxdata.begin(), pxdata.end(), 0);
}
for (unsigned int f = 0; f < frames; ++f)
{
for (unsigned int y = 0; y < IMAGE_HEIGHT; ++y)
{
for (int x = 0; x < 32; x++)
for (unsigned int x = 0; x < ANIM_FRAME_WIDTH; ++x)
{
pxdata[y * 96 + x + 32] = icdata[y * 32 + x]; // | 0xFF000000
// NOTE: pxdata is stacked horizontal, anim_data is stacked vertical
pxdata[y * BANNER_WIDTH + f * ANIM_FRAME_WIDTH + x] =
anim_data[f * ANIM_FRAME_WIDTH * IMAGE_HEIGHT + y * IMAGE_HEIGHT + x];
}
}
}
anim_img_strip = wxImageFromMemoryRGBA(pxdata.data(), BANNER_WIDTH, IMAGE_HEIGHT);
}
wxBitmap map = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32);
images[i * 2] = list->Add(map);
if (numFrames > 0)
else
{
memset(pxdata, 0, 96 * 32 * 4);
int frames = 3;
if (numFrames < frames)
frames = numFrames;
for (int f = 0; f < frames; f++)
{
for (int y = 0; y < 32; y++)
{
for (int x = 0; x < 32; x++)
{
pxdata[y * 96 + x + 32 * f] = animData[f * 32 * 32 + y * 32 + x];
}
}
}
wxBitmap icon = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32);
images[i * 2 + 1] = list->Add(icon);
// No Animation found, use an empty placeholder instead.
anim_img_strip.Create(BANNER_WIDTH, IMAGE_HEIGHT, false);
anim_img_strip.Clear(0xFF);
anim_img_strip.SetMaskColour(0xFF, 0xFF, 0xFF);
}
// Decode Banner if it exists
{
wxImage image;
if (memoryCard[card]->ReadBannerRGBA8(file_index, pxdata.data()))
{
image = wxImageFromMemoryRGBA(pxdata.data(), BANNER_WIDTH, IMAGE_HEIGHT);
}
else
{
// Use first frame of animation instead.
image = anim_img_strip.Size(wxSize(ANIM_FRAME_WIDTH, IMAGE_HEIGHT), wxPoint(0, 0));
}
images[i * 2] = list->Add(WxUtils::ScaleImageToBitmap(image, this, m_image_list_size));
}
images[i * 2 + 1] =
list->Add(WxUtils::ScaleImageToBitmap(anim_img_strip, this, m_image_list_size));
}
int pagesMax = (mcmSettings.usePages) ? (page[card] + 1) * itemsPerPage : 128;

View File

@ -131,5 +131,6 @@ private:
void OnRightClick(wxMouseEvent& event);
};
wxSize m_image_list_size;
CMemcardListCtrl* m_MemcardList[2];
};

View File

@ -12,6 +12,8 @@
ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list)
: wxDialog(parent, wxID_ANY, _("Select Game"))
{
const int space5 = FromDIP(5);
m_game_lbox =
new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &ChangeGameDialog::OnPick, this);
@ -22,8 +24,11 @@ ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const
ok_btn->Bind(wxEVT_BUTTON, &ChangeGameDialog::OnPick, this);
wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5);
szr->Add(ok_btn, 0, wxALL | wxALIGN_RIGHT, 5);
szr->AddSpacer(space5);
szr->Add(m_game_lbox, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr->AddSpacer(space5);
szr->Add(ok_btn, 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, space5);
szr->AddSpacer(space5);
SetSizerAndFit(szr);
SetFocus();

View File

@ -7,6 +7,7 @@
#include <wx/gauge.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include "Common/StringUtil.h"
@ -17,43 +18,54 @@ MD5Dialog::MD5Dialog(wxWindow* parent, NetPlayServer* server, std::vector<const
const std::string& game)
: wxDialog(parent, wxID_ANY, _("MD5 Checksum")), m_netplay_server(server)
{
Bind(wxEVT_CLOSE_WINDOW, &MD5Dialog::OnClose, this);
const int space5 = FromDIP(5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(new wxStaticText(this, wxID_ANY, _("Computing MD5 Checksum for:") + "\n" + game,
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL),
0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(new wxStaticText(this, wxID_ANY,
wxString::Format(_("Computing MD5 Checksum for:\n%s"), game),
wxDefaultPosition, wxDefaultSize,
wxALIGN_CENTRE_HORIZONTAL | wxST_NO_AUTORESIZE),
0, wxEXPAND | wxLEFT | wxRIGHT, space5);
for (const Player* player : players)
{
wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(
wxVERTICAL, this, player->name + " (p" + std::to_string(player->pid) + ")");
wxGauge* gauge = new wxGauge(this, wxID_ANY, 100);
wxGauge* gauge = new wxGauge(player_szr->GetStaticBox(), wxID_ANY, 100);
m_progress_bars[player->pid] = gauge;
player_szr->Add(gauge, 0, wxEXPAND | wxALL, 5);
m_result_labels[player->pid] =
new wxStaticText(this, wxID_ANY, _("Computing..."), wxDefaultPosition, wxSize(250, 20),
wxALIGN_CENTRE_HORIZONTAL);
new wxStaticText(player_szr->GetStaticBox(), wxID_ANY, _("Computing..."));
m_result_labels[player->pid]->SetSize(250, 15);
player_szr->Add(m_result_labels[player->pid], 0, wxALL, 5);
player_szr->AddSpacer(space5);
player_szr->Add(gauge, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
player_szr->AddSpacer(space5);
player_szr->Add(m_result_labels[player->pid], 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT,
space5);
player_szr->AddSpacer(space5);
player_szr->SetMinSize(FromDIP(wxSize(250, -1)));
main_sizer->Add(player_szr, 0, wxEXPAND | wxALL, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(player_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
}
m_final_result_label =
new wxStaticText(this, wxID_ANY,
" ", // so it takes space
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
main_sizer->Add(m_final_result_label, 1, wxALL, 5);
wxButton* close_btn = new wxButton(this, wxID_ANY, _("Close"));
close_btn->Bind(wxEVT_BUTTON, &MD5Dialog::OnCloseBtnPressed, this);
main_sizer->Add(close_btn, 0, wxEXPAND | wxALL, 5);
main_sizer->AddSpacer(space5);
main_sizer->Add(m_final_result_label, 1, wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(CreateStdDialogButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
SetSizerAndFit(main_sizer);
Bind(wxEVT_BUTTON, &MD5Dialog::OnCloseBtnPressed, this, wxID_CLOSE);
Bind(wxEVT_CLOSE_WINDOW, &MD5Dialog::OnClose, this);
SetFocus();
Center();
}
@ -65,6 +77,7 @@ void MD5Dialog::SetProgress(int pid, int progress)
m_progress_bars[pid]->SetValue(progress);
m_result_labels[pid]->SetLabel(_("Computing: ") + std::to_string(progress) + "%");
Layout();
Update();
}
@ -76,11 +89,12 @@ void MD5Dialog::SetResult(int pid, const std::string& result)
m_result_labels[pid]->SetLabel(result);
m_hashes.push_back(result);
if (m_hashes.size() <= 1)
return;
wxString label = AllHashesMatch() ? _("Hashes match!") : _("Hashes do not match.");
m_final_result_label->SetLabel(label);
if (m_hashes.size() > 1)
{
wxString label = AllHashesMatch() ? _("Hashes match!") : _("Hashes do not match.");
m_final_result_label->SetLabel(label);
}
Layout();
}
bool MD5Dialog::AllHashesMatch() const
@ -89,7 +103,7 @@ bool MD5Dialog::AllHashesMatch() const
m_hashes.end();
}
void MD5Dialog::OnClose(wxCloseEvent& event)
void MD5Dialog::OnClose(wxCloseEvent&)
{
m_netplay_server->AbortMD5();
}

View File

@ -5,6 +5,7 @@
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/choice.h>
#include <wx/gbsizer.h>
#include <wx/listbox.h>
#include <wx/notebook.h>
#include <wx/panel.h>
@ -41,50 +42,50 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
inifile.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay");
wxPanel* const panel = new wxPanel(this);
panel->Bind(wxEVT_CHAR_HOOK, &NetPlaySetupFrame::OnKeyDown, this);
CreateGUI();
SetIcons(WxUtils::GetDolphinIconBundle());
// top row
wxBoxSizer* const trav_szr = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL);
{
// Connection Config
wxStaticText* const connectiontype_lbl = new wxStaticText(
panel, wxID_ANY, _("Connection Type:"), wxDefaultPosition, wxSize(100, -1));
std::string temp;
netplay_section.Get("Nickname", &temp, "Player");
m_nickname_text->SetValue(StrToWxStr(temp));
m_direct_traversal = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1));
m_direct_traversal->Bind(wxEVT_CHOICE, &NetPlaySetupFrame::OnDirectTraversalChoice, this);
m_direct_traversal->Append(_("Direct Connection"));
m_direct_traversal->Append(_("Traversal Server"));
temp.clear();
netplay_section.Get("HostCode", &temp, "00000000");
m_connect_hashcode_text->SetValue(StrToWxStr(temp));
trav_szr->Add(connectiontype_lbl, 0, wxCENTER, 5);
trav_szr->AddSpacer(5);
trav_szr->Add(m_direct_traversal, 0, wxCENTER, 5);
temp.clear();
netplay_section.Get("Address", &temp, "127.0.0.1");
m_connect_ip_text->SetValue(StrToWxStr(temp));
m_trav_reset_btn = new wxButton(panel, wxID_ANY, _("Reset Traversal Settings"),
wxDefaultPosition, wxSize(-1, 25));
m_trav_reset_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnResetTraversal, this);
temp.clear();
netplay_section.Get("ConnectPort", &temp,
std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
m_connect_port_text->SetValue(StrToWxStr(temp));
trav_szr->AddSpacer(5);
temp.clear();
netplay_section.Get("HostPort", &temp, std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
m_host_port_text->SetValue(StrToWxStr(temp));
trav_szr->Add(m_trav_reset_btn, 0, wxRIGHT);
temp.clear();
if (netplay_section.Get("SelectedHostGame", &temp, ""))
m_game_lbox->SetStringSelection(StrToWxStr(temp));
// Nickname
wxStaticText* const nick_lbl =
new wxStaticText(panel, wxID_ANY, _("Nickname:"), wxDefaultPosition, wxSize(100, -1));
#ifdef USE_UPNP
bool use_upnp = false;
netplay_section.Get("UseUPNP", &use_upnp, false);
m_upnp_chk->SetValue(use_upnp);
#endif
std::string nickname;
netplay_section.Get("Nickname", &nickname, "Player");
unsigned int listen_port = 0;
netplay_section.Get("ListenPort", &listen_port, 0);
m_traversal_listen_port_enabled->SetValue(listen_port != 0);
m_traversal_listen_port->Enable(m_traversal_listen_port_enabled->IsChecked());
m_traversal_listen_port->SetValue(listen_port);
m_nickname_text =
new wxTextCtrl(panel, wxID_ANY, StrToWxStr(nickname), wxDefaultPosition, wxSize(150, -1));
nick_szr->Add(nick_lbl, 0, wxCENTER);
nick_szr->Add(m_nickname_text, 0, wxALL, 5);
std::string travChoice;
netplay_section.Get("TraversalChoice", &travChoice, "direct");
if (travChoice == "traversal")
temp.clear();
netplay_section.Get("TraversalChoice", &temp, "direct");
if (temp == "traversal")
{
m_direct_traversal->Select(TRAVERSAL_CHOICE);
}
@ -93,37 +94,96 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
m_direct_traversal->Select(DIRECT_CHOICE);
}
m_traversal_lbl = new wxStaticText(panel, wxID_ANY, GetTraversalLabelText(netplay_section));
m_traversal_lbl->SetLabelText(GetTraversalLabelText(netplay_section));
}
// tabs
m_notebook = new wxNotebook(panel, wxID_ANY);
wxPanel* const connect_tab = new wxPanel(m_notebook, wxID_ANY);
m_notebook->AddPage(connect_tab, _("Connect"));
wxPanel* const host_tab = new wxPanel(m_notebook, wxID_ANY);
m_notebook->AddPage(host_tab, _("Host"));
Center();
Show();
// Needs to be done last or it set up the spacing on the page correctly
wxCommandEvent ev;
OnDirectTraversalChoice(ev);
}
void NetPlaySetupFrame::CreateGUI()
{
const int space5 = FromDIP(5);
wxPanel* const panel = new wxPanel(this);
panel->Bind(wxEVT_CHAR_HOOK, &NetPlaySetupFrame::OnKeyDown, this);
// Connection Config
wxStaticText* const connectiontype_lbl = new wxStaticText(panel, wxID_ANY, _("Connection Type:"));
m_direct_traversal = new wxChoice(panel, wxID_ANY);
m_direct_traversal->Bind(wxEVT_CHOICE, &NetPlaySetupFrame::OnDirectTraversalChoice, this);
m_direct_traversal->Append(_("Direct Connection"));
m_direct_traversal->Append(_("Traversal Server"));
m_trav_reset_btn = new wxButton(panel, wxID_ANY, _("Reset Traversal Settings"));
m_trav_reset_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnResetTraversal, this);
// Nickname
wxStaticText* const nick_lbl = new wxStaticText(panel, wxID_ANY, _("Nickname:"));
m_nickname_text = new wxTextCtrl(panel, wxID_ANY, "Player");
m_traversal_lbl = new wxStaticText(panel, wxID_ANY, "Traversal Server");
wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit"));
quit_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnQuit, this);
wxGridBagSizer* top_sizer = new wxGridBagSizer(space5, space5);
top_sizer->Add(connectiontype_lbl, wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
top_sizer->Add(WxUtils::GiveMinSizeDIP(m_direct_traversal, wxSize(100, -1)), wxGBPosition(0, 1),
wxDefaultSpan, wxEXPAND);
top_sizer->Add(m_trav_reset_btn, wxGBPosition(0, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
top_sizer->Add(nick_lbl, wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
top_sizer->Add(WxUtils::GiveMinSizeDIP(m_nickname_text, wxSize(150, -1)), wxGBPosition(1, 1),
wxDefaultSpan, wxEXPAND);
m_notebook = CreateNotebookGUI(panel);
m_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &NetPlaySetupFrame::OnTabChanged, this);
// main sizer
wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
main_szr->AddSpacer(space5);
main_szr->Add(top_sizer, 0, wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(m_traversal_lbl, 0, wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(m_notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, space5);
main_szr->AddSpacer(space5);
main_szr->Add(quit_btn, 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
panel->SetSizerAndFit(main_szr);
main_szr->SetSizeHints(this);
}
wxNotebook* NetPlaySetupFrame::CreateNotebookGUI(wxWindow* parent)
{
const int space5 = FromDIP(5);
wxNotebook* const notebook = new wxNotebook(parent, wxID_ANY);
wxPanel* const connect_tab = new wxPanel(notebook, wxID_ANY);
notebook->AddPage(connect_tab, _("Connect"));
wxPanel* const host_tab = new wxPanel(notebook, wxID_ANY);
notebook->AddPage(host_tab, _("Host"));
// connect tab
{
m_ip_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Host Code :"));
std::string last_hash_code;
netplay_section.Get("HostCode", &last_hash_code, "00000000");
std::string last_ip_address;
netplay_section.Get("Address", &last_ip_address, "127.0.0.1");
m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(last_ip_address));
m_connect_hashcode_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(last_hash_code));
m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, "127.0.0.1");
m_connect_hashcode_text = new wxTextCtrl(connect_tab, wxID_ANY, "00000000");
// Will be overridden by OnDirectTraversalChoice, but is necessary
// so that both inputs do not take up space
m_connect_hashcode_text->Hide();
m_client_port_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Port :"));
// string? w/e
std::string port;
netplay_section.Get("ConnectPort", &port,
std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(port));
m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY,
std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, _("Connect"));
connect_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnJoin, this);
@ -139,19 +199,22 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
"Wiimote netplay is experimental and should not be expected to work.\n"));
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
top_szr->Add(m_ip_lbl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
top_szr->Add(m_connect_ip_text, 3);
top_szr->Add(m_connect_hashcode_text, 3);
top_szr->Add(m_client_port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5);
top_szr->Add(m_connect_port_text, 1);
top_szr->Add(m_ip_lbl, 0, wxALIGN_CENTER_VERTICAL);
top_szr->Add(m_connect_ip_text, 3, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
top_szr->Add(m_connect_hashcode_text, 3, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
top_szr->Add(m_client_port_lbl, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
top_szr->Add(m_connect_port_text, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL);
con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
con_szr->AddSpacer(space5);
con_szr->Add(top_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
con_szr->AddStretchSpacer(1);
con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5);
con_szr->AddSpacer(space5);
con_szr->Add(alert_lbl, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
con_szr->AddStretchSpacer(1);
con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5);
con_szr->AddSpacer(space5);
con_szr->Add(connect_btn, 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, space5);
con_szr->AddSpacer(space5);
connect_tab->SetSizerAndFit(con_szr);
}
@ -159,21 +222,13 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
// host tab
{
m_host_port_lbl = new wxStaticText(host_tab, wxID_ANY, _("Port :"));
// string? w/e
std::string port;
netplay_section.Get("HostPort", &port, std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, StrToWxStr(port));
m_host_port_text =
new wxTextCtrl(host_tab, wxID_ANY, std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
m_traversal_listen_port_enabled = new wxCheckBox(host_tab, wxID_ANY, _("Force Listen Port: "));
m_traversal_listen_port = new wxSpinCtrl(host_tab, wxID_ANY, "", wxDefaultPosition,
wxSize(80, -1), wxSP_ARROW_KEYS, 1, 65535);
unsigned int listen_port;
netplay_section.Get("ListenPort", &listen_port, 0);
m_traversal_listen_port_enabled->SetValue(listen_port != 0);
m_traversal_listen_port->Enable(m_traversal_listen_port_enabled->IsChecked());
m_traversal_listen_port->SetValue(listen_port);
wxDefaultSize, wxSP_ARROW_KEYS, 1, 65535);
m_traversal_listen_port->SetMinSize(WxUtils::GetTextWidgetMinSize(m_traversal_listen_port));
m_traversal_listen_port_enabled->Bind(wxEVT_CHECKBOX,
&NetPlaySetupFrame::OnTraversalListenPortChanged, this);
@ -187,63 +242,35 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
new wxListBox(host_tab, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &NetPlaySetupFrame::OnHost, this);
NetPlayDialog::FillWithGameNames(m_game_lbox, *game_list);
std::string last_hosted_game;
if (netplay_section.Get("SelectedHostGame", &last_hosted_game, ""))
m_game_lbox->SetStringSelection(last_hosted_game);
NetPlayDialog::FillWithGameNames(m_game_lbox, *m_game_list);
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
top_szr->Add(m_host_port_lbl, 0, wxCENTER | wxRIGHT, 5);
top_szr->Add(m_host_port_text, 0);
top_szr->Add(m_host_port_lbl, 0, wxALIGN_CENTER_VERTICAL);
top_szr->Add(m_host_port_text, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
#ifdef USE_UPNP
m_upnp_chk = new wxCheckBox(host_tab, wxID_ANY, _("Forward port (UPnP)"));
top_szr->Add(m_upnp_chk, 0, wxALL, 5);
top_szr->Add(m_upnp_chk, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
#endif
wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL);
bottom_szr->Add(m_traversal_listen_port_enabled, 0, wxCENTER | wxLEFT, 5);
bottom_szr->Add(m_traversal_listen_port, 0, wxCENTER, 0);
wxBoxSizer* const host_btn_szr = new wxBoxSizer(wxVERTICAL);
host_btn_szr->Add(host_btn, 0, wxCENTER | wxALIGN_RIGHT, 0);
bottom_szr->Add(host_btn_szr, 1, wxALL, 5);
bottom_szr->Add(m_traversal_listen_port_enabled, 0, wxALIGN_CENTER_VERTICAL);
bottom_szr->Add(m_traversal_listen_port, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
bottom_szr->AddStretchSpacer();
bottom_szr->Add(host_btn, 0, wxLEFT, space5);
wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL);
host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5);
host_szr->Add(bottom_szr, 0, wxEXPAND, 0);
// NOTE: Top row can disappear entirely
host_szr->Add(top_szr, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, space5);
host_szr->AddSpacer(space5);
host_szr->Add(m_game_lbox, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
host_szr->AddSpacer(space5);
host_szr->Add(bottom_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
host_szr->AddSpacer(space5);
host_tab->SetSizerAndFit(host_szr);
}
// bottom row
wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit"));
quit_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnQuit, this);
// main sizer
wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
main_szr->Add(trav_szr, 0, wxALL | wxALIGN_LEFT, 5);
main_szr->Add(nick_szr, 0, wxALL | wxALIGN_LEFT, 5);
main_szr->Add(m_traversal_lbl, 0, wxALL | wxALIGN_LEFT, 5);
main_szr->Add(m_notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, 5);
main_szr->Add(quit_btn, 0, wxALL | wxALIGN_RIGHT, 5);
panel->SetSizerAndFit(main_szr);
// Handle focus on tab changes
panel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &NetPlaySetupFrame::OnTabChanged, this);
// wxBoxSizer* const diag_szr = new wxBoxSizer(wxVERTICAL);
// diag_szr->Add(panel, 1, wxEXPAND);
// SetSizerAndFit(diag_szr);
main_szr->SetSizeHints(this);
Center();
Show();
// Needs to be done last or it set up the spacing on the page correctly
wxCommandEvent ev;
OnDirectTraversalChoice(ev);
return notebook;
}
NetPlaySetupFrame::~NetPlaySetupFrame()
@ -278,6 +305,10 @@ NetPlaySetupFrame::~NetPlaySetupFrame()
m_traversal_listen_port->GetValue() :
0);
#ifdef USE_UPNP
netplay_section.Set("UseUPNP", m_upnp_chk->GetValue(), false);
#endif
inifile.Save(dolphin_ini);
main_frame->g_NetPlaySetupDiag = nullptr;
}
@ -395,7 +426,7 @@ void NetPlaySetupFrame::OnDirectTraversalChoice(wxCommandEvent& event)
if (sel == TRAVERSAL_CHOICE)
{
m_traversal_lbl->Show();
m_traversal_lbl->SetLabelText(m_traversal_string);
m_trav_reset_btn->Show();
m_connect_hashcode_text->Show();
m_connect_ip_text->Hide();
@ -420,7 +451,7 @@ void NetPlaySetupFrame::OnDirectTraversalChoice(wxCommandEvent& event)
}
else
{
m_traversal_lbl->Hide();
m_traversal_lbl->SetLabel(wxEmptyString);
m_trav_reset_btn->Hide();
m_connect_hashcode_text->Hide();
m_connect_ip_text->Show();
@ -446,7 +477,19 @@ void NetPlaySetupFrame::OnDirectTraversalChoice(wxCommandEvent& event)
m_upnp_chk->Show();
#endif
}
m_connect_ip_text->GetParent()->Layout();
// wxWidgets' layout engine sucks. It only updates when a size event occurs so we
// have to manually invoke the layout system.
// Caveat: This only works if the new layout is not substantially different from the
// old one because otherwise the minimum sizes assigned by SetSizerAndFit won't make
// sense and the layout will break (overlapping widgets). You can't just SetSizeHints
// because that will change the current sizes as well as the minimum sizes, it's a mess.
for (wxWindow* tab : m_notebook->GetChildren())
tab->Layout();
// Because this is a wxFrame, not a dialog, everything is inside a wxPanel which
// is the only direct child of the frame.
GetChildren()[0]->Layout();
DispatchFocus();
}
@ -476,16 +519,8 @@ void NetPlaySetupFrame::OnTabChanged(wxCommandEvent& event)
// Propagate event
event.Skip();
// Delaying action so the first tab order element doesn't override the focus
m_notebook->Bind(wxEVT_IDLE, &NetPlaySetupFrame::OnAfterTabChange, this);
}
void NetPlaySetupFrame::OnAfterTabChange(wxIdleEvent&)
{
// Unbinding so we don't hog the idle event
m_notebook->Unbind(wxEVT_IDLE, &NetPlaySetupFrame::OnAfterTabChange, this);
DispatchFocus();
// Let the base class fiddle with the focus first then correct it afterwards
CallAfter(&NetPlaySetupFrame::DispatchFocus);
}
void NetPlaySetupFrame::DispatchFocus()

View File

@ -12,6 +12,7 @@ class CGameListCtrl;
class wxCheckBox;
class wxChoice;
class wxListBox;
class wxNotebook;
class wxSpinCtrl;
class wxStaticText;
class wxTextCtrl;
@ -29,7 +30,9 @@ private:
static constexpr int DIRECT_CHOICE = 0;
static constexpr int TRAVERSAL_CHOICE = 1;
void GetWindowRect(const IniFile::Section& section, wxRect* rect) const;
void CreateGUI();
wxNotebook* CreateNotebookGUI(wxWindow* parent);
void OnJoin(wxCommandEvent& event);
void OnHost(wxCommandEvent& event);
void DoJoin();
@ -40,7 +43,6 @@ private:
void OnTraversalListenPortChanged(wxCommandEvent& event);
void OnKeyDown(wxKeyEvent& event);
void OnTabChanged(wxCommandEvent& event);
void OnAfterTabChange(wxIdleEvent& event);
void DispatchFocus();
wxStaticText* m_ip_lbl;
@ -63,5 +65,6 @@ private:
wxCheckBox* m_upnp_chk;
#endif
wxString m_traversal_string;
const CGameListCtrl* const m_game_list;
};

View File

@ -4,6 +4,7 @@
#include <algorithm>
#include <cstddef>
#include <limits>
#include <sstream>
#include <string>
#include <tuple>
@ -21,6 +22,7 @@
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/spinctrl.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/textctrl.h>
@ -67,12 +69,52 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
m_host_copy_btn_is_retry(false), m_is_hosting(is_hosting), m_game_list(game_list)
{
Bind(wxEVT_THREAD, &NetPlayDialog::OnThread, this);
CreateGUI();
SetIcons(WxUtils::GetDolphinIconBundle());
Center();
// Remember the window size and position for NetWindow
{
IniFile inifile;
inifile.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay");
int winPosX, winPosY, winWidth, winHeight;
netplay_section.Get("NetWindowPosX", &winPosX, std::numeric_limits<int>::min());
netplay_section.Get("NetWindowPosY", &winPosY, std::numeric_limits<int>::min());
netplay_section.Get("NetWindowWidth", &winWidth, -1);
netplay_section.Get("NetWindowHeight", &winHeight, -1);
WxUtils::SetWindowSizeAndFitToScreen(this, wxPoint(winPosX, winPosY),
wxSize(winWidth, winHeight), GetSize());
}
}
void NetPlayDialog::CreateGUI()
{
const int space5 = FromDIP(5);
// NOTE: The design operates top down. Margins / padding are handled by the outermost
// sizers, this makes the design easier to change. Inner sizers should only pad between
// widgets, they should never have prepended or appended margins/spacers.
wxPanel* const panel = new wxPanel(this);
wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
main_szr->AddSpacer(space5);
main_szr->Add(CreateTopGUI(panel), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(CreateMiddleGUI(panel), 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(CreateBottomGUI(panel), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
panel->SetSizerAndFit(main_szr);
main_szr->SetSizeHints(this);
SetSize(FromDIP(wxSize(768, 768 - 128)));
}
m_game_btn = new wxButton(panel, wxID_ANY, StrToWxStr(m_selected_game).Prepend(_(" Game : ")),
wxSizer* NetPlayDialog::CreateTopGUI(wxWindow* parent)
{
m_game_btn = new wxButton(parent, wxID_ANY, _(" Game : ") + StrToWxStr(m_selected_game),
wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
if (m_is_hosting)
@ -80,11 +122,12 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
else
m_game_btn->Disable();
top_szr->Add(m_game_btn, 1, wxALL | wxEXPAND);
wxBoxSizer* top_szr = new wxBoxSizer(wxHORIZONTAL);
top_szr->Add(m_game_btn, 1, wxEXPAND);
if (m_is_hosting)
{
m_MD5_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1));
m_MD5_choice = new wxChoice(parent, wxID_ANY, wxDefaultPosition, FromDIP(wxSize(150, -1)));
m_MD5_choice->Bind(wxEVT_CHOICE, &NetPlayDialog::OnMD5ComputeRequested, this);
m_MD5_choice->Append(_("MD5 check..."));
m_MD5_choice->Append(_("Current game"));
@ -92,59 +135,89 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
m_MD5_choice->Append(_("SD card"));
m_MD5_choice->SetSelection(0);
top_szr->Add(m_MD5_choice, 0, wxALL);
top_szr->Add(m_MD5_choice, 0, wxALIGN_CENTER_VERTICAL);
}
// middle crap
return top_szr;
}
// chat
m_chat_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxSizer* NetPlayDialog::CreateMiddleGUI(wxWindow* parent)
{
const int space5 = FromDIP(5);
wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL);
mid_szr->Add(CreateChatGUI(parent), 1, wxEXPAND);
mid_szr->Add(CreatePlayerListGUI(parent), 0, wxEXPAND | wxLEFT, space5);
return mid_szr;
}
wxSizer* NetPlayDialog::CreateChatGUI(wxWindow* parent)
{
const int space5 = FromDIP(5);
wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, parent, _("Chat"));
parent = chat_szr->GetStaticBox();
m_chat_text = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_READONLY | wxTE_MULTILINE);
m_chat_msg_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxSize(-1, 25), wxTE_PROCESS_ENTER);
m_chat_msg_text = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxTE_PROCESS_ENTER);
m_chat_msg_text->Bind(wxEVT_TEXT_ENTER, &NetPlayDialog::OnChat, this);
m_chat_msg_text->SetMaxLength(2000);
wxButton* const chat_msg_btn =
new wxButton(panel, wxID_ANY, _("Send"), wxDefaultPosition, wxSize(-1, 26));
new wxButton(parent, wxID_ANY, _("Send"), wxDefaultPosition,
wxSize(-1, m_chat_msg_text->GetBestSize().GetHeight()));
chat_msg_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnChat, this);
wxBoxSizer* const chat_msg_szr = new wxBoxSizer(wxHORIZONTAL);
chat_msg_szr->Add(m_chat_msg_text, 1);
chat_msg_szr->Add(chat_msg_btn, 0);
// NOTE: Remember that fonts are configurable, setting sizes of anything that contains
// text in pixels is dangerous because the text may end up being clipped.
chat_msg_szr->Add(WxUtils::GiveMinSizeDIP(m_chat_msg_text, wxSize(-1, 25)), 1,
wxALIGN_CENTER_VERTICAL);
chat_msg_szr->Add(chat_msg_btn, 0, wxEXPAND);
wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Chat"));
chat_szr->Add(m_chat_text, 1, wxEXPAND);
chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, 5);
chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, space5);
return chat_szr;
}
m_player_lbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxSize(256, -1));
wxSizer* NetPlayDialog::CreatePlayerListGUI(wxWindow* parent)
{
const int space5 = FromDIP(5);
wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Players"));
wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, parent, _("Players"));
// Static box is a widget, new widgets should be children instead of siblings to avoid various
// flickering problems.
parent = player_szr->GetStaticBox();
m_player_lbox = new wxListBox(parent, wxID_ANY, wxDefaultPosition, FromDIP(wxSize(256, -1)), 0,
nullptr, wxLB_HSCROLL);
// player list
if (m_is_hosting && g_TraversalClient)
{
wxBoxSizer* const host_szr = new wxBoxSizer(wxHORIZONTAL);
m_host_type_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(76, -1));
m_host_type_choice = new wxChoice(parent, wxID_ANY, wxDefaultPosition, FromDIP(wxSize(76, -1)));
m_host_type_choice->Bind(wxEVT_CHOICE, &NetPlayDialog::OnChoice, this);
m_host_type_choice->Append(_("Room ID:"));
host_szr->Add(m_host_type_choice);
m_host_label = new wxStaticText(panel, wxID_ANY, "555.555.555.555:55555", wxDefaultPosition,
wxDefaultSize, wxST_NO_AUTORESIZE | wxALIGN_LEFT);
// Update() should fix this immediately.
m_host_label->SetLabel("");
host_szr->Add(m_host_label, 1, wxLEFT | wxCENTER, 5);
m_host_copy_btn = new wxButton(panel, wxID_ANY, _("Copy"));
m_host_copy_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnCopyIP, this);
m_host_copy_btn->Disable();
host_szr->Add(m_host_copy_btn, 0, wxLEFT | wxCENTER, 5);
player_szr->Add(host_szr, 0, wxEXPAND | wxBOTTOM, 5);
m_host_type_choice->Select(0);
m_host_label = new wxStaticText(parent, wxID_ANY, "555.555.555.555:55555", wxDefaultPosition,
wxDefaultSize, wxST_NO_AUTORESIZE);
// Update() should fix this immediately.
m_host_label->SetLabel("");
m_host_copy_btn = new wxButton(parent, wxID_ANY, _("Copy"));
m_host_copy_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnCopyIP, this);
m_host_copy_btn->Disable();
UpdateHostLabel();
wxBoxSizer* const host_szr = new wxBoxSizer(wxHORIZONTAL);
host_szr->Add(m_host_type_choice);
host_szr->Add(m_host_label, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
host_szr->Add(m_host_copy_btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
player_szr->Add(host_szr, 0, wxEXPAND, space5);
}
player_szr->Add(m_player_lbox, 1, wxEXPAND);
@ -152,59 +225,54 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
if (m_is_hosting)
{
m_player_lbox->Bind(wxEVT_LISTBOX, &NetPlayDialog::OnPlayerSelect, this);
m_kick_btn = new wxButton(panel, wxID_ANY, _("Kick Player"));
m_kick_btn = new wxButton(parent, wxID_ANY, _("Kick Player"));
m_kick_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnKick, this);
player_szr->Add(m_kick_btn, 0, wxEXPAND | wxTOP, 5);
m_kick_btn->Disable();
m_player_config_btn = new wxButton(panel, wxID_ANY, _("Assign Controller Ports"));
m_player_config_btn = new wxButton(parent, wxID_ANY, _("Assign Controller Ports"));
m_player_config_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnAssignPads, this);
player_szr->Add(m_player_config_btn, 0, wxEXPAND | wxTOP, 5);
player_szr->Add(m_kick_btn, 0, wxEXPAND | wxTOP, space5);
player_szr->Add(m_player_config_btn, 0, wxEXPAND | wxTOP, space5);
}
return player_szr;
}
wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL);
mid_szr->Add(chat_szr, 1, wxEXPAND | wxRIGHT, 5);
mid_szr->Add(player_szr, 0, wxEXPAND);
// bottom crap
wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit Netplay"));
quit_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnQuit, this);
wxSizer* NetPlayDialog::CreateBottomGUI(wxWindow* parent)
{
const int space5 = FromDIP(5);
wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL);
if (is_hosting)
if (m_is_hosting)
{
m_start_btn = new wxButton(panel, wxID_ANY, _("Start"));
m_start_btn = new wxButton(parent, wxID_ANY, _("Start"));
m_start_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnStart, this);
bottom_szr->Add(m_start_btn);
bottom_szr->Add(new wxStaticText(panel, wxID_ANY, _("Buffer:")), 0, wxLEFT | wxCENTER, 5);
wxStaticText* buffer_lbl = new wxStaticText(parent, wxID_ANY, _("Buffer:"));
wxSpinCtrl* const padbuf_spin =
new wxSpinCtrl(panel, wxID_ANY, std::to_string(INITIAL_PAD_BUFFER_SIZE), wxDefaultPosition,
wxSize(64, -1), wxSP_ARROW_KEYS, 0, 200, INITIAL_PAD_BUFFER_SIZE);
new wxSpinCtrl(parent, wxID_ANY, std::to_string(INITIAL_PAD_BUFFER_SIZE), wxDefaultPosition,
wxDefaultSize, wxSP_ARROW_KEYS, 0, 200, INITIAL_PAD_BUFFER_SIZE);
padbuf_spin->Bind(wxEVT_SPINCTRL, &NetPlayDialog::OnAdjustBuffer, this);
bottom_szr->AddSpacer(3);
bottom_szr->Add(padbuf_spin, 0, wxCENTER);
bottom_szr->AddSpacer(5);
m_memcard_write = new wxCheckBox(panel, wxID_ANY, _("Write to memcards/SD"));
bottom_szr->Add(m_memcard_write, 0, wxCENTER);
padbuf_spin->SetMinSize(WxUtils::GetTextWidgetMinSize(padbuf_spin));
m_memcard_write = new wxCheckBox(parent, wxID_ANY, _("Write to memcards/SD"));
bottom_szr->Add(m_start_btn, 0, wxALIGN_CENTER_VERTICAL);
bottom_szr->Add(buffer_lbl, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
bottom_szr->Add(padbuf_spin, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
bottom_szr->Add(m_memcard_write, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
bottom_szr->AddSpacer(space5);
}
bottom_szr->AddSpacer(5);
m_record_chkbox = new wxCheckBox(panel, wxID_ANY, _("Record inputs"));
bottom_szr->Add(m_record_chkbox, 0, wxCENTER);
m_record_chkbox = new wxCheckBox(parent, wxID_ANY, _("Record inputs"));
bottom_szr->AddStretchSpacer(1);
wxButton* quit_btn = new wxButton(parent, wxID_ANY, _("Quit Netplay"));
quit_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnQuit, this);
bottom_szr->Add(m_record_chkbox, 0, wxALIGN_CENTER_VERTICAL);
bottom_szr->AddStretchSpacer();
bottom_szr->Add(quit_btn);
// main sizer
wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
main_szr->Add(top_szr, 0, wxEXPAND | wxALL, 5);
main_szr->Add(mid_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, 5);
main_szr->Add(bottom_szr, 0, wxEXPAND | wxALL, 5);
panel->SetSizerAndFit(main_szr);
main_szr->SetSizeHints(this);
return bottom_szr;
}
NetPlayDialog::~NetPlayDialog()

View File

@ -19,6 +19,7 @@ class wxButton;
class wxCheckBox;
class wxChoice;
class wxListBox;
class wxSizer;
class wxStaticText;
class wxString;
class wxTextCtrl;
@ -101,6 +102,13 @@ public:
bool IsRecording() override;
private:
void CreateGUI();
wxSizer* CreateTopGUI(wxWindow* parent);
wxSizer* CreateMiddleGUI(wxWindow* parent);
wxSizer* CreateChatGUI(wxWindow* parent);
wxSizer* CreatePlayerListGUI(wxWindow* parent);
wxSizer* CreateBottomGUI(wxWindow* parent);
void OnChat(wxCommandEvent& event);
void OnQuit(wxCommandEvent& event);
void OnThread(wxThreadEvent& event);
@ -133,7 +141,7 @@ private:
wxStaticText* m_host_label;
wxChoice* m_host_type_choice;
wxButton* m_host_copy_btn;
wxChoice* m_MD5_choice;
wxChoice* m_MD5_choice = nullptr;
MD5Dialog* m_MD5_dialog = nullptr;
bool m_host_copy_btn_is_retry;
bool m_is_hosting;

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <wx/choice.h>
#include <wx/gbsizer.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
@ -10,79 +11,63 @@
#include "Core/NetPlayProto.h"
#include "Core/NetPlayServer.h"
#include "DolphinWX/NetPlay/PadMapDialog.h"
#include "DolphinWX/WxUtils.h"
PadMapDialog::PadMapDialog(wxWindow* parent, NetPlayServer* server, NetPlayClient* client)
: wxDialog(parent, wxID_ANY, _("Controller Ports")), m_pad_mapping(server->GetPadMapping()),
m_wii_mapping(server->GetWiimoteMapping()), m_player_list(client->GetPlayers())
{
wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL);
h_szr->AddSpacer(10);
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
wxGridBagSizer* pad_sizer = new wxGridBagSizer(space5, space10);
wxArrayString player_names;
player_names.Add(_("None"));
for (auto& player : m_player_list)
player_names.Add(player->name);
for (const auto& player : m_player_list)
player_names.Add(StrToWxStr(player->name));
for (unsigned int i = 0; i < 4; ++i)
{
wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL);
v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("GC Port ")) + (wxChar)('1' + i))), 1,
wxALIGN_CENTER_HORIZONTAL);
auto build_choice = [&](unsigned int base_idx, unsigned int idx, const PadMappingArray& mapping,
const wxString& port_name) {
pad_sizer->Add(new wxStaticText(this, wxID_ANY, wxString::Format("%s %d", port_name, idx + 1)),
wxGBPosition(0, base_idx + idx), wxDefaultSpan, wxALIGN_CENTER);
m_map_cbox[i] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names);
m_map_cbox[i]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this);
if (m_pad_mapping[i] == -1)
{
m_map_cbox[i]->Select(0);
}
else
{
for (unsigned int j = 0; j < m_player_list.size(); j++)
{
if (m_pad_mapping[i] == m_player_list[j]->pid)
m_map_cbox[i]->Select(j + 1);
}
}
v_szr->Add(m_map_cbox[i], 1);
h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20);
h_szr->AddSpacer(10);
}
for (unsigned int i = 0; i < 4; ++i)
{
wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL);
v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("Wiimote ")) + (wxChar)('1' + i))), 1,
wxALIGN_CENTER_HORIZONTAL);
m_map_cbox[i + 4] =
m_map_cbox[base_idx + idx] =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names);
m_map_cbox[i + 4]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this);
if (m_wii_mapping[i] == -1)
{
m_map_cbox[i + 4]->Select(0);
}
else
m_map_cbox[base_idx + idx]->Select(0);
m_map_cbox[base_idx + idx]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this);
if (mapping[idx] != -1)
{
for (unsigned int j = 0; j < m_player_list.size(); j++)
{
if (m_wii_mapping[i] == m_player_list[j]->pid)
m_map_cbox[i + 4]->Select(j + 1);
if (m_pad_mapping[idx] == m_player_list[j]->pid)
{
m_map_cbox[base_idx + idx]->Select(j + 1);
break;
}
}
}
// Combo boxes break on Windows when wxEXPAND-ed vertically but you can't control the
// direction of expansion in a grid sizer. Solution is to wrap in a box sizer.
wxBoxSizer* wrapper = new wxBoxSizer(wxHORIZONTAL);
wrapper->Add(m_map_cbox[base_idx + idx], 1, wxALIGN_CENTER_VERTICAL);
pad_sizer->Add(wrapper, wxGBPosition(1, base_idx + idx), wxDefaultSpan, wxEXPAND);
};
v_szr->Add(m_map_cbox[i + 4], 1);
h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20);
h_szr->AddSpacer(10);
for (unsigned int i = 0; i < 4; ++i)
{
// This looks a little weird but it's fine because we're using a grid bag sizer;
// we can add columns in any order.
build_choice(0, i, m_pad_mapping, _("GC Port"));
build_choice(4, i, m_wii_mapping, _("Wiimote"));
}
wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
main_szr->Add(h_szr);
main_szr->AddSpacer(5);
main_szr->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, 20);
main_szr->AddSpacer(5);
main_szr->AddSpacer(space10);
main_szr->Add(pad_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space10);
main_szr->AddSpacer(space10);
main_szr->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, space10);
main_szr->AddSpacer(space5);
SetSizerAndFit(main_szr);
SetFocus();
}

View File

@ -12,7 +12,9 @@
class NetPlayClient;
class NetPlayServer;
class Player;
class wxArrayString;
class wxChoice;
class wxSizer;
class PadMapDialog final : public wxDialog
{

View File

@ -52,7 +52,8 @@ void CPatchAddEdit::CreateGUIControls(int _selection)
itCurEntry = tempEntries.begin();
wxBoxSizer* sEditPatch = new wxBoxSizer(wxVERTICAL);
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
wxStaticText* EditPatchNameText = new wxStaticText(this, wxID_ANY, _("Name:"));
EditPatchName = new wxTextCtrl(this, wxID_ANY);
@ -89,32 +90,38 @@ void CPatchAddEdit::CreateGUIControls(int _selection)
EntryRemove->Disable();
wxBoxSizer* sEditPatchName = new wxBoxSizer(wxHORIZONTAL);
sEditPatchName->Add(EditPatchNameText, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
sEditPatchName->Add(EditPatchName, 1, wxEXPAND | wxALL, 5);
sEditPatch->Add(sEditPatchName, 0, wxEXPAND);
sEditPatchName->Add(EditPatchNameText, 0, wxALIGN_CENTER_VERTICAL);
sEditPatchName->Add(EditPatchName, 1, wxEXPAND | wxLEFT, space5);
sbEntry = new wxStaticBoxSizer(wxVERTICAL, this,
wxString::Format(_("Entry 1/%d"), (int)tempEntries.size()));
currentItem = 1;
wxGridBagSizer* sgEntry = new wxGridBagSizer(0, 0);
sgEntry->Add(EditPatchType, wxGBPosition(0, 0), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
sgEntry->Add(EditPatchOffsetText, wxGBPosition(1, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sgEntry->Add(EditPatchOffset, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
sgEntry->Add(EditPatchValueText, wxGBPosition(2, 0), wxGBSpan(1, 1),
wxALIGN_CENTER_VERTICAL | wxALL, 5);
sgEntry->Add(EditPatchValue, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(3, 1), wxEXPAND | wxALL, 5);
wxGridBagSizer* sgEntry = new wxGridBagSizer(space10, space10);
sgEntry->Add(EditPatchType, wxGBPosition(0, 0), wxGBSpan(1, 2), wxEXPAND);
sgEntry->Add(EditPatchOffsetText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sgEntry->Add(EditPatchOffset, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND);
sgEntry->Add(EditPatchValueText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sgEntry->Add(EditPatchValue, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND);
sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(3, 1), wxEXPAND);
sgEntry->AddGrowableCol(1);
wxBoxSizer* sEntryAddRemove = new wxBoxSizer(wxHORIZONTAL);
sEntryAddRemove->Add(EntryAdd, 0, wxALL, 5);
sEntryAddRemove->Add(EntryRemove, 0, wxALL, 5);
sbEntry->Add(sgEntry, 0, wxEXPAND);
sbEntry->Add(sEntryAddRemove, 0, wxEXPAND);
sEntryAddRemove->Add(EntryAdd, 0, wxALIGN_CENTER_VERTICAL);
sEntryAddRemove->Add(EntryRemove, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
sbEntry->AddSpacer(space5);
sbEntry->Add(sgEntry, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbEntry->AddSpacer(space5);
sbEntry->Add(sEntryAddRemove, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbEntry->AddSpacer(space5);
sEditPatch->Add(sbEntry, 0, wxEXPAND | wxALL, 5);
sEditPatch->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
wxBoxSizer* sEditPatch = new wxBoxSizer(wxVERTICAL);
sEditPatch->AddSpacer(space5);
sEditPatch->Add(sEditPatchName, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sEditPatch->AddSpacer(space5);
sEditPatch->Add(sbEntry, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sEditPatch->AddSpacer(space5);
sEditPatch->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sEditPatch->AddSpacer(space5);
SetSizerAndFit(sEditPatch);
SetFocus();
}

View File

@ -2,15 +2,13 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <math.h>
#include <unordered_map>
#include <cmath>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
@ -37,45 +35,54 @@ PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::
// Create our UI classes
const PostProcessingShaderConfiguration::ConfigMap& config_map = m_post_processor->GetOptions();
std::vector<std::unique_ptr<ConfigGrouping>> config_groups;
config_groups.reserve(config_map.size());
m_config_map.reserve(config_map.size());
for (const auto& it : config_map)
{
std::unique_ptr<ConfigGrouping> group;
if (it.second.m_type ==
PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL)
{
ConfigGrouping* group =
new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_TOGGLE, it.second.m_gui_name,
it.first, it.second.m_dependent_option, &it.second);
m_config_map[it.first] = group;
group = std::make_unique<ConfigGrouping>(ConfigGrouping::WidgetType::TYPE_TOGGLE,
it.second.m_gui_name, it.first,
it.second.m_dependent_option, &it.second);
}
else
{
ConfigGrouping* group =
new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_SLIDER, it.second.m_gui_name,
it.first, it.second.m_dependent_option, &it.second);
m_config_map[it.first] = group;
group = std::make_unique<ConfigGrouping>(ConfigGrouping::WidgetType::TYPE_SLIDER,
it.second.m_gui_name, it.first,
it.second.m_dependent_option, &it.second);
}
m_config_map[it.first] = group.get();
config_groups.emplace_back(std::move(group));
}
// Arrange our vectors based on dependency
for (const auto& it : m_config_map)
for (auto& group : config_groups)
{
const std::string parent_name = it.second->GetParent();
if (parent_name.size())
const std::string& parent_name = group->GetParent();
if (parent_name.empty())
{
// Since it depends on a different object, push it to a parent's object
m_config_map[parent_name]->AddChild(m_config_map[it.first]);
// It doesn't have a parent, just push it to the vector
m_config_groups.emplace_back(std::move(group));
}
else
{
// It doesn't have a child, just push it to the vector
m_config_groups.push_back(m_config_map[it.first]);
// Since it depends on a different object, push it to a parent's object
m_config_map[parent_name]->AddChild(std::move(group));
}
}
config_groups.clear(); // Full of null unique_ptrs now
config_groups.shrink_to_fit();
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
// Generate our UI
wxNotebook* const notebook = new wxNotebook(this, wxID_ANY);
wxPanel* const page_general = new wxPanel(notebook);
wxFlexGridSizer* const szr_general = new wxFlexGridSizer(2, 5, 5);
wxFlexGridSizer* const szr_general = new wxFlexGridSizer(2, space5, space5);
// Now let's actually populate our window with our information
bool add_general_page = false;
@ -85,7 +92,8 @@ PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::
{
// Options with children get their own tab
wxPanel* const page_option = new wxPanel(notebook);
wxFlexGridSizer* const szr_option = new wxFlexGridSizer(2, 10, 5);
wxBoxSizer* const wrap_sizer = new wxBoxSizer(wxVERTICAL);
wxFlexGridSizer* const szr_option = new wxFlexGridSizer(2, space10, space5);
it->GenerateUI(this, page_option, szr_option);
// Add all the children
@ -93,8 +101,11 @@ PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::
{
child->GenerateUI(this, page_option, szr_option);
}
page_option->SetSizerAndFit(szr_option);
notebook->AddPage(page_option, _(it->GetGUIName()));
wrap_sizer->AddSpacer(space5);
wrap_sizer->Add(szr_option, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
wrap_sizer->AddSpacer(space5);
page_option->SetSizerAndFit(wrap_sizer);
notebook->AddPage(page_option, it->GetGUIName());
}
else
{
@ -110,20 +121,30 @@ PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::
if (add_general_page)
{
page_general->SetSizerAndFit(szr_general);
wxBoxSizer* const wrap_sizer = new wxBoxSizer(wxVERTICAL);
wrap_sizer->AddSpacer(space5);
wrap_sizer->Add(szr_general, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
wrap_sizer->AddSpacer(space5);
page_general->SetSizerAndFit(wrap_sizer);
notebook->InsertPage(0, page_general, _("General"));
}
// Close Button
wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close"));
btn_close->Bind(wxEVT_BUTTON, &PostProcessingConfigDiag::Event_ClickClose, this);
Bind(wxEVT_CLOSE_WINDOW, &PostProcessingConfigDiag::Event_Close, this);
wxStdDialogButtonSizer* const btn_strip = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
btn_strip->GetAffirmativeButton()->SetLabel(_("Close"));
SetEscapeId(wxID_OK); // Treat closing the window by 'X' or hitting escape as 'OK'
wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5);
szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5);
szr_main->AddSpacer(space5);
szr_main->Add(notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_main->AddSpacer(space5);
szr_main->Add(btn_strip, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_main->AddSpacer(space5);
szr_main->SetMinSize(FromDIP(wxSize(400, -1)));
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(szr_main);
Center();
SetFocus();
@ -145,7 +166,7 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
{
if (m_type == WidgetType::TYPE_TOGGLE)
{
m_option_checkbox = new wxCheckBox(parent, wxID_ANY, _(m_gui_name));
m_option_checkbox = new wxCheckBox(parent, wxID_ANY, m_gui_name);
m_option_checkbox->SetValue(m_config_option->m_bool_value);
m_option_checkbox->Bind(wxEVT_CHECKBOX, &PostProcessingConfigDiag::Event_CheckBox, dialog,
wxID_ANY, wxID_ANY, new UserEventData(m_option));
@ -162,8 +183,8 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
else
vector_size = m_config_option->m_float_values.size();
wxFlexGridSizer* const szr_values = new wxFlexGridSizer(vector_size + 1, 0, 0);
wxStaticText* const option_static_text = new wxStaticText(parent, wxID_ANY, _(m_gui_name));
wxFlexGridSizer* const szr_values = new wxFlexGridSizer(vector_size + 1);
wxStaticText* const option_static_text = new wxStaticText(parent, wxID_ANY, m_gui_name);
sizer->Add(option_static_text);
for (size_t i = 0; i < vector_size; ++i)
@ -185,7 +206,7 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
// This may not be 100% spot on accurate since developers can have odd stepping intervals
// set.
// Round up so if it is outside our range, then set it to the minimum or maximum
steps = ceil(range / (double)m_config_option->m_integer_step_values[i]);
steps = std::ceil(range / (double)m_config_option->m_integer_step_values[i]);
// Default value is just the currently set value here
current_value = m_config_option->m_integer_values[i];
@ -196,7 +217,7 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
// Same as above but with floats
float range =
m_config_option->m_float_max_values[i] - m_config_option->m_float_min_values[i];
steps = ceil(range / m_config_option->m_float_step_values[i]);
steps = std::ceil(range / m_config_option->m_float_step_values[i]);
// We need to convert our default float value from a float to the nearest step value range
current_value =
@ -204,8 +225,9 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
string_value = std::to_string(m_config_option->m_float_values[i]);
}
wxSlider* slider = new wxSlider(parent, wxID_ANY, current_value, 0, steps, wxDefaultPosition,
wxSize(200, -1), wxSL_HORIZONTAL | wxSL_BOTTOM);
DolphinSlider* slider =
new DolphinSlider(parent, wxID_ANY, current_value, 0, steps, wxDefaultPosition,
parent->FromDIP(wxSize(200, -1)), wxSL_HORIZONTAL | wxSL_BOTTOM);
wxTextCtrl* text_ctrl = new wxTextCtrl(parent, wxID_ANY, string_value);
// Disable the textctrl, it's only there to show the absolute value from the slider
@ -222,18 +244,18 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
if (vector_size == 1)
{
szr_values->Add(m_option_sliders[0], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
szr_values->Add(m_option_text_ctrls[0]);
szr_values->Add(m_option_sliders[0], 0, wxALIGN_CENTER_VERTICAL);
szr_values->Add(m_option_text_ctrls[0], 0, wxALIGN_CENTER_VERTICAL);
sizer->Add(szr_values);
}
else
{
wxFlexGridSizer* const szr_inside = new wxFlexGridSizer(2, 0, 0);
wxFlexGridSizer* const szr_inside = new wxFlexGridSizer(2);
for (size_t i = 0; i < vector_size; ++i)
{
szr_inside->Add(m_option_sliders[i], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
szr_inside->Add(m_option_text_ctrls[i]);
szr_inside->Add(m_option_sliders[i], 0, wxALIGN_CENTER_VERTICAL);
szr_inside->Add(m_option_text_ctrls[i], 0, wxALIGN_CENTER_VERTICAL);
}
szr_values->Add(szr_inside);
@ -313,13 +335,3 @@ void PostProcessingConfigDiag::Event_Slider(wxCommandEvent& ev)
}
ev.Skip();
}
void PostProcessingConfigDiag::Event_ClickClose(wxCommandEvent&)
{
Close();
}
void PostProcessingConfigDiag::Event_Close(wxCloseEvent& ev)
{
EndModal(wxID_OK);
}

View File

@ -4,14 +4,16 @@
#pragma once
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <wx/dialog.h>
#include <wx/slider.h>
#include <wx/textctrl.h>
#include "DolphinWX/DolphinSlider.h"
#include "VideoCommon/PostProcessing.h"
class wxButton;
@ -54,9 +56,12 @@ private:
{
}
void AddChild(ConfigGrouping* child) { m_children.push_back(child); }
void AddChild(std::unique_ptr<ConfigGrouping>&& child)
{
m_children.emplace_back(std::move(child));
}
bool HasChildren() { return m_children.size() != 0; }
std::vector<ConfigGrouping*>& GetChildren() { return m_children; }
const std::vector<std::unique_ptr<ConfigGrouping>>& GetChildren() { return m_children; }
// Gets the string that is shown in the UI for the option
const std::string& GetGUIName() { return m_gui_name; }
// Gets the option name for use in the shader
@ -86,21 +91,19 @@ private:
// For TYPE_SLIDER
// Can have up to 4
std::vector<wxSlider*> m_option_sliders;
std::vector<DolphinSlider*> m_option_sliders;
std::vector<wxTextCtrl*> m_option_text_ctrls;
std::vector<ConfigGrouping*> m_children;
std::vector<std::unique_ptr<ConfigGrouping>> m_children;
};
// WX UI things
void Event_Close(wxCloseEvent&);
void Event_ClickClose(wxCommandEvent&);
void Event_Slider(wxCommandEvent& ev);
void Event_CheckBox(wxCommandEvent& ev);
const std::string& m_shader;
PostProcessingShaderConfiguration* m_post_processor;
std::map<std::string, ConfigGrouping*> m_config_map;
std::vector<ConfigGrouping*> m_config_groups;
std::unordered_map<std::string, ConfigGrouping*> m_config_map;
std::vector<std::unique_ptr<ConfigGrouping>> m_config_groups;
};

View File

@ -36,11 +36,12 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
wxString(wxString::Format(_("Dolphin %s Graphics Configuration"), title)))
{
VideoConfig& vconfig = g_Config;
vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
wxNotebook* const notebook = new wxNotebook(this, wxID_ANY);
const int space5 = FromDIP(5);
// -- GENERAL --
{
wxPanel* const page_general = new wxPanel(notebook);
@ -51,9 +52,11 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
{
wxStaticBoxSizer* const group_rendering =
new wxStaticBoxSizer(wxVERTICAL, page_general, _("Rendering"));
szr_general->Add(group_rendering, 0, wxEXPAND | wxALL, 5);
wxGridSizer* const szr_rendering = new wxGridSizer(2, 5, 5);
group_rendering->Add(szr_rendering, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_general->AddSpacer(space5);
szr_general->Add(group_rendering, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
wxGridSizer* const szr_rendering = new wxGridSizer(2, space5, space5);
group_rendering->Add(szr_rendering, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_rendering->AddSpacer(space5);
// backend
wxStaticText* const label_backend = new wxStaticText(page_general, wxID_ANY, _("Backend:"));
@ -68,8 +71,8 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
choice_backend->SetStringSelection(StrToWxStr(g_video_backend->GetName()));
choice_backend->Bind(wxEVT_CHOICE, &SoftwareVideoConfigDialog::Event_Backend, this);
szr_rendering->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5);
szr_rendering->Add(choice_backend, 1, 0, 0);
szr_rendering->Add(label_backend, 0, wxALIGN_CENTER_VERTICAL);
szr_rendering->Add(choice_backend, 0, wxALIGN_CENTER_VERTICAL);
if (Core::GetState() != Core::CORE_UNINITIALIZED)
{
@ -86,9 +89,11 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
{
wxStaticBoxSizer* const group_info =
new wxStaticBoxSizer(wxVERTICAL, page_general, _("Overlay Information"));
szr_general->Add(group_info, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
wxGridSizer* const szr_info = new wxGridSizer(2, 5, 5);
group_info->Add(szr_info, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_general->AddSpacer(space5);
szr_general->Add(group_info, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
wxGridSizer* const szr_info = new wxGridSizer(2, space5, space5);
group_info->Add(szr_info, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_info->AddSpacer(space5);
szr_info->Add(
new SettingCheckBox(page_general, _("Various Statistics"), "", vconfig.bOverlayStats));
@ -98,9 +103,11 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
{
wxStaticBoxSizer* const group_utility =
new wxStaticBoxSizer(wxVERTICAL, page_general, _("Utility"));
szr_general->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5);
group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_general->AddSpacer(space5);
szr_general->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
wxGridSizer* const szr_utility = new wxGridSizer(2, space5, space5);
group_utility->Add(szr_utility, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_utility->AddSpacer(space5);
szr_utility->Add(
new SettingCheckBox(page_general, _("Dump Textures"), "", vconfig.bDumpTextures));
@ -110,10 +117,12 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
// - debug only
wxStaticBoxSizer* const group_debug_only_utility =
new wxStaticBoxSizer(wxHORIZONTAL, page_general, _("Debug Only"));
group_utility->Add(group_debug_only_utility, 0, wxEXPAND | wxBOTTOM, 5);
wxGridSizer* const szr_debug_only_utility = new wxGridSizer(2, 5, 5);
group_debug_only_utility->Add(szr_debug_only_utility, 1,
wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
group_utility->Add(group_debug_only_utility, 0, wxEXPAND);
group_utility->AddSpacer(space5);
wxGridSizer* const szr_debug_only_utility = new wxGridSizer(2, space5, space5);
group_debug_only_utility->AddSpacer(space5);
group_debug_only_utility->Add(szr_debug_only_utility, 0, wxEXPAND | wxBOTTOM, space5);
group_debug_only_utility->AddSpacer(space5);
szr_debug_only_utility->Add(
new SettingCheckBox(page_general, _("Dump TEV Stages"), "", vconfig.bDumpTevStages));
@ -125,23 +134,33 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
{
wxStaticBoxSizer* const group_misc =
new wxStaticBoxSizer(wxVERTICAL, page_general, _("Drawn Object Range"));
szr_general->Add(group_misc, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, 5, 5);
group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_general->AddSpacer(space5);
szr_general->Add(group_misc, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, space5, space5);
group_misc->Add(szr_misc, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_misc->AddSpacer(space5);
szr_misc->Add(
new IntegerSetting<int>(page_general, _("Start"), vconfig.drawStart, 0, 100000));
szr_misc->Add(new IntegerSetting<int>(page_general, _("End"), vconfig.drawEnd, 0, 100000));
}
szr_general->AddSpacer(space5);
page_general->SetSizerAndFit(szr_general);
}
wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5);
szr_main->Add(new wxButton(this, wxID_OK, _("Close"), wxDefaultPosition), 0,
wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5);
wxStdDialogButtonSizer* const btn_sizer = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
btn_sizer->GetAffirmativeButton()->SetLabel(_("Close"));
wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
szr_main->AddSpacer(space5);
szr_main->Add(notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_main->AddSpacer(space5);
szr_main->Add(btn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_main->AddSpacer(space5);
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(szr_main);
Center();
SetFocus();

View File

@ -2,6 +2,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cstddef>
#include <wx/bitmap.h>
#include <wx/checkbox.h>
@ -23,7 +25,9 @@
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h"
#include "Core/Movie.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/TASInputDlg.h"
#include "DolphinWX/WxUtils.h"
#include "InputCommon/GCPadStatus.h"
#include "InputCommon/InputConfig.h"
@ -63,37 +67,38 @@ void TASInputDlg::CreateBaseLayout()
m_controls[0] = &m_main_stick.x_cont;
m_controls[1] = &m_main_stick.y_cont;
m_a = CreateButton("A");
m_a = CreateButton(_("A"));
m_a.checkbox->SetClientData(&m_a);
m_b = CreateButton("B");
m_b = CreateButton(_("B"));
m_b.checkbox->SetClientData(&m_b);
m_dpad_up = CreateButton("Up");
m_dpad_up = CreateButton(_("Up"));
m_dpad_up.checkbox->SetClientData(&m_dpad_up);
m_dpad_right = CreateButton("Right");
m_dpad_right = CreateButton(_("Right"));
m_dpad_right.checkbox->SetClientData(&m_dpad_right);
m_dpad_down = CreateButton("Down");
m_dpad_down = CreateButton(_("Down"));
m_dpad_down.checkbox->SetClientData(&m_dpad_down);
m_dpad_left = CreateButton("Left");
m_dpad_left = CreateButton(_("Left"));
m_dpad_left.checkbox->SetClientData(&m_dpad_left);
m_buttons_dpad = new wxGridSizer(3);
m_buttons_dpad->AddSpacer(20);
const int space20 = FromDIP(20);
m_buttons_dpad->Add(space20, space20);
m_buttons_dpad->Add(m_dpad_up.checkbox);
m_buttons_dpad->AddSpacer(20);
m_buttons_dpad->Add(space20, space20);
m_buttons_dpad->Add(m_dpad_left.checkbox);
m_buttons_dpad->AddSpacer(20);
m_buttons_dpad->Add(space20, space20);
m_buttons_dpad->Add(m_dpad_right.checkbox);
m_buttons_dpad->AddSpacer(20);
m_buttons_dpad->Add(space20, space20);
m_buttons_dpad->Add(m_dpad_down.checkbox);
m_buttons_dpad->AddSpacer(20);
m_buttons_dpad->Add(space20, space20);
}
const int TASInputDlg::m_gc_pad_buttons_bitmask[12] = {
static constexpr int s_gc_pad_buttons_bitmask[12] = {
PAD_BUTTON_DOWN, PAD_BUTTON_UP, PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT,
PAD_BUTTON_A, PAD_BUTTON_B, PAD_BUTTON_X, PAD_BUTTON_Y,
PAD_TRIGGER_Z, PAD_TRIGGER_L, PAD_TRIGGER_R, PAD_BUTTON_START};
const int TASInputDlg::m_wii_buttons_bitmask[11] = {
static constexpr int s_wii_buttons_bitmask[11] = {
WiimoteEmu::Wiimote::PAD_DOWN, WiimoteEmu::Wiimote::PAD_UP,
WiimoteEmu::Wiimote::PAD_LEFT, WiimoteEmu::Wiimote::PAD_RIGHT,
WiimoteEmu::Wiimote::BUTTON_A, WiimoteEmu::Wiimote::BUTTON_B,
@ -102,7 +107,7 @@ const int TASInputDlg::m_wii_buttons_bitmask[11] = {
WiimoteEmu::Wiimote::BUTTON_HOME,
};
const int TASInputDlg::m_cc_buttons_bitmask[15] = {
static constexpr int s_cc_buttons_bitmask[15] = {
WiimoteEmu::Classic::PAD_DOWN, WiimoteEmu::Classic::PAD_UP,
WiimoteEmu::Classic::PAD_LEFT, WiimoteEmu::Classic::PAD_RIGHT,
WiimoteEmu::Classic::BUTTON_A, WiimoteEmu::Classic::BUTTON_B,
@ -113,13 +118,11 @@ const int TASInputDlg::m_cc_buttons_bitmask[15] = {
WiimoteEmu::Classic::BUTTON_HOME,
};
const std::string TASInputDlg::m_cc_button_names[] = {
"Down", "Up", "Left", "Right", "A", "B", "X", "Y", "+", "-", "L", "R", "ZR", "ZL", "Home"};
void TASInputDlg::CreateWiiLayout(int num)
{
if (m_has_layout)
return;
const int space5 = FromDIP(5);
CreateBaseLayout();
@ -142,23 +145,17 @@ void TASInputDlg::CreateWiiLayout(int num)
wxStaticBoxSizer* const axisBox =
CreateAccelLayout(&m_x_cont, &m_y_cont, &m_z_cont, _("Orientation"));
wxStaticBoxSizer* const m_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
wxGridSizer* const m_buttons_grid = new wxGridSizer(4);
m_plus = CreateButton("+");
m_plus = CreateButton(_("+"));
m_plus.checkbox->SetClientData(&m_plus);
m_minus = CreateButton("-");
m_minus = CreateButton(_("-"));
m_minus.checkbox->SetClientData(&m_minus);
m_one = CreateButton("1");
m_one = CreateButton(_("1"));
m_one.checkbox->SetClientData(&m_one);
m_two = CreateButton("2");
m_two = CreateButton(_("2"));
m_two.checkbox->SetClientData(&m_two);
m_home = CreateButton("Home");
m_home = CreateButton(_("Home"));
m_home.checkbox->SetClientData(&m_home);
m_main_szr = new wxBoxSizer(wxVERTICAL);
m_wiimote_szr = new wxBoxSizer(wxHORIZONTAL);
m_ext_szr = new wxBoxSizer(wxHORIZONTAL);
m_cc_szr = CreateCCLayout();
if (Core::IsRunning())
@ -196,12 +193,10 @@ void TASInputDlg::CreateWiiLayout(int num)
wxStaticBoxSizer* const nunchukaxisBox =
CreateAccelLayout(&m_nx_cont, &m_ny_cont, &m_nz_cont, _("Nunchuk orientation"));
m_c = CreateButton("C");
m_c = CreateButton(_("C"));
m_c.checkbox->SetClientData(&m_c);
m_z = CreateButton("Z");
m_z = CreateButton(_("Z"));
m_z.checkbox->SetClientData(&m_z);
m_ext_szr->Add(m_c_stick_szr, 0, wxLEFT | wxBOTTOM | wxRIGHT, 5);
m_ext_szr->Add(nunchukaxisBox);
for (Control* const control : m_controls)
{
@ -209,21 +204,35 @@ void TASInputDlg::CreateWiiLayout(int num)
control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this);
}
m_ext_szr = new wxBoxSizer(wxHORIZONTAL);
m_ext_szr->Add(m_c_stick_szr, 0, wxBOTTOM, space5);
m_ext_szr->AddSpacer(space5);
m_ext_szr->Add(nunchukaxisBox, 0, wxBOTTOM, space5);
wxGridSizer* const buttons_grid = new wxGridSizer(4);
for (unsigned int i = 4; i < ArraySize(m_buttons); ++i)
if (m_buttons[i] != nullptr)
m_buttons_grid->Add(m_buttons[i]->checkbox);
m_buttons_grid->AddSpacer(5);
buttons_grid->Add(m_buttons[i]->checkbox);
buttons_grid->Add(space5, space5);
m_buttons_box->Add(m_buttons_grid);
m_buttons_box->Add(m_buttons_dpad);
wxStaticBoxSizer* const buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
buttons_box->Add(buttons_grid);
buttons_box->Add(m_buttons_dpad, 0, wxTOP, space5);
m_wiimote_szr->Add(m_main_stick_szr, 0, wxALL, 5);
m_wiimote_szr->Add(axisBox, 0, wxTOP | wxRIGHT, 5);
m_wiimote_szr->Add(m_buttons_box, 0, wxTOP | wxRIGHT, 5);
m_main_szr->Add(m_wiimote_szr);
m_main_szr->Add(m_ext_szr);
m_main_szr->Add(m_cc_szr);
m_wiimote_szr = new wxBoxSizer(wxHORIZONTAL);
m_wiimote_szr->AddSpacer(space5);
m_wiimote_szr->Add(m_main_stick_szr);
m_wiimote_szr->Add(axisBox, 0, wxLEFT, space5);
m_wiimote_szr->Add(buttons_box, 0, wxLEFT, space5);
m_wiimote_szr->AddSpacer(space5);
// NOTE: Not all of these are visible at the same time.
m_main_szr = new wxBoxSizer(wxVERTICAL);
m_main_szr->Add(m_wiimote_szr, 0, wxTOP | wxBOTTOM, space5);
m_main_szr->Add(m_ext_szr, 0, wxLEFT | wxRIGHT, space5);
m_main_szr->Add(m_cc_szr, 0, wxLEFT | wxRIGHT, space5);
SetSizer(m_main_szr);
HandleExtensionChange();
FinishLayout();
}
@ -239,11 +248,12 @@ void TASInputDlg::FinishLayout()
wxBoxSizer* TASInputDlg::CreateCCLayout()
{
wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
for (size_t i = 0; i < ArraySize(m_cc_buttons); ++i)
const std::array<wxString, 15> button_names{{_("Down"), _("Up"), _("Left"), _("Right"), _("A"),
_("B"), _("X"), _("Y"), _("+"), _("-"), _("L"),
_("R"), _("ZR"), _("ZL"), _("Home")}};
for (size_t i = 0; i < button_names.size(); ++i)
{
m_cc_buttons[i] = CreateButton(m_cc_button_names[i]);
m_cc_buttons[i] = CreateButton(button_names[i]);
m_cc_buttons[i].checkbox->SetClientData(&m_cc_buttons[i]);
}
@ -265,6 +275,9 @@ wxBoxSizer* TASInputDlg::CreateCCLayout()
m_cc_l = CreateControl(wxSL_VERTICAL, -1, 100, false, 31, 0);
m_cc_r = CreateControl(wxSL_VERTICAL, -1, 100, false, 31, 0);
const int space5 = FromDIP(5);
const int space20 = FromDIP(20);
wxStaticBoxSizer* const shoulder_box =
new wxStaticBoxSizer(wxHORIZONTAL, this, _("Shoulder Buttons"));
shoulder_box->Add(m_cc_l.slider, 0, wxALIGN_CENTER_VERTICAL);
@ -272,32 +285,37 @@ wxBoxSizer* TASInputDlg::CreateCCLayout()
shoulder_box->Add(m_cc_r.slider, 0, wxALIGN_CENTER_VERTICAL);
shoulder_box->Add(m_cc_r.text, 0, wxALIGN_CENTER_VERTICAL);
wxStaticBoxSizer* const cc_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
wxGridSizer* const cc_buttons_grid = new wxGridSizer(4);
wxGridSizer* const cc_buttons_dpad = new wxGridSizer(3);
cc_buttons_dpad->AddSpacer(20);
cc_buttons_dpad->Add(space20, space20);
cc_buttons_dpad->Add(m_cc_buttons[1].checkbox);
cc_buttons_dpad->AddSpacer(20);
cc_buttons_dpad->Add(space20, space20);
cc_buttons_dpad->Add(m_cc_buttons[2].checkbox);
cc_buttons_dpad->AddSpacer(20);
cc_buttons_dpad->Add(space20, space20);
cc_buttons_dpad->Add(m_cc_buttons[3].checkbox);
cc_buttons_dpad->AddSpacer(20);
cc_buttons_dpad->Add(space20, space20);
cc_buttons_dpad->Add(m_cc_buttons[0].checkbox);
cc_buttons_dpad->AddSpacer(20);
cc_buttons_dpad->Add(space20, space20);
for (auto button : m_cc_buttons)
wxGridSizer* const cc_buttons_grid = new wxGridSizer(4);
for (auto& button : m_cc_buttons)
if (!button.checkbox->GetContainingSizer())
cc_buttons_grid->Add(button.checkbox);
cc_buttons_grid->AddSpacer(5);
cc_buttons_grid->Add(space5, space5);
wxStaticBoxSizer* const cc_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
cc_buttons_box->Add(cc_buttons_grid);
cc_buttons_box->Add(cc_buttons_dpad);
cc_buttons_box->Add(cc_buttons_dpad, 0, wxTOP, space5);
szr->Add(m_cc_l_stick_szr, 0, wxALL, 5);
szr->Add(m_cc_r_stick_szr, 0, wxALL, 5);
szr->Add(shoulder_box, 0, wxLEFT | wxRIGHT, 5);
szr->Add(cc_buttons_box, 0, wxTOP | wxRIGHT, 5);
wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
szr->AddSpacer(space5);
szr->Add(m_cc_l_stick_szr, 0, wxTOP | wxBOTTOM, space5);
szr->AddSpacer(space5);
szr->Add(m_cc_r_stick_szr, 0, wxTOP | wxBOTTOM, space5);
szr->AddSpacer(space5);
szr->Add(shoulder_box, 0, wxTOP | wxBOTTOM, space5);
szr->AddSpacer(space5);
szr->Add(cc_buttons_box, 0, wxTOP | wxBOTTOM, space5);
szr->AddSpacer(space5);
for (Control* const control : m_cc_controls)
{
@ -327,8 +345,9 @@ void TASInputDlg::HandleExtensionChange()
m_main_szr->Hide(m_cc_szr);
m_main_szr->Show(m_wiimote_szr);
}
SetSizerAndFit(m_main_szr, true);
ResetValues();
m_main_szr->SetSizeHints(this);
Layout();
}
void TASInputDlg::CreateGCLayout()
@ -350,8 +369,6 @@ void TASInputDlg::CreateGCLayout()
m_controls[4] = &m_l_cont;
m_controls[5] = &m_r_cont;
wxBoxSizer* const top_box = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* const bottom_box = new wxBoxSizer(wxHORIZONTAL);
m_main_stick = CreateStick(ID_MAIN_STICK, 255, 255, 128, 128, false, true);
wxStaticBoxSizer* const main_box = CreateStickLayout(&m_main_stick, _("Main Stick"));
@ -373,38 +390,45 @@ void TASInputDlg::CreateGCLayout()
control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this);
}
wxStaticBoxSizer* const m_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
wxGridSizer* const m_buttons_grid = new wxGridSizer(4);
m_x = CreateButton("X");
m_x = CreateButton(_("X"));
m_x.checkbox->SetClientData(&m_x);
m_y = CreateButton("Y");
m_y = CreateButton(_("Y"));
m_y.checkbox->SetClientData(&m_y);
m_l = CreateButton("L");
m_l = CreateButton(_("L"));
m_l.checkbox->SetClientData(&m_l);
m_r = CreateButton("R");
m_r = CreateButton(_("R"));
m_r.checkbox->SetClientData(&m_r);
m_z = CreateButton("Z");
m_z = CreateButton(_("Z"));
m_z.checkbox->SetClientData(&m_z);
m_start = CreateButton("Start");
m_start = CreateButton(_("Start"));
m_start.checkbox->SetClientData(&m_start);
const int space5 = FromDIP(5);
wxGridSizer* const buttons_grid = new wxGridSizer(4);
for (unsigned int i = 4; i < ArraySize(m_buttons); ++i)
if (m_buttons[i] != nullptr)
m_buttons_grid->Add(m_buttons[i]->checkbox, false);
m_buttons_grid->AddSpacer(5);
buttons_grid->Add(m_buttons[i]->checkbox, false);
buttons_grid->Add(space5, space5);
m_buttons_box->Add(m_buttons_grid);
m_buttons_box->Add(m_buttons_dpad);
wxStaticBoxSizer* const buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
buttons_box->Add(buttons_grid);
buttons_box->Add(m_buttons_dpad);
wxBoxSizer* const top_box = new wxBoxSizer(wxHORIZONTAL);
top_box->Add(main_box);
top_box->Add(c_box, 0, wxLEFT, space5);
wxBoxSizer* const bottom_box = new wxBoxSizer(wxHORIZONTAL);
bottom_box->Add(shoulder_box);
bottom_box->Add(buttons_box, 0, wxLEFT, space5);
wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
top_box->Add(main_box, 0, wxALL, 5);
top_box->Add(c_box, 0, wxTOP | wxRIGHT, 5);
bottom_box->Add(shoulder_box, 0, wxLEFT | wxRIGHT, 5);
bottom_box->Add(m_buttons_box, 0, wxBOTTOM, 5);
main_szr->Add(top_box);
main_szr->Add(bottom_box);
main_szr->AddSpacer(space5);
main_szr->Add(top_box, 0, wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(bottom_box, 0, wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
SetSizerAndFit(main_szr);
ResetValues();
@ -414,21 +438,20 @@ void TASInputDlg::CreateGCLayout()
TASInputDlg::Control TASInputDlg::CreateControl(long style, int width, int height, bool reverse,
u32 range, u32 default_value)
{
Control tempCont;
tempCont.range = range;
tempCont.default_value = default_value;
tempCont.slider = new wxSlider(this, m_eleID++, default_value, 0, range, wxDefaultPosition,
wxDefaultSize, style);
tempCont.slider->SetMinSize(wxSize(width, height));
tempCont.slider->Bind(wxEVT_SLIDER, &TASInputDlg::UpdateFromSliders, this);
tempCont.text = new wxTextCtrl(this, m_eleID++, std::to_string(default_value), wxDefaultPosition,
wxSize(40, 20));
tempCont.text->SetMaxLength(range > 999 ? 4 : 3);
tempCont.text_id = m_eleID - 1;
tempCont.text->Bind(wxEVT_TEXT, &TASInputDlg::UpdateFromText, this);
tempCont.slider_id = m_eleID - 2;
tempCont.reverse = reverse;
return tempCont;
Control control;
control.range = range;
control.default_value = default_value;
control.slider_id = m_eleID++;
control.slider = new DolphinSlider(this, control.slider_id, default_value, 0, range,
wxDefaultPosition, FromDIP(wxSize(width, height)), style);
control.slider->Bind(wxEVT_SLIDER, &TASInputDlg::UpdateFromSliders, this);
control.text_id = m_eleID++;
control.text = new wxTextCtrl(this, control.text_id, std::to_string(default_value));
control.text->SetMaxLength(range > 999 ? 4 : 3);
control.text->SetMinSize(WxUtils::GetTextWidgetMinSize(control.text, range));
control.text->Bind(wxEVT_TEXT, &TASInputDlg::UpdateFromText, this);
control.reverse = reverse;
return control;
}
TASInputDlg::Stick TASInputDlg::CreateStick(int id_stick, int xRange, int yRange, u32 defaultX,
@ -446,18 +469,23 @@ TASInputDlg::Stick TASInputDlg::CreateStick(int id_stick, int xRange, int yRange
return tempStick;
}
wxStaticBoxSizer* TASInputDlg::CreateStickLayout(Stick* tempStick, const wxString& title)
wxStaticBoxSizer* TASInputDlg::CreateStickLayout(Stick* stick, const wxString& title)
{
wxStaticBoxSizer* const temp_box = new wxStaticBoxSizer(wxHORIZONTAL, this, title);
wxFlexGridSizer* grid = new wxFlexGridSizer(2, 3, 3);
const int space3 = FromDIP(3);
grid->Add(tempStick->x_cont.slider, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM);
grid->Add(tempStick->x_cont.text, 0, wxEXPAND);
grid->Add(tempStick->bitmap, 0, wxALL | wxALIGN_CENTER, 3);
grid->Add(tempStick->y_cont.slider, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
grid->Add(1, 1);
grid->Add(tempStick->y_cont.text, 0, wxEXPAND);
temp_box->Add(grid, 1, wxEXPAND | wxALL, 3);
wxStaticBoxSizer* const temp_box = new wxStaticBoxSizer(wxVERTICAL, this, title);
wxFlexGridSizer* const layout = new wxFlexGridSizer(2, space3, space3);
layout->Add(stick->x_cont.slider, 0, wxEXPAND);
layout->Add(stick->x_cont.text, 0, wxALIGN_CENTER);
layout->Add(stick->bitmap, 0, wxALIGN_RIGHT);
layout->Add(stick->y_cont.slider, 0, wxEXPAND);
layout->AddSpacer(1); // Placeholder for unused cell
layout->Add(stick->y_cont.text, 0, wxALIGN_CENTER);
temp_box->AddSpacer(space3);
temp_box->Add(layout, 0, wxLEFT | wxRIGHT, space3);
temp_box->AddSpacer(space3);
return temp_box;
}
@ -468,6 +496,7 @@ wxStaticBoxSizer* TASInputDlg::CreateAccelLayout(Control* x, Control* y, Control
wxStaticBoxSizer* const xBox = new wxStaticBoxSizer(wxVERTICAL, this, _("X"));
wxStaticBoxSizer* const yBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Y"));
wxStaticBoxSizer* const zBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Z"));
const int space5 = FromDIP(5);
xBox->Add(x->slider, 0, wxALIGN_CENTER_HORIZONTAL);
xBox->Add(x->text, 0, wxALIGN_CENTER_HORIZONTAL);
@ -475,21 +504,25 @@ wxStaticBoxSizer* TASInputDlg::CreateAccelLayout(Control* x, Control* y, Control
yBox->Add(y->text, 0, wxALIGN_CENTER_HORIZONTAL);
zBox->Add(z->slider, 0, wxALIGN_CENTER_HORIZONTAL);
zBox->Add(z->text, 0, wxALIGN_CENTER_HORIZONTAL);
temp_box->Add(xBox, 0, wxLEFT | wxBOTTOM | wxRIGHT, 5);
temp_box->Add(yBox, 0, wxRIGHT, 5);
temp_box->Add(zBox, 0, wxRIGHT, 5);
temp_box->AddSpacer(space5);
temp_box->Add(xBox, 0, wxBOTTOM, space5);
temp_box->AddSpacer(space5);
temp_box->Add(yBox, 0, wxBOTTOM, space5);
temp_box->AddSpacer(space5);
temp_box->Add(zBox, 0, wxBOTTOM, space5);
temp_box->AddSpacer(space5);
return temp_box;
}
TASInputDlg::Button TASInputDlg::CreateButton(const std::string& name)
TASInputDlg::Button TASInputDlg::CreateButton(const wxString& name)
{
Button temp;
wxCheckBox* checkbox = new wxCheckBox(this, m_eleID++, name);
temp.id = m_eleID++;
wxCheckBox* checkbox = new wxCheckBox(this, temp.id, name);
checkbox->Bind(wxEVT_RIGHT_DOWN, &TASInputDlg::SetTurbo, this);
checkbox->Bind(wxEVT_LEFT_DOWN, &TASInputDlg::SetTurbo, this);
checkbox->Bind(wxEVT_CHECKBOX, &TASInputDlg::OnCheckboxToggle, this);
temp.checkbox = checkbox;
temp.id = m_eleID - 1;
return temp;
}
@ -606,7 +639,7 @@ void TASInputDlg::SetWiiButtons(u16* butt)
for (unsigned int i = 0; i < 11; ++i)
{
if (m_buttons[i] != nullptr)
*butt |= (m_buttons[i]->is_checked) ? m_wii_buttons_bitmask[i] : 0;
*butt |= (m_buttons[i]->is_checked) ? s_wii_buttons_bitmask[i] : 0;
}
ButtonTurbo();
}
@ -625,7 +658,7 @@ void TASInputDlg::GetKeyBoardInput(GCPadStatus* PadStatus)
for (unsigned int i = 0; i < ArraySize(m_buttons); ++i)
{
if (m_buttons[i] != nullptr)
SetButtonValue(m_buttons[i], ((PadStatus->button & m_gc_pad_buttons_bitmask[i]) != 0));
SetButtonValue(m_buttons[i], ((PadStatus->button & s_gc_pad_buttons_bitmask[i]) != 0));
}
SetButtonValue(&m_l,
((PadStatus->triggerLeft) == 255) || ((PadStatus->button & PAD_TRIGGER_L) != 0));
@ -648,7 +681,7 @@ void TASInputDlg::GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, in
{
if (m_buttons[i] != nullptr)
SetButtonValue(m_buttons[i],
(((wm_buttons*)coreData)->hex & m_wii_buttons_bitmask[i]) != 0);
(((wm_buttons*)coreData)->hex & s_wii_buttons_bitmask[i]) != 0);
}
}
if (accelData)
@ -688,7 +721,7 @@ void TASInputDlg::GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, in
cc.bt.hex = cc.bt.hex ^ 0xFFFF;
for (unsigned int i = 0; i < 15; ++i)
{
SetButtonValue(&m_cc_buttons[i], ((cc.bt.hex & m_cc_buttons_bitmask[i]) != 0));
SetButtonValue(&m_cc_buttons[i], ((cc.bt.hex & s_cc_buttons_bitmask[i]) != 0));
}
if (m_cc_l.value == 31)
@ -835,7 +868,7 @@ void TASInputDlg::GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext,
for (unsigned int i = 0; i < ArraySize(m_cc_buttons); ++i)
{
cc.bt.hex |= (m_cc_buttons[i].is_checked) ? m_cc_buttons_bitmask[i] : 0;
cc.bt.hex |= (m_cc_buttons[i].is_checked) ? s_cc_buttons_bitmask[i] : 0;
}
cc.bt.hex ^= 0xFFFF;
@ -877,9 +910,9 @@ void TASInputDlg::GetValues(GCPadStatus* PadStatus)
if (m_buttons[i] != nullptr)
{
if (m_buttons[i]->is_checked)
PadStatus->button |= m_gc_pad_buttons_bitmask[i];
PadStatus->button |= s_gc_pad_buttons_bitmask[i];
else
PadStatus->button &= ~m_gc_pad_buttons_bitmask[i];
PadStatus->button &= ~s_gc_pad_buttons_bitmask[i];
}
}
@ -1042,8 +1075,9 @@ void TASInputDlg::OnMouseDownL(wxMouseEvent& event)
return;
wxPoint ptM(event.GetPosition());
stick->x_cont.value = ptM.x * stick->x_cont.range / 127;
stick->y_cont.value = ptM.y * stick->y_cont.range / 127;
wxSize bitmap_size = FromDIP(wxSize(127, 127));
stick->x_cont.value = ptM.x * stick->x_cont.range / bitmap_size.GetWidth();
stick->y_cont.value = ptM.y * stick->y_cont.range / bitmap_size.GetHeight();
if ((unsigned)stick->y_cont.value > stick->y_cont.range)
stick->y_cont.value = stick->y_cont.range;
@ -1055,12 +1089,8 @@ void TASInputDlg::OnMouseDownL(wxMouseEvent& event)
if (stick->x_cont.reverse)
stick->x_cont.value = stick->x_cont.range - (u16)stick->x_cont.value;
stick->x_cont.value = (unsigned int)stick->x_cont.value > stick->x_cont.range ?
stick->x_cont.range :
stick->x_cont.value;
stick->y_cont.value = (unsigned int)stick->y_cont.value > stick->y_cont.range ?
stick->y_cont.range :
stick->y_cont.value;
stick->x_cont.value = std::min<u32>(stick->x_cont.value, stick->x_cont.range);
stick->y_cont.value = std::min<u32>(stick->y_cont.value, stick->y_cont.range);
// This updates sliders and the bitmap too.
stick->x_cont.text->SetValue(std::to_string(stick->x_cont.value));
@ -1188,9 +1218,19 @@ wxBitmap TASInputDlg::CreateStickBitmap(int x, int y)
x = x / 2;
y = y / 2;
// Scale for screen DPI
static constexpr int WIDTH = 129;
static constexpr int HEIGHT = 129;
wxSize bitmap_size = FromDIP(wxSize(WIDTH, HEIGHT));
double scale_x = bitmap_size.GetWidth() / static_cast<double>(WIDTH);
double scale_y = bitmap_size.GetHeight() / static_cast<double>(HEIGHT);
wxMemoryDC memDC;
wxBitmap bitmap(129, 129);
wxBitmap bitmap;
bitmap.CreateScaled(bitmap_size.GetWidth(), bitmap_size.GetHeight(), wxBITMAP_SCREEN_DEPTH,
GetContentScaleFactor());
memDC.SelectObject(bitmap);
memDC.SetUserScale(scale_x, scale_y);
memDC.SetBackground(*wxLIGHT_GREY_BRUSH);
memDC.Clear();
memDC.SetBrush(*wxWHITE_BRUSH);
@ -1198,7 +1238,8 @@ wxBitmap TASInputDlg::CreateStickBitmap(int x, int y)
memDC.SetPen(wxPen(*wxBLACK, 3, wxPENSTYLE_SOLID));
memDC.DrawLine(64, 64, x, y);
memDC.SetPen(*wxBLACK_PEN);
memDC.CrossHair(64, 64);
memDC.DrawLine(64, 0, 64, HEIGHT); // CrossHair doesn't work @96DPI on Windows for some reason
memDC.DrawLine(0, 64, WIDTH, 64);
memDC.SetBrush(*wxBLUE_BRUSH);
memDC.DrawCircle(x, y, 5);
memDC.SelectObject(wxNullBitmap);

View File

@ -13,8 +13,8 @@
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "InputCommon/GCPadStatus.h"
class DolphinSlider;
class wxCheckBox;
class wxSlider;
class wxStaticBitmap;
class wxTextCtrl;
@ -25,36 +25,24 @@ public:
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP);
void OnCloseWindow(wxCloseEvent& event);
void UpdateFromSliders(wxCommandEvent& event);
void UpdateFromText(wxCommandEvent& event);
void OnMouseDownL(wxMouseEvent& event);
void OnMouseUpR(wxMouseEvent& event);
void OnRightClickSlider(wxMouseEvent& event);
void ResetValues();
void GetValues(GCPadStatus* PadStatus);
void GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key);
void SetTurbo(wxMouseEvent& event);
void ButtonTurbo();
void GetKeyBoardInput(GCPadStatus* PadStatus);
void GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key);
void CreateGCLayout();
void CreateWiiLayout(int num);
wxBitmap CreateStickBitmap(int x, int y);
void SetWiiButtons(u16* butt);
void HandleExtensionChange();
private:
const int ID_C_STICK = 1001;
const int ID_MAIN_STICK = 1002;
const int ID_CC_L_STICK = 1003;
const int ID_CC_R_STICK = 1004;
static constexpr int ID_C_STICK = 1001;
static constexpr int ID_MAIN_STICK = 1002;
static constexpr int ID_CC_L_STICK = 1003;
static constexpr int ID_CC_R_STICK = 1004;
int m_eleID = 1005;
struct Control
{
wxTextCtrl* text;
wxSlider* slider;
DolphinSlider* slider;
int value = -1;
int text_id;
int slider_id;
@ -100,9 +88,22 @@ private:
bool reverseY);
wxStaticBoxSizer* CreateStickLayout(Stick* tempStick, const wxString& title);
wxStaticBoxSizer* CreateAccelLayout(Control* x, Control* y, Control* z, const wxString& title);
Button CreateButton(const std::string& name);
Button CreateButton(const wxString& name);
Control CreateControl(long style, int width, int height, bool reverse = false, u32 range = 255,
u32 default_value = 128);
wxBitmap CreateStickBitmap(int x, int y);
void OnCloseWindow(wxCloseEvent& event);
void UpdateFromSliders(wxCommandEvent& event);
void UpdateFromText(wxCommandEvent& event);
void OnMouseDownL(wxMouseEvent& event);
void OnMouseUpR(wxMouseEvent& event);
void OnRightClickSlider(wxMouseEvent& event);
void SetTurbo(wxMouseEvent& event);
void ButtonTurbo();
void HandleExtensionChange();
void ResetValues();
void SetWiiButtons(u16* butt);
enum
{
@ -127,10 +128,6 @@ private:
Button m_cc_buttons[15];
Control* m_controls[10];
Control* m_cc_controls[6];
static const int m_gc_pad_buttons_bitmask[12];
static const int m_wii_buttons_bitmask[11];
static const int m_cc_buttons_bitmask[15];
static const std::string m_cc_button_names[15];
u8 m_ext = 0;
wxBoxSizer* m_main_szr;
wxBoxSizer* m_wiimote_szr;

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <map>
#include <string>
#include <utility>
@ -12,11 +13,11 @@
#include <wx/choice.h>
#include <wx/control.h>
#include <wx/dialog.h>
#include <wx/gbsizer.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/stattext.h>
#include "Common/Assert.h"
@ -76,18 +77,14 @@ void SettingChoice::UpdateValue(wxCommandEvent& ev)
ev.Skip();
}
void VideoConfigDiag::Event_ClickClose(wxCommandEvent&)
{
Close();
}
void VideoConfigDiag::Event_Close(wxCloseEvent& ev)
void VideoConfigDiag::Event_Close(wxCommandEvent& ev)
{
g_Config.Save(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
EndModal(wxID_OK);
ev.Skip();
}
static wxString default_desc =
wxTRANSLATE("Move the mouse pointer over an option to display a detailed description.");
#if defined(_WIN32)
static wxString backend_desc =
wxTRANSLATE("Selects what graphics API to use internally.\nThe software renderer is extremely "
@ -352,6 +349,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
Bind(wxEVT_UPDATE_UI, &VideoConfigDiag::OnUpdateUI, this);
wxNotebook* const notebook = new wxNotebook(this, wxID_ANY);
const int space5 = FromDIP(5);
// -- GENERAL --
{
@ -361,7 +359,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
// - basic
{
wxFlexGridSizer* const szr_basic = new wxFlexGridSizer(2, 5, 5);
wxFlexGridSizer* const szr_basic = new wxFlexGridSizer(2, space5, space5);
// backend
{
@ -378,8 +376,8 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
wxGetTranslation(StrToWxStr(g_video_backend->GetDisplayName())));
choice_backend->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_Backend, this);
szr_basic->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5);
szr_basic->Add(choice_backend, 1, 0, 0);
szr_basic->Add(label_backend, 0, wxALIGN_CENTER_VERTICAL);
szr_basic->Add(choice_backend, 0, wxALIGN_CENTER_VERTICAL);
}
// adapter (D3D only)
@ -396,12 +394,12 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
choice_adapter->Select(vconfig.iAdapter);
label_adapter = new wxStaticText(page_general, wxID_ANY, _("Adapter:"));
szr_basic->Add(label_adapter, 1, wxALIGN_CENTER_VERTICAL, 5);
szr_basic->Add(choice_adapter, 1, 0, 0);
szr_basic->Add(label_adapter, 0, wxALIGN_CENTER_VERTICAL);
szr_basic->Add(choice_adapter, 0, wxALIGN_CENTER_VERTICAL);
}
// - display
wxFlexGridSizer* const szr_display = new wxFlexGridSizer(2, 5, 5);
wxFlexGridSizer* const szr_display = new wxFlexGridSizer(2, space5, space5);
{
#if !defined(__APPLE__)
@ -420,9 +418,12 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
choice_display_resolution->SetStringSelection(
StrToWxStr(SConfig::GetInstance().strFullscreenResolution));
// "Auto" is used as a keyword, convert to translated string
if (SConfig::GetInstance().strFullscreenResolution == "Auto")
choice_display_resolution->SetSelection(0);
szr_display->Add(label_display_resolution, 1, wxALIGN_CENTER_VERTICAL, 0);
szr_display->Add(choice_display_resolution);
szr_display->Add(label_display_resolution, 0, wxALIGN_CENTER_VERTICAL);
szr_display->Add(choice_display_resolution, 0, wxALIGN_CENTER_VERTICAL);
}
#endif
@ -431,12 +432,12 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
const wxString ar_choices[] = {_("Auto"), _("Force 16:9"), _("Force 4:3"),
_("Stretch to Window")};
szr_display->Add(new wxStaticText(page_general, wxID_ANY, _("Aspect Ratio:")), 1,
wxALIGN_CENTER_VERTICAL, 0);
szr_display->Add(new wxStaticText(page_general, wxID_ANY, _("Aspect Ratio:")), 0,
wxALIGN_CENTER_VERTICAL);
wxChoice* const choice_aspect =
CreateChoice(page_general, vconfig.iAspectRatio, wxGetTranslation(ar_desc),
sizeof(ar_choices) / sizeof(*ar_choices), ar_choices);
szr_display->Add(choice_aspect, 1, 0, 0);
szr_display->Add(choice_aspect, 0, wxALIGN_CENTER_VERTICAL);
}
// various other display options
@ -450,7 +451,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
}
// - other
wxFlexGridSizer* const szr_other = new wxFlexGridSizer(2, 5, 5);
wxFlexGridSizer* const szr_other = new wxFlexGridSizer(2, space5, space5);
{
szr_other->Add(CreateCheckBox(page_general, _("Show FPS"), wxGetTranslation(show_fps_desc),
@ -488,20 +489,28 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
wxStaticBoxSizer* const group_basic =
new wxStaticBoxSizer(wxVERTICAL, page_general, _("Basic"));
group_basic->Add(szr_basic, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_general->Add(group_basic, 0, wxEXPAND | wxALL, 5);
group_basic->Add(szr_basic, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_basic->AddSpacer(space5);
wxStaticBoxSizer* const group_display =
new wxStaticBoxSizer(wxVERTICAL, page_general, _("Display"));
group_display->Add(szr_display, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_general->Add(group_display, 0, wxEXPAND | wxALL, 5);
group_display->Add(szr_display, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_display->AddSpacer(space5);
wxStaticBoxSizer* const group_other =
new wxStaticBoxSizer(wxVERTICAL, page_general, _("Other"));
group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_general->Add(group_other, 0, wxEXPAND | wxALL, 5);
group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_other->AddSpacer(space5);
szr_general->AddSpacer(space5);
szr_general->Add(group_basic, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_general->AddSpacer(space5);
szr_general->Add(group_display, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_general->AddSpacer(space5);
szr_general->Add(group_other, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
}
szr_general->AddSpacer(space5);
szr_general->AddStretchSpacer();
CreateDescriptionArea(page_general, szr_general);
page_general->SetSizerAndFit(szr_general);
@ -514,7 +523,9 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
wxBoxSizer* const szr_enh_main = new wxBoxSizer(wxVERTICAL);
// - enhancements
wxFlexGridSizer* const szr_enh = new wxFlexGridSizer(2, 5, 5);
wxGridBagSizer* const szr_enh = new wxGridBagSizer(space5, space5);
const wxGBSpan span2(1, 2);
int row = 0;
// Internal resolution
{
@ -540,9 +551,10 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
if (vconfig.iEFBScale > 11)
choice_efbscale->SetSelection(12);
szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Internal Resolution:")), 1,
wxALIGN_CENTER_VERTICAL, 0);
szr_enh->Add(choice_efbscale);
szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Internal Resolution:")),
wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
szr_enh->Add(choice_efbscale, wxGBPosition(row, 1), span2, wxALIGN_CENTER_VERTICAL);
row += 1;
}
// AA
@ -553,23 +565,25 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
PopulateAAList();
choice_aamode->Bind(wxEVT_CHOICE, &VideoConfigDiag::OnAAChanged, this);
szr_enh->Add(text_aamode, 1, wxALIGN_CENTER_VERTICAL, 0);
szr_enh->Add(choice_aamode);
szr_enh->Add(text_aamode, wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
szr_enh->Add(choice_aamode, wxGBPosition(row, 1), span2, wxALIGN_CENTER_VERTICAL);
row += 1;
}
// AF
{
const wxString af_choices[] = {"1x", "2x", "4x", "8x", "16x"};
szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Anisotropic Filtering:")), 1,
wxALIGN_CENTER_VERTICAL, 0);
szr_enh->Add(
CreateChoice(page_enh, vconfig.iMaxAnisotropy, wxGetTranslation(af_desc), 5, af_choices));
const std::array<wxString, 5> af_choices{{"1x", "2x", "4x", "8x", "16x"}};
szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Anisotropic Filtering:")),
wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
szr_enh->Add(CreateChoice(page_enh, vconfig.iMaxAnisotropy, wxGetTranslation(af_desc),
af_choices.size(), af_choices.data()),
wxGBPosition(row, 1), span2, wxALIGN_CENTER_VERTICAL);
row += 1;
}
// postproc shader
if (vconfig.backend_info.bSupportsPostProcessing)
{
wxFlexGridSizer* const szr_pp = new wxFlexGridSizer(3, 5, 5);
choice_ppshader = new wxChoice(page_enh, wxID_ANY);
RegisterControl(choice_ppshader, wxGetTranslation(ppshader_desc));
button_config_pp = new wxButton(page_enh, wxID_ANY, _("Config"));
@ -579,11 +593,11 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
choice_ppshader->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_PPShader, this);
button_config_pp->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ConfigurePPShader, this);
szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Post-Processing Effect:")), 1,
wxALIGN_CENTER_VERTICAL, 0);
szr_pp->Add(choice_ppshader);
szr_pp->Add(button_config_pp);
szr_enh->Add(szr_pp);
szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Post-Processing Effect:")),
wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
szr_enh->Add(choice_ppshader, wxGBPosition(row, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
szr_enh->Add(button_config_pp, wxGBPosition(row, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
row += 1;
}
else
{
@ -592,31 +606,38 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
}
// Scaled copy, PL, Bilinear filter
szr_enh->Add(CreateCheckBox(page_enh, _("Scaled EFB Copy"),
wxGetTranslation(scaled_efb_copy_desc), vconfig.bCopyEFBScaled));
szr_enh->Add(CreateCheckBox(page_enh, _("Per-Pixel Lighting"),
wxGetTranslation(pixel_lighting_desc),
vconfig.bEnablePixelLighting));
szr_enh->Add(CreateCheckBox(page_enh, _("Force Texture Filtering"),
wxGetTranslation(force_filtering_desc), vconfig.bForceFiltering));
szr_enh->Add(CreateCheckBox(page_enh, _("Widescreen Hack"), wxGetTranslation(ws_hack_desc),
vconfig.bWidescreenHack));
szr_enh->Add(CreateCheckBox(page_enh, _("Disable Fog"), wxGetTranslation(disable_fog_desc),
vconfig.bDisableFog));
wxGridSizer* const cb_szr = new wxGridSizer(2, space5, space5);
cb_szr->Add(CreateCheckBox(page_enh, _("Scaled EFB Copy"),
wxGetTranslation(scaled_efb_copy_desc), vconfig.bCopyEFBScaled));
cb_szr->Add(CreateCheckBox(page_enh, _("Per-Pixel Lighting"),
wxGetTranslation(pixel_lighting_desc),
vconfig.bEnablePixelLighting));
cb_szr->Add(CreateCheckBox(page_enh, _("Force Texture Filtering"),
wxGetTranslation(force_filtering_desc), vconfig.bForceFiltering));
cb_szr->Add(CreateCheckBox(page_enh, _("Widescreen Hack"), wxGetTranslation(ws_hack_desc),
vconfig.bWidescreenHack));
cb_szr->Add(CreateCheckBox(page_enh, _("Disable Fog"), wxGetTranslation(disable_fog_desc),
vconfig.bDisableFog));
szr_enh->Add(cb_szr, wxGBPosition(row, 0), wxGBSpan(1, 3));
row += 1;
wxStaticBoxSizer* const group_enh =
new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Enhancements"));
group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_enh_main->Add(group_enh, 0, wxEXPAND | wxALL, 5);
group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_enh->AddSpacer(space5);
szr_enh_main->AddSpacer(space5);
szr_enh_main->Add(group_enh, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
// - stereoscopy
if (vconfig.backend_info.bSupportsGeometryShaders)
{
wxFlexGridSizer* const szr_stereo = new wxFlexGridSizer(2, 5, 5);
wxFlexGridSizer* const szr_stereo = new wxFlexGridSizer(2, space5, space5);
szr_stereo->AddGrowableCol(1);
szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Stereoscopic 3D Mode:")), 1,
wxALIGN_CENTER_VERTICAL, 0);
szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Stereoscopic 3D Mode:")), 0,
wxALIGN_CENTER_VERTICAL);
const wxString stereo_choices[] = {_("Off"), _("Side-by-Side"), _("Top-and-Bottom"),
_("Anaglyph"), _("Nvidia 3D Vision")};
@ -626,37 +647,41 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
ArraySize(stereo_choices) - 1,
stereo_choices);
stereo_choice->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_StereoMode, this);
szr_stereo->Add(stereo_choice);
szr_stereo->Add(stereo_choice, 0, wxALIGN_CENTER_VERTICAL);
wxSlider* const sep_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoDepth, 0, 100,
wxDefaultPosition, wxDefaultSize);
DolphinSlider* const sep_slider =
new DolphinSlider(page_enh, wxID_ANY, vconfig.iStereoDepth, 0, 100, wxDefaultPosition,
FromDIP(wxSize(200, -1)));
sep_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoDepth, this);
RegisterControl(sep_slider, wxGetTranslation(stereo_depth_desc));
szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Depth:")), 1, wxALIGN_CENTER_VERTICAL,
0);
szr_stereo->Add(sep_slider, 0, wxEXPAND | wxRIGHT);
szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Depth:")));
szr_stereo->Add(sep_slider);
conv_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoConvergencePercentage, 0, 200,
wxDefaultPosition, wxDefaultSize, wxSL_AUTOTICKS);
conv_slider =
new DolphinSlider(page_enh, wxID_ANY, vconfig.iStereoConvergencePercentage, 0, 200,
wxDefaultPosition, FromDIP(wxSize(200, -1)), wxSL_AUTOTICKS);
conv_slider->ClearTicks();
conv_slider->SetTick(100);
conv_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoConvergence, this);
RegisterControl(conv_slider, wxGetTranslation(stereo_convergence_desc));
szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Convergence:")), 1,
wxALIGN_CENTER_VERTICAL, 0);
szr_stereo->Add(conv_slider, 0, wxEXPAND | wxRIGHT);
szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Convergence:")));
szr_stereo->Add(conv_slider);
szr_stereo->Add(CreateCheckBox(page_enh, _("Swap Eyes"), wxGetTranslation(stereo_swap_desc),
vconfig.bStereoSwapEyes));
wxStaticBoxSizer* const group_stereo =
new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Stereoscopy"));
group_stereo->Add(szr_stereo, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_enh_main->Add(group_stereo, 0, wxEXPAND | wxALL, 5);
group_stereo->Add(szr_stereo, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_stereo->AddSpacer(space5);
szr_enh_main->AddSpacer(space5);
szr_enh_main->Add(group_stereo, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
}
szr_enh_main->AddSpacer(space5);
szr_enh_main->AddStretchSpacer();
CreateDescriptionArea(page_enh, szr_enh_main);
page_enh->SetSizerAndFit(szr_enh_main);
@ -674,53 +699,71 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
szr_efb->Add(CreateCheckBox(page_hacks, _("Skip EFB Access from CPU"),
wxGetTranslation(efb_access_desc), vconfig.bEFBAccessEnable, true),
0, wxBOTTOM | wxLEFT, 5);
0, wxLEFT | wxRIGHT, space5);
szr_efb->AddSpacer(space5);
szr_efb->Add(CreateCheckBox(page_hacks, _("Ignore Format Changes"),
wxGetTranslation(efb_emulate_format_changes_desc),
vconfig.bEFBEmulateFormatChanges, true),
0, wxBOTTOM | wxLEFT, 5);
0, wxLEFT | wxRIGHT, space5);
szr_efb->AddSpacer(space5);
szr_efb->Add(CreateCheckBox(page_hacks, _("Store EFB Copies to Texture Only"),
wxGetTranslation(skip_efb_copy_to_ram_desc),
vconfig.bSkipEFBCopyToRam),
0, wxBOTTOM | wxLEFT, 5);
0, wxLEFT | wxRIGHT, space5);
szr_efb->AddSpacer(space5);
szr_hacks->Add(szr_efb, 0, wxEXPAND | wxALL, 5);
szr_hacks->AddSpacer(space5);
szr_hacks->Add(szr_efb, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
// Texture cache
{
wxStaticBoxSizer* const szr_safetex =
new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("Texture Cache"));
new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Texture Cache"));
// TODO: Use wxSL_MIN_MAX_LABELS or wxSL_VALUE_LABEL with wx 2.9.1
wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 2, wxDefaultPosition,
wxDefaultSize, wxSL_HORIZONTAL | wxSL_BOTTOM);
int slider_pos = -1;
if (vconfig.iSafeTextureCache_ColorSamples == 0)
slider_pos = 0;
else if (vconfig.iSafeTextureCache_ColorSamples == 512)
slider_pos = 1;
else if (vconfig.iSafeTextureCache_ColorSamples == 128)
slider_pos = 2;
DolphinSlider* const stc_slider =
new DolphinSlider(page_hacks, wxID_ANY, std::max(slider_pos, 0), 0, 2, wxDefaultPosition,
wxDefaultSize, wxSL_HORIZONTAL | wxSL_BOTTOM);
stc_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_Stc, this);
RegisterControl(stc_slider, wxGetTranslation(stc_desc));
if (vconfig.iSafeTextureCache_ColorSamples == 0)
stc_slider->SetValue(0);
else if (vconfig.iSafeTextureCache_ColorSamples == 512)
stc_slider->SetValue(1);
else if (vconfig.iSafeTextureCache_ColorSamples == 128)
stc_slider->SetValue(2);
else
stc_slider->Disable(); // Using custom number of samples; TODO: Inform the user why this is
// disabled..
wxBoxSizer* const slide_szr = new wxBoxSizer(wxHORIZONTAL);
slide_szr->Add(new wxStaticText(page_hacks, wxID_ANY, _("Accuracy:")), 0,
wxALIGN_CENTER_VERTICAL);
slide_szr->AddStretchSpacer(1);
slide_szr->Add(new wxStaticText(page_hacks, wxID_ANY, _("Safe")), 0,
wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
slide_szr->Add(stc_slider, 2, wxALIGN_CENTER_VERTICAL);
slide_szr->Add(new wxStaticText(page_hacks, wxID_ANY, _("Fast")), 0, wxALIGN_CENTER_VERTICAL);
szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Accuracy:")), 0, wxALL, 5);
szr_safetex->AddStretchSpacer(1);
szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Safe")), 0,
wxLEFT | wxTOP | wxBOTTOM, 5);
szr_safetex->Add(stc_slider, 2, wxRIGHT, 0);
szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Fast")), 0,
wxRIGHT | wxTOP | wxBOTTOM, 5);
szr_hacks->Add(szr_safetex, 0, wxEXPAND | wxALL, 5);
szr_safetex->Add(slide_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
if (slider_pos == -1)
{
stc_slider->Disable();
wxString msg = wxString::Format(_("Hash tap count is set to %d which is non-standard.\n"
"You will need to edit the INI manually."),
vconfig.iSafeTextureCache_ColorSamples);
szr_safetex->AddSpacer(space5);
szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, msg), 0,
wxALIGN_RIGHT | wxLEFT | wxRIGHT, space5);
}
szr_safetex->AddSpacer(space5);
szr_hacks->AddSpacer(space5);
szr_hacks->Add(szr_safetex, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
}
// - XFB
{
wxStaticBoxSizer* const group_xfb =
new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("External Frame Buffer (XFB)"));
new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("External Frame Buffer (XFB)"));
SettingCheckBox* disable_xfb = CreateCheckBox(
page_hacks, _("Disable"), wxGetTranslation(xfb_desc), vconfig.bUseXFB, true);
@ -729,16 +772,22 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
real_xfb = CreateRadioButton(page_hacks, _("Real"), wxGetTranslation(xfb_real_desc),
vconfig.bUseRealXFB);
group_xfb->Add(disable_xfb, 0, wxLEFT | wxRIGHT | wxBOTTOM, 5);
group_xfb->AddStretchSpacer(1);
group_xfb->Add(virtual_xfb, 0, wxRIGHT, 5);
group_xfb->Add(real_xfb, 0, wxRIGHT, 5);
szr_hacks->Add(group_xfb, 0, wxEXPAND | wxALL, 5);
wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
szr->Add(disable_xfb, 0, wxALIGN_CENTER_VERTICAL);
szr->AddStretchSpacer(1);
szr->Add(virtual_xfb, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
szr->Add(real_xfb, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
group_xfb->Add(szr, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_xfb->AddSpacer(space5);
szr_hacks->AddSpacer(space5);
szr_hacks->Add(group_xfb, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
} // xfb
// - other hacks
{
wxGridSizer* const szr_other = new wxGridSizer(2, 5, 5);
wxGridSizer* const szr_other = new wxGridSizer(2, space5, space5);
szr_other->Add(CreateCheckBox(page_hacks, _("Fast Depth Calculation"),
wxGetTranslation(fast_depth_calc_desc),
vconfig.bFastDepthCalc));
@ -748,10 +797,14 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
wxStaticBoxSizer* const group_other =
new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Other"));
group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_hacks->Add(group_other, 0, wxEXPAND | wxALL, 5);
group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_other->AddSpacer(space5);
szr_hacks->AddSpacer(space5);
szr_hacks->Add(group_other, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
}
szr_hacks->AddSpacer(space5);
szr_hacks->AddStretchSpacer();
CreateDescriptionArea(page_hacks, szr_hacks);
page_hacks->SetSizerAndFit(szr_hacks);
@ -765,7 +818,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
// - debug
{
wxGridSizer* const szr_debug = new wxGridSizer(2, 5, 5);
wxGridSizer* const szr_debug = new wxGridSizer(2, space5, space5);
szr_debug->Add(CreateCheckBox(page_advanced, _("Enable Wireframe"),
wxGetTranslation(wireframe_desc), vconfig.bWireFrame));
@ -779,13 +832,16 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
wxStaticBoxSizer* const group_debug =
new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Debugging"));
szr_advanced->Add(group_debug, 0, wxEXPAND | wxALL, 5);
group_debug->Add(szr_debug, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
group_debug->Add(szr_debug, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_debug->AddSpacer(space5);
szr_advanced->AddSpacer(space5);
szr_advanced->Add(group_debug, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
}
// - utility
{
wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5);
wxGridSizer* const szr_utility = new wxGridSizer(2, space5, space5);
szr_utility->Add(CreateCheckBox(page_advanced, _("Dump Textures"),
wxGetTranslation(dump_textures_desc), vconfig.bDumpTextures));
@ -807,13 +863,16 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
wxStaticBoxSizer* const group_utility =
new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Utility"));
szr_advanced->Add(group_utility, 0, wxEXPAND | wxALL, 5);
group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_utility->AddSpacer(space5);
szr_advanced->AddSpacer(space5);
szr_advanced->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
}
// - misc
{
wxGridSizer* const szr_misc = new wxGridSizer(2, 5, 5);
wxGridSizer* const szr_misc = new wxGridSizer(2, space5, space5);
szr_misc->Add(
CreateCheckBox(page_advanced, _("Crop"), wxGetTranslation(crop_desc), vconfig.bCrop));
@ -844,24 +903,34 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
wxStaticBoxSizer* const group_misc =
new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Misc"));
szr_advanced->Add(group_misc, 0, wxEXPAND | wxALL, 5);
group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
group_misc->AddSpacer(space5);
szr_advanced->AddSpacer(space5);
szr_advanced->Add(group_misc, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
}
szr_advanced->AddSpacer(space5);
szr_advanced->AddStretchSpacer();
CreateDescriptionArea(page_advanced, szr_advanced);
page_advanced->SetSizerAndFit(szr_advanced);
}
wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close"));
btn_close->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ClickClose, this);
wxStdDialogButtonSizer* btn_sizer = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
btn_sizer->GetAffirmativeButton()->SetLabel(_("Close"));
SetEscapeId(wxID_OK); // Escape key or window manager 'X'
Bind(wxEVT_CLOSE_WINDOW, &VideoConfigDiag::Event_Close, this);
Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_Close, this, wxID_OK);
wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5);
szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5);
szr_main->AddSpacer(space5);
szr_main->Add(notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_main->AddSpacer(space5);
szr_main->Add(btn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_main->AddSpacer(space5);
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(szr_main);
Center();
SetFocus();
@ -871,8 +940,18 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
void VideoConfigDiag::Event_DisplayResolution(wxCommandEvent& ev)
{
SConfig::GetInstance().strFullscreenResolution =
WxStrToStr(choice_display_resolution->GetStringSelection());
// "Auto" has been translated, it needs to be the English string "Auto" to work
switch (choice_display_resolution->GetSelection())
{
case 0:
SConfig::GetInstance().strFullscreenResolution = "Auto";
break;
case wxNOT_FOUND:
break; // Nothing is selected.
default:
SConfig::GetInstance().strFullscreenResolution =
WxStrToStr(choice_display_resolution->GetStringSelection());
}
#if defined(HAVE_XRANDR) && HAVE_XRANDR
main_frame->m_XRRConfig->Update();
#endif
@ -936,43 +1015,43 @@ void VideoConfigDiag::Evt_EnterControl(wxMouseEvent& ev)
// look up the description of the selected control and assign it to the current description text
// object's label
descr_text->SetLabel(ctrl_descs[ctrl]);
descr_text->Wrap(descr_text->GetContainingSizer()->GetSize().x - 20);
descr_text->Wrap(descr_text->GetSize().GetWidth());
ev.Skip();
}
// TODO: Don't hardcode the size of the description area via line breaks
#define DEFAULT_DESC_TEXT \
_("Move the mouse pointer over an option to display a detailed description.\n\n\n\n\n\n\n")
void VideoConfigDiag::Evt_LeaveControl(wxMouseEvent& ev)
{
// look up description text control and reset its label
wxWindow* ctrl = (wxWindow*)ev.GetEventObject();
wxWindow* ctrl = static_cast<wxWindow*>(ev.GetEventObject());
if (!ctrl)
return;
wxStaticText* descr_text = desc_texts[ctrl->GetParent()];
if (!descr_text)
return;
descr_text->SetLabel(DEFAULT_DESC_TEXT);
descr_text->Wrap(descr_text->GetContainingSizer()->GetSize().x - 20);
descr_text->SetLabel(wxGetTranslation(default_desc));
descr_text->Wrap(descr_text->GetSize().GetWidth());
ev.Skip();
}
void VideoConfigDiag::CreateDescriptionArea(wxPanel* const page, wxBoxSizer* const sizer)
{
const int space5 = FromDIP(5);
// Create description frame
wxStaticBoxSizer* const desc_sizer = new wxStaticBoxSizer(wxVERTICAL, page, _("Description"));
sizer->Add(desc_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
sizer->Add(desc_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer->AddSpacer(space5);
// Need to call SetSizerAndFit here, since we don't want the description texts to change the
// dialog width
page->SetSizerAndFit(sizer);
// Create description text
wxStaticText* const desc_text = new wxStaticText(page, wxID_ANY, DEFAULT_DESC_TEXT);
desc_text->Wrap(desc_sizer->GetSize().x - 20);
desc_sizer->Add(desc_text, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
// Create description text (220 = 75*4 (75 chars), 80 = 10*8 (10 lines))
wxStaticText* const desc_text =
new wxStaticText(page, wxID_ANY, wxGetTranslation(default_desc), wxDefaultPosition,
wxDLG_UNIT(this, wxSize(220, 80)), wxST_NO_AUTORESIZE);
desc_text->Wrap(desc_text->GetMinWidth());
desc_sizer->Add(desc_text, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
desc_sizer->AddSpacer(space5);
// Store description text object for later lookup
desc_texts.emplace(page, desc_text);

View File

@ -21,6 +21,7 @@
#include "Common/SysConf.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/PostProcessingConfigDiag.h"
#include "DolphinWX/WxUtils.h"
#include "VideoCommon/PostProcessing.h"
@ -100,8 +101,7 @@ protected:
wxMessageBox(_("Software rendering is an order of magnitude slower than using the "
"other backends.\nIt's only useful for debugging purposes.\nDo you "
"really want to enable software rendering? If unsure, select 'No'."),
_("Warning"), wxYES_NO | wxNO_DEFAULT | wxICON_EXCLAMATION,
wxWindow::FindFocus()));
_("Warning"), wxYES_NO | wxNO_DEFAULT | wxICON_EXCLAMATION, this));
}
if (do_switch)
@ -198,8 +198,7 @@ protected:
ev.Skip();
}
void Event_ClickClose(wxCommandEvent&);
void Event_Close(wxCloseEvent&);
void Event_Close(wxCommandEvent&);
// Enables/disables UI elements depending on current config
void OnUpdateUI(wxUpdateUIEvent& ev)
@ -274,7 +273,7 @@ protected:
wxStaticText* text_aamode;
wxChoice* choice_aamode;
wxSlider* conv_slider;
DolphinSlider* conv_slider;
wxStaticText* label_display_resolution;

View File

@ -2,21 +2,36 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cmath>
#include <string>
#include <wx/app.h>
#include <wx/bitmap.h>
#include <wx/choice.h>
#include <wx/combo.h>
#include <wx/combobox.h>
#include <wx/display.h>
#include <wx/gdicmn.h>
#include <wx/image.h>
#include <wx/msgdlg.h>
#include <wx/mstream.h>
#include <wx/sizer.h>
#include <wx/spinctrl.h>
#include <wx/toolbar.h>
#include <wx/toplevel.h>
#include <wx/utils.h>
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "DolphinWX/WxUtils.h"
#ifdef _WIN32
#include <Windows.h>
#endif
namespace WxUtils
{
// Launch a file according to its mime type
@ -55,45 +70,10 @@ void ShowErrorDialog(const wxString& error_msg)
wxMessageBox(error_msg, _("Error"), wxOK | wxICON_ERROR);
}
wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size)
{
const std::string path_base = File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP + name;
std::string path = path_base + ".png";
double scale_factor = 1.0;
#ifdef __APPLE__
if (wxTheApp->GetTopWindow()->GetContentScaleFactor() >= 2)
{
const std::string path_2x = path_base + "@2x.png";
if (File::Exists(path_2x))
{
path = path_2x;
scale_factor = 2.0;
}
}
#endif
wxImage image(StrToWxStr(path), wxBITMAP_TYPE_PNG);
if (padded_size != wxSize())
{
// Add padding if necessary (or crop, but images aren't supposed to be large enough to require
// that).
// The image will be left-aligned and vertically centered.
const wxSize scaled_padded_size = padded_size * scale_factor;
image.Resize(scaled_padded_size,
wxPoint(0, (scaled_padded_size.GetHeight() - image.GetHeight()) / 2));
}
#ifdef __APPLE__
return wxBitmap(image, -1, scale_factor);
#else
return wxBitmap(image);
#endif
}
wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original)
{
wxImage image = original.ConvertToImage();
return wxBitmap(image.ConvertToDisabled(240));
return wxBitmap(image.ConvertToDisabled(240), wxBITMAP_SCREEN_DEPTH, original.GetScaleFactor());
}
void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, const wxBitmap& bitmap,
@ -105,6 +85,440 @@ void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, con
wxITEM_NORMAL, shortHelp);
}
wxIconBundle GetDolphinIconBundle()
{
static wxIconBundle s_bundle;
if (!s_bundle.IsEmpty())
return s_bundle;
#ifdef _WIN32
// Convert the Windows ICO file into a wxIconBundle by tearing it apart into each individual
// sub-icon using the Win32 API. This is necessary because WX uses its own wxIcons internally
// which (unlike QIcon in Qt) only contain 1 image per icon, hence why wxIconBundle exists.
HINSTANCE dolphin = GetModuleHandleW(nullptr);
for (int size : {16, 32, 48, 256})
{
// Extract resource from embedded DolphinWX.rc
HANDLE win32_icon =
LoadImageW(dolphin, L"\"DOLPHIN\"", IMAGE_ICON, size, size, LR_CREATEDIBSECTION);
if (win32_icon && win32_icon != INVALID_HANDLE_VALUE)
{
wxIcon icon;
icon.CreateFromHICON(reinterpret_cast<HICON>(win32_icon));
s_bundle.AddIcon(icon);
}
}
#else
for (const char* fname : {"Dolphin.png", "dolphin_logo.png", "dolphin_logo@2x.png"})
{
wxImage image{StrToWxStr(File::GetSysDirectory() + RESOURCES_DIR DIR_SEP + fname),
wxBITMAP_TYPE_PNG};
if (image.IsOk())
{
wxIcon icon;
icon.CopyFromBitmap(image);
s_bundle.AddIcon(icon);
}
}
#endif
return s_bundle;
}
wxRect GetVirtualScreenGeometry()
{
wxRect geometry;
for (unsigned int i = 0, end = wxDisplay::GetCount(); i < end; ++i)
geometry.Union(wxDisplay(i).GetGeometry());
return geometry;
}
void SetWindowSizeAndFitToScreen(wxTopLevelWindow* tlw, wxPoint pos, wxSize size,
wxSize default_size)
{
if (tlw->IsMaximized())
return;
// NOTE: Positions can be negative and still be valid. Coordinates are relative to the
// primary monitor so if the primary monitor is in the middle then (-1000, 10) is a
// valid position on the monitor to the left of the primary. (This does not apply to
// sizes obviously)
wxRect screen_geometry;
wxRect window_geometry{pos, size};
if (wxDisplay::GetCount() > 1)
screen_geometry = GetVirtualScreenGeometry();
else
screen_geometry = wxDisplay(0).GetClientArea();
// Initialize the default size if it is wxDefaultSize or otherwise negative.
default_size.DecTo(screen_geometry.GetSize());
default_size.IncTo(tlw->GetMinSize());
if (!default_size.IsFullySpecified())
default_size.SetDefaults(wxDisplay(0).GetClientArea().GetSize() / 2);
// If the position we're given doesn't make sense then go with the current position.
// (Assuming the window was created with wxDefaultPosition then this should be reasonable)
if (pos.x - screen_geometry.GetLeft() < -1000 || pos.y - screen_geometry.GetTop() < -1000 ||
pos.x - screen_geometry.GetRight() > 1000 || pos.y - screen_geometry.GetBottom() > 1000)
{
window_geometry.SetPosition(tlw->GetPosition());
}
// If the window is bigger than all monitors combined, or negative (uninitialized) then reset it.
if (window_geometry.IsEmpty() || window_geometry.GetWidth() > screen_geometry.GetWidth() ||
window_geometry.GetHeight() > screen_geometry.GetHeight())
{
window_geometry.SetSize(default_size);
}
// Check if the window entirely lives on a single monitor without spanning.
// If the window does not span multiple screens then we should constrain it within that
// single monitor instead of the entire virtual desktop space.
// The benefit to doing this is that we can account for the OS X menu bar and Windows task
// bar which are treated as invisible when only looking at the virtual desktop instead of
// an individual screen.
if (wxDisplay::GetCount() > 1)
{
// SPECIAL CASE: If the window is entirely outside the visible area of the desktop then we
// put it back on the primary (zero) monitor.
wxRect monitor_intersection{window_geometry};
int the_monitor = 0;
if (!monitor_intersection.Intersect(screen_geometry).IsEmpty())
{
std::array<int, 4> monitors{{wxDisplay::GetFromPoint(monitor_intersection.GetTopLeft()),
wxDisplay::GetFromPoint(monitor_intersection.GetTopRight()),
wxDisplay::GetFromPoint(monitor_intersection.GetBottomLeft()),
wxDisplay::GetFromPoint(monitor_intersection.GetBottomRight())}};
the_monitor = wxNOT_FOUND;
bool intersected = false;
for (int one_monitor : monitors)
{
if (one_monitor == the_monitor || one_monitor == wxNOT_FOUND)
continue;
if (the_monitor != wxNOT_FOUND)
{
// The window is spanning multiple screens.
the_monitor = wxNOT_FOUND;
break;
}
the_monitor = one_monitor;
intersected = true;
}
// If we get wxNOT_FOUND for all corners then there are holes in the virtual desktop and the
// entire window is lost in one. (e.g. 3 monitors in an 'L', window in top-right)
if (!intersected)
the_monitor = 0;
}
if (the_monitor != wxNOT_FOUND)
{
// We'll only use the client area of this monitor if the window will actually fit.
// (It may not fit if the window is spilling off the edge so it isn't entirely visible)
wxRect client_area{wxDisplay(the_monitor).GetClientArea()};
if (client_area.GetWidth() >= window_geometry.GetWidth() &&
client_area.GetHeight() >= window_geometry.GetHeight())
{
screen_geometry = client_area;
}
}
}
// The window SHOULD be small enough to fit on the screen, but it might be spilling off an edge
// so we'll snap it to the nearest edge as necessary.
if (!screen_geometry.Contains(window_geometry))
{
// NOTE: The order is important here, if the window *is* too big to fit then it will snap to
// the top-left corner.
int spill_x = std::max(0, window_geometry.GetRight() - screen_geometry.GetRight());
int spill_y = std::max(0, window_geometry.GetBottom() - screen_geometry.GetBottom());
window_geometry.Offset(-spill_x, -spill_y);
if (window_geometry.GetTop() < screen_geometry.GetTop())
window_geometry.SetTop(screen_geometry.GetTop());
if (window_geometry.GetLeft() < screen_geometry.GetLeft())
window_geometry.SetLeft(screen_geometry.GetLeft());
}
tlw->SetSize(window_geometry, wxSIZE_ALLOW_MINUS_ONE);
}
wxSizer* GiveMinSize(wxWindow* window, const wxSize& min_size)
{
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
int flags = wxEXPAND;
// On Windows comboboxes will misrender when stretched vertically.
if (wxDynamicCast(window, wxChoice) || wxDynamicCast(window, wxComboBox) ||
wxDynamicCast(window, wxComboCtrl))
flags = wxALIGN_CENTER_VERTICAL;
sizer->Add(window, 1, flags);
sizer->SetMinSize(min_size);
return sizer;
}
wxSizer* GiveMinSizeDIP(wxWindow* window, const wxSize& min_size)
{
return GiveMinSize(window, window->FromDIP(min_size));
}
wxSize GetTextWidgetMinSize(const wxControl* control, const wxString& value)
{
return control->GetSizeFromTextSize(control->GetTextExtent(value));
}
wxSize GetTextWidgetMinSize(const wxControl* control, unsigned int value)
{
return GetTextWidgetMinSize(control, wxString::Format("%u", value));
}
wxSize GetTextWidgetMinSize(const wxControl* control, int value)
{
return GetTextWidgetMinSize(control, wxString::Format("%d", value));
}
wxSize GetTextWidgetMinSize(const wxSpinCtrl* spinner)
{
wxSize size = GetTextWidgetMinSize(spinner, spinner->GetMin());
size.IncTo(GetTextWidgetMinSize(spinner, spinner->GetMax()));
return size;
}
static wxImage LoadScaledImage(const std::string& file_path, const wxWindow* context,
const wxSize& output_size, const wxRect& usable_rect, LSIFlags flags,
const wxColour& fill_color)
{
std::string fpath, fname, fext;
SplitPath(file_path, &fpath, &fname, &fext);
const double window_scale_factor = context->GetContentScaleFactor();
// Compute the total scale factor from the ratio of DIPs to window pixels (FromDIP) and
// window pixels to framebuffer pixels (GetContentScaleFactor).
// NOTE: Usually only one of these is meaningful:
// - On Windows/GTK2: content_scale = 1.0, FromDIP = 96DPI -> Screen DPI
// - On Mac OS X: content_scale = screen_dpi / 96, FromDIP = 96DPI -> 96DPI (no-op)
// [The 1024 is arbitrarily large to minimise rounding error, it has no significance]
const double scale_factor = (context->FromDIP(1024) / 1024.0) * window_scale_factor;
// We search for files on quarter ratios of DIPs to framebuffer pixels.
// By default, the algorithm prefers to find an exact or bigger size then downscale if
// needed but will resort to upscaling if a bigger image cannot be found.
// E.g. A basic retina screen on Mac OS X has a scale_factor of 2.0, so we would look for
// @2x, @2.25x, @2.5x, @2.75x, @3x, @1.75x, @1.5x, @1.25x, @1x, then give up.
// (At 125% on Windows the search is @1.25, @1.5, @1.75, @2, @2.25, @1)
// If flags does not include LSI_SCALE_DOWN (i.e. we would be forced to crop big
// images instead of scaling them) then we will only accept smaller sizes, i.e.
// @2x, @1.75, @1.5, @1.25, @1, then give up.
// NOTE: We do a lot of exact comparisons against floating point here but it's fine
// because the numbers involved are all powers of 2 so can be represented exactly.
wxImage image;
double selected_image_scale = 1;
{
auto image_check = [&](double scale) -> bool {
std::string path = fpath + fname + StringFromFormat("@%gx", scale) + fext;
if (!File::Exists(path))
{
// Special Case: @1x may not have a suffix at all.
if (scale != 1.0 || !File::Exists(file_path))
return false;
path = file_path;
}
if (!image.LoadFile(StrToWxStr(path), wxBITMAP_TYPE_ANY))
return false;
selected_image_scale = scale;
return true;
};
const bool prefer_smaller = !(flags & LSI_SCALE_DOWN);
const double scale_factor_quarter =
prefer_smaller ? std::floor(scale_factor * 4) / 4 : std::ceil(scale_factor * 4) / 4;
// Search for bigger sizes first (preferred)
if (!prefer_smaller)
{
// We search within a 'circle' of the exact match limited by scale=1.0.
// i.e. scale_factor = 1.5, radius = 0.5; scale = 2.5, radius = 1.5.
// The minimum radius is 1.0.
double limit = std::max(scale_factor_quarter * 2 - 1, scale_factor_quarter + 1);
for (double quarter = scale_factor_quarter; quarter <= limit; quarter += 0.25)
{
if (image_check(quarter))
break;
}
}
// If we didn't hit a bigger size then we'll fallback to looking for smaller ones
if (!image.IsOk())
{
double quarter = scale_factor_quarter;
if (!prefer_smaller) // So we don't recheck the exact match
quarter -= 0.25;
for (; quarter >= 1.0; quarter -= 0.25)
{
if (image_check(quarter))
break;
}
}
}
// The file apparently does not exist so we give up. Create a white square placeholder instead.
if (!image.IsOk())
{
wxLogError("Could not find resource: %s", StrToWxStr(file_path));
image.Create(1, 1, false);
image.Clear(0xFF);
}
return ScaleImage(image, selected_image_scale, window_scale_factor, output_size, usable_rect,
flags, fill_color);
}
wxBitmap LoadScaledBitmap(const std::string& file_path, const wxWindow* context,
const wxSize& output_size, const wxRect& usable_rect, LSIFlags flags,
const wxColour& fill_color)
{
return wxBitmap(LoadScaledImage(file_path, context, output_size, usable_rect, flags, fill_color),
wxBITMAP_SCREEN_DEPTH, context->GetContentScaleFactor());
}
wxBitmap LoadScaledResourceBitmap(const std::string& name, const wxWindow* context,
const wxSize& output_size, const wxRect& usable_rect,
LSIFlags flags, const wxColour& fill_color)
{
std::string path = File::GetSysDirectory() + RESOURCES_DIR DIR_SEP + name + ".png";
return LoadScaledBitmap(path, context, output_size, usable_rect, flags, fill_color);
}
wxBitmap LoadScaledThemeBitmap(const std::string& name, const wxWindow* context,
const wxSize& output_size, const wxRect& usable_rect, LSIFlags flags,
const wxColour& fill_color)
{
std::string path = File::GetThemeDir(SConfig::GetInstance().theme_name) + name + ".png";
return LoadScaledBitmap(path, context, output_size, usable_rect, flags, fill_color);
}
wxBitmap ScaleImageToBitmap(const wxImage& image, const wxWindow* context,
const wxSize& output_size, const wxRect& usable_rect, LSIFlags flags,
const wxColour& fill_color)
{
double scale_factor = context->GetContentScaleFactor();
return wxBitmap(ScaleImage(image, 1.0, scale_factor, output_size, usable_rect, flags, fill_color),
wxBITMAP_SCREEN_DEPTH, scale_factor);
}
wxBitmap ScaleImageToBitmap(const wxImage& image, const wxWindow* context, double source_scale,
LSIFlags flags, const wxColour& fill_color)
{
double scale_factor = context->GetContentScaleFactor();
return wxBitmap(ScaleImage(image, source_scale, scale_factor, wxDefaultSize, wxDefaultSize, flags,
fill_color),
wxBITMAP_SCREEN_DEPTH, scale_factor);
}
wxImage ScaleImage(wxImage image, double source_scale_factor, double content_scale_factor,
wxSize output_size, wxRect usable_rect, LSIFlags flags,
const wxColour& fill_color)
{
if (!image.IsOk())
{
wxFAIL_MSG("WxUtils::ScaleImage expects a valid image.");
return image;
}
if (content_scale_factor != 1.0)
{
output_size *= content_scale_factor;
usable_rect.SetPosition(usable_rect.GetPosition() * content_scale_factor);
usable_rect.SetSize(usable_rect.GetSize() * content_scale_factor);
}
// Fix the output size if it's unset.
wxSize img_size = image.GetSize();
if (output_size.GetWidth() < 1)
output_size.SetWidth(
static_cast<int>(img_size.GetWidth() * (content_scale_factor / source_scale_factor)));
if (output_size.GetHeight() < 1)
output_size.SetHeight(
static_cast<int>(img_size.GetHeight() * (content_scale_factor / source_scale_factor)));
// Fix the usable rect. If it's empty then the whole canvas is usable.
if (usable_rect.IsEmpty())
{
// Constructs a temp wxRect 0,0->output_size then move assigns it.
usable_rect = output_size;
}
else if (!usable_rect.Intersects(output_size))
{
wxFAIL_MSG("Usable Zone Rectangle is not inside the canvas. Check the output size is correct.");
image.Create(1, 1, false);
image.SetRGB(0, 0, fill_color.Red(), fill_color.Green(), fill_color.Blue());
if (fill_color.Alpha() == wxALPHA_TRANSPARENT)
image.SetMaskColour(fill_color.Red(), fill_color.Green(), fill_color.Blue());
usable_rect = output_size;
}
// Step 1: Scale the image
if ((flags & LSI_SCALE) != LSI_SCALE_NONE)
{
if (flags & LSI_SCALE_NO_ASPECT)
{
// Stretch scale without preserving the aspect ratio.
bool scale_width = (img_size.GetWidth() > usable_rect.GetWidth() && flags & LSI_SCALE_DOWN) ||
(img_size.GetWidth() < usable_rect.GetWidth() && flags & LSI_SCALE_UP);
bool scale_height =
(img_size.GetHeight() > usable_rect.GetHeight() && flags & LSI_SCALE_DOWN) ||
(img_size.GetHeight() < usable_rect.GetHeight() && flags & LSI_SCALE_UP);
if (scale_width || scale_height)
{
// NOTE: Using BICUBIC instead of HIGH because it's the same internally
// except that downscaling uses a box filter with awful obvious aliasing
// for non-integral scale factors.
image.Rescale(scale_width ? usable_rect.GetWidth() : img_size.GetWidth(),
scale_height ? usable_rect.GetHeight() : img_size.GetHeight(),
wxIMAGE_QUALITY_BICUBIC);
}
}
else
{
// Scale while preserving the aspect ratio.
double scale = std::min(static_cast<double>(usable_rect.GetWidth()) / img_size.GetWidth(),
static_cast<double>(usable_rect.GetHeight()) / img_size.GetHeight());
int target_width = static_cast<int>(img_size.GetWidth() * scale);
int target_height = static_cast<int>(img_size.GetHeight() * scale);
// Bilinear produces sharper images when upscaling, bicubic tends to smear/blur sharp edges.
if (scale > 1.0 && flags & LSI_SCALE_UP)
image.Rescale(target_width, target_height, wxIMAGE_QUALITY_BILINEAR);
else if (scale < 1.0 && flags & LSI_SCALE_DOWN)
image.Rescale(target_width, target_height, wxIMAGE_QUALITY_BICUBIC);
}
img_size = image.GetSize();
}
// Step 2: Resize the canvas to match the output size.
// NOTE: If NOT using LSI_SCALE_DOWN then this will implicitly crop the image
if (img_size != output_size || usable_rect.GetPosition() != wxPoint())
{
wxPoint base = usable_rect.GetPosition();
if (flags & LSI_ALIGN_HCENTER)
base.x += (usable_rect.GetWidth() - img_size.GetWidth()) / 2;
else if (flags & LSI_ALIGN_RIGHT)
base.x += usable_rect.GetWidth() - img_size.GetWidth();
if (flags & LSI_ALIGN_VCENTER)
base.y += (usable_rect.GetHeight() - img_size.GetHeight()) / 2;
else if (flags & LSI_ALIGN_BOTTOM)
base.y += usable_rect.GetHeight() - img_size.GetHeight();
int r = -1, g = -1, b = -1;
if (fill_color.Alpha() != wxALPHA_TRANSPARENT)
{
r = fill_color.Red();
g = fill_color.Green();
b = fill_color.Blue();
}
image.Resize(output_size, base, r, g, b);
}
return image;
}
} // namespace
std::string WxStrToStr(const wxString& str)

View File

@ -5,11 +5,18 @@
#pragma once
#include <string>
#include <wx/colour.h>
#include <wx/gdicmn.h>
#include <wx/string.h>
class wxControl;
class wxBitmap;
class wxImage;
class wxSizer;
class wxSpinCtrl;
class wxToolBar;
class wxTopLevelWindow;
class wxWindow;
namespace WxUtils
{
@ -22,9 +29,6 @@ void Explore(const std::string& path);
// Displays a wxMessageBox geared for errors
void ShowErrorDialog(const wxString& error_msg);
// Reads a PNG from the Resources folder
wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size = wxSize());
// From a wxBitmap, creates the corresponding disabled version for toolbar buttons
wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original);
@ -32,6 +36,111 @@ wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original);
void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, const wxBitmap& bitmap,
const wxString& shortHelp);
// Gets a complete set of window icons at all relevant sizes, use with wxTopLevelWindow::SetIcons
wxIconBundle GetDolphinIconBundle();
// Get the dimensions of the virtual desktop that spans all monitors.
// Matches GetSystemMetrics(SM_XVIRTUALSCREEN), etc on Windows.
wxRect GetVirtualScreenGeometry();
// Takes a top-level window and resizes / repositions it so it fits on the screen.
// Supports spanning multiple monitors if there are multiple monitors.
// Will snap to edge if the window is small enough to fit but spills over the boundary.
void SetWindowSizeAndFitToScreen(wxTopLevelWindow* tlw, wxPoint pos, wxSize size,
wxSize default_size = wxDefaultSize);
// wxSizers use the minimum size of a widget when computing layout instead of the best size.
// The best size is only taken when the minsize is -1,-1 (i.e. undefined).
// This means that elements with a MinSize specified will always have that exact size unless
// wxEXPAND-ed.
// This problem can be resolved by wrapping the widget in a sizer and setting the minimum size on
// the sizer instead. Sizers will always use the best size of the widget, treating their own MinSize
// as a floor which is usually what you want.
wxSizer* GiveMinSize(wxWindow* window, const wxSize& min_size);
wxSizer* GiveMinSizeDIP(wxWindow* window, const wxSize& min_size);
// Compute the proper size for a text widget (wxTextCtrl, wxChoice, wxSpinCtrl, etc)
// Based on the text it will be required to hold. This gives the element the minimum
// width to hold the largest text value instead of being arbitrarily wide.
wxSize GetTextWidgetMinSize(const wxControl* control, const wxString& value);
wxSize GetTextWidgetMinSize(const wxControl* control, unsigned int value);
wxSize GetTextWidgetMinSize(const wxControl* control, int value);
wxSize GetTextWidgetMinSize(const wxSpinCtrl* spinner);
enum LSIFlags : unsigned int
{
LSI_SCALE_NONE = 0, // Disable scaling, only resize canvas
LSI_SCALE_UP = 1, // Scale up if needed, but crop instead of scaling down
LSI_SCALE_DOWN = 2, // Scale down if needed, only expand canvas instead of scaling up
LSI_SCALE = LSI_SCALE_UP | LSI_SCALE_DOWN, // Scale either way as needed.
LSI_SCALE_NO_ASPECT = 8, // Disable preserving the aspect ratio of the image.
LSI_ALIGN_LEFT = 0, // Place image at the left edge of canvas
LSI_ALIGN_RIGHT = 0x10, // Place image at the right edge of canvas
LSI_ALIGN_HCENTER = 0x20, // Place image in the horizontal center of canvas
LSI_ALIGN_TOP = 0, // Place image at the top of the canvas
LSI_ALIGN_BOTTOM = 0x40, // Place image at the bottom of the canvas
LSI_ALIGN_VCENTER = 0x80, // Place image in the vertical center of canvas
LSI_ALIGN_CENTER = LSI_ALIGN_HCENTER | LSI_ALIGN_VCENTER,
LSI_DEFAULT = LSI_SCALE | LSI_ALIGN_CENTER
};
constexpr LSIFlags operator|(LSIFlags left, LSIFlags right)
{
return static_cast<LSIFlags>(static_cast<unsigned int>(left) | right);
}
constexpr LSIFlags operator&(LSIFlags left, LSIFlags right)
{
return static_cast<LSIFlags>(static_cast<unsigned int>(left) & right);
}
// Swiss army knife loader function for preparing a scaled resource image file.
// Only the path and context are mandatory, other parameters can be ignored.
// NOTE: All size parameters are in window pixels, not DIPs or framebuffer pixels.
// output_size = size of image canvas if different from native image size. E.g. 96x32
// usable_rect = part of image canvas that is considered usable. E.g. 0,0 -> 32,32
// Usable zone is helpful if the canvas is bigger than the area which will be drawn on screen.
// flags = See LSIFlags
// fill_color = Color to fill the unused canvas area (due to aspect ratio or usable_rect).
wxBitmap LoadScaledBitmap(const std::string& file_path, const wxWindow* context,
const wxSize& output_size = wxDefaultSize,
const wxRect& usable_rect = wxDefaultSize, LSIFlags flags = LSI_DEFAULT,
const wxColour& fill_color = wxTransparentColour);
wxBitmap LoadScaledResourceBitmap(const std::string& name, const wxWindow* context,
const wxSize& output_size = wxDefaultSize,
const wxRect& usable_rect = wxDefaultSize,
LSIFlags flags = LSI_DEFAULT,
const wxColour& fill_color = wxTransparentColour);
wxBitmap LoadScaledThemeBitmap(const std::string& name, const wxWindow* context,
const wxSize& output_size = wxDefaultSize,
const wxRect& usable_rect = wxDefaultSize,
LSIFlags flags = LSI_DEFAULT,
const wxColour& fill_color = wxTransparentColour);
// Variant of LoadScaledBitmap to scale an image that didn't come from a file.
wxBitmap ScaleImageToBitmap(const wxImage& image, const wxWindow* context,
const wxSize& output_size = wxDefaultSize,
const wxRect& usable_rect = wxDefaultSize, LSIFlags flags = LSI_DEFAULT,
const wxColour& fill_color = wxTransparentColour);
// Rescales image to screen DPI.
// "Source scale" is essentially the image's DPI as a ratio to 96DPI, e.g. 144DPI image has a
// scale of 1.5.
wxBitmap ScaleImageToBitmap(const wxImage& image, const wxWindow* context, double source_scale,
LSIFlags flags = LSI_DEFAULT,
const wxColour& fill_color = wxTransparentColour);
// Internal scaling engine behind all the Scaling functions.
// Exposes all control parameters instead of infering them from other sources.
// "Content scale" is a factor applied to output_size and usable_rect internally to convert them
// to framebuffer pixel sizes.
// NOTE: Source scale factor only matters if you don't explicitly specify the output size.
wxImage ScaleImage(wxImage image, double source_scale_factor = 1.0,
double content_scale_factor = 1.0, wxSize output_size = wxDefaultSize,
wxRect usable_rect = wxDefaultSize, LSIFlags flags = LSI_DEFAULT,
const wxColour& fill_color = wxTransparentColour);
} // namespace
std::string WxStrToStr(const wxString& str);