From 9df83889007ee275bac79b3d4afa966882e9a32d Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Mon, 25 Jul 2016 17:37:51 +0000 Subject: [PATCH 01/16] WXMSW-Patch: Fix wxTipWindow internal assertion failure. --- Externals/wxWidgets3/src/generic/tipwin.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Externals/wxWidgets3/src/generic/tipwin.cpp b/Externals/wxWidgets3/src/generic/tipwin.cpp index abe66b3275..b022ac3c4f 100644 --- a/Externals/wxWidgets3/src/generic/tipwin.cpp +++ b/Externals/wxWidgets3/src/generic/tipwin.cpp @@ -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); From 73a20551dfc20e38927337704f475117ee9b0363 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Sun, 2 Oct 2016 03:05:55 +0000 Subject: [PATCH 02/16] WX: HiDPI Support Framework Portable flexible HiDPI image loading and other support for Windows/GTK/OSX. --- Source/Core/DolphinWX/CMakeLists.txt | 1 + Source/Core/DolphinWX/DolphinSlider.cpp | 126 +++++ Source/Core/DolphinWX/DolphinSlider.h | 51 ++ Source/Core/DolphinWX/DolphinWX.vcxproj | 2 + .../Core/DolphinWX/DolphinWX.vcxproj.filters | 11 +- Source/Core/DolphinWX/WxUtils.cpp | 439 ++++++++++++++++-- Source/Core/DolphinWX/WxUtils.h | 111 ++++- 7 files changed, 706 insertions(+), 35 deletions(-) create mode 100644 Source/Core/DolphinWX/DolphinSlider.cpp create mode 100644 Source/Core/DolphinWX/DolphinSlider.h diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index 9a01978bbc..27d7c73385 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -40,6 +40,7 @@ set(GUI_SRCS NetPlay/NetPlaySetupFrame.cpp NetPlay/NetWindow.cpp NetPlay/PadMapDialog.cpp + DolphinSlider.cpp FifoPlayerDlg.cpp Frame.cpp FrameAui.cpp diff --git a/Source/Core/DolphinWX/DolphinSlider.cpp b/Source/Core/DolphinWX/DolphinSlider.cpp new file mode 100644 index 0000000000..673c5fd4cc --- /dev/null +++ b/Source/Core/DolphinWX/DolphinSlider.cpp @@ -0,0 +1,126 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include + +#include "DolphinWX/DolphinSlider.h" + +#ifdef __WXMSW__ +#define WIN32_LEAN_AND_MEAN 1 +// clang-format off +#include +#include +// 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(helper->GetHWND()), TBM_GETTHUMBRECT, 0, + reinterpret_cast(&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(r.right + r.left); + scroll_size = ::GetSystemMetrics(SM_CXVSCROLL); + } + else + { + computed_size = static_cast(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 diff --git a/Source/Core/DolphinWX/DolphinSlider.h b/Source/Core/DolphinWX/DolphinSlider.h new file mode 100644 index 0000000000..df3883e478 --- /dev/null +++ b/Source/Core/DolphinWX/DolphinSlider.h @@ -0,0 +1,51 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +// 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; +}; diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj index 43bcc08c8a..d2e6fa30ba 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj @@ -89,6 +89,7 @@ + @@ -131,6 +132,7 @@ + diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters index 2386e891db..4d597345d1 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters @@ -28,6 +28,9 @@ {9d8b4144-f335-4fa4-b995-852533298474} + + {a894e2e3-e577-4b65-8572-055699f23a49} + @@ -208,6 +211,9 @@ GUI\NetPlay + + GUI\Widgets + @@ -381,6 +387,9 @@ GUI\NetPlay + + GUI\Widgets + @@ -393,4 +402,4 @@ - \ No newline at end of file + diff --git a/Source/Core/DolphinWX/WxUtils.cpp b/Source/Core/DolphinWX/WxUtils.cpp index c9449df3f8..3d86954d76 100644 --- a/Source/Core/DolphinWX/WxUtils.cpp +++ b/Source/Core/DolphinWX/WxUtils.cpp @@ -2,18 +2,29 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include +#include #include #include #include +#include +#include +#include +#include #include #include #include -#include +#include +#include #include +#include #include #include "Common/CommonPaths.h" #include "Common/FileUtil.h" +#include "Common/StringUtil.h" +#include "Core/ConfigManager.h" #include "DolphinWX/WxUtils.h" @@ -57,43 +68,15 @@ void ShowErrorDialog(const wxString& error_msg) 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 + wxWindow* context = wxTheApp->GetTopWindow(); + return LoadScaledResourceBitmap(name, context, padded_size, wxDefaultSize, + LSI_SCALE_DOWN | LSI_ALIGN_VCENTER, *wxWHITE); } 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 +88,396 @@ void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, con wxITEM_NORMAL, shortHelp); } +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 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(img_size.GetWidth() * (content_scale_factor / source_scale_factor))); + if (output_size.GetHeight() < 1) + output_size.SetHeight( + static_cast(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(usable_rect.GetWidth()) / img_size.GetWidth(), + static_cast(usable_rect.GetHeight()) / img_size.GetHeight()); + int target_width = static_cast(img_size.GetWidth() * scale); + int target_height = static_cast(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) diff --git a/Source/Core/DolphinWX/WxUtils.h b/Source/Core/DolphinWX/WxUtils.h index 1f7937e819..9b379532ff 100644 --- a/Source/Core/DolphinWX/WxUtils.h +++ b/Source/Core/DolphinWX/WxUtils.h @@ -5,11 +5,18 @@ #pragma once #include +#include #include #include +class wxControl; class wxBitmap; +class wxImage; +class wxSizer; +class wxSpinCtrl; class wxToolBar; +class wxTopLevelWindow; +class wxWindow; namespace WxUtils { @@ -23,7 +30,7 @@ void Explore(const std::string& path); void ShowErrorDialog(const wxString& error_msg); // Reads a PNG from the Resources folder -wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size = wxSize()); +wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size = wxDefaultSize); // From a wxBitmap, creates the corresponding disabled version for toolbar buttons wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original); @@ -32,6 +39,108 @@ wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original); void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, const wxBitmap& bitmap, const wxString& shortHelp); +// 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(static_cast(left) | right); +} +constexpr LSIFlags operator&(LSIFlags left, LSIFlags right) +{ + return static_cast(static_cast(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); From 107d4afb0891aa57246ef3960f09279132fec4bc Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Sun, 14 Aug 2016 19:54:01 +0000 Subject: [PATCH 03/16] WX: HiDPI: Dolphin Main UI (CFrame) --- Source/Core/Core/ConfigManager.cpp | 21 ++-- Source/Core/Core/ConfigManager.h | 7 +- Source/Core/DolphinWX/Debugger/CodeWindow.cpp | 18 +-- Source/Core/DolphinWX/Frame.cpp | 39 +++--- Source/Core/DolphinWX/Frame.h | 6 +- Source/Core/DolphinWX/FrameTools.cpp | 106 ++++++---------- Source/Core/DolphinWX/GameListCtrl.cpp | 114 +++++++++++------- Source/Core/DolphinWX/GameListCtrl.h | 2 +- Source/Core/DolphinWX/ISOFile.cpp | 11 +- Source/Core/DolphinWX/Main.cpp | 48 +------- 10 files changed, 169 insertions(+), 203 deletions(-) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index b6b74e5160..86cc0b4b1e 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #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; diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index f2275bb4c4..5ea7a58386 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include @@ -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::min(); + int iRenderWindowYPos = std::numeric_limits::min(); + int iRenderWindowWidth = -1; + int iRenderWindowHeight = -1; bool bRenderWindowAutoSize = false, bKeepWindowOnTop = false; bool bFullscreen = false, bRenderToMain = false; bool bProgressive = false, bPAL60 = false; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp index aff5d48577..db1fb5e31f 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include @@ -666,19 +667,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 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], diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index 422867e904..3dfd4f5e0e 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -86,7 +86,7 @@ CRenderFrame::CRenderFrame(wxFrame* parent, wxWindowID id, const wxString& title { // Give it an icon wxIcon IconTemp; - IconTemp.CopyFromBitmap(WxUtils::LoadResourceBitmap("Dolphin")); + IconTemp.CopyFromBitmap(WxUtils::LoadScaledResourceBitmap("Dolphin", this)); SetIcon(IconTemp); DragAcceptFiles(true); @@ -381,22 +381,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 +483,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); @@ -680,7 +684,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)) { @@ -930,7 +935,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)) { diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index 33857e7a9f..8ebed24d80 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -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; @@ -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; diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 29b8bca723..8ebce0d9a1 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include @@ -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 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(); @@ -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 @@ -1912,7 +1883,8 @@ void CFrame::UpdateGUI() void CFrame::UpdateGameList() { - m_GameListCtrl->Update(); + if (m_GameListCtrl) + m_GameListCtrl->ReloadList(); } void CFrame::GameListChanged(wxCommandEvent& event) @@ -1987,11 +1959,7 @@ void CFrame::GameListChanged(wxCommandEvent& event) break; } - // Update gamelist - if (m_GameListCtrl) - { - m_GameListCtrl->Update(); - } + UpdateGameList(); } // Enable and disable the toolbar @@ -2047,6 +2015,6 @@ void CFrame::OnChangeColumnsVisible(wxCommandEvent& event) default: return; } - m_GameListCtrl->Update(); + UpdateGameList(); SConfig::GetInstance().SaveSettings(); } diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index f9ef00d910..c5b093880d 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -187,47 +188,70 @@ CGameListCtrl::~CGameListCtrl() } template -static void InitBitmap(wxImageList* img_list, std::vector* vector, T index, - const std::string& name) +static void InitBitmap(wxImageList* img_list, std::vector* vector, wxWindow* context, + const wxSize& usable_size, T index, const std::string& name) { - wxSize size(96, 32); - (*vector)[static_cast(index)] = img_list->Add(WxUtils::LoadResourceBitmap(name, size)); + wxSize size = img_list->GetSize(); + (*vector)[static_cast(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(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(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"); } void CGameListCtrl::BrowseForDirectory() @@ -252,11 +276,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 +321,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++) @@ -502,7 +528,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 +1124,7 @@ void CGameListCtrl::OnDeleteISO(wxCommandEvent& WXUNUSED(event)) { for (const GameListItem* iso : GetAllSelectedISOs()) File::Delete(iso->GetFileName()); - Update(); + ReloadList(); } } @@ -1269,7 +1295,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 +1368,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)) diff --git a/Source/Core/DolphinWX/GameListCtrl.h b/Source/Core/DolphinWX/GameListCtrl.h index adf4a6f154..34f65fa725 100644 --- a/Source/Core/DolphinWX/GameListCtrl.h +++ b/Source/Core/DolphinWX/GameListCtrl.h @@ -38,7 +38,7 @@ public: long style); ~CGameListCtrl(); - void Update() override; + void ReloadList(); void BrowseForDirectory(); const GameListItem* GetISO(size_t index) const; diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp index 1b986c02c6..54669a34a5 100644 --- a/Source/Core/DolphinWX/ISOFile.cpp +++ b/Source/Core/DolphinWX/ISOFile.cpp @@ -283,19 +283,16 @@ bool GameListItem::ReadPNGBanner(const std::string& path) wxBitmap GameListItem::ScaleBanner(wxImage* image) { - const double gui_scale = wxTheApp->GetTopWindow()->GetContentScaleFactor(); + wxWindow* window = wxTheApp->GetTopWindow(); + const double gui_scale = window->GetContentScaleFactor() * (window->FromDIP(1024) / 1024.0); 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); + wxIMAGE_QUALITY_BICUBIC); 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 + return wxBitmap(*image, wxBITMAP_SCREEN_DEPTH, window->GetContentScaleFactor()); } std::string GameListItem::GetDescription(DiscIO::Language language) const diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp index 9eef4b3d0c..bdf6ada482 100644 --- a/Source/Core/DolphinWX/Main.cpp +++ b/Source/Core/DolphinWX/Main.cpp @@ -53,25 +53,6 @@ #include #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(); From 42b6ea4c81b6bf395643aa5f9b77c500ef7e0249 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Tue, 2 Aug 2016 06:20:46 +0000 Subject: [PATCH 04/16] WX: HiDPI: AboutDolphin --- Source/Core/DolphinWX/AboutDolphin.cpp | 28 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/Source/Core/DolphinWX/AboutDolphin.cpp b/Source/Core/DolphinWX/AboutDolphin.cpp index 90702ae34e..9fb555c4a9 100644 --- a/Source/Core/DolphinWX/AboutDolphin.cpp +++ b/Source/Core/DolphinWX/AboutDolphin.cpp @@ -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); From 3b11581aff0fc7b1e248f1e9a67e35854f7c32b8 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Wed, 3 Aug 2016 11:14:52 +0000 Subject: [PATCH 05/16] WX: HiDPI: ISOProperties And related ARCodeAddEdit/PatchAddEdit. Change ISOFile to use wxImage instead of wxBitmap since bitmaps require a screen context and banner images have a fixed resolution. --- Source/Core/DolphinWX/GameListCtrl.cpp | 13 +- Source/Core/DolphinWX/GameListCtrl.h | 1 + Source/Core/DolphinWX/ISOFile.cpp | 31 +--- Source/Core/DolphinWX/ISOFile.h | 8 +- Source/Core/DolphinWX/ISOProperties.cpp | 223 ++++++++++++++---------- Source/Core/DolphinWX/ISOProperties.h | 4 +- Source/Core/DolphinWX/PatchAddEdit.cpp | 45 +++-- 7 files changed, 179 insertions(+), 146 deletions(-) diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index c5b093880d..858d273996 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -252,6 +252,9 @@ void CGameListCtrl::InitBitmaps() 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() @@ -431,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; diff --git a/Source/Core/DolphinWX/GameListCtrl.h b/Source/Core/DolphinWX/GameListCtrl.h index 34f65fa725..467271d68e 100644 --- a/Source/Core/DolphinWX/GameListCtrl.h +++ b/Source/Core/DolphinWX/GameListCtrl.h @@ -70,6 +70,7 @@ private: std::vector m_FlagImageIndex; std::vector m_PlatformImageIndex; std::vector m_EmuStateImageIndex; + std::vector m_utility_game_banners; std::vector> m_ISOFiles; void ClearIsoFiles() { m_ISOFiles.clear(); } diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp index 54669a34a5..05379a98a8 100644 --- a/Source/Core/DolphinWX/ISOFile.cpp +++ b/Source/Core/DolphinWX/ISOFile.cpp @@ -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 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,22 +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) -{ - wxWindow* window = wxTheApp->GetTopWindow(); - const double gui_scale = window->GetContentScaleFactor() * (window->FromDIP(1024) / 1024.0); - 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_BICUBIC); - image->Resize(wxSize(target_width, target_height), wxPoint(), 0xFF, 0xFF, 0xFF); - return wxBitmap(*image, wxBITMAP_SCREEN_DEPTH, window->GetContentScaleFactor()); + m_image = image; + return true; } std::string GameListItem::GetDescription(DiscIO::Language language) const diff --git a/Source/Core/DolphinWX/ISOFile.h b/Source/Core/DolphinWX/ISOFile.h index b5c19dd5ef..b8b0127e70 100644 --- a/Source/Core/DolphinWX/ISOFile.h +++ b/Source/Core/DolphinWX/ISOFile.h @@ -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 m_pImage; @@ -107,6 +109,4 @@ private: void ReadVolumeBanner(const std::vector& buffer, int width, int height); // Outputs to m_Bitmap bool ReadPNGBanner(const std::string& path); - - static wxBitmap ScaleBanner(wxImage* image); }; diff --git a/Source/Core/DolphinWX/ISOProperties.cpp b/Source/Core/DolphinWX/ISOProperties.cpp index 54ca974fdb..5dcbcf591a 100644 --- a/Source/Core/DolphinWX/ISOProperties.cpp +++ b/Source/Core/DolphinWX/ISOProperties.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -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 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(); } diff --git a/Source/Core/DolphinWX/ISOProperties.h b/Source/Core/DolphinWX/ISOProperties.h index c3e70e62dd..922b188dde 100644 --- a/Source/Core/DolphinWX/ISOProperties.h +++ b/Source/Core/DolphinWX/ISOProperties.h @@ -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; diff --git a/Source/Core/DolphinWX/PatchAddEdit.cpp b/Source/Core/DolphinWX/PatchAddEdit.cpp index a845c60016..e58b90a913 100644 --- a/Source/Core/DolphinWX/PatchAddEdit.cpp +++ b/Source/Core/DolphinWX/PatchAddEdit.cpp @@ -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(); } From b6fb56e97870ff020fed378a65d4ba4099f92bfc Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Tue, 2 Aug 2016 06:21:01 +0000 Subject: [PATCH 06/16] WX: HiDPI: MemcardManager Required a partial rewrite of the image loading code because it was working in unscaled wxBitmaps. Needed to make it produce wxImages and scale them instead. --- Source/Core/DolphinWX/MemcardManager.cpp | 204 ++++++++++++----------- Source/Core/DolphinWX/MemcardManager.h | 1 + 2 files changed, 110 insertions(+), 95 deletions(-) diff --git a/Source/Core/DolphinWX/MemcardManager.cpp b/Source/Core/DolphinWX/MemcardManager.cpp index d181e1da07..f5da01a43a 100644 --- a/Source/Core/DolphinWX/MemcardManager.cpp +++ b/Source/Core/DolphinWX/MemcardManager.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -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 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 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 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 pxdata(BANNER_WIDTH * IMAGE_HEIGHT); + std::vector anim_delay(ANIM_MAX_FRAMES); + std::vector 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; diff --git a/Source/Core/DolphinWX/MemcardManager.h b/Source/Core/DolphinWX/MemcardManager.h index 3f307117b9..edfd5fac74 100644 --- a/Source/Core/DolphinWX/MemcardManager.h +++ b/Source/Core/DolphinWX/MemcardManager.h @@ -131,5 +131,6 @@ private: void OnRightClick(wxMouseEvent& event); }; + wxSize m_image_list_size; CMemcardListCtrl* m_MemcardList[2]; }; From 8fe94c3c508f70ec26305d48a8582222b2c12e9d Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Tue, 2 Aug 2016 06:21:08 +0000 Subject: [PATCH 07/16] WX: HiDPI: FifoPlayerDlg --- Source/Core/DolphinWX/FifoPlayerDlg.cpp | 295 ++++++++++++------------ Source/Core/DolphinWX/FifoPlayerDlg.h | 1 - 2 files changed, 142 insertions(+), 154 deletions(-) diff --git a/Source/Core/DolphinWX/FifoPlayerDlg.cpp b/Source/Core/DolphinWX/FifoPlayerDlg.cpp index aed9ad53b7..15c965cad7 100644 --- a/Source/Core/DolphinWX/FifoPlayerDlg.cpp +++ b/Source/Core/DolphinWX/FifoPlayerDlg.cpp @@ -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")); diff --git a/Source/Core/DolphinWX/FifoPlayerDlg.h b/Source/Core/DolphinWX/FifoPlayerDlg.h index 16f562e3c7..819e103f6b 100644 --- a/Source/Core/DolphinWX/FifoPlayerDlg.h +++ b/Source/Core/DolphinWX/FifoPlayerDlg.h @@ -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); From c893447913917e7104a1b7fd566e75d7c5c31a4c Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Mon, 3 Oct 2016 06:56:45 +0000 Subject: [PATCH 08/16] WX: HiDPI: CheatsWindow Changed the Cheat Search tab to disable the scan buttons while there is not a game running and enable when it starts. Also added double-click to create code to the result list. --- .../Core/DolphinWX/Cheats/CheatSearchTab.cpp | 125 ++++++++++++------ Source/Core/DolphinWX/Cheats/CheatSearchTab.h | 9 +- Source/Core/DolphinWX/Cheats/CheatsWindow.cpp | 64 +++++---- Source/Core/DolphinWX/Cheats/CheatsWindow.h | 5 +- .../DolphinWX/Cheats/CreateCodeDialog.cpp | 48 +++---- .../Core/DolphinWX/Cheats/CreateCodeDialog.h | 2 - .../Core/DolphinWX/Cheats/GeckoCodeDiag.cpp | 56 ++++---- 7 files changed, 186 insertions(+), 123 deletions(-) diff --git a/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp b/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp index 25ad5860e5..494f818c3f 100644 --- a/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp +++ b/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp @@ -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 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(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; diff --git a/Source/Core/DolphinWX/Cheats/CheatSearchTab.h b/Source/Core/DolphinWX/Cheats/CheatSearchTab.h index 119eb88e47..6d53169d68 100644 --- a/Source/Core/DolphinWX/Cheats/CheatSearchTab.h +++ b/Source/Core/DolphinWX/Cheats/CheatSearchTab.h @@ -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 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; diff --git a/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp b/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp index a6c6bad730..a313d4c2a0 100644 --- a/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp +++ b/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp @@ -55,13 +55,14 @@ 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)); + SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); + SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER); Center(); Show(); } @@ -71,8 +72,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 +88,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 +111,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 +148,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 +180,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 +211,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 +259,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 +300,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()); } diff --git a/Source/Core/DolphinWX/Cheats/CheatsWindow.h b/Source/Core/DolphinWX/Cheats/CheatsWindow.h index 4302cb8af0..0d32bfb8b2 100644 --- a/Source/Core/DolphinWX/Cheats/CheatsWindow.h +++ b/Source/Core/DolphinWX/Cheats/CheatsWindow.h @@ -7,13 +7,13 @@ #include #include #include -#include #include #include #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(); diff --git a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp index 32b4ac09a9..8f398bd513 100644 --- a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp +++ b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp @@ -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(); } diff --git a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h index 8eae79e564..6df209426c 100644 --- a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h +++ b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h @@ -26,6 +26,4 @@ private: wxCheckBox* m_checkbox_use_hex; void PressOK(wxCommandEvent&); - void PressCancel(wxCommandEvent&); - void OnEvent_Close(wxCloseEvent& ev); }; diff --git a/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp b/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp index 8625324b94..f2b275a9be 100644 --- a/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp +++ b/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp @@ -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)); } } From a4d633de159400e7be7b94e2d87ab7419e065302 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Tue, 2 Aug 2016 06:22:37 +0000 Subject: [PATCH 09/16] WX: HiDPI: Config Panes --- .../DolphinWX/Config/AdvancedConfigPane.cpp | 61 +++++++------- .../DolphinWX/Config/AdvancedConfigPane.h | 4 +- .../Core/DolphinWX/Config/AudioConfigPane.cpp | 59 ++++++++----- .../Core/DolphinWX/Config/AudioConfigPane.h | 4 +- Source/Core/DolphinWX/Config/ConfigMain.cpp | 13 ++- .../DolphinWX/Config/GameCubeConfigPane.cpp | 45 ++++++---- .../DolphinWX/Config/GeneralConfigPane.cpp | 43 +++++++--- .../DolphinWX/Config/InterfaceConfigPane.cpp | 43 ++++++---- .../Core/DolphinWX/Config/PathConfigPane.cpp | 50 ++++++----- .../Core/DolphinWX/Config/WiiConfigPane.cpp | 84 ++++++++++--------- Source/Core/DolphinWX/Config/WiiConfigPane.h | 5 +- 11 files changed, 244 insertions(+), 167 deletions(-) diff --git a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp index c245a358cb..406e76785f 100644 --- a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp @@ -7,9 +7,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -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); } diff --git a/Source/Core/DolphinWX/Config/AdvancedConfigPane.h b/Source/Core/DolphinWX/Config/AdvancedConfigPane.h index 64296ef2f3..4b19e35c55 100644 --- a/Source/Core/DolphinWX/Config/AdvancedConfigPane.h +++ b/Source/Core/DolphinWX/Config/AdvancedConfigPane.h @@ -6,9 +6,9 @@ #include +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; diff --git a/Source/Core/DolphinWX/Config/AudioConfigPane.cpp b/Source/Core/DolphinWX/Config/AudioConfigPane.cpp index 97dc4ca145..f1125700fc 100644 --- a/Source/Core/DolphinWX/Config/AudioConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/AudioConfigPane.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -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) diff --git a/Source/Core/DolphinWX/Config/AudioConfigPane.h b/Source/Core/DolphinWX/Config/AudioConfigPane.h index b2a988371c..877be31da5 100644 --- a/Source/Core/DolphinWX/Config/AudioConfigPane.h +++ b/Source/Core/DolphinWX/Config/AudioConfigPane.h @@ -8,10 +8,10 @@ #include #include +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; diff --git a/Source/Core/DolphinWX/Config/ConfigMain.cpp b/Source/Core/DolphinWX/Config/ConfigMain.cpp index b41e0c9ed7..1836167ede 100644 --- a/Source/Core/DolphinWX/Config/ConfigMain.cpp +++ b/Source/Core/DolphinWX/Config/ConfigMain.cpp @@ -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(); diff --git a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp index bd66b56705..06892a26bb 100644 --- a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp @@ -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); } diff --git a/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp b/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp index 454fb3a59f..e5f81f7736 100644 --- a/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp @@ -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); } diff --git a/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp b/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp index 988230612f..2927114e58 100644 --- a/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,7 @@ #include "DolphinWX/X11Utils.h" #endif -static const std::array language_ids = {{ +static const std::array 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()]; diff --git a/Source/Core/DolphinWX/Config/PathConfigPane.cpp b/Source/Core/DolphinWX/Config/PathConfigPane.cpp index 896073bb9a..08664dee29 100644 --- a/Source/Core/DolphinWX/Config/PathConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/PathConfigPane.cpp @@ -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); } diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp index 559bee6051..c53b5757d2 100644 --- a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp @@ -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); } diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.h b/Source/Core/DolphinWX/Config/WiiConfigPane.h index ac482277fd..a185751c24 100644 --- a/Source/Core/DolphinWX/Config/WiiConfigPane.h +++ b/Source/Core/DolphinWX/Config/WiiConfigPane.h @@ -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; }; From 741dfce05e74e2dcafe250893a3f882ecd6b01b1 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Tue, 2 Aug 2016 06:22:44 +0000 Subject: [PATCH 10/16] WX: HiDPI: ControllerConfigDiag Minor appearance change to align wiimote and gamecube sections. --- .../DolphinWX/Config/GCAdapterConfigDiag.cpp | 12 +- .../Core/DolphinWX/ControllerConfigDiag.cpp | 174 ++++++++++-------- Source/Core/DolphinWX/ControllerConfigDiag.h | 9 +- 3 files changed, 107 insertions(+), 88 deletions(-) diff --git a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp index d15f4a5e4f..975502718a 100644 --- a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp +++ b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp @@ -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(); diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp index 58ddcbaf8a..6f489fa270 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp +++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #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 src_choices = { + const std::array 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); diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h index 48a8e4b9fe..1f4bdab5cc 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.h +++ b/Source/Core/DolphinWX/ControllerConfigDiag.h @@ -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); From ac404517a392d6eaf0e9c6d45ee8609e14897025 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Tue, 2 Aug 2016 06:22:48 +0000 Subject: [PATCH 11/16] WX: HiDPI: InputConfigDiag Slight redesign of Control Configuration sub-window since SL_LABELS can't be used with DolphinSlider. --- Source/Core/DolphinWX/InputConfigDiag.cpp | 385 +++++++++++------ Source/Core/DolphinWX/InputConfigDiag.h | 32 +- .../Core/DolphinWX/InputConfigDiagBitmaps.cpp | 393 ++++++++++-------- 3 files changed, 486 insertions(+), 324 deletions(-) diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp index 1be1a2436c..7978226711 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.cpp +++ b/Source/Core/DolphinWX/InputConfigDiag.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -25,9 +27,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -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(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(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(event.GetPosition()) / SLIDER_TICK_COUNT; +} + +void ControlDialog::OnRangeSpin(wxSpinEvent& event) +{ + m_range_slider->SetValue(event.GetValue()); + control_reference->range = static_cast(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(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(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 exclude_buttons = {"Mic", "Modifier"}; - const std::vector exclude_groups = {"IR", "Swing", "Tilt", "Shake", - "UDP Wiimote", "Extension", "Rumble"}; + static constexpr std::array exclude_buttons{{"Mic", "Modifier"}}; + static constexpr std::array 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(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(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* 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(); diff --git a/Source/Core/DolphinWX/InputConfigDiag.h b/Source/Core/DolphinWX/InputConfigDiag.h index 41390d8d60..210a01d312 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.h +++ b/Source/Core/DolphinWX/InputConfigDiag.h @@ -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 options; ControllerEmu::ControlGroup* const control_group; wxStaticBitmap* static_bitmap; std::vector control_buttons; + double m_scale; }; class ControlGroupsSizer : public wxBoxSizer diff --git a/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp b/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp index 8f972c9091..fa4f10ff13 100644 --- a/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp +++ b/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include #include #include #include @@ -11,8 +13,10 @@ #include #include #include +#include #include #include +#include #include #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& 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(g->control_group->controls.size()); + std::vector 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(g->control_group->controls.size()); + std::vector 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(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(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 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(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); } } From 2dfd04d7a57e309fe3343e207448020a650c2745 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Tue, 2 Aug 2016 06:22:53 +0000 Subject: [PATCH 12/16] WX: HiDPI: TASInputDlg --- Source/Core/DolphinWX/TASInputDlg.cpp | 305 +++++++++++++++----------- Source/Core/DolphinWX/TASInputDlg.h | 43 ++-- 2 files changed, 193 insertions(+), 155 deletions(-) diff --git a/Source/Core/DolphinWX/TASInputDlg.cpp b/Source/Core/DolphinWX/TASInputDlg.cpp index 6bf57383b1..08b586bd97 100644 --- a/Source/Core/DolphinWX/TASInputDlg.cpp +++ b/Source/Core/DolphinWX/TASInputDlg.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include #include #include #include @@ -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 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(stick->x_cont.value, stick->x_cont.range); + stick->y_cont.value = std::min(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(WIDTH); + double scale_y = bitmap_size.GetHeight() / static_cast(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); diff --git a/Source/Core/DolphinWX/TASInputDlg.h b/Source/Core/DolphinWX/TASInputDlg.h index 0e44f292e1..5fee27b792 100644 --- a/Source/Core/DolphinWX/TASInputDlg.h +++ b/Source/Core/DolphinWX/TASInputDlg.h @@ -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; From ef0d21299ab5b62158927f0cab799f33f33c2bea Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Tue, 2 Aug 2016 06:22:58 +0000 Subject: [PATCH 13/16] WX: HiDPI: VideoConfigDiag Resolved "TODO" for Texture Cache safety, added explanation message. Resolved "TODO" for default description, no longer uses default text for sizing Fixed a memory leak in PostProcessingConfigDiag where it was never freeing any of the objects it allocated in its constructor. Minor design change to PostProcessingConfigDiag to give padding around elements consistent with the rest of Dolphin's user interface (5px). --- .../DolphinWX/PostProcessingConfigDiag.cpp | 114 +++--- .../Core/DolphinWX/PostProcessingConfigDiag.h | 23 +- .../DolphinWX/SoftwareVideoConfigDialog.cpp | 65 ++-- Source/Core/DolphinWX/VideoConfigDiag.cpp | 357 +++++++++++------- Source/Core/DolphinWX/VideoConfigDiag.h | 9 +- 5 files changed, 340 insertions(+), 228 deletions(-) diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp index 19c4a2b952..019bdbe887 100644 --- a/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp +++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp @@ -2,15 +2,13 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include -#include +#include #include #include #include #include #include -#include #include #include @@ -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> config_groups; + config_groups.reserve(config_map.size()); + m_config_map.reserve(config_map.size()); for (const auto& it : config_map) { + std::unique_ptr 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::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::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); -} diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.h b/Source/Core/DolphinWX/PostProcessingConfigDiag.h index fa896c1fb1..ec366e8635 100644 --- a/Source/Core/DolphinWX/PostProcessingConfigDiag.h +++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.h @@ -4,14 +4,16 @@ #pragma once -#include +#include #include +#include +#include #include #include -#include #include +#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&& child) + { + m_children.emplace_back(std::move(child)); + } bool HasChildren() { return m_children.size() != 0; } - std::vector& GetChildren() { return m_children; } + const std::vector>& 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 m_option_sliders; + std::vector m_option_sliders; std::vector m_option_text_ctrls; - std::vector m_children; + std::vector> 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 m_config_map; - std::vector m_config_groups; + std::unordered_map m_config_map; + std::vector> m_config_groups; }; diff --git a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp index 87c947bfcd..e8b29081a7 100644 --- a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp +++ b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp @@ -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(page_general, _("Start"), vconfig.drawStart, 0, 100000)); szr_misc->Add(new IntegerSetting(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(); diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 147ff94376..38fe322b01 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -12,11 +13,11 @@ #include #include #include +#include #include #include #include #include -#include #include #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 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(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); diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h index cc07c62ca6..dcff2803e2 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.h +++ b/Source/Core/DolphinWX/VideoConfigDiag.h @@ -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; From f39c301579a5a88caa7cb4cea9e6d44f7d4c94df Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Tue, 2 Aug 2016 06:23:02 +0000 Subject: [PATCH 14/16] WX: HiDPI: NetPlay Several refactors of GUI creation into separate functions where the function was too large or intermixed different concerns making it hard to modify. --- .../DolphinWX/NetPlay/ChangeGameDialog.cpp | 9 +- Source/Core/DolphinWX/NetPlay/MD5Dialog.cpp | 58 ++-- .../DolphinWX/NetPlay/NetPlaySetupFrame.cpp | 305 ++++++++++-------- .../DolphinWX/NetPlay/NetPlaySetupFrame.h | 7 +- Source/Core/DolphinWX/NetPlay/NetWindow.cpp | 205 ++++++++---- Source/Core/DolphinWX/NetPlay/NetWindow.h | 10 +- .../Core/DolphinWX/NetPlay/PadMapDialog.cpp | 91 +++--- Source/Core/DolphinWX/NetPlay/PadMapDialog.h | 2 + 8 files changed, 405 insertions(+), 282 deletions(-) diff --git a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp index be1173e12e..b685e89b08 100644 --- a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp +++ b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp @@ -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(); diff --git a/Source/Core/DolphinWX/NetPlay/MD5Dialog.cpp b/Source/Core/DolphinWX/NetPlay/MD5Dialog.cpp index 2eb8547693..c2e7ccfd4f 100644 --- a/Source/Core/DolphinWX/NetPlay/MD5Dialog.cpp +++ b/Source/Core/DolphinWX/NetPlay/MD5Dialog.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "Common/StringUtil.h" @@ -17,43 +18,54 @@ MD5Dialog::MD5Dialog(wxWindow* parent, NetPlayServer* server, std::vectorAdd(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(); } diff --git a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp index c9f0e0f86b..230f12bbe8 100644 --- a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp +++ b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -41,50 +42,54 @@ 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); - - // top row - wxBoxSizer* const trav_szr = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL); + CreateGUI(); { - // Connection Config - wxStaticText* const connectiontype_lbl = new wxStaticText( - panel, wxID_ANY, _("Connection Type:"), wxDefaultPosition, wxSize(100, -1)); + wxIcon icon; + icon.CopyFromBitmap(WxUtils::LoadScaledResourceBitmap("Dolphin", this)); + SetIcon(icon); + } - 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")); + { + std::string temp; + netplay_section.Get("Nickname", &temp, "Player"); + m_nickname_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("HostCode", &temp, "00000000"); + m_connect_hashcode_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("Address", &temp, "127.0.0.1"); + m_connect_ip_text->SetValue(StrToWxStr(temp)); - trav_szr->AddSpacer(5); + temp.clear(); + netplay_section.Get("ConnectPort", &temp, + std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT)); + m_connect_port_text->SetValue(StrToWxStr(temp)); - trav_szr->Add(m_trav_reset_btn, 0, wxRIGHT); + temp.clear(); + netplay_section.Get("HostPort", &temp, std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT)); + m_host_port_text->SetValue(StrToWxStr(temp)); - // Nickname - wxStaticText* const nick_lbl = - new wxStaticText(panel, wxID_ANY, _("Nickname:"), wxDefaultPosition, wxSize(100, -1)); + temp.clear(); + if (netplay_section.Get("SelectedHostGame", &temp, "")) + m_game_lbox->SetStringSelection(StrToWxStr(temp)); - std::string nickname; - netplay_section.Get("Nickname", &nickname, "Player"); +#ifdef USE_UPNP + bool use_upnp = false; + netplay_section.Get("UseUPNP", &use_upnp, false); + m_upnp_chk->SetValue(use_upnp); +#endif - m_nickname_text = - new wxTextCtrl(panel, wxID_ANY, StrToWxStr(nickname), wxDefaultPosition, wxSize(150, -1)); + 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); - 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 +98,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 +203,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 +226,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 +246,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 +309,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 +430,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 +455,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 +481,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 +523,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() diff --git a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h index be565b1452..a91e26989b 100644 --- a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h +++ b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h @@ -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; }; diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp index 18dabd91e2..1c7a7dc57f 100644 --- a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -67,12 +69,51 @@ 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(); + 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::min()); + netplay_section.Get("NetWindowPosY", &winPosY, std::numeric_limits::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 +121,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 +134,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 +224,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() diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.h b/Source/Core/DolphinWX/NetPlay/NetWindow.h index f6623a8a1c..1dd36c52e4 100644 --- a/Source/Core/DolphinWX/NetPlay/NetWindow.h +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.h @@ -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; diff --git a/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp b/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp index b5e5badc7c..d2bef9a687 100644 --- a/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp +++ b/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include @@ -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(); } diff --git a/Source/Core/DolphinWX/NetPlay/PadMapDialog.h b/Source/Core/DolphinWX/NetPlay/PadMapDialog.h index 30d0266555..d8f4167eb6 100644 --- a/Source/Core/DolphinWX/NetPlay/PadMapDialog.h +++ b/Source/Core/DolphinWX/NetPlay/PadMapDialog.h @@ -12,7 +12,9 @@ class NetPlayClient; class NetPlayServer; class Player; +class wxArrayString; class wxChoice; +class wxSizer; class PadMapDialog final : public wxDialog { From 27d295ec7e456240d97327b3c4351d3e168c479f Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Mon, 3 Oct 2016 07:29:50 +0000 Subject: [PATCH 15/16] WX: HiDPI: FrameAUI / Debugger Changes: - MemoryWindow was cleaned up and gives more feedback on searches. Some bugs were fixed as well: - A complex bug that allowed tearing off tabs and opening multiple copies of a debug panel which lead to segfaults - Another segfault related to right-click menus on code/memory views when those tools were floating in their own window. --- .../Core/DolphinWX/Debugger/BreakpointDlg.cpp | 12 +- .../DolphinWX/Debugger/BreakpointView.cpp | 4 +- .../Core/DolphinWX/Debugger/BreakpointView.h | 2 +- .../DolphinWX/Debugger/BreakpointWindow.cpp | 24 +- .../DolphinWX/Debugger/BreakpointWindow.h | 12 +- Source/Core/DolphinWX/Debugger/CodeView.cpp | 230 +++++----- Source/Core/DolphinWX/Debugger/CodeView.h | 14 +- Source/Core/DolphinWX/Debugger/CodeWindow.cpp | 125 +++--- Source/Core/DolphinWX/Debugger/CodeWindow.h | 105 +++-- .../Debugger/CodeWindowFunctions.cpp | 246 ++++------- .../DolphinWX/Debugger/DSPDebugWindow.cpp | 46 +- .../Core/DolphinWX/Debugger/DSPDebugWindow.h | 4 +- .../DolphinWX/Debugger/DSPRegisterView.cpp | 4 +- .../Core/DolphinWX/Debugger/DSPRegisterView.h | 2 +- .../Core/DolphinWX/Debugger/DebuggerPanel.cpp | 123 ++---- .../Core/DolphinWX/Debugger/DebuggerPanel.h | 6 - Source/Core/DolphinWX/Debugger/JitWindow.cpp | 14 +- Source/Core/DolphinWX/Debugger/JitWindow.h | 4 +- .../DolphinWX/Debugger/MemoryCheckDlg.cpp | 37 +- Source/Core/DolphinWX/Debugger/MemoryView.cpp | 371 ++++++++-------- Source/Core/DolphinWX/Debugger/MemoryView.h | 38 +- .../Core/DolphinWX/Debugger/MemoryWindow.cpp | 414 ++++++++---------- Source/Core/DolphinWX/Debugger/MemoryWindow.h | 43 +- .../Core/DolphinWX/Debugger/RegisterView.cpp | 12 +- Source/Core/DolphinWX/Debugger/RegisterView.h | 4 +- .../DolphinWX/Debugger/RegisterWindow.cpp | 4 +- Source/Core/DolphinWX/Debugger/WatchView.cpp | 14 +- Source/Core/DolphinWX/Debugger/WatchView.h | 2 +- .../Core/DolphinWX/Debugger/WatchWindow.cpp | 9 +- Source/Core/DolphinWX/Frame.cpp | 53 +-- Source/Core/DolphinWX/Frame.h | 11 +- Source/Core/DolphinWX/FrameAui.cpp | 195 +++++---- Source/Core/DolphinWX/FrameTools.cpp | 31 +- Source/Core/DolphinWX/Globals.h | 8 +- Source/Core/DolphinWX/LogConfigWindow.cpp | 28 +- Source/Core/DolphinWX/LogConfigWindow.h | 1 - Source/Core/DolphinWX/LogWindow.cpp | 18 +- Source/Core/DolphinWX/LogWindow.h | 7 +- Source/Core/DolphinWX/WxUtils.cpp | 7 - Source/Core/DolphinWX/WxUtils.h | 3 - 40 files changed, 1108 insertions(+), 1179 deletions(-) diff --git a/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp b/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp index 9665bb271e..b9d1bca401 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp +++ b/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp @@ -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(); } diff --git a/Source/Core/DolphinWX/Debugger/BreakpointView.cpp b/Source/Core/DolphinWX/Debugger/BreakpointView.cpp index 743bfec2b8..d9242992ea 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointView.cpp +++ b/Source/Core/DolphinWX/Debugger/BreakpointView.cpp @@ -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(); } } diff --git a/Source/Core/DolphinWX/Debugger/BreakpointView.h b/Source/Core/DolphinWX/Debugger/BreakpointView.h index a7d37bb5bb..79a1283a45 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointView.h +++ b/Source/Core/DolphinWX/Debugger/BreakpointView.h @@ -11,6 +11,6 @@ class CBreakPointView : public wxListCtrl public: CBreakPointView(wxWindow* parent, const wxWindowID id); - void Update() override; + void Repopulate(); void DeleteCurrentSelection(); }; diff --git a/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp b/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp index 133e563fea..881add3f9d 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include + // clang-format off #include #include @@ -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 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)) diff --git a/Source/Core/DolphinWX/Debugger/BreakpointWindow.h b/Source/Core/DolphinWX/Debugger/BreakpointWindow.h index 67b8cb912f..3f07e81fb5 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointWindow.h +++ b/Source/Core/DolphinWX/Debugger/BreakpointWindow.h @@ -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); }; diff --git a/Source/Core/DolphinWX/Debugger/CodeView.cpp b/Source/Core/DolphinWX/Debugger/CodeView.cpp index 22119b6bac..8bc07036b3 100644 --- a/Source/Core/DolphinWX/Debugger/CodeView.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeView.cpp @@ -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 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 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(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& ctx, int x, int y) -{ - std::vector 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(); diff --git a/Source/Core/DolphinWX/Debugger/CodeView.h b/Source/Core/DolphinWX/Debugger/CodeView.h index a29053dd1f..52e07e0cf8 100644 --- a/Source/Core/DolphinWX/Debugger/CodeView.h +++ b/Source/Core/DolphinWX/Debugger/CodeView.h @@ -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& dc, int x, int y); - struct BlrStruct // for IDM_INSERTBLR { u32 address; @@ -70,6 +61,8 @@ private: }; std::vector 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; }; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp index db1fb5e31f..b3b4bf8ac6 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp @@ -44,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" @@ -54,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(); @@ -88,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(); @@ -144,30 +154,30 @@ void CCodeWindow::OnHostMessage(wxCommandEvent& event) { case IDM_NOTIFY_MAP_LOADED: NotifyMapLoaded(); - if (m_BreakpointWindow) - m_BreakpointWindow->NotifyUpdate(); + if (HasPanel()) + GetPanel()->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()) + GetPanel()->NotifyUpdate(); + if (HasPanel()) + GetPanel()->NotifyUpdate(); + if (HasPanel()) + GetPanel()->Refresh(); break; case IDM_UPDATE_BREAKPOINTS: - if (m_BreakpointWindow) - m_BreakpointWindow->NotifyUpdate(); + Repopulate(); + if (HasPanel()) + GetPanel()->NotifyUpdate(); + if (HasPanel()) + GetPanel()->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()->ViewAddr(codeview->GetSelection()); break; } } @@ -195,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: @@ -373,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(); } @@ -386,7 +400,7 @@ void CCodeWindow::ToggleBreakpoint() { if (codeview) codeview->ToggleBreakpoint(codeview->GetSelection()); - Update(); + Repopulate(); } } @@ -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); diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.h b/Source/Core/DolphinWX/Debugger/CodeWindow.h index 5788d7d062..0cd6604261 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.h +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.h @@ -4,6 +4,8 @@ #pragma once +#include + #include #include #include @@ -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 +struct DebugPanelToID; + +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_BREAKPOINT_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_REGISTER_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_WATCH_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_MEMORY_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_JIT_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_SOUND_WINDOW; +}; +template <> +struct DebugPanelToID +{ + 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 + T* GetPanel() const + { + return static_cast(GetUntypedPanel(Details::DebugPanelToID::ID)); + } + template + bool HasPanel() const + { + return HasUntypedPanel(Details::DebugPanelToID::ID); + } + template + T* RequirePanel() + { + if (T* p = GetPanel()) + 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::ID, true); + return GetPanel(); + } // 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 m_sibling_panels; + + CFrame* Parent; CCodeView* codeview; wxListBox* callstack; wxListBox* symbols; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp index 0a1300146b..42a4b8f22c 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -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(); + 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); } } diff --git a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp index 199f1d376e..69301fc233 100644 --- a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp @@ -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() diff --git a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h index 51519f010c..c67f2f7682 100644 --- a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h +++ b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h @@ -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); diff --git a/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp b/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp index 5caa406d25..4f0d6fb2d3 100644 --- a/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp +++ b/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp @@ -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(); diff --git a/Source/Core/DolphinWX/Debugger/DSPRegisterView.h b/Source/Core/DolphinWX/Debugger/DSPRegisterView.h index a8ad3fd60d..dccfb7f975 100644 --- a/Source/Core/DolphinWX/Debugger/DSPRegisterView.h +++ b/Source/Core/DolphinWX/Debugger/DSPRegisterView.h @@ -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. diff --git a/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp b/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp index c1a6a90eca..b8a909bf85 100644 --- a/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp +++ b/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp @@ -11,6 +11,7 @@ #include #include +#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; diff --git a/Source/Core/DolphinWX/Debugger/DebuggerPanel.h b/Source/Core/DolphinWX/Debugger/DebuggerPanel.h index cc30037366..3e9864cd6c 100644 --- a/Source/Core/DolphinWX/Debugger/DebuggerPanel.h +++ b/Source/Core/DolphinWX/Debugger/DebuggerPanel.h @@ -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); diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.cpp b/Source/Core/DolphinWX/Debugger/JitWindow.cpp index 4bc9dfedb9..79f1daffe4 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/JitWindow.cpp @@ -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() { } diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.h b/Source/Core/DolphinWX/Debugger/JitWindow.h index 5bfd31d0a8..aa647efe8b 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.h +++ b/Source/Core/DolphinWX/Debugger/JitWindow.h @@ -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*/); diff --git a/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp b/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp index 0f8f1263f9..51cfc7b462 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp @@ -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(); diff --git a/Source/Core/DolphinWX/Debugger/MemoryView.cpp b/Source/Core/DolphinWX/Debugger/MemoryView.cpp index f5bebea901..47c2969dc2 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryView.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryView.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include #include #include #include @@ -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(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(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(); 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(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(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(mem_data >> (24 - i * 8)); + if (std::isprint(byte)) + dis += static_cast(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) diff --git a/Source/Core/DolphinWX/Debugger/MemoryView.h b/Source/Core/DolphinWX/Debugger/MemoryView.h index 03cb68d21f..396b84b1c0 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryView.h +++ b/Source/Core/DolphinWX/Debugger/MemoryView.h @@ -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; }; diff --git a/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp b/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp index 17dea4a17d..a70ba2db94 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp @@ -2,9 +2,10 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include #include #include -#include #include #include #include @@ -12,10 +13,13 @@ #include #include #include +#include #include #include #include +#include #include +#include #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(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(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 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(ev.GetInt())); + int idx = -1; + if (itr != map.end()) + idx = static_cast(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 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 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(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(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(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()); diff --git a/Source/Core/DolphinWX/Debugger/MemoryWindow.h b/Source/Core/DolphinWX/Debugger/MemoryWindow.h index f9ff2ca285..cf3800e292 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryWindow.h +++ b/Source/Core/DolphinWX/Debugger/MemoryWindow.h @@ -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; }; diff --git a/Source/Core/DolphinWX/Debugger/RegisterView.cpp b/Source/Core/DolphinWX/Debugger/RegisterView.cpp index 96518b3ea3..002e29e9e1 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterView.cpp +++ b/Source/Core/DolphinWX/Debugger/RegisterView.cpp @@ -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(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(); + CMemoryWindow* memory_window = code_window->GetPanel(); switch (event.GetId()) { diff --git a/Source/Core/DolphinWX/Debugger/RegisterView.h b/Source/Core/DolphinWX/Debugger/RegisterView.h index 5da6c206fe..d17696f67c 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterView.h +++ b/Source/Core/DolphinWX/Debugger/RegisterView.h @@ -51,7 +51,7 @@ public: void UpdateCachedRegs(); private: - static constexpr size_t NUM_SPECIALS = 14; + static constexpr int NUM_SPECIALS = 14; std::array m_CachedRegs{}; std::array 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); diff --git a/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp b/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp index 03d1afbab8..b849eb86fe 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp @@ -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(); } diff --git a/Source/Core/DolphinWX/Debugger/WatchView.cpp b/Source/Core/DolphinWX/Debugger/WatchView.cpp index ec3227b33d..1eab82db35 100644 --- a/Source/Core/DolphinWX/Debugger/WatchView.cpp +++ b/Source/Core/DolphinWX/Debugger/WatchView.cpp @@ -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(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(); + CMemoryWindow* memory_window = code_window->GetPanel(); + CBreakPointWindow* breakpoint_window = code_window->GetPanel(); wxString strNewVal; TMemCheck MemCheck; diff --git a/Source/Core/DolphinWX/Debugger/WatchView.h b/Source/Core/DolphinWX/Debugger/WatchView.h index b00c290a0b..624526fe19 100644 --- a/Source/Core/DolphinWX/Debugger/WatchView.h +++ b/Source/Core/DolphinWX/Debugger/WatchView.h @@ -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); diff --git a/Source/Core/DolphinWX/Debugger/WatchWindow.cpp b/Source/Core/DolphinWX/Debugger/WatchWindow.cpp index f43190a5d3..45a55eebe5 100644 --- a/Source/Core/DolphinWX/Debugger/WatchWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/WatchWindow.cpp @@ -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)) diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index 3dfd4f5e0e..2b3cdb0959 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -323,14 +323,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() @@ -643,11 +638,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(); @@ -745,6 +739,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; @@ -826,33 +825,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() diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index 8ebed24d80..2f2f4ce6aa 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -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; @@ -130,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); @@ -211,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(); @@ -228,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); diff --git a/Source/Core/DolphinWX/FrameAui.cpp b/Source/Core/DolphinWX/FrameAui.cpp index e5ea077a28..4bc4e50206 100644 --- a/Source/Core/DolphinWX/FrameAui.cpp +++ b/Source/Core/DolphinWX/FrameAui.cpp @@ -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(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(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() diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 8ebce0d9a1..52bca00dc2 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -642,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()) + g_pCodeWindow->GetPanel()->LoadAll(); + if (g_pCodeWindow->HasPanel()) + g_pCodeWindow->GetPanel()->LoadAll(); } } } @@ -842,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(); } @@ -1165,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()) + g_pCodeWindow->GetPanel()->SaveAll(); + PowerPC::watches.Clear(); + if (g_pCodeWindow->HasPanel()) + g_pCodeWindow->GetPanel()->SaveAll(); + PowerPC::breakpoints.Clear(); + PowerPC::memchecks.Clear(); + if (g_pCodeWindow->HasPanel()) + g_pCodeWindow->GetPanel()->NotifyUpdate(); g_symbolDB.Clear(); Host_NotifyMapLoaded(); } diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h index 2aa26350a6..8a303aa1ef 100644 --- a/Source/Core/DolphinWX/Globals.h +++ b/Source/Core/DolphinWX/Globals.h @@ -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 diff --git a/Source/Core/DolphinWX/LogConfigWindow.cpp b/Source/Core/DolphinWX/LogConfigWindow.cpp index da517d288f..52562507f6 100644 --- a/Source/Core/DolphinWX/LogConfigWindow.cpp +++ b/Source/Core/DolphinWX/LogConfigWindow.cpp @@ -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() diff --git a/Source/Core/DolphinWX/LogConfigWindow.h b/Source/Core/DolphinWX/LogConfigWindow.h index 3259c060ec..027372880b 100644 --- a/Source/Core/DolphinWX/LogConfigWindow.h +++ b/Source/Core/DolphinWX/LogConfigWindow.h @@ -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); diff --git a/Source/Core/DolphinWX/LogWindow.cpp b/Source/Core/DolphinWX/LogWindow.cpp index a971fe98e0..fff56dd260 100644 --- a/Source/Core/DolphinWX/LogWindow.cpp +++ b/Source/Core/DolphinWX/LogWindow.cpp @@ -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(i), diff --git a/Source/Core/DolphinWX/LogWindow.h b/Source/Core/DolphinWX/LogWindow.h index 61fa12f71c..26d931d52b 100644 --- a/Source/Core/DolphinWX/LogWindow.h +++ b/Source/Core/DolphinWX/LogWindow.h @@ -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> 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(); }; diff --git a/Source/Core/DolphinWX/WxUtils.cpp b/Source/Core/DolphinWX/WxUtils.cpp index 3d86954d76..7a7763df48 100644 --- a/Source/Core/DolphinWX/WxUtils.cpp +++ b/Source/Core/DolphinWX/WxUtils.cpp @@ -66,13 +66,6 @@ void ShowErrorDialog(const wxString& error_msg) wxMessageBox(error_msg, _("Error"), wxOK | wxICON_ERROR); } -wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size) -{ - wxWindow* context = wxTheApp->GetTopWindow(); - return LoadScaledResourceBitmap(name, context, padded_size, wxDefaultSize, - LSI_SCALE_DOWN | LSI_ALIGN_VCENTER, *wxWHITE); -} - wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original) { wxImage image = original.ConvertToImage(); diff --git a/Source/Core/DolphinWX/WxUtils.h b/Source/Core/DolphinWX/WxUtils.h index 9b379532ff..521979d32c 100644 --- a/Source/Core/DolphinWX/WxUtils.h +++ b/Source/Core/DolphinWX/WxUtils.h @@ -29,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 = wxDefaultSize); - // From a wxBitmap, creates the corresponding disabled version for toolbar buttons wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original); From c4f5ced37ca9eff6a5c62c08f1cc7a9e6dc47f7d Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Mon, 3 Oct 2016 07:19:56 +0000 Subject: [PATCH 16/16] WX: Replace SetIcon with SetIcons(wxIconBundle) Setting a single icon at a single resolution doesn't scale well, Windows requires a 16x16 icon for the window and a 32x32/48x48 for the taskbar. Providing all icons produces less pixellated results at HiDPI. --- Source/Core/DolphinWX/Cheats/CheatsWindow.cpp | 1 + Source/Core/DolphinWX/Frame.cpp | 4 +- .../DolphinWX/NetPlay/NetPlaySetupFrame.cpp | 6 +-- Source/Core/DolphinWX/NetPlay/NetWindow.cpp | 1 + Source/Core/DolphinWX/WxUtils.cpp | 48 +++++++++++++++++++ Source/Core/DolphinWX/WxUtils.h | 3 ++ 6 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp b/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp index a313d4c2a0..af4ec1c177 100644 --- a/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp +++ b/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp @@ -61,6 +61,7 @@ wxCheatsWindow::wxCheatsWindow(wxWindow* const parent) UpdateGUI(); wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &wxCheatsWindow::OnLocalGameIniModified, this); + SetIcons(WxUtils::GetDolphinIconBundle()); SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER); Center(); diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index 2b3cdb0959..5cfbc79937 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -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::LoadScaledResourceBitmap("Dolphin", this)); - SetIcon(IconTemp); + SetIcons(WxUtils::GetDolphinIconBundle()); DragAcceptFiles(true); Bind(wxEVT_DROP_FILES, &CRenderFrame::OnDropFiles, this); diff --git a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp index 230f12bbe8..21dbce3217 100644 --- a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp +++ b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp @@ -43,11 +43,7 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); CreateGUI(); - { - wxIcon icon; - icon.CopyFromBitmap(WxUtils::LoadScaledResourceBitmap("Dolphin", this)); - SetIcon(icon); - } + SetIcons(WxUtils::GetDolphinIconBundle()); { std::string temp; diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp index 1c7a7dc57f..90f60e3c1b 100644 --- a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp @@ -70,6 +70,7 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const { Bind(wxEVT_THREAD, &NetPlayDialog::OnThread, this); CreateGUI(); + SetIcons(WxUtils::GetDolphinIconBundle()); Center(); // Remember the window size and position for NetWindow diff --git a/Source/Core/DolphinWX/WxUtils.cpp b/Source/Core/DolphinWX/WxUtils.cpp index 7a7763df48..ef22a09d43 100644 --- a/Source/Core/DolphinWX/WxUtils.cpp +++ b/Source/Core/DolphinWX/WxUtils.cpp @@ -28,6 +28,10 @@ #include "DolphinWX/WxUtils.h" +#ifdef _WIN32 +#include +#endif + namespace WxUtils { // Launch a file according to its mime type @@ -81,6 +85,50 @@ 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(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; diff --git a/Source/Core/DolphinWX/WxUtils.h b/Source/Core/DolphinWX/WxUtils.h index 521979d32c..6cb449ae2d 100644 --- a/Source/Core/DolphinWX/WxUtils.h +++ b/Source/Core/DolphinWX/WxUtils.h @@ -36,6 +36,9 @@ 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();