mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-05-07 13:37:46 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
d3f7f1da66
62 changed files with 1388 additions and 165 deletions
|
|
@ -6,7 +6,7 @@
|
|||
QT_HOST="http://qt.mirror.constant.com/"
|
||||
QT_URL_VER=$(echo "$QT_VER" | sed "s/\.//g")
|
||||
QT_VER_MSVC_UP=$(echo "${QT_VER_MSVC}" | tr '[:lower:]' '[:upper:]')
|
||||
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}."
|
||||
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt${QT_VER_MAIN}_${QT_URL_VER}_${QT_VER_MSVC}_64/qt.qt${QT_VER_MAIN}.${QT_URL_VER}."
|
||||
QT_PREFIX_2="win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
|
||||
QT_SUFFIX="-Windows-Windows_11_24H2-${QT_VER_MSVC_UP}-Windows-Windows_11_24H2-X86_64.7z"
|
||||
QT_BASE_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtbase${QT_SUFFIX}"
|
||||
|
|
|
|||
14
.github/workflows/rpcs3.yml
vendored
14
.github/workflows/rpcs3.yml
vendored
|
|
@ -30,23 +30,23 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- os: ubuntu-24.04
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.9"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.10"
|
||||
build_sh: "/rpcs3/.ci/build-linux.sh"
|
||||
compiler: clang
|
||||
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
|
||||
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
|
||||
- os: ubuntu-24.04
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.9"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.10"
|
||||
build_sh: "/rpcs3/.ci/build-linux.sh"
|
||||
compiler: gcc
|
||||
- os: ubuntu-24.04-arm
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.9"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.10"
|
||||
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
|
||||
compiler: clang
|
||||
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
|
||||
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
|
||||
- os: ubuntu-24.04-arm
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.9"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.10"
|
||||
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
|
||||
compiler: gcc
|
||||
name: RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }}
|
||||
|
|
@ -134,7 +134,7 @@ jobs:
|
|||
runs-on: macos-14
|
||||
env:
|
||||
CCACHE_DIR: /tmp/ccache_dir
|
||||
QT_VER: '6.10.2'
|
||||
QT_VER: '6.11.0'
|
||||
QT_VER_MAIN: '6'
|
||||
LLVM_COMPILER_VER: '21'
|
||||
RELEASE_MESSAGE: ../GitHubReleaseMessage.txt
|
||||
|
|
@ -213,9 +213,9 @@ jobs:
|
|||
env:
|
||||
COMPILER: msvc
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.10.2'
|
||||
QT_VER: '6.11.0'
|
||||
QT_VER_MSVC: 'msvc2022'
|
||||
QT_DATE: '202601261212'
|
||||
QT_DATE: '202603180535'
|
||||
LLVM_VER: '19.1.7'
|
||||
VULKAN_VER: '1.3.268.0'
|
||||
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
||||
|
|
|
|||
2
3rdparty/libpng/libpng
vendored
2
3rdparty/libpng/libpng
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit c3e304954a9cfd154bc0dfbfea2b01cd61d6546d
|
||||
Subproject commit d5515b5b8be3901aac04e5bd8bd5c89f287bcd33
|
||||
2
3rdparty/wolfssl/wolfssl
vendored
2
3rdparty/wolfssl/wolfssl
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit b077c81eb635392e694ccedbab8b644297ec0285
|
||||
Subproject commit 922d04b3568c6428a9fb905ddee3ef5a68db3108
|
||||
10
BUILDING.md
10
BUILDING.md
|
|
@ -20,26 +20,26 @@ The following tools are required to build RPCS3 on Windows 10 or later:
|
|||
with standalone **CMake** tool.
|
||||
|
||||
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
|
||||
- [Qt 6.10.2](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
|
||||
- [Qt 6.11.0](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
|
||||
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
|
||||
The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode.
|
||||
|
||||
In order to build **RPCS3** with the `sln` solution (with **Visual Studio**), **Qt** libs need to be detected. To detect the libs:
|
||||
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.10.2\msvc2022_64\`
|
||||
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.11.0\msvc2022_64\`
|
||||
- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022)
|
||||
|
||||
**NOTE:** If you have issues with the **Visual Studio Qt Plugin**, you may want to uninstall it and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2022) instead.
|
||||
|
||||
In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool):
|
||||
- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.10.2\msvc2022_64\`
|
||||
- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.11.0\msvc2022_64\`
|
||||
|
||||
### Linux
|
||||
|
||||
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager:
|
||||
- Clang 17+ or GCC 13+
|
||||
- [CMake 3.28.0+](https://www.cmake.org/download/)
|
||||
- [Qt 6.10.2](https://www.qt.io/download-qt-installer)
|
||||
- [Qt 6.11.0](https://www.qt.io/download-qt-installer)
|
||||
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
- [SDL3](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ Start **Visual Studio**, click on `Open a project or solution` and select the `r
|
|||
##### Configuring the Qt Plugin (if used)
|
||||
|
||||
1) go to `Extensions->Qt VS Tools->Qt Versions`
|
||||
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.10.2\msvc2022_64`, version will fill in automatically
|
||||
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.11.0\msvc2022_64`, version will fill in automatically
|
||||
3) go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the **Legacy Qt Plugin**)
|
||||
4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**)
|
||||
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ namespace cfg
|
|||
|
||||
void set(const s64& value)
|
||||
{
|
||||
ensure(value >= Min && value <= Max);
|
||||
if (value < Min || value > Max) fmt::throw_exception("'%s': value %d out of bounds (min=%d, max=%d)", m_name, value, Min, Max);
|
||||
m_value = static_cast<int_type>(value);
|
||||
}
|
||||
|
||||
|
|
@ -484,7 +484,7 @@ namespace cfg
|
|||
|
||||
void set(const f64& value)
|
||||
{
|
||||
ensure(value >= Min && value <= Max);
|
||||
if (value < Min || value > Max) fmt::throw_exception("'%s': value %d out of bounds (min=%d, max=%d)", m_name, value, Min, Max);
|
||||
m_value = static_cast<float_type>(value);
|
||||
}
|
||||
|
||||
|
|
@ -571,7 +571,7 @@ namespace cfg
|
|||
|
||||
void set(const u64& value)
|
||||
{
|
||||
ensure(value >= Min && value <= Max);
|
||||
if (value < Min || value > Max) fmt::throw_exception("'%s': value %d out of bounds (min=%d, max=%d)", m_name, value, Min, Max);
|
||||
m_value = static_cast<int_type>(value);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
set(WOLFSSL_LIBRARY ON)
|
||||
set(WOLFSSL_INCLUDE_DIR ON)
|
||||
set(WOLFSSL_LIBRARIES wolfssl)
|
||||
set(WOLFSSL_LIBRARY wolfssl)
|
||||
set(WOLFSSL_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/3rdparty/wolfssl)
|
||||
set(WOLFSSL_FOUND TRUE)
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ if(USE_SYSTEM_ZLIB)
|
|||
find_package(ZLIB)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
|
||||
else()
|
||||
add_library(ZLIB::ZLIB INTERFACE IMPORTED)
|
||||
add_library(ZLIB::ZLIB STATIC IMPORTED)
|
||||
set_target_properties(ZLIB::ZLIB PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES zlibstatic
|
||||
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib/libzlibstatic.a"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/3rdparty/zlib/zlib;${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib")
|
||||
set(ZLIB_FOUND TRUE)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1286,7 +1286,7 @@ extern bool ppu_patch(u32 addr, u32 value)
|
|||
{
|
||||
if (addr % 4)
|
||||
{
|
||||
ppu_log.fatal("Patch failed at 0x%x: unanligned memory address.", addr);
|
||||
ppu_log.fatal("Patch failed at 0x%x: unaligned memory address.", addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2323,7 +2323,7 @@ public:
|
|||
llvm::Value* loop_dictator_after_adjustment{};
|
||||
|
||||
spu_opcode_t reg_target{};
|
||||
reg_target.rt = reduced_loop_info->cond_val_register_idx;
|
||||
reg_target.rt = static_cast<u32>(reduced_loop_info->cond_val_register_idx);
|
||||
|
||||
if (reg_target.rt != reduced_loop_info->cond_val_register_idx)
|
||||
{
|
||||
|
|
@ -2375,7 +2375,7 @@ public:
|
|||
else
|
||||
{
|
||||
spu_opcode_t reg_incr{};
|
||||
reg_incr.rt = reduced_loop_info->cond_val_incr;
|
||||
reg_incr.rt = static_cast<u32>(reduced_loop_info->cond_val_incr);
|
||||
|
||||
if (reg_incr.rt != reduced_loop_info->cond_val_incr)
|
||||
{
|
||||
|
|
@ -2425,7 +2425,7 @@ public:
|
|||
else
|
||||
{
|
||||
spu_opcode_t reg_target2{};
|
||||
reg_target2.rt = reduced_loop_info->cond_val_register_argument_idx;
|
||||
reg_target2.rt = static_cast<u32>(reduced_loop_info->cond_val_register_argument_idx);
|
||||
|
||||
if (reg_target2.rt != reduced_loop_info->cond_val_register_argument_idx)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ struct cfg_recording final : cfg::node
|
|||
node_video(cfg::node* _this) : cfg::node(_this, "Video") {}
|
||||
|
||||
cfg::uint<0, 60> framerate{this, "Framerate", 30};
|
||||
cfg::uint<0, 7680> width{this, "Width", 1280};
|
||||
cfg::uint<0, 4320> height{this, "Height", 720};
|
||||
cfg::uint<640, 7680> width{this, "Width", 1280};
|
||||
cfg::uint<360, 4320> height{this, "Height", 720};
|
||||
cfg::uint<0, 192> pixel_format{this, "AVPixelFormat", 0}; // AVPixelFormat::AV_PIX_FMT_YUV420P
|
||||
cfg::uint<0, 0xFFFF> video_codec{this, "AVCodecID", 12}; // AVCodecID::AV_CODEC_ID_MPEG4
|
||||
cfg::uint<0, 25000000> video_bps{this, "Video Bitrate", 4000000};
|
||||
cfg::uint<0, 5> max_b_frames{this, "Max B-Frames", 2};
|
||||
cfg::uint<0, 20> gop_size{this, "Group of Pictures Size", 12};
|
||||
cfg::uint<1'000'000, 60'000'000> video_bps{this, "Video Bitrate", 4'000'000};
|
||||
cfg::uint<0, 3> max_b_frames{this, "Max B-Frames", 2};
|
||||
cfg::uint<1, 120> gop_size{this, "Group of Pictures Size", 30};
|
||||
|
||||
} video{ this };
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ struct cfg_recording final : cfg::node
|
|||
node_audio(cfg::node* _this) : cfg::node(_this, "Audio") {}
|
||||
|
||||
cfg::uint<0x10000, 0x17000> audio_codec{this, "AVCodecID", 86018}; // AVCodecID::AV_CODEC_ID_AAC
|
||||
cfg::uint<0, 25000000> audio_bps{this, "Audio Bitrate", 320000};
|
||||
cfg::uint<64'000, 320'000> audio_bps{this, "Audio Bitrate", 192'000};
|
||||
|
||||
} audio{ this };
|
||||
|
||||
|
|
|
|||
|
|
@ -431,25 +431,25 @@ namespace rsx
|
|||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::set_text(const std::string& text)
|
||||
void overlay_element::set_text(std::string_view text)
|
||||
{
|
||||
std::u32string new_text = utf8_to_u32string(text);
|
||||
const bool is_dirty = this->text != new_text;
|
||||
this->text = std::move(new_text);
|
||||
|
||||
if (is_dirty)
|
||||
{
|
||||
this->text = std::move(new_text);
|
||||
m_is_compiled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void overlay_element::set_unicode_text(const std::u32string& text)
|
||||
void overlay_element::set_unicode_text(std::u32string_view text)
|
||||
{
|
||||
const bool is_dirty = this->text != text;
|
||||
this->text = text;
|
||||
|
||||
if (is_dirty)
|
||||
{
|
||||
this->text = text;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,8 +242,8 @@ namespace rsx
|
|||
// NOTE: Functions as a simple position offset. Top left corner is the anchor.
|
||||
virtual void set_margin(u16 left, u16 top);
|
||||
virtual void set_margin(u16 margin);
|
||||
virtual void set_text(const std::string& text);
|
||||
virtual void set_unicode_text(const std::u32string& text);
|
||||
virtual void set_text(std::string_view text);
|
||||
virtual void set_unicode_text(std::u32string_view text);
|
||||
void set_text(localized_string_id id);
|
||||
void set_text(const localized_string& container);
|
||||
virtual void set_font(const char* font_name, u16 font_size);
|
||||
|
|
|
|||
|
|
@ -95,12 +95,12 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
void edit_text::set_text(const std::string& text)
|
||||
void edit_text::set_text(std::string_view text)
|
||||
{
|
||||
set_unicode_text(utf8_to_u32string(text));
|
||||
}
|
||||
|
||||
void edit_text::set_unicode_text(const std::u32string& text)
|
||||
void edit_text::set_unicode_text(std::u32string_view text)
|
||||
{
|
||||
value = text;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ namespace rsx
|
|||
|
||||
using label::label;
|
||||
|
||||
void set_text(const std::string& text) override;
|
||||
void set_unicode_text(const std::u32string& text) override;
|
||||
void set_text(std::string_view text) override;
|
||||
void set_unicode_text(std::u32string_view text) override;
|
||||
|
||||
void set_placeholder(const std::u32string& placeholder_text);
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ namespace rsx
|
|||
return m_loc_id == id;
|
||||
}
|
||||
|
||||
bool message_item::text_matches(const std::u32string& text) const
|
||||
bool message_item::text_matches(std::u32string_view text) const
|
||||
{
|
||||
return m_text.text == text;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace rsx
|
|||
compiled_resource& get_compiled() override;
|
||||
|
||||
bool id_matches(localized_string_id id) const;
|
||||
bool text_matches(const std::u32string& text) const;
|
||||
bool text_matches(std::u32string_view text) const;
|
||||
|
||||
void set_label_text(const std::string& text);
|
||||
|
||||
|
|
|
|||
|
|
@ -948,7 +948,7 @@ namespace rsx
|
|||
perf_overlay->set_update_interval(perf_settings.update_interval);
|
||||
perf_overlay->set_font(perf_settings.font);
|
||||
perf_overlay->set_font_size(perf_settings.font_size);
|
||||
perf_overlay->set_margins(perf_settings.margin_x, perf_settings.margin_y, perf_settings.center_x.get(), perf_settings.center_y.get());
|
||||
perf_overlay->set_margins(static_cast<f32>(perf_settings.margin_x.get()), static_cast<f32>(perf_settings.margin_y.get()), perf_settings.center_x.get(), perf_settings.center_y.get());
|
||||
perf_overlay->use_window_space = perf_settings.perf_overlay_use_window_space.get();
|
||||
perf_overlay->set_opacity(perf_settings.opacity / 100.f);
|
||||
perf_overlay->set_body_colors(perf_settings.color_body, perf_settings.background_body);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ namespace rsx
|
|||
set_pos(x + dx, y + dy);
|
||||
}
|
||||
|
||||
void progress_bar::set_text(const std::string& str)
|
||||
void progress_bar::set_text(std::string_view str)
|
||||
{
|
||||
text_view.set_text(str);
|
||||
text_view.align_text(text_align::center);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace rsx
|
|||
void set_pos(s16 _x, s16 _y) override;
|
||||
void set_size(u16 _w, u16 _h) override;
|
||||
void translate(s16 dx, s16 dy) override;
|
||||
void set_text(const std::string& str) override;
|
||||
void set_text(std::string_view str) override;
|
||||
|
||||
compiled_resource& get_compiled() override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ static auto s_ascii_lowering_map = []()
|
|||
}();
|
||||
|
||||
template<typename F>
|
||||
void process_multibyte(const std::string& s, F&& func)
|
||||
void process_multibyte(std::string_view s, F&& func)
|
||||
{
|
||||
const usz end = s.length();
|
||||
for (usz index = 0; index < end; ++index)
|
||||
|
|
@ -110,7 +110,7 @@ void process_multibyte(const std::string& s, F&& func)
|
|||
}
|
||||
}
|
||||
|
||||
std::string utf8_to_ascii8(const std::string& utf8_string)
|
||||
std::string utf8_to_ascii8(std::string_view utf8_string)
|
||||
{
|
||||
std::string out;
|
||||
out.reserve(utf8_string.length());
|
||||
|
|
@ -135,7 +135,7 @@ std::string utf8_to_ascii8(const std::string& utf8_string)
|
|||
return out;
|
||||
}
|
||||
|
||||
std::string utf16_to_ascii8(const std::u16string& utf16_string)
|
||||
std::string utf16_to_ascii8(std::u16string_view utf16_string)
|
||||
{
|
||||
// Strip extended codes, map to '#' instead (placeholder)
|
||||
std::string out;
|
||||
|
|
@ -152,7 +152,7 @@ std::string utf16_to_ascii8(const std::u16string& utf16_string)
|
|||
return out;
|
||||
}
|
||||
|
||||
std::u16string ascii8_to_utf16(const std::string& ascii_string)
|
||||
std::u16string ascii8_to_utf16(std::string_view ascii_string)
|
||||
{
|
||||
std::u16string out;
|
||||
out.reserve(ascii_string.length());
|
||||
|
|
@ -168,7 +168,7 @@ std::u16string ascii8_to_utf16(const std::string& ascii_string)
|
|||
return out;
|
||||
}
|
||||
|
||||
std::u32string utf8_to_u32string(const std::string& utf8_string)
|
||||
std::u32string utf8_to_u32string(std::string_view utf8_string)
|
||||
{
|
||||
std::u32string result;
|
||||
result.reserve(utf8_string.size());
|
||||
|
|
@ -181,7 +181,7 @@ std::u32string utf8_to_u32string(const std::string& utf8_string)
|
|||
return result;
|
||||
}
|
||||
|
||||
std::u16string u32string_to_utf16(const std::u32string& utf32_string)
|
||||
std::u16string u32string_to_utf16(std::u32string_view utf32_string)
|
||||
{
|
||||
std::u16string result;
|
||||
result.reserve(utf32_string.size());
|
||||
|
|
@ -194,7 +194,7 @@ std::u16string u32string_to_utf16(const std::u32string& utf32_string)
|
|||
return result;
|
||||
}
|
||||
|
||||
std::u32string utf16_to_u32string(const std::u16string& utf16_string)
|
||||
std::u32string utf16_to_u32string(std::u16string_view utf16_string)
|
||||
{
|
||||
std::u32string result;
|
||||
result.reserve(utf16_string.size());
|
||||
|
|
|
|||
|
|
@ -218,9 +218,9 @@ void operator < (const vector3_base<T>& lhs, T rhs)
|
|||
using vector3i = vector3_base<int>;
|
||||
using vector3f = vector3_base<float>;
|
||||
|
||||
std::string utf8_to_ascii8(const std::string& utf8_string);
|
||||
std::string utf16_to_ascii8(const std::u16string& utf16_string);
|
||||
std::u16string ascii8_to_utf16(const std::string& ascii_string);
|
||||
std::u32string utf8_to_u32string(const std::string& utf8_string);
|
||||
std::u16string u32string_to_utf16(const std::u32string& utf32_string);
|
||||
std::u32string utf16_to_u32string(const std::u16string& utf16_string);
|
||||
std::string utf8_to_ascii8(std::string_view utf8_string);
|
||||
std::string utf16_to_ascii8(std::u16string_view utf16_string);
|
||||
std::u16string ascii8_to_utf16(std::string_view ascii_string);
|
||||
std::u32string utf8_to_u32string(std::string_view utf8_string);
|
||||
std::u16string u32string_to_utf16(std::u32string_view utf32_string);
|
||||
std::u32string utf16_to_u32string(std::u16string_view utf16_string);
|
||||
|
|
|
|||
|
|
@ -1868,6 +1868,7 @@ namespace rsx
|
|||
}
|
||||
default:
|
||||
rsx_log.fatal("Unhandled framebuffer option changed 0x%x", opt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2837,7 +2837,7 @@ bool Emulator::Pause(bool freeze_emulation, bool show_resume_message)
|
|||
auto msg_ref = std::make_shared<atomic_t<u32>>(1);
|
||||
|
||||
// No timeout
|
||||
rsx::overlays::queue_message(status == system_state::paused ? localized_string_id::EMULATION_PAUSED_RESUME_WITH_START : localized_string_id::EMULATION_FROZEN, -1, msg_ref);
|
||||
rsx::overlays::queue_message(status == system_state::paused ? localized_string_id::EMULATION_PAUSED_RESUME_WITH_START : localized_string_id::EMULATION_FROZEN, umax, msg_ref);
|
||||
m_pause_msgs_refs.emplace_back(msg_ref);
|
||||
|
||||
auto refresh_l = [this, msg_ref, status]()
|
||||
|
|
@ -3160,7 +3160,11 @@ void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op, bool savesta
|
|||
|
||||
if (async_op)
|
||||
{
|
||||
std::thread{perform_kill}.detach();
|
||||
std::thread{[perform_kill]()
|
||||
{
|
||||
thread_base::set_name("Perform Kill");
|
||||
perform_kill();
|
||||
}}.detach();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ void headless_application::InitializeCallbacks()
|
|||
{
|
||||
EmuCallbacks callbacks = CreateCallbacks();
|
||||
|
||||
callbacks.try_to_quit = [this](bool force_quit, std::function<void()> on_exit) -> bool
|
||||
callbacks.try_to_quit = [](bool force_quit, std::function<void()> on_exit) -> bool
|
||||
{
|
||||
if (force_quit)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ DYNAMIC_IMPORT("ntdll.dll", NtSetTimerResolution, NTSTATUS(ULONG DesiredResoluti
|
|||
#include "rpcs3_version.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/system_utils.hpp"
|
||||
#include "Emu/RSX/Overlays/overlay_message.h"
|
||||
#include <thread>
|
||||
#include <charconv>
|
||||
|
||||
|
|
@ -312,7 +313,8 @@ public:
|
|||
{
|
||||
if (msg == logs::level::fatal || (msg == logs::level::always && m_log_always))
|
||||
{
|
||||
std::string _msg = "RPCS3: ";
|
||||
static const std::string rpcs3_prefix = "RPCS3: ";
|
||||
std::string _msg = rpcs3_prefix;
|
||||
|
||||
if (!prefix.empty())
|
||||
{
|
||||
|
|
@ -351,7 +353,11 @@ public:
|
|||
#endif
|
||||
if (msg == logs::level::fatal)
|
||||
{
|
||||
std::string overlay_msg = "Fatal error: " + _msg.substr(rpcs3_prefix.size());
|
||||
fmt::trim_back(overlay_msg, " \t\n");
|
||||
|
||||
// Pause emulation if fatal error encountered
|
||||
rsx::overlays::queue_message(overlay_msg, umax);
|
||||
Emu.Pause(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -386,6 +386,9 @@
|
|||
<ClCompile Include="QTGeneratedFiles\Debug\moc_pad_settings_dialog.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_recording_settings_dialog.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_patch_creator_dialog.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -689,6 +692,9 @@
|
|||
<ClCompile Include="QTGeneratedFiles\Release\moc_pad_settings_dialog.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QTGeneratedFiles\Release\moc_recording_settings_dialog.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QTGeneratedFiles\Release\moc_patch_creator_dialog.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -868,6 +874,7 @@
|
|||
<ClCompile Include="rpcs3qt\osk_dialog_frame.cpp" />
|
||||
<ClCompile Include="rpcs3qt\pad_led_settings_dialog.cpp" />
|
||||
<ClCompile Include="rpcs3qt\pad_motion_settings_dialog.cpp" />
|
||||
<ClCompile Include="rpcs3qt\recording_settings_dialog.cpp" />
|
||||
<ClCompile Include="rpcs3qt\patch_creator_dialog.cpp" />
|
||||
<ClCompile Include="rpcs3qt\patch_manager_dialog.cpp" />
|
||||
<ClCompile Include="rpcs3qt\pkg_install_dialog.cpp" />
|
||||
|
|
@ -1157,6 +1164,7 @@
|
|||
<ClInclude Include="QTGeneratedFiles\ui_pad_led_settings_dialog.h" />
|
||||
<ClInclude Include="QTGeneratedFiles\ui_pad_motion_settings_dialog.h" />
|
||||
<ClInclude Include="QTGeneratedFiles\ui_pad_settings_dialog.h" />
|
||||
<ClInclude Include="QTGeneratedFiles\ui_recording_settings_dialog.h" />
|
||||
<ClInclude Include="QTGeneratedFiles\ui_patch_creator_dialog.h" />
|
||||
<ClInclude Include="QTGeneratedFiles\ui_patch_manager_dialog.h" />
|
||||
<ClInclude Include="QTGeneratedFiles\ui_settings_dialog.h" />
|
||||
|
|
@ -1624,6 +1632,16 @@
|
|||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\protobuf\protobuf\src" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg"</Command>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="rpcs3qt\recording_settings_dialog.h">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\protobuf\protobuf\src" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\protobuf\protobuf\src" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg"</Command>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="rpcs3qt\pad_device_info.h" />
|
||||
<ClInclude Include="rpcs3qt\permissions.h" />
|
||||
<ClInclude Include="rpcs3qt\progress_indicator.h" />
|
||||
|
|
@ -2196,6 +2214,16 @@
|
|||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\uic.exe" -o ".\QTGeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="rpcs3qt\recording_settings_dialog.ui">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\uic.exe" -o ".\QTGeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\uic.exe" -o ".\QTGeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="rpcs3qt\shortcut_dialog.ui">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Uic%27ing %(Identity)...</Message>
|
||||
|
|
|
|||
|
|
@ -291,6 +291,12 @@
|
|||
<ClCompile Include="QTGeneratedFiles\Release\moc_pad_settings_dialog.cpp">
|
||||
<Filter>Generated Files\Release</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_recording_settings_dialog.cpp">
|
||||
<Filter>Generated Files\Debug</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QTGeneratedFiles\Release\moc_recording_settings_dialog.cpp">
|
||||
<Filter>Generated Files\Release</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_rsx_debugger.cpp">
|
||||
<Filter>Generated Files\Debug</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -441,6 +447,9 @@
|
|||
<ClCompile Include="rpcs3qt\pad_settings_dialog.cpp">
|
||||
<Filter>Gui\settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="rpcs3qt\recording_settings_dialog.cpp">
|
||||
<Filter>Gui\settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="rpcs3qt\log_frame.cpp">
|
||||
<Filter>Gui\log</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1304,6 +1313,9 @@
|
|||
<ClInclude Include="QTGeneratedFiles\ui_pad_led_settings_dialog.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="QTGeneratedFiles\ui_recording_settings_dialog.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="QTGeneratedFiles\ui_settings_dialog.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -1555,6 +1567,9 @@
|
|||
<CustomBuild Include="rpcs3qt\settings_dialog.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="rpcs3qt\recording_settings_dialog.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="rpcs3qt\welcome_dialog.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</CustomBuild>
|
||||
|
|
@ -1597,6 +1612,9 @@
|
|||
<CustomBuild Include="rpcs3qt\pad_led_settings_dialog.h">
|
||||
<Filter>Gui\settings</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="rpcs3qt\recording_settings_dialog.h">
|
||||
<Filter>Gui\settings</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="rpcs3qt\log_frame.h">
|
||||
<Filter>Gui\log</Filter>
|
||||
</CustomBuild>
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ add_library(rpcs3_ui STATIC
|
|||
qt_video_source.cpp
|
||||
raw_mouse_settings_dialog.cpp
|
||||
register_editor_dialog.cpp
|
||||
recording_settings_dialog.cpp
|
||||
recvmessage_dialog_frame.cpp
|
||||
render_creator.cpp
|
||||
rpcn_settings_dialog.cpp
|
||||
|
|
@ -135,6 +136,7 @@ add_library(rpcs3_ui STATIC
|
|||
patch_creator_dialog.ui
|
||||
patch_manager_dialog.ui
|
||||
ps_move_tracker_dialog.ui
|
||||
recording_settings_dialog.ui
|
||||
settings_dialog.ui
|
||||
shortcut_dialog.ui
|
||||
welcome_dialog.ui
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ void auto_pause_settings_dialog::ShowContextMenu(const QPoint &pos)
|
|||
OnEntryConfig(idx, true);
|
||||
});
|
||||
connect(remove, &QAction::triggered, this, &auto_pause_settings_dialog::OnRemove);
|
||||
connect(config, &QAction::triggered, this, [=, this]() {OnEntryConfig(row, false); });
|
||||
connect(config, &QAction::triggered, this, [=]() {OnEntryConfig(row, false); });
|
||||
|
||||
myMenu.exec(m_pause_list->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ clans_settings_dialog::clans_settings_dialog(QWidget* parent)
|
|||
g_cfg_clans.save();
|
||||
});
|
||||
|
||||
connect(m_cbx_protocol, &QComboBox::currentIndexChanged, this, [this](int index)
|
||||
connect(m_cbx_protocol, &QComboBox::currentIndexChanged, this, [](int index)
|
||||
{
|
||||
if (index < 0)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "progress_dialog.h"
|
||||
|
||||
#include "util/logs.hpp"
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
|
|
@ -82,6 +83,8 @@ void downloader::start(const std::string& url, bool follow_location, bool show_p
|
|||
|
||||
m_thread = QThread::create([this]
|
||||
{
|
||||
thread_base::set_name("Downloader");
|
||||
|
||||
// Reset error buffer before we call curl_easy_perform
|
||||
m_curl->reset_error_buffer();
|
||||
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ bool emu_settings::ValidateSettings(bool cleanup)
|
|||
bool is_clean = true;
|
||||
|
||||
std::function<void(int, YAML::Node&, std::vector<std::string>&, cfg::_base*)> search_level;
|
||||
search_level = [&search_level, &is_clean, &cleanup, this](int level, YAML::Node& yml_node, std::vector<std::string>& keys, cfg::_base* cfg_base)
|
||||
search_level = [&search_level, &is_clean, &cleanup](int level, YAML::Node& yml_node, std::vector<std::string>& keys, cfg::_base* cfg_base)
|
||||
{
|
||||
if (!yml_node || !yml_node.IsMap())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ find_dialog::find_dialog(QPlainTextEdit* edit, QWidget *parent, Qt::WindowFlags
|
|||
|
||||
QCheckBox* cb_case_sensitive = new QCheckBox(tr("Case sensitive"));
|
||||
cb_case_sensitive->setChecked(m_case_sensitive);
|
||||
connect(cb_case_sensitive, &QCheckBox::toggled, this, [=](bool checked)
|
||||
connect(cb_case_sensitive, &QCheckBox::toggled, this, [this](bool checked)
|
||||
{
|
||||
m_case_sensitive = checked;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -908,7 +908,7 @@ void game_list_actions::BatchActionBySerials(progress_dialog* pdlg, const std::s
|
|||
|
||||
const int serials_size = ::narrow<int>(serials.size());
|
||||
|
||||
*iterate_over_serial = [=, this, index_ptr = index](int index)
|
||||
*iterate_over_serial = [=, index_ptr = index](int index)
|
||||
{
|
||||
if (index == serials_size)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ game_list_grid::game_list_grid()
|
|||
Q_EMIT IconReady(game, item);
|
||||
};
|
||||
|
||||
connect(this, &game_list_grid::IconReady, this, [this](const game_info& game, const movie_item_base* item)
|
||||
connect(this, &game_list_grid::IconReady, this, [](const game_info& game, const movie_item_base* item)
|
||||
{
|
||||
if (game && item && game->item == item) item->image_change_callback();
|
||||
}, Qt::QueuedConnection); // The default 'AutoConnection' doesn't seem to work in this specific case...
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ game_list_table::game_list_table(game_list_frame* frame, std::shared_ptr<persist
|
|||
}
|
||||
});
|
||||
|
||||
connect(this, &game_list::IconReady, this, [this](const game_info& game, const movie_item_base* item)
|
||||
connect(this, &game_list::IconReady, this, [](const game_info& game, const movie_item_base* item)
|
||||
{
|
||||
if (game && item && game->item == item) item->image_change_callback();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -793,7 +793,7 @@ f64 gs_frame::client_display_rate()
|
|||
{
|
||||
f64 rate = 20.; // Minimum is 20
|
||||
|
||||
Emu.BlockingCallFromMainThread([this, &rate]()
|
||||
Emu.BlockingCallFromMainThread([&rate]()
|
||||
{
|
||||
const QList<QScreen*> screens = QGuiApplication::screens();
|
||||
|
||||
|
|
|
|||
|
|
@ -737,8 +737,8 @@ void gui_application::InitializeCallbacks()
|
|||
callbacks.get_msg_dialog = [this]() -> std::shared_ptr<MsgDialogBase> { return m_show_gui ? std::make_shared<msg_dialog_frame>() : nullptr; };
|
||||
callbacks.get_osk_dialog = [this]() -> std::shared_ptr<OskDialogBase> { return m_show_gui ? std::make_shared<osk_dialog_frame>() : nullptr; };
|
||||
callbacks.get_save_dialog = []() -> std::unique_ptr<SaveDialogBase> { return std::make_unique<save_data_dialog>(); };
|
||||
callbacks.get_sendmessage_dialog = [this]() -> std::shared_ptr<SendMessageDialogBase> { return std::make_shared<sendmessage_dialog_frame>(); };
|
||||
callbacks.get_recvmessage_dialog = [this]() -> std::shared_ptr<RecvMessageDialogBase> { return std::make_shared<recvmessage_dialog_frame>(); };
|
||||
callbacks.get_sendmessage_dialog = []() -> std::shared_ptr<SendMessageDialogBase> { return std::make_shared<sendmessage_dialog_frame>(); };
|
||||
callbacks.get_recvmessage_dialog = []() -> std::shared_ptr<RecvMessageDialogBase> { return std::make_shared<recvmessage_dialog_frame>(); };
|
||||
callbacks.get_trophy_notification_dialog = [this]() -> std::unique_ptr<TrophyNotificationBase> { return std::make_unique<trophy_notification_helper>(m_game_window); };
|
||||
|
||||
callbacks.on_run = [this](bool start_playtime) { OnEmulatorRun(start_playtime); };
|
||||
|
|
@ -839,7 +839,7 @@ void gui_application::InitializeCallbacks()
|
|||
};
|
||||
}
|
||||
|
||||
callbacks.on_emulation_stop_no_response = [this](std::shared_ptr<atomic_t<bool>> closed_successfully, int seconds_waiting_already)
|
||||
callbacks.on_emulation_stop_no_response = [](std::shared_ptr<atomic_t<bool>> closed_successfully, int seconds_waiting_already)
|
||||
{
|
||||
const std::string terminate_message = tr("Stopping emulator took too long."
|
||||
"\nSome thread has probably deadlocked. Aborting.").toStdString();
|
||||
|
|
@ -849,7 +849,7 @@ void gui_application::InitializeCallbacks()
|
|||
report_fatal_error(terminate_message);
|
||||
}
|
||||
|
||||
Emu.CallFromMainThread([this, closed_successfully, seconds_waiting_already, terminate_message]
|
||||
Emu.CallFromMainThread([closed_successfully, seconds_waiting_already, terminate_message]
|
||||
{
|
||||
const auto seconds = std::make_shared<int>(seconds_waiting_already);
|
||||
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ void kernel_explorer::update()
|
|||
|
||||
add_solid_node(find_node(root, additional_nodes::process_info), QString::fromStdString(fmt::format("Process Info, Sdk Version: 0x%08x, PPC SEG: %#x, SFO Category: %s (Fake: %s)", g_ps3_process_info.sdk_ver, g_ps3_process_info.ppc_seg, Emu.GetCat(), Emu.GetFakeCat())));
|
||||
|
||||
auto display_program_segments = [this](QTreeWidgetItem* tree, const ppu_module<lv2_obj>& m)
|
||||
auto display_program_segments = [](QTreeWidgetItem* tree, const ppu_module<lv2_obj>& m)
|
||||
{
|
||||
for (usz i = 0; i < m.segs.size(); i++)
|
||||
{
|
||||
|
|
@ -661,7 +661,7 @@ void kernel_explorer::update()
|
|||
const s32 prio = ppu.prio.load().prio;
|
||||
std::string prio_text = fmt::format("%4d", prio);
|
||||
prio_text = fmt::replace_all(prio_text, " ", " ");
|
||||
|
||||
|
||||
ppu_threads.emplace_back(prio, fmt::format(u8"PPU 0x%07x: PRIO: %s, “%s”Joiner: %s, Status: %s, State: %s, %s func: “%s”%s", id, prio_text, *ppu.ppu_tname.load(), ppu.joiner.load(), status, ppu.state.load()
|
||||
, ppu.ack_suspend ? "After" : (ppu.current_function ? "In" : "Last"), func ? func : "", get_wait_time_str(ppu.start_time)));
|
||||
}, idm::unlocked);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#include "welcome_dialog.h"
|
||||
#include "music_player_dialog.h"
|
||||
#include "sound_effect_manager_dialog.h"
|
||||
#include "recording_settings_dialog.h"
|
||||
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
|
|
@ -1734,7 +1735,7 @@ void main_window::DecryptSPRXLibraries()
|
|||
dlg->set_button_enabled(QDialogButtonBox::StandardButton::Ok, text.size() - (text.indexOf('x') + 1) == 32);
|
||||
});
|
||||
|
||||
connect(dlg, &QDialog::accepted, this, [this, iterate, dlg, mod_index, decrypter, repeat_count]()
|
||||
connect(dlg, &QDialog::accepted, this, [iterate, dlg, mod_index, decrypter, repeat_count]()
|
||||
{
|
||||
std::string text = dlg->get_input_text().toStdString();
|
||||
|
||||
|
|
@ -3120,16 +3121,22 @@ void main_window::CreateConnects()
|
|||
|
||||
connect(ui->actionManage_Screenshots, &QAction::triggered, this, [this]
|
||||
{
|
||||
screenshot_manager_dialog* screenshot_manager = new screenshot_manager_dialog();
|
||||
screenshot_manager_dialog* screenshot_manager = new screenshot_manager_dialog(m_game_list_frame ? m_game_list_frame->GetGameInfo() : std::vector<game_info>{});
|
||||
screenshot_manager->show();
|
||||
});
|
||||
|
||||
connect(ui->actionManage_SoundEffects, &QAction::triggered, this, [this]
|
||||
connect(ui->actionManage_SoundEffects, &QAction::triggered, this, []
|
||||
{
|
||||
sound_effect_manager_dialog* dlg = new sound_effect_manager_dialog();
|
||||
dlg->show();
|
||||
});
|
||||
|
||||
connect(ui->actionRecording, &QAction::triggered, this, [this]
|
||||
{
|
||||
recording_settings_dialog* dlg = new recording_settings_dialog(this);
|
||||
dlg->open();
|
||||
});
|
||||
|
||||
connect(ui->toolsCgDisasmAct, &QAction::triggered, this, [this]
|
||||
{
|
||||
cg_disasm_window* cgdw = new cg_disasm_window(m_gui_settings);
|
||||
|
|
@ -3376,7 +3383,7 @@ void main_window::CreateConnects()
|
|||
welcome->open();
|
||||
});
|
||||
|
||||
connect(ui->supportAct, &QAction::triggered, this, [this]
|
||||
connect(ui->supportAct, &QAction::triggered, this, []
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl("https://rpcs3.net/patreon"));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@
|
|||
<addaction name="separator"/>
|
||||
<addaction name="confShortcutsAct"/>
|
||||
<addaction name="actionManage_SoundEffects"/>
|
||||
<addaction name="actionRecording"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="confAutopauseManagerAct"/>
|
||||
</widget>
|
||||
|
|
@ -1536,6 +1537,11 @@
|
|||
<string>Play Hover Music</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRecording">
|
||||
<property name="text">
|
||||
<string>Recording</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
|
|
|
|||
|
|
@ -504,6 +504,8 @@ memory_viewer_panel::memory_viewer_panel(QWidget* parent, std::shared_ptr<CPUDis
|
|||
|
||||
m_search_thread = QThread::create([this, wstr, m_modes = m_modes]()
|
||||
{
|
||||
thread_base::set_name("MemViewerSearch");
|
||||
|
||||
gui_log.notice("Searching for %s (mode: %s)", wstr, m_modes);
|
||||
|
||||
u64 found = 0;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "movie_item_base.h"
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
movie_item_base::movie_item_base() : qt_video_source()
|
||||
{
|
||||
|
|
@ -33,6 +34,8 @@ void movie_item_base::call_icon_load_func(int index)
|
|||
m_icon_loading = true;
|
||||
m_icon_load_thread.reset(QThread::create([this, index]()
|
||||
{
|
||||
thread_base::set_name(fmt::format("IconLoad %d", index));
|
||||
|
||||
if (m_icon_load_callback)
|
||||
{
|
||||
m_icon_load_callback(index);
|
||||
|
|
@ -63,6 +66,8 @@ void movie_item_base::call_size_calc_func()
|
|||
m_size_on_disk_loading = true;
|
||||
m_size_calc_thread.reset(QThread::create([this]()
|
||||
{
|
||||
thread_base::set_name("SizeCalc");
|
||||
|
||||
if (m_size_calc_callback)
|
||||
{
|
||||
m_size_calc_callback();
|
||||
|
|
|
|||
|
|
@ -405,6 +405,8 @@ void ps_move_tracker_dialog::reset_camera()
|
|||
|
||||
m_tracker_thread.reset(QThread::create([this]()
|
||||
{
|
||||
thread_base::set_name("PS Move Tracker");
|
||||
|
||||
while (!m_stop_threads)
|
||||
{
|
||||
process_camera_frame();
|
||||
|
|
|
|||
|
|
@ -279,6 +279,11 @@ namespace gui
|
|||
exp_img.setDevicePixelRatio(device_pixel_ratio);
|
||||
exp_img.fill(Qt::transparent);
|
||||
|
||||
if (pixmap.isNull())
|
||||
{
|
||||
return exp_img;
|
||||
}
|
||||
|
||||
// Load scaled pixmap
|
||||
pixmap = pixmap.scaled(icon_size, Qt::KeepAspectRatio, mode);
|
||||
|
||||
|
|
|
|||
455
rpcs3/rpcs3qt/recording_settings_dialog.cpp
Normal file
455
rpcs3/rpcs3qt/recording_settings_dialog.cpp
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
#include "stdafx.h"
|
||||
#include "recording_settings_dialog.h"
|
||||
#include "ui_recording_settings_dialog.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma GCC diagnostic ignored "-Wextra"
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
extern "C" {
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavformat/avformat.h"
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(cfg_log, "CFG");
|
||||
|
||||
static std::vector<const AVCodec*> get_video_codecs(const AVOutputFormat* fmt)
|
||||
{
|
||||
std::vector<const AVCodec*> codecs;
|
||||
|
||||
void* opaque = nullptr;
|
||||
while (const AVCodec* codec = av_codec_iterate(&opaque))
|
||||
{
|
||||
if (!codec->pix_fmts)
|
||||
continue;
|
||||
|
||||
if (codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL)
|
||||
continue;
|
||||
|
||||
if (codec->type != AVMediaType::AVMEDIA_TYPE_VIDEO)
|
||||
continue;
|
||||
|
||||
switch (codec->id)
|
||||
{
|
||||
case AV_CODEC_ID_H264:
|
||||
case AV_CODEC_ID_HEVC:
|
||||
case AV_CODEC_ID_MPEG4:
|
||||
case AV_CODEC_ID_AV1:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!av_codec_is_encoder(codec))
|
||||
continue;
|
||||
|
||||
if (avformat_query_codec(fmt, codec->id, FF_COMPLIANCE_NORMAL) != 1)
|
||||
continue;
|
||||
|
||||
codecs.push_back(codec);
|
||||
}
|
||||
|
||||
return codecs;
|
||||
}
|
||||
|
||||
static std::vector<const AVCodec*> get_audio_codecs(const AVOutputFormat* fmt)
|
||||
{
|
||||
std::vector<const AVCodec*> codecs;
|
||||
|
||||
void* opaque = nullptr;
|
||||
while (const AVCodec* codec = av_codec_iterate(&opaque))
|
||||
{
|
||||
if (codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL)
|
||||
continue;
|
||||
|
||||
if (codec->type != AVMediaType::AVMEDIA_TYPE_AUDIO)
|
||||
continue;
|
||||
|
||||
if (!av_codec_is_encoder(codec))
|
||||
continue;
|
||||
|
||||
if (avformat_query_codec(fmt, codec->id, FF_COMPLIANCE_NORMAL) != 1)
|
||||
continue;
|
||||
|
||||
codecs.push_back(codec);
|
||||
}
|
||||
|
||||
return codecs;
|
||||
}
|
||||
|
||||
recording_settings_dialog::recording_settings_dialog(QWidget* parent)
|
||||
: QDialog(parent), ui(new Ui::recording_settings_dialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (!g_cfg_recording.load())
|
||||
{
|
||||
cfg_log.notice("Could not load recording config. Using defaults.");
|
||||
}
|
||||
|
||||
ui->combo_presets->addItem(tr("720p 30fps"), static_cast<int>(quality_preset::_720p_30));
|
||||
ui->combo_presets->addItem(tr("720p 60fps"), static_cast<int>(quality_preset::_720p_60));
|
||||
ui->combo_presets->addItem(tr("1080p 30fps"), static_cast<int>(quality_preset::_1080p_30));
|
||||
ui->combo_presets->addItem(tr("1080p 60fps"), static_cast<int>(quality_preset::_1080p_60));
|
||||
ui->combo_presets->addItem(tr("1440p 30fps"), static_cast<int>(quality_preset::_1440p_30));
|
||||
ui->combo_presets->addItem(tr("1440p 60fps"), static_cast<int>(quality_preset::_1440p_60));
|
||||
ui->combo_presets->addItem(tr("2160p 30fps"), static_cast<int>(quality_preset::_2160p_30));
|
||||
ui->combo_presets->addItem(tr("2160p 60fps"), static_cast<int>(quality_preset::_2160p_60));
|
||||
ui->combo_presets->addItem(tr("Custom"), static_cast<int>(quality_preset::custom));
|
||||
connect(ui->combo_presets, &QComboBox::currentIndexChanged, this, [this](int index)
|
||||
{
|
||||
const QVariant var = ui->combo_presets->itemData(index);
|
||||
if (var.canConvert<int>())
|
||||
{
|
||||
const quality_preset preset = static_cast<quality_preset>(var.toInt());
|
||||
select_preset(preset, g_cfg_recording);
|
||||
update_ui();
|
||||
}
|
||||
});
|
||||
|
||||
ui->combo_resolution->addItem("360p", QVariant::fromValue(QPair<int, int>(640, 360)));
|
||||
ui->combo_resolution->addItem("480p", QVariant::fromValue(QPair<int, int>(854, 480)));
|
||||
ui->combo_resolution->addItem("720p", QVariant::fromValue(QPair<int, int>(1280, 720)));
|
||||
ui->combo_resolution->addItem("1080p", QVariant::fromValue(QPair<int, int>(1920, 1080)));
|
||||
ui->combo_resolution->addItem("1440p", QVariant::fromValue(QPair<int, int>(2560, 1440)));
|
||||
ui->combo_resolution->addItem("2160p", QVariant::fromValue(QPair<int, int>(3840, 2160)));
|
||||
connect(ui->combo_resolution, &QComboBox::currentIndexChanged, this, [this](int index)
|
||||
{
|
||||
const QVariant var = ui->combo_resolution->itemData(index);
|
||||
if (var.canConvert<QPair<int, int>>())
|
||||
{
|
||||
const QPair<int, int> size = var.value<QPair<int, int>>();
|
||||
g_cfg_recording.video.width.set(size.first);
|
||||
g_cfg_recording.video.height.set(size.second);
|
||||
update_preset();
|
||||
}
|
||||
});
|
||||
|
||||
const AVOutputFormat* fmt = av_guess_format("mp4", nullptr, nullptr);
|
||||
m_video_codecs = get_video_codecs(fmt);
|
||||
m_audio_codecs = get_audio_codecs(fmt);
|
||||
|
||||
for (const AVCodec* codec : m_video_codecs)
|
||||
{
|
||||
if (!codec) continue;
|
||||
|
||||
const std::string name = codec->long_name ? codec->long_name : avcodec_get_name(codec->id);
|
||||
ui->combo_video_codec->addItem(QString::fromStdString(name), static_cast<int>(codec->id));
|
||||
}
|
||||
|
||||
for (const AVCodec* codec : m_audio_codecs)
|
||||
{
|
||||
if (!codec) continue;
|
||||
|
||||
const std::string name = codec->long_name ? codec->long_name : avcodec_get_name(codec->id);
|
||||
ui->combo_audio_codec->addItem(QString::fromStdString(name), static_cast<int>(codec->id));
|
||||
}
|
||||
|
||||
connect(ui->combo_video_codec, &QComboBox::currentIndexChanged, this, [this](int index)
|
||||
{
|
||||
const QVariant var = ui->combo_video_codec->itemData(index);
|
||||
if (var.canConvert<int>())
|
||||
{
|
||||
const int codec_id = var.toInt();
|
||||
g_cfg_recording.video.video_codec.set(codec_id);
|
||||
update_preset();
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->combo_audio_codec, &QComboBox::currentIndexChanged, this, [this](int index)
|
||||
{
|
||||
const QVariant var = ui->combo_audio_codec->itemData(index);
|
||||
if (var.canConvert<int>())
|
||||
{
|
||||
const int codec_id = var.toInt();
|
||||
g_cfg_recording.audio.audio_codec.set(codec_id);
|
||||
update_preset();
|
||||
}
|
||||
});
|
||||
|
||||
ui->combo_framerate->addItem("30", 30);
|
||||
ui->combo_framerate->addItem("60", 60);
|
||||
connect(ui->combo_framerate, &QComboBox::currentIndexChanged, this, [this](int index)
|
||||
{
|
||||
const QVariant var = ui->combo_framerate->itemData(index);
|
||||
if (var.canConvert<int>())
|
||||
{
|
||||
const int fps = var.toInt();
|
||||
g_cfg_recording.video.framerate.set(fps);
|
||||
update_preset();
|
||||
}
|
||||
});
|
||||
|
||||
ui->spinbox_video_bitrate->setSingleStep(1);
|
||||
ui->spinbox_video_bitrate->setMinimum(g_cfg_recording.video.video_bps.min);
|
||||
ui->spinbox_video_bitrate->setMaximum(g_cfg_recording.video.video_bps.max);
|
||||
connect(ui->spinbox_video_bitrate, &QSpinBox::valueChanged, this, [this](int value)
|
||||
{
|
||||
g_cfg_recording.video.video_bps.set(value);
|
||||
update_preset();
|
||||
});
|
||||
|
||||
ui->spinbox_audio_bitrate->setSingleStep(1);
|
||||
ui->spinbox_audio_bitrate->setMinimum(g_cfg_recording.audio.audio_bps.min);
|
||||
ui->spinbox_audio_bitrate->setMaximum(g_cfg_recording.audio.audio_bps.max);
|
||||
connect(ui->spinbox_audio_bitrate, &QSpinBox::valueChanged, this, [this](int value)
|
||||
{
|
||||
g_cfg_recording.audio.audio_bps.set(value);
|
||||
update_preset();
|
||||
});
|
||||
|
||||
ui->spinbox_gop_size->setSingleStep(1);
|
||||
ui->spinbox_gop_size->setMinimum(g_cfg_recording.video.gop_size.min);
|
||||
ui->spinbox_gop_size->setMaximum(g_cfg_recording.video.gop_size.max);
|
||||
connect(ui->spinbox_gop_size, &QSpinBox::valueChanged, this, [this](int value)
|
||||
{
|
||||
g_cfg_recording.video.gop_size.set(value);
|
||||
update_preset();
|
||||
});
|
||||
|
||||
ui->spinbox_max_b_frames->setSingleStep(1);
|
||||
ui->spinbox_max_b_frames->setMinimum(g_cfg_recording.video.max_b_frames.min);
|
||||
ui->spinbox_max_b_frames->setMaximum(g_cfg_recording.video.max_b_frames.max);
|
||||
connect(ui->spinbox_max_b_frames, &QSpinBox::valueChanged, this, [this](int value)
|
||||
{
|
||||
g_cfg_recording.video.max_b_frames.set(value);
|
||||
update_preset();
|
||||
});
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::clicked, [this](QAbstractButton* button)
|
||||
{
|
||||
if (button == ui->buttonBox->button(QDialogButtonBox::Save))
|
||||
{
|
||||
g_cfg_recording.save();
|
||||
accept();
|
||||
}
|
||||
else if (button == ui->buttonBox->button(QDialogButtonBox::Cancel))
|
||||
{
|
||||
reject();
|
||||
}
|
||||
else if (button == ui->buttonBox->button(QDialogButtonBox::RestoreDefaults))
|
||||
{
|
||||
g_cfg_recording.from_default();
|
||||
update_ui();
|
||||
update_preset();
|
||||
}
|
||||
});
|
||||
|
||||
connect(this, &QDialog::rejected, this, []()
|
||||
{
|
||||
if (!g_cfg_recording.load())
|
||||
{
|
||||
cfg_log.notice("Could not load recording config. Using defaults.");
|
||||
}
|
||||
});
|
||||
|
||||
update_ui();
|
||||
update_preset();
|
||||
}
|
||||
|
||||
recording_settings_dialog::~recording_settings_dialog()
|
||||
{
|
||||
}
|
||||
|
||||
void recording_settings_dialog::update_preset()
|
||||
{
|
||||
const quality_preset preset = current_preset();
|
||||
ui->combo_presets->setCurrentIndex(ui->combo_presets->findData(static_cast<int>(preset)));
|
||||
}
|
||||
|
||||
void recording_settings_dialog::update_ui()
|
||||
{
|
||||
ui->combo_resolution->blockSignals(true);
|
||||
ui->combo_framerate->blockSignals(true);
|
||||
ui->combo_video_codec->blockSignals(true);
|
||||
ui->combo_audio_codec->blockSignals(true);
|
||||
ui->spinbox_video_bitrate->blockSignals(true);
|
||||
ui->spinbox_audio_bitrate->blockSignals(true);
|
||||
ui->spinbox_gop_size->blockSignals(true);
|
||||
ui->spinbox_max_b_frames->blockSignals(true);
|
||||
|
||||
ui->combo_resolution->setCurrentIndex(ui->combo_resolution->findData(QVariant::fromValue(QPair<int, int>(g_cfg_recording.video.width.get(), g_cfg_recording.video.height.get()))));
|
||||
ui->combo_framerate->setCurrentIndex(ui->combo_framerate->findData(static_cast<int>(g_cfg_recording.video.framerate.get())));
|
||||
ui->combo_video_codec->setCurrentIndex(ui->combo_video_codec->findData(static_cast<int>(g_cfg_recording.video.video_codec.get())));
|
||||
ui->combo_audio_codec->setCurrentIndex(ui->combo_audio_codec->findData(static_cast<int>(g_cfg_recording.audio.audio_codec.get())));
|
||||
ui->spinbox_video_bitrate->setValue(g_cfg_recording.video.video_bps);
|
||||
ui->spinbox_audio_bitrate->setValue(g_cfg_recording.audio.audio_bps);
|
||||
ui->spinbox_gop_size->setValue(g_cfg_recording.video.gop_size);
|
||||
ui->spinbox_max_b_frames->setValue(g_cfg_recording.video.max_b_frames);
|
||||
|
||||
ui->combo_resolution->blockSignals(false);
|
||||
ui->combo_framerate->blockSignals(false);
|
||||
ui->combo_video_codec->blockSignals(false);
|
||||
ui->combo_audio_codec->blockSignals(false);
|
||||
ui->spinbox_video_bitrate->blockSignals(false);
|
||||
ui->spinbox_audio_bitrate->blockSignals(false);
|
||||
ui->spinbox_gop_size->blockSignals(false);
|
||||
ui->spinbox_max_b_frames->blockSignals(false);
|
||||
|
||||
const auto get_codec_name = [](const std::vector<const AVCodec*>& codecs, u32 id)
|
||||
{
|
||||
for (const AVCodec* codec : codecs)
|
||||
{
|
||||
if (codec && codec->id == static_cast<AVCodecID>(id))
|
||||
{
|
||||
const std::string name = codec->long_name ? codec->long_name : avcodec_get_name(codec->id);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return std::string();
|
||||
};
|
||||
|
||||
ui->label_info_keys->setText(
|
||||
tr("Resolution:") + "\n" +
|
||||
tr("Framerate:") + "\n" +
|
||||
tr("Video Codec:") + "\n" +
|
||||
tr("Video Bitrate:") + "\n" +
|
||||
tr("Audio Codec:") + "\n" +
|
||||
tr("Audio Bitrate:") + "\n" +
|
||||
tr("Gop-Size:") + "\n" +
|
||||
tr("Max B-Frames:")
|
||||
);
|
||||
|
||||
ui->label_info_values->setText(QString::fromStdString(
|
||||
fmt::format("%d x %d\n%d fps\n%s\n%d\n%s\n%d\n%d\n%d",
|
||||
g_cfg_recording.video.width.get(), g_cfg_recording.video.height.get(),
|
||||
g_cfg_recording.video.framerate.get(),
|
||||
get_codec_name(m_video_codecs, g_cfg_recording.video.video_codec.get()),
|
||||
g_cfg_recording.video.video_bps.get(),
|
||||
get_codec_name(m_audio_codecs, g_cfg_recording.audio.audio_codec.get()),
|
||||
g_cfg_recording.audio.audio_bps.get(),
|
||||
g_cfg_recording.video.gop_size.get(),
|
||||
g_cfg_recording.video.max_b_frames.get()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
void recording_settings_dialog::select_preset(quality_preset preset, cfg_recording& cfg)
|
||||
{
|
||||
if (preset == quality_preset::custom)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cfg.audio.audio_codec.set(static_cast<u32>(AVCodecID::AV_CODEC_ID_AAC));
|
||||
cfg.audio.audio_bps.set(192'000); // 192 kbps
|
||||
|
||||
cfg.video.video_codec.set(static_cast<u32>(AVCodecID::AV_CODEC_ID_MPEG4));
|
||||
cfg.video.pixel_format.set(static_cast<u32>(::AV_PIX_FMT_YUV420P));
|
||||
|
||||
switch (preset)
|
||||
{
|
||||
case quality_preset::_720p_30:
|
||||
case quality_preset::_720p_60:
|
||||
cfg.video.width.set(1280);
|
||||
cfg.video.height.set(720);
|
||||
break;
|
||||
case quality_preset::_1080p_30:
|
||||
case quality_preset::_1080p_60:
|
||||
cfg.video.width.set(1920);
|
||||
cfg.video.height.set(1080);
|
||||
break;
|
||||
case quality_preset::_1440p_30:
|
||||
case quality_preset::_1440p_60:
|
||||
cfg.video.width.set(2560);
|
||||
cfg.video.height.set(1440);
|
||||
break;
|
||||
case quality_preset::_2160p_30:
|
||||
case quality_preset::_2160p_60:
|
||||
cfg.video.width.set(3840);
|
||||
cfg.video.height.set(2160);
|
||||
break;
|
||||
case quality_preset::custom:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (preset)
|
||||
{
|
||||
case quality_preset::_720p_30:
|
||||
case quality_preset::_1080p_30:
|
||||
case quality_preset::_1440p_30:
|
||||
case quality_preset::_2160p_30:
|
||||
cfg.video.framerate.set(30);
|
||||
break;
|
||||
case quality_preset::_720p_60:
|
||||
case quality_preset::_1080p_60:
|
||||
case quality_preset::_1440p_60:
|
||||
case quality_preset::_2160p_60:
|
||||
cfg.video.framerate.set(60);
|
||||
break;
|
||||
case quality_preset::custom:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (preset)
|
||||
{
|
||||
case quality_preset::_720p_30:
|
||||
cfg.video.video_bps.set(4'000'000);
|
||||
break;
|
||||
case quality_preset::_720p_60:
|
||||
cfg.video.video_bps.set(6'000'000);
|
||||
break;
|
||||
case quality_preset::_1080p_30:
|
||||
cfg.video.video_bps.set(8'000'000);
|
||||
break;
|
||||
case quality_preset::_1080p_60:
|
||||
cfg.video.video_bps.set(12'000'000);
|
||||
break;
|
||||
case quality_preset::_1440p_30:
|
||||
cfg.video.video_bps.set(16'000'000);
|
||||
break;
|
||||
case quality_preset::_1440p_60:
|
||||
cfg.video.video_bps.set(24'000'000);
|
||||
break;
|
||||
case quality_preset::_2160p_30:
|
||||
cfg.video.video_bps.set(40'000'000);
|
||||
break;
|
||||
case quality_preset::_2160p_60:
|
||||
cfg.video.video_bps.set(60'000'000);
|
||||
break;
|
||||
case quality_preset::custom:
|
||||
break;
|
||||
}
|
||||
|
||||
cfg.video.gop_size.set(cfg.video.framerate.get());
|
||||
cfg.video.max_b_frames.set(2);
|
||||
}
|
||||
|
||||
recording_settings_dialog::quality_preset recording_settings_dialog::current_preset()
|
||||
{
|
||||
for (u32 i = 0; i < static_cast<u32>(quality_preset::custom); i++)
|
||||
{
|
||||
const quality_preset preset = static_cast<quality_preset>(i);
|
||||
|
||||
cfg_recording cfg;
|
||||
select_preset(preset, cfg);
|
||||
|
||||
if (g_cfg_recording.video.framerate.get() == cfg.video.framerate.get() &&
|
||||
g_cfg_recording.video.width.get() == cfg.video.width.get() &&
|
||||
g_cfg_recording.video.height.get() == cfg.video.height.get() &&
|
||||
g_cfg_recording.video.pixel_format.get() == cfg.video.pixel_format.get() &&
|
||||
g_cfg_recording.video.video_codec.get() == cfg.video.video_codec.get() &&
|
||||
g_cfg_recording.video.video_bps.get() == cfg.video.video_bps.get() &&
|
||||
g_cfg_recording.video.max_b_frames.get() == cfg.video.max_b_frames.get() &&
|
||||
g_cfg_recording.video.gop_size.get() == cfg.video.gop_size.get() &&
|
||||
g_cfg_recording.audio.audio_codec.get() == cfg.audio.audio_codec.get() &&
|
||||
g_cfg_recording.audio.audio_bps.get() == cfg.audio.audio_bps.get())
|
||||
{
|
||||
return preset;
|
||||
}
|
||||
}
|
||||
|
||||
return quality_preset::custom;
|
||||
}
|
||||
47
rpcs3/rpcs3qt/recording_settings_dialog.h
Normal file
47
rpcs3/rpcs3qt/recording_settings_dialog.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "Emu/Io/recording_config.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class recording_settings_dialog;
|
||||
}
|
||||
|
||||
struct AVCodec;
|
||||
|
||||
class recording_settings_dialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
recording_settings_dialog(QWidget* parent = nullptr);
|
||||
virtual ~recording_settings_dialog();
|
||||
|
||||
private:
|
||||
enum class quality_preset
|
||||
{
|
||||
_720p_30,
|
||||
_720p_60,
|
||||
_1080p_30,
|
||||
_1080p_60,
|
||||
_1440p_30,
|
||||
_1440p_60,
|
||||
_2160p_30,
|
||||
_2160p_60,
|
||||
custom
|
||||
};
|
||||
|
||||
void update_preset();
|
||||
void update_ui();
|
||||
|
||||
static void select_preset(quality_preset preset, cfg_recording& cfg);
|
||||
static quality_preset current_preset();
|
||||
|
||||
Ui::recording_settings_dialog* ui;
|
||||
|
||||
std::vector<const AVCodec*> m_video_codecs;
|
||||
std::vector<const AVCodec*> m_audio_codecs;
|
||||
};
|
||||
273
rpcs3/rpcs3qt/recording_settings_dialog.ui
Normal file
273
rpcs3/rpcs3qt/recording_settings_dialog.ui
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>recording_settings_dialog</class>
|
||||
<widget class="QDialog" name="recording_settings_dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>692</width>
|
||||
<height>734</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Recording Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="main_layout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="presets_tab">
|
||||
<attribute name="title">
|
||||
<string>Presets</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="layout_presets_tab">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_presets">
|
||||
<property name="title">
|
||||
<string>Preset</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_presets">
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_presets"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_info">
|
||||
<property name="title">
|
||||
<string>Info</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="layout_gb_info">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_info_keys">
|
||||
<property name="text">
|
||||
<string>Keys</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_info_values">
|
||||
<property name="text">
|
||||
<string>Values</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="info_spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="spacer_presets_tab">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="advanced_tab">
|
||||
<attribute name="title">
|
||||
<string>Advanced</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="layout_advanced_tab">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_advanced_video">
|
||||
<property name="title">
|
||||
<string>Video</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_advanced_video">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_video_codec">
|
||||
<property name="title">
|
||||
<string>Codec</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_video_codec">
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_video_codec"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_resolution">
|
||||
<property name="title">
|
||||
<string>Resolution</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_resolution">
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_resolution"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_framerate">
|
||||
<property name="title">
|
||||
<string>Framerate</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_framerate">
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_framerate"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_video_bitrate">
|
||||
<property name="title">
|
||||
<string>Bitrate</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_video_bitrate">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinbox_video_bitrate"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_gop_size">
|
||||
<property name="title">
|
||||
<string>Group of Pictures Size</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_gop_size">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinbox_gop_size"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_max_b_frames">
|
||||
<property name="title">
|
||||
<string>Max. B-Frames</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_max_b_frames">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinbox_max_b_frames"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_advanced_audio">
|
||||
<property name="title">
|
||||
<string>Audio</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_advanced_audio">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_audio_codec">
|
||||
<property name="title">
|
||||
<string>Codec</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_audio_codec">
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_audio_codec"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_audio_bitrate">
|
||||
<property name="title">
|
||||
<string>Bitrate</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_gb_audio_bitrate">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinbox_audio_bitrate"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="spacer_advanced_tab">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::RestoreDefaults|QDialogButtonBox::StandardButton::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>recording_settings_dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>recording_settings_dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -575,7 +575,7 @@ void savestate_manager_dialog::ShowGameTableContextMenu(const QPoint& pos)
|
|||
if (!name.isEmpty())
|
||||
{
|
||||
QAction* copy_name = new QAction(tr("&Copy Name"), menu);
|
||||
connect(copy_name, &QAction::triggered, this, [this, name]()
|
||||
connect(copy_name, &QAction::triggered, this, [name]()
|
||||
{
|
||||
QApplication::clipboard()->setText(name);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,26 +1,40 @@
|
|||
#include "screenshot_item.h"
|
||||
#include "qt_utils.h"
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
screenshot_item::screenshot_item(QWidget* parent)
|
||||
screenshot_item::screenshot_item(QWidget* parent, QSize icon_size, const QString& icon_path, const QPixmap& placeholder)
|
||||
: flow_widget_item(parent)
|
||||
, m_icon_path(icon_path)
|
||||
, m_icon_size(icon_size)
|
||||
{
|
||||
setToolTip(icon_path);
|
||||
|
||||
cb_on_first_visibility = [this]()
|
||||
{
|
||||
m_thread.reset(QThread::create([this]()
|
||||
{
|
||||
const QPixmap pixmap = gui::utils::get_aligned_pixmap(icon_path, icon_size, 1.0, Qt::SmoothTransformation, gui::utils::align_h::center, gui::utils::align_v::center);
|
||||
thread_base::set_name("Screenshot item");
|
||||
|
||||
const QPixmap src_icon = QPixmap(m_icon_path);
|
||||
if (src_icon.isNull()) return;
|
||||
|
||||
const QPixmap pixmap = gui::utils::get_aligned_pixmap(src_icon, m_icon_size, 1.0, Qt::SmoothTransformation, gui::utils::align_h::center, gui::utils::align_v::center);
|
||||
Q_EMIT signal_icon_update(pixmap);
|
||||
}));
|
||||
m_thread->start();
|
||||
};
|
||||
|
||||
label = new QLabel(this);
|
||||
m_label = new QLabel(this);
|
||||
m_label->setPixmap(placeholder);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(label);
|
||||
layout->addWidget(m_label);
|
||||
setLayout(layout);
|
||||
|
||||
connect(this, &screenshot_item::signal_icon_update, this, &screenshot_item::update_icon, Qt::ConnectionType::QueuedConnection);
|
||||
}
|
||||
|
||||
screenshot_item::~screenshot_item()
|
||||
|
|
@ -30,3 +44,23 @@ screenshot_item::~screenshot_item()
|
|||
m_thread->wait();
|
||||
}
|
||||
}
|
||||
|
||||
void screenshot_item::update_icon(const QPixmap& pixmap)
|
||||
{
|
||||
if (m_label)
|
||||
{
|
||||
m_label->setPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void screenshot_item::mouseDoubleClickEvent(QMouseEvent* ev)
|
||||
{
|
||||
flow_widget_item::mouseDoubleClickEvent(ev);
|
||||
|
||||
if (!ev) return;
|
||||
|
||||
if (ev->button() == Qt::LeftButton)
|
||||
{
|
||||
Q_EMIT signal_icon_preview(m_icon_path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,29 @@
|
|||
#include "flow_widget_item.h"
|
||||
#include <QLabel>
|
||||
#include <QThread>
|
||||
#include <QMouseEvent>
|
||||
|
||||
class screenshot_item : public flow_widget_item
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
screenshot_item(QWidget* parent);
|
||||
screenshot_item(QWidget* parent, QSize icon_size, const QString& icon_path, const QPixmap& placeholder);
|
||||
virtual ~screenshot_item();
|
||||
|
||||
QString icon_path;
|
||||
QSize icon_size;
|
||||
QLabel* label{};
|
||||
|
||||
private:
|
||||
QLabel* m_label{};
|
||||
QString m_icon_path;
|
||||
QSize m_icon_size;
|
||||
std::unique_ptr<QThread> m_thread;
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent* ev) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void signal_icon_update(const QPixmap& pixmap);
|
||||
void signal_icon_preview(const QString& path);
|
||||
|
||||
public Q_SLOTS:
|
||||
void update_icon(const QPixmap& pixmap);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@
|
|||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QGroupBox>
|
||||
#include <QScreen>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtConcurrent>
|
||||
|
||||
LOG_CHANNEL(gui_log, "GUI");
|
||||
|
||||
screenshot_manager_dialog::screenshot_manager_dialog(QWidget* parent) : QDialog(parent)
|
||||
screenshot_manager_dialog::screenshot_manager_dialog(const std::vector<game_info>& games, QWidget* parent)
|
||||
: QDialog(parent), m_games(games)
|
||||
{
|
||||
setWindowTitle(tr("Screenshots"));
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
|
@ -28,11 +30,50 @@ screenshot_manager_dialog::screenshot_manager_dialog(QWidget* parent) : QDialog(
|
|||
m_placeholder = QPixmap(m_icon_size);
|
||||
m_placeholder.fill(Qt::gray);
|
||||
|
||||
connect(this, &screenshot_manager_dialog::signal_icon_preview, this, &screenshot_manager_dialog::show_preview);
|
||||
connect(this, &screenshot_manager_dialog::signal_entry_parsed, this, &screenshot_manager_dialog::add_entry);
|
||||
connect(this, &screenshot_manager_dialog::signal_entry_parsed, this, &screenshot_manager_dialog::add_entry, Qt::ConnectionType::QueuedConnection);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout;
|
||||
m_combo_sort_filter = new QComboBox();
|
||||
m_combo_sort_filter->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
m_combo_sort_filter->addItem(tr("Sort by Game"), static_cast<int>(sort_filter::game));
|
||||
m_combo_sort_filter->addItem(tr("Sort by Date"), static_cast<int>(sort_filter::date));
|
||||
connect(m_combo_sort_filter, &QComboBox::currentIndexChanged, this, [this](int /*index*/){ reload(); });
|
||||
|
||||
m_combo_type_filter = new QComboBox();
|
||||
m_combo_type_filter->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
m_combo_type_filter->addItem(tr("All Screenshots"), static_cast<int>(type_filter::all));
|
||||
m_combo_type_filter->addItem(tr("RPCS3 Screenshots"), static_cast<int>(type_filter::rpcs3));
|
||||
m_combo_type_filter->addItem(tr("Cell Screenshots"), static_cast<int>(type_filter::cell));
|
||||
connect(m_combo_type_filter, &QComboBox::currentIndexChanged, this, [this](int /*index*/){ reload(); });
|
||||
|
||||
m_combo_game_filter = new QComboBox();
|
||||
m_combo_game_filter->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
m_combo_game_filter->addItem(tr("All Games"), QString());
|
||||
connect(m_combo_game_filter, &QComboBox::currentIndexChanged, this, [this](int /*index*/){ reload(); });
|
||||
|
||||
QHBoxLayout* sort_layout = new QHBoxLayout();
|
||||
sort_layout->addWidget(m_combo_sort_filter);
|
||||
QGroupBox* gb_sort = new QGroupBox(tr("Sort"));
|
||||
gb_sort->setLayout(sort_layout);
|
||||
|
||||
QHBoxLayout* type_layout = new QHBoxLayout();
|
||||
type_layout->addWidget(m_combo_type_filter);
|
||||
QGroupBox* gb_type = new QGroupBox(tr("Filter Type"));
|
||||
gb_type->setLayout(type_layout);
|
||||
|
||||
QHBoxLayout* game_layout = new QHBoxLayout();
|
||||
game_layout->addWidget(m_combo_game_filter);
|
||||
QGroupBox* gb_game = new QGroupBox(tr("Filter Game"));
|
||||
gb_game->setLayout(game_layout);
|
||||
|
||||
QHBoxLayout* top_layout = new QHBoxLayout();
|
||||
top_layout->addWidget(gb_sort);
|
||||
top_layout->addWidget(gb_type);
|
||||
top_layout->addWidget(gb_game);
|
||||
top_layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum));
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addLayout(top_layout);
|
||||
layout->addWidget(m_flow_widget);
|
||||
setLayout(layout);
|
||||
|
||||
|
|
@ -47,14 +88,8 @@ screenshot_manager_dialog::~screenshot_manager_dialog()
|
|||
|
||||
void screenshot_manager_dialog::add_entry(const QString& path)
|
||||
{
|
||||
screenshot_item* item = new screenshot_item(m_flow_widget);
|
||||
ensure(item->label);
|
||||
item->setToolTip(path);
|
||||
item->installEventFilter(this);
|
||||
item->label->setPixmap(m_placeholder);
|
||||
item->icon_path = path;
|
||||
item->icon_size = m_icon_size;
|
||||
connect(item, &screenshot_item::signal_icon_update, this, &screenshot_manager_dialog::update_icon);
|
||||
screenshot_item* item = new screenshot_item(m_flow_widget, m_icon_size, path, m_placeholder);
|
||||
connect(item, &screenshot_item::signal_icon_preview, this, &screenshot_manager_dialog::show_preview);
|
||||
|
||||
m_flow_widget->add_widget(item);
|
||||
}
|
||||
|
|
@ -65,28 +100,74 @@ void screenshot_manager_dialog::show_preview(const QString& path)
|
|||
preview->show();
|
||||
}
|
||||
|
||||
void screenshot_manager_dialog::update_icon(const QPixmap& pixmap)
|
||||
{
|
||||
if (screenshot_item* item = static_cast<screenshot_item*>(QObject::sender()))
|
||||
{
|
||||
if (item->label)
|
||||
{
|
||||
item->label->setPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void screenshot_manager_dialog::reload()
|
||||
{
|
||||
m_abort_parsing = true;
|
||||
m_parsing_watcher.disconnect();
|
||||
gui::utils::stop_future_watcher(m_parsing_watcher, true);
|
||||
|
||||
const std::string screenshot_path_qt = fs::get_config_dir() + "screenshots/";
|
||||
const std::string screenshot_path_cell = rpcs3::utils::get_hdd0_dir() + "/photo/";
|
||||
const type_filter t_filter = static_cast<type_filter>(m_combo_type_filter->currentData().toInt());
|
||||
const sort_filter s_filter = static_cast<sort_filter>(m_combo_sort_filter->currentData().toInt());
|
||||
const QString game_filter = m_combo_game_filter->currentData().toString();
|
||||
|
||||
const std::string screenshot_path_rpcs3 = fs::get_config_dir() + "screenshots/";
|
||||
const std::string screenshot_path_cell = rpcs3::utils::get_hdd0_dir() + "/photo/";
|
||||
|
||||
std::vector<std::string> folders;
|
||||
switch (t_filter)
|
||||
{
|
||||
case type_filter::all:
|
||||
folders.push_back(screenshot_path_rpcs3);
|
||||
folders.push_back(screenshot_path_cell);
|
||||
break;
|
||||
case type_filter::rpcs3:
|
||||
folders.push_back(screenshot_path_rpcs3);
|
||||
break;
|
||||
case type_filter::cell:
|
||||
folders.push_back(screenshot_path_cell);
|
||||
break;
|
||||
}
|
||||
|
||||
m_flow_widget->clear();
|
||||
m_game_folders.clear();
|
||||
m_abort_parsing = false;
|
||||
m_parsing_watcher.setFuture(QtConcurrent::map(m_parsing_threads, [this, screenshot_path_qt, screenshot_path_cell](int index)
|
||||
|
||||
connect(&m_parsing_watcher, &QFutureWatcher<void>::finished, this, [this]()
|
||||
{
|
||||
std::vector<std::pair<QString, QString>> games;
|
||||
for (const auto& [dirname, paths] : m_game_folders)
|
||||
{
|
||||
const std::string serial = dirname.toStdString();
|
||||
std::string text = serial;
|
||||
for (const auto& game : m_games)
|
||||
{
|
||||
if (game && game->info.serial == serial)
|
||||
{
|
||||
text = fmt::format("%s (%s)", game->info.name, serial);
|
||||
break;
|
||||
}
|
||||
}
|
||||
games.push_back(std::pair(dirname, QString::fromStdString(text)));
|
||||
}
|
||||
|
||||
std::sort(games.begin(), games.end(), [](const std::pair<QString, QString>& l, const std::pair<QString, QString>& r)
|
||||
{
|
||||
return l.second < r.second;
|
||||
});
|
||||
|
||||
const QString old_filter = m_combo_game_filter->currentData().toString();
|
||||
m_combo_game_filter->blockSignals(true);
|
||||
m_combo_game_filter->clear();
|
||||
m_combo_game_filter->addItem(tr("All Games"), QString());
|
||||
for (const auto& [dirname, text] : games)
|
||||
{
|
||||
m_combo_game_filter->addItem(text, dirname);
|
||||
}
|
||||
m_combo_game_filter->setCurrentIndex(m_combo_game_filter->findData(old_filter));
|
||||
m_combo_game_filter->blockSignals(false);
|
||||
});
|
||||
|
||||
m_parsing_watcher.setFuture(QtConcurrent::map(m_parsing_threads, [this, folders, game_filter, s_filter](int index)
|
||||
{
|
||||
if (index != 0)
|
||||
{
|
||||
|
|
@ -95,26 +176,68 @@ void screenshot_manager_dialog::reload()
|
|||
|
||||
const QStringList filter{ QStringLiteral("*.png") };
|
||||
|
||||
for (const std::string& path : { screenshot_path_qt, screenshot_path_cell })
|
||||
for (const std::string& folder : folders)
|
||||
{
|
||||
if (m_abort_parsing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.empty())
|
||||
if (folder.empty())
|
||||
{
|
||||
gui_log.error("Screenshot manager: Trying to load screenshots from empty path!");
|
||||
continue;
|
||||
}
|
||||
|
||||
QDirIterator dir_iter(QString::fromStdString(path), filter, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
QDirIterator dir_iter(QString::fromStdString(folder), filter, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
|
||||
while (dir_iter.hasNext() && !m_abort_parsing)
|
||||
{
|
||||
Q_EMIT signal_entry_parsed(dir_iter.next());
|
||||
QFileInfo info(dir_iter.next());
|
||||
const QString dirname = info.dir().dirName();
|
||||
m_game_folders[dirname].push_back(std::move(info));
|
||||
}
|
||||
}
|
||||
|
||||
switch (s_filter)
|
||||
{
|
||||
case sort_filter::game:
|
||||
{
|
||||
for (const auto& [dirname, infos] : m_game_folders)
|
||||
{
|
||||
if (game_filter.isEmpty() || game_filter == dirname)
|
||||
{
|
||||
for (const QFileInfo& info : infos)
|
||||
{
|
||||
Q_EMIT signal_entry_parsed(info.filePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sort_filter::date:
|
||||
{
|
||||
std::vector<QFileInfo> sorted_infos;
|
||||
for (const auto& [dirname, infos] : m_game_folders)
|
||||
{
|
||||
if (game_filter.isEmpty() || game_filter == dirname)
|
||||
{
|
||||
sorted_infos.insert(sorted_infos.end(), infos.begin(), infos.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(sorted_infos.begin(), sorted_infos.end(), [](const QFileInfo& a, const QFileInfo& b)
|
||||
{
|
||||
return a.lastModified() < b.lastModified();
|
||||
});
|
||||
|
||||
for (const QFileInfo& info : sorted_infos)
|
||||
{
|
||||
Q_EMIT signal_entry_parsed(info.filePath());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -123,17 +246,3 @@ void screenshot_manager_dialog::showEvent(QShowEvent* event)
|
|||
QDialog::showEvent(event);
|
||||
reload();
|
||||
}
|
||||
|
||||
bool screenshot_manager_dialog::eventFilter(QObject* watched, QEvent* event)
|
||||
{
|
||||
if (event && event->type() == QEvent::MouseButtonDblClick && static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
|
||||
{
|
||||
if (screenshot_item* item = static_cast<screenshot_item*>(watched))
|
||||
{
|
||||
Q_EMIT signal_icon_preview(item->icon_path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "flow_widget.h"
|
||||
#include "gui_game_info.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFutureWatcher>
|
||||
#include <QPixmap>
|
||||
#include <QSize>
|
||||
#include <QEvent>
|
||||
#include <QShowEvent>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
class screenshot_manager_dialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
screenshot_manager_dialog(QWidget* parent = nullptr);
|
||||
screenshot_manager_dialog(const std::vector<game_info>& games, QWidget* parent = nullptr);
|
||||
~screenshot_manager_dialog();
|
||||
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void signal_entry_parsed(const QString& path);
|
||||
void signal_icon_preview(const QString& path);
|
||||
|
||||
public Q_SLOTS:
|
||||
void update_icon(const QPixmap& pixmap);
|
||||
|
||||
private Q_SLOTS:
|
||||
void add_entry(const QString& path);
|
||||
|
|
@ -36,11 +35,28 @@ protected:
|
|||
private:
|
||||
void reload();
|
||||
|
||||
enum class type_filter
|
||||
{
|
||||
all,
|
||||
rpcs3,
|
||||
cell
|
||||
};
|
||||
|
||||
enum class sort_filter
|
||||
{
|
||||
game,
|
||||
date
|
||||
};
|
||||
|
||||
std::vector<game_info> m_games;
|
||||
bool m_abort_parsing = false;
|
||||
const std::array<int, 1> m_parsing_threads{0};
|
||||
QFutureWatcher<void> m_parsing_watcher;
|
||||
flow_widget* m_flow_widget = nullptr;
|
||||
|
||||
QComboBox* m_combo_sort_filter = nullptr;
|
||||
QComboBox* m_combo_game_filter = nullptr;
|
||||
QComboBox* m_combo_type_filter = nullptr;
|
||||
QSize m_icon_size;
|
||||
QPixmap m_placeholder;
|
||||
std::map<QString, std::vector<QFileInfo>> m_game_folders;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -858,7 +858,7 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
|
|||
ui->vulkansched->setEnabled(is_vulkan);
|
||||
};
|
||||
|
||||
const auto apply_fsr_specific_options = [r_creator, this]()
|
||||
const auto apply_fsr_specific_options = [this]()
|
||||
{
|
||||
const auto [text, value] = get_data(ui->outputScalingMode, ui->outputScalingMode->currentIndex());
|
||||
const bool fsr_selected = static_cast<output_scaling_mode>(value) == output_scaling_mode::fsr;
|
||||
|
|
@ -2095,7 +2095,7 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
|
|||
|
||||
connect(ui->edit_button_game_window_title_format, &QAbstractButton::clicked, [get_game_window_title, set_game_window_title, this]()
|
||||
{
|
||||
auto get_game_window_title_label = [get_game_window_title, set_game_window_title, this](const QString& format)
|
||||
auto get_game_window_title_label = [get_game_window_title](const QString& format)
|
||||
{
|
||||
const QString game_window_title = get_game_window_title(format);
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ sound_effect_manager_dialog::sound_effect_manager_dialog(QWidget* parent)
|
|||
}
|
||||
|
||||
QPushButton* button = new QPushButton("", this);
|
||||
connect(button, &QAbstractButton::clicked, this, [this, button, sound, name]()
|
||||
connect(button, &QAbstractButton::clicked, this, [this, sound, name]()
|
||||
{
|
||||
const std::string path = rsx::overlays::get_sound_filepath(sound);
|
||||
if (fs::is_file(path))
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ namespace gui::utils
|
|||
}
|
||||
|
||||
const std::vector<u8> data = vdf.to_vector<u8>();
|
||||
vdf.close();
|
||||
|
||||
usz last_pos = 0;
|
||||
usz pos = 0;
|
||||
|
||||
|
|
@ -507,9 +509,17 @@ namespace gui::utils
|
|||
sys_log.success("Removed steam shortcut(s) for '%s'", entry.app_name);
|
||||
}
|
||||
|
||||
update_steam_input_config(user_dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool steam_shortcut::steam_installed()
|
||||
{
|
||||
const std::string path = get_steam_path();
|
||||
return !path.empty() && fs::is_dir(path);
|
||||
}
|
||||
|
||||
u32 steam_shortcut::crc32(const std::string& data)
|
||||
{
|
||||
u32 crc = 0xFFFFFFFF;
|
||||
|
|
@ -527,12 +537,6 @@ namespace gui::utils
|
|||
return ~crc;
|
||||
}
|
||||
|
||||
bool steam_shortcut::steam_installed()
|
||||
{
|
||||
const std::string path = get_steam_path();
|
||||
return !path.empty() && fs::is_dir(path);
|
||||
}
|
||||
|
||||
u32 steam_shortcut::steam_appid(const std::string& exe, const std::string& name)
|
||||
{
|
||||
return crc32(exe + name) | 0x80000000;
|
||||
|
|
@ -667,8 +671,177 @@ namespace gui::utils
|
|||
return str;
|
||||
}
|
||||
|
||||
void steam_shortcut::update_steam_input_config(const std::string& user_dir)
|
||||
{
|
||||
if (m_entries_to_add.empty() && m_entries_to_remove.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string vdf_path = user_dir + "localconfig.vdf";
|
||||
const std::string backup_path = fs::get_config_dir() + "/localconfig.vdf.backup";
|
||||
|
||||
if (fs::is_file(vdf_path) && !fs::copy_file(vdf_path, backup_path, true))
|
||||
{
|
||||
sys_log.error("Failed to backup steam localconfig file '%s'", vdf_path);
|
||||
return;
|
||||
}
|
||||
|
||||
fs::file vdf(vdf_path);
|
||||
if (!vdf)
|
||||
{
|
||||
sys_log.error("update_steam_input_config: Failed to open steam localconfig file '%s': %s", vdf_path, fs::g_tls_error);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string content = vdf.to_string();
|
||||
vdf.close();
|
||||
|
||||
static const std::string app_section_start = "\n\t\"apps\"\n\t{";
|
||||
static const std::string app_section_end = "\n\t}\n";
|
||||
static const std::string entry_section_end = "\n\t\t}";
|
||||
|
||||
bool nothing_to_remove = m_entries_to_remove.empty();
|
||||
|
||||
usz app_pos = content.rfind(app_section_start);
|
||||
if (app_pos == umax)
|
||||
{
|
||||
if (!nothing_to_remove)
|
||||
{
|
||||
// We don't have to remove anything because this section did not exist
|
||||
sys_log.notice("update_steam_input_config: Could not find \"apps\" section. No need to remove anything.");
|
||||
nothing_to_remove = true;
|
||||
}
|
||||
|
||||
if (m_entries_to_add.empty())
|
||||
{
|
||||
return; // Nothing to do anyway
|
||||
}
|
||||
|
||||
const usz insert_pos = content.rfind("\n}");
|
||||
if (insert_pos == umax)
|
||||
{
|
||||
sys_log.error("update_steam_input_config: Could not find main section end");
|
||||
return;
|
||||
}
|
||||
|
||||
sys_log.notice("update_steam_input_config: Inserting missing \"apps\" section");
|
||||
content.insert(insert_pos, fmt::format("%s\n\t}", app_section_start));
|
||||
|
||||
app_pos = content.rfind(app_section_start);
|
||||
ensure(app_pos != umax);
|
||||
}
|
||||
|
||||
const usz search_start = app_pos + app_section_start.size();
|
||||
|
||||
const usz insert_pos = content.find(app_section_end, search_start);
|
||||
if (insert_pos == umax)
|
||||
{
|
||||
sys_log.error("update_steam_input_config: Could not find apps section end");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto appid_string = [](s32 signed_appid)
|
||||
{
|
||||
return fmt::format("\n\t\t\"%d\"\n", signed_appid);
|
||||
};
|
||||
|
||||
const auto find_entry = [&content, &appid_string, search_start, insert_pos](s32 signed_appid) -> usz
|
||||
{
|
||||
const usz pos = content.find(appid_string(signed_appid), search_start);
|
||||
if (pos >= insert_pos) return umax;
|
||||
return pos;
|
||||
};
|
||||
|
||||
bool dirty = false;
|
||||
|
||||
for (const shortcut_entry& entry : m_entries_to_remove)
|
||||
{
|
||||
constexpr bool removal_diabled = true; // Disabled for now. Steam doesn't seem to remove the entries either
|
||||
if constexpr (removal_diabled)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (nothing_to_remove)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const s32 signed_appid = static_cast<s32>(entry.appid);
|
||||
const usz pos = find_entry(signed_appid);
|
||||
|
||||
if (pos == umax)
|
||||
{
|
||||
// does not exist, do nothing
|
||||
sys_log.notice("update_steam_input_config: Entry for '%s' with appid '%d' does not exist. Skipping removal", entry.app_name, signed_appid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the opening brace of this entry
|
||||
const usz pos_brace_open = content.find('{', pos);
|
||||
if (pos_brace_open == umax || pos_brace_open >= insert_pos)
|
||||
{
|
||||
sys_log.error("update_steam_input_config: Can't find opening brace for entry for '%s' with appid '%d'.", entry.app_name, signed_appid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the closing brace
|
||||
const usz pos_brace_close = content.find(entry_section_end, pos_brace_open);
|
||||
if (pos_brace_close == umax || pos_brace_close >= insert_pos)
|
||||
{
|
||||
sys_log.error("update_steam_input_config: Can't find closing brace for entry for '%s' with appid '%d'.", entry.app_name, signed_appid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Include the closing brace line
|
||||
const usz erase_end = pos_brace_close + entry_section_end.size();
|
||||
|
||||
// Erase the whole block
|
||||
content.erase(pos, erase_end - pos);
|
||||
|
||||
sys_log.notice("update_steam_input_config: Removed '%s' with appid '%d'", entry.app_name, signed_appid);
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
for (const shortcut_entry& entry : m_entries_to_add)
|
||||
{
|
||||
const s32 signed_appid = static_cast<s32>(entry.appid);
|
||||
const usz pos = find_entry(signed_appid);
|
||||
|
||||
if (pos != umax)
|
||||
{
|
||||
// already exists, do nothing
|
||||
sys_log.notice("update_steam_input_config: Entry for '%s' with appid '%d' already exists", entry.app_name, signed_appid);
|
||||
continue;
|
||||
}
|
||||
|
||||
sys_log.notice("update_steam_input_config: Inserting '%s' with appid '%d'", entry.app_name, signed_appid);
|
||||
content.insert(insert_pos, fmt::format(
|
||||
"%s"
|
||||
"\t\t{\n"
|
||||
"\t\t\t\"UseSteamControllerConfig\"\t\t\"0\"\n"
|
||||
//"\t\t\t\"SteamControllerRumble\"\t\t\"-1\"\n"
|
||||
//"\t\t\t\"SteamControllerRumbleIntensity\"\t\t\"320\"\n"
|
||||
"\t\t}", appid_string(signed_appid)));
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (dirty && !fs::write_file(vdf_path, fs::rewrite, content))
|
||||
{
|
||||
sys_log.error("Failed to update steam localconfig '%s': '%s'", vdf_path, fs::g_tls_error);
|
||||
|
||||
if (!fs::copy_file(backup_path, vdf_path, true))
|
||||
{
|
||||
sys_log.error("Failed to restore steam localconfig backup: '%s'", fs::g_tls_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string get_registry_string(const wchar_t* key, const wchar_t* name)
|
||||
static std::string get_registry_string(const wchar_t* key, const wchar_t* name)
|
||||
{
|
||||
HKEY hkey = NULL;
|
||||
LSTATUS status = RegOpenKeyW(HKEY_CURRENT_USER, key, &hkey);
|
||||
|
|
@ -832,6 +1005,7 @@ namespace gui::utils
|
|||
// }
|
||||
|
||||
const std::string content = vdf.to_string();
|
||||
vdf.close();
|
||||
|
||||
usz user_count = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ namespace gui::utils
|
|||
|
||||
bool parse_file(const std::string& path);
|
||||
|
||||
void update_steam_input_config(const std::string& user_dir);
|
||||
|
||||
static u32 crc32(const std::string& data);
|
||||
static u32 steam_appid(const std::string& exe, const std::string& name);
|
||||
|
||||
|
|
@ -115,7 +117,7 @@ namespace gui::utils
|
|||
static std::string steamid64_to_32(const std::string& steam_id);
|
||||
static std::string get_steam_path();
|
||||
static std::string get_last_active_steam_user(const std::string& steam_path);
|
||||
|
||||
|
||||
static std::string get_steam_banner_path(steam_banner banner, const std::string& grid_dir, u32 appid);
|
||||
static void create_steam_banner(steam_banner banner, const std::string& src_path, const QPixmap& src_icon, const std::string& grid_dir, const shortcut_entry& entry);
|
||||
|
||||
|
|
|
|||
|
|
@ -392,7 +392,7 @@ trophy_manager_dialog::trophy_manager_dialog(std::shared_ptr<gui_settings> gui_s
|
|||
m_trophy_table->create_header_actions(m_trophy_column_acts,
|
||||
[this](int col) { return m_gui_settings->GetTrophylistColVisibility(static_cast<gui::trophy_list_columns>(col)); },
|
||||
[this](int col, bool visible) { m_gui_settings->SetTrophylistColVisibility(static_cast<gui::trophy_list_columns>(col), visible); });
|
||||
|
||||
|
||||
m_game_table->create_header_actions(m_game_column_acts,
|
||||
[this](int col) { return m_gui_settings->GetTrophyGamelistColVisibility(static_cast<gui::trophy_game_list_columns>(col)); },
|
||||
[this](int col, bool visible) { m_gui_settings->SetTrophyGamelistColVisibility(static_cast<gui::trophy_game_list_columns>(col), visible); });
|
||||
|
|
@ -651,7 +651,7 @@ void trophy_manager_dialog::ResizeGameIcons()
|
|||
const int trophy_index = item->data(GameUserRole::GameIndex).toInt();
|
||||
QString trophy_icon_path = QString::fromStdString(m_trophies_db[trophy_index]->path);
|
||||
|
||||
item->set_icon_load_func([this, icon_path = std::move(trophy_icon_path), localized_icon, trophy_index, cancel = item->icon_loading_aborted(), dpr](int index)
|
||||
item->set_icon_load_func([this, icon_path = std::move(trophy_icon_path), localized_icon, cancel = item->icon_loading_aborted(), dpr](int index)
|
||||
{
|
||||
if (cancel && cancel->load())
|
||||
{
|
||||
|
|
@ -897,7 +897,7 @@ void trophy_manager_dialog::ShowTrophyTableContextMenu(const QPoint& pos)
|
|||
if (!name.isEmpty() && !desc.isEmpty())
|
||||
{
|
||||
QAction* copy_both = new QAction(tr("&Copy Name + Description"), copy_menu);
|
||||
connect(copy_both, &QAction::triggered, this, [this, name, desc]()
|
||||
connect(copy_both, &QAction::triggered, this, [name, desc]()
|
||||
{
|
||||
QApplication::clipboard()->setText(name % QStringLiteral("\n\n") % desc);
|
||||
});
|
||||
|
|
@ -907,7 +907,7 @@ void trophy_manager_dialog::ShowTrophyTableContextMenu(const QPoint& pos)
|
|||
if (!name.isEmpty())
|
||||
{
|
||||
QAction* copy_name = new QAction(tr("&Copy Name"), copy_menu);
|
||||
connect(copy_name, &QAction::triggered, this, [this, name]()
|
||||
connect(copy_name, &QAction::triggered, this, [name]()
|
||||
{
|
||||
QApplication::clipboard()->setText(name);
|
||||
});
|
||||
|
|
@ -917,7 +917,7 @@ void trophy_manager_dialog::ShowTrophyTableContextMenu(const QPoint& pos)
|
|||
if (!desc.isEmpty())
|
||||
{
|
||||
QAction* copy_desc = new QAction(tr("&Copy Description"), copy_menu);
|
||||
connect(copy_desc, &QAction::triggered, this, [this, desc]()
|
||||
connect(copy_desc, &QAction::triggered, this, [desc]()
|
||||
{
|
||||
QApplication::clipboard()->setText(desc);
|
||||
});
|
||||
|
|
@ -1038,7 +1038,7 @@ void trophy_manager_dialog::ShowGameTableContextMenu(const QPoint& pos)
|
|||
if (!name.isEmpty())
|
||||
{
|
||||
QAction* copy_name = new QAction(tr("&Copy Name"), menu);
|
||||
connect(copy_name, &QAction::triggered, this, [this, name]()
|
||||
connect(copy_name, &QAction::triggered, this, [name]()
|
||||
{
|
||||
QApplication::clipboard()->setText(name);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QTextBrowser>
|
||||
#include <QThread>
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
#include <7z.h>
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ vfs_dialog_path_widget::vfs_dialog_path_widget(const QString& name, const QStrin
|
|||
item->setCheckState(Qt::CheckState::Checked);
|
||||
});
|
||||
|
||||
connect(m_dir_list, &QListWidget::currentRowChanged, this, [this, button_remove_dir](int row)
|
||||
connect(m_dir_list, &QListWidget::currentRowChanged, this, [button_remove_dir](int row)
|
||||
{
|
||||
button_remove_dir->setEnabled(row > 0);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -743,7 +743,26 @@ std::pair<u64, u64> utils::get_memory_usage()
|
|||
status.dwLength = sizeof(status);
|
||||
::GlobalMemoryStatusEx(&status);
|
||||
return { status.ullTotalPhys, status.ullTotalPhys - status.ullAvailPhys };
|
||||
#elif __linux__
|
||||
std::ifstream proc("/proc/meminfo");
|
||||
std::string line;
|
||||
uint64_t mem_total = get_total_memory();
|
||||
uint64_t mem_available = 0;
|
||||
|
||||
while (std::getline(proc, line))
|
||||
{
|
||||
if (line.rfind("MemTotal:", 0) == 0 && line.find("kB") != std::string::npos)
|
||||
{
|
||||
mem_total = std::stoull(line.substr(line.find_first_of("0123456789"))) * 1024;
|
||||
}
|
||||
else if (line.rfind("MemAvailable:", 0) == 0 && line.find("kB") != std::string::npos)
|
||||
{
|
||||
mem_available = std::stoull(line.substr(line.find_first_of("0123456789"))) * 1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return { mem_total, mem_total - mem_available };
|
||||
#else
|
||||
// TODO
|
||||
return { get_total_memory(), 0 };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue