Compare commits
5 commits
4e9ede3e85
...
36fae75437
Author | SHA1 | Date | |
---|---|---|---|
36fae75437 | |||
e8d45d294a | |||
d8d1ccbe62 | |||
1290f7dca3 | |||
4a1e0e27ab |
31 changed files with 227 additions and 1093 deletions
167
CMakeLists.txt
167
CMakeLists.txt
|
@ -139,50 +139,65 @@ endif()
|
|||
|
||||
# Set bundled sdl2/qt as dependent options.
|
||||
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
||||
cmake_dependent_option(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" OFF)
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "NOT MSVC" OFF)
|
||||
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}")
|
||||
endif()
|
||||
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF)
|
||||
cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
|
||||
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
|
||||
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
|
||||
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
|
||||
|
||||
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" OFF)
|
||||
|
||||
set(EXT_DEFAULT OFF)
|
||||
|
||||
if (MSVC OR ANDROID)
|
||||
set(EXT_DEFAULT ON)
|
||||
endif()
|
||||
option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if needed. Externals will still be fetched." ${EXT_DEFAULT})
|
||||
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" OFF "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
if (ENABLE_SDL2)
|
||||
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "NOT MSVC" OFF)
|
||||
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}")
|
||||
endif()
|
||||
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF)
|
||||
|
||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT WIN32 OR NOT ARCHITECTURE_arm64" OFF)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
|
||||
|
||||
option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if needed. Externals will still be fetched." ${EXT_DEFAULT})
|
||||
|
||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
option(ENABLE_WIFI_SCAN "Enable WiFi scanning" OFF)
|
||||
|
||||
cmake_dependent_option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF "ENABLE_QT" OFF)
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" OFF "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
|
||||
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
|
||||
|
||||
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
|
||||
|
||||
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
|
||||
|
||||
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF "ENABLE_QT" OFF)
|
||||
|
||||
option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
|
||||
|
||||
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
message(STATUS "Using Precompiled Headers.")
|
||||
set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
|
||||
endif()
|
||||
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ${EXT_DEFAULT})
|
||||
|
||||
# TODO(crueter): CI this?
|
||||
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
|
||||
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL2;NOT ANDROID" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||
|
||||
option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF)
|
||||
if(YUZU_ENABLE_LTO)
|
||||
include(CheckIPOSupported)
|
||||
|
@ -190,42 +205,17 @@ if(YUZU_ENABLE_LTO)
|
|||
if(NOT COMPILER_SUPPORTS_LTO)
|
||||
message(FATAL_ERROR "Your compiler does not support interprocedural optimization (IPO). Re-run CMake with -DYUZU_ENABLE_LTO=OFF.")
|
||||
endif()
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ${COMPILER_SUPPORTS_LTO})
|
||||
endif()
|
||||
option(USE_CCACHE "Use ccache for compilation" OFF)
|
||||
set(CCACHE_PATH "ccache" CACHE STRING "Path to ccache binary")
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_BINARY ${CCACHE_PATH})
|
||||
if(CCACHE_BINARY)
|
||||
message(STATUS "Found ccache at: ${CCACHE_BINARY}")
|
||||
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_BINARY})
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_BINARY})
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
message(FATAL_ERROR "Precompiled headers are incompatible with ccache. Re-run CMake with -DYUZU_USE_PRECOMPILED_HEADERS=OFF.")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# TODO(crueter): CI this?
|
||||
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
|
||||
|
||||
cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL2;NOT ANDROID" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||
|
||||
option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF)
|
||||
|
||||
set(YUZU_TZDB_PATH "" CACHE STRING "Path to a pre-downloaded timezone database")
|
||||
|
||||
cmake_dependent_option(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "LINUX" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_APPLE_USE_BUNDLED_MONTENVK "Download bundled MoltenVK lib" ON "APPLE" OFF)
|
||||
|
||||
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
|
||||
|
||||
set(DEFAULT_ENABLE_OPENSSL ON)
|
||||
|
@ -238,12 +228,15 @@ if (ANDROID OR WIN32 OR APPLE OR PLATFORM_SUN)
|
|||
# your own copy of it.
|
||||
set(DEFAULT_ENABLE_OPENSSL OFF)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
set(DEFAULT_ENABLE_OPENSSL ON)
|
||||
endif()
|
||||
|
||||
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
|
||||
|
||||
if (ENABLE_OPENSSL)
|
||||
cmake_dependent_option(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" "${MSVC}" "NOT ANDROID" ON)
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" "${MSVC}" "NOT ANDROID" ON)
|
||||
endif()
|
||||
|
||||
if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL)
|
||||
|
@ -270,6 +263,21 @@ if (ANDROID)
|
|||
set(CMAKE_POLICY_VERSION_MINIMUM 3.5) # Workaround for Oboe
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
if (MSVC AND CCACHE)
|
||||
# buildcache does not properly cache PCH files, leading to compilation errors.
|
||||
# See https://github.com/mbitsnbites/buildcache/discussions/230
|
||||
message(WARNING "buildcache does not properly support Precompiled Headers. Disabling PCH")
|
||||
set(DYNARMIC_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
|
||||
set(YUZU_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
message(STATUS "Using Precompiled Headers.")
|
||||
set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
|
||||
endif()
|
||||
|
||||
# Default to a Release build
|
||||
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)
|
||||
|
@ -886,47 +894,24 @@ if (MSVC AND CXX_CLANG)
|
|||
link_libraries(llvm-mingw-runtime)
|
||||
endif()
|
||||
|
||||
#[[
|
||||
search order:
|
||||
- gold (GCC only) - the best, generally, but unfortunately not packaged anymore
|
||||
- mold (GCC only) - generally does well on GCC
|
||||
- ldd - preferred on clang
|
||||
- bfd - the final fallback
|
||||
- If none are found (macOS uses ld.prime, etc) just use the default linker
|
||||
]]
|
||||
if (YUZU_USE_FASTER_LD)
|
||||
find_program(LINKER_BFD bfd)
|
||||
if (LINKER_BFD)
|
||||
set(LINKER bfd)
|
||||
endif()
|
||||
|
||||
find_program(LINKER_LLD lld)
|
||||
if (LINKER_LLD)
|
||||
# fallback if everything fails (bfd)
|
||||
set(LINKER bfd)
|
||||
# clang should always use lld
|
||||
find_program(LLD lld)
|
||||
if (LLD)
|
||||
set(LINKER lld)
|
||||
endif()
|
||||
|
||||
# GNU appears to work better with mold
|
||||
# TODO: mold has been slow lately, see if better options exist (search for gold?)
|
||||
if (CXX_GCC)
|
||||
find_program(LINKER_MOLD mold)
|
||||
if (LINKER_MOLD AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
|
||||
find_program(MOLD mold)
|
||||
if (MOLD AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
|
||||
set(LINKER mold)
|
||||
endif()
|
||||
|
||||
find_program(LINKER_GOLD gold)
|
||||
if (LINKER_GOLD)
|
||||
set(LINKER gold)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LINKER)
|
||||
message(NOTICE "Selecting ${LINKER} as linker")
|
||||
add_link_options("-fuse-ld=${LINKER}")
|
||||
else()
|
||||
message(WARNING "No faster linker found--using default")
|
||||
endif()
|
||||
|
||||
if (LINKER STREQUAL "lld" AND CXX_GCC)
|
||||
message(WARNING "Using lld on GCC may cause issues with certain LTO settings. If the program fails to compile, disable YUZU_USE_FASTER_LD, or install mold or GNU gold.")
|
||||
endif()
|
||||
message(NOTICE "Selecting ${LINKER} as linker")
|
||||
add_link_options("-fuse-ld=${LINKER}")
|
||||
endif()
|
||||
|
||||
# Set runtime library to MD/MDd for all configurations
|
||||
|
|
|
@ -10,7 +10,6 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi
|
|||
set(package_base_url "https://github.com/eden-emulator/")
|
||||
set(package_repo "no_platform")
|
||||
set(package_extension "no_platform")
|
||||
set(CACHE_KEY "")
|
||||
|
||||
# TODO(crueter): Need to convert ffmpeg to a CI.
|
||||
if (WIN32 OR FORCE_WIN_ARCHIVES)
|
||||
|
@ -34,9 +33,8 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi
|
|||
else()
|
||||
message(FATAL_ERROR "No package available for this platform")
|
||||
endif()
|
||||
string(CONCAT package_url "${package_base_url}" "${package_repo}")
|
||||
string(CONCAT full_url "${package_url}" "${remote_path}" "${lib_name}" "${package_extension}")
|
||||
message(STATUS "Resolved bundled URL: ${full_url}")
|
||||
set(package_url "${package_base_url}${package_repo}")
|
||||
set(full_url ${package_url}${remote_path}${lib_name}${package_extension})
|
||||
|
||||
# TODO(crueter): DELETE THIS ENTIRELY, GLORY BE TO THE CI!
|
||||
AddPackage(
|
||||
|
@ -49,12 +47,26 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi
|
|||
# TODO(crueter): hash
|
||||
)
|
||||
|
||||
if (DEFINED ${cpm_key}_SOURCE_DIR)
|
||||
set(${prefix_var} "${${cpm_key}_SOURCE_DIR}" PARENT_SCOPE)
|
||||
message(STATUS "Using bundled binaries at ${${cpm_key}_SOURCE_DIR}")
|
||||
else()
|
||||
message(FATAL_ERROR "AddPackage did not set ${cpm_key}_SOURCE_DIR")
|
||||
set(${prefix_var} "${${cpm_key}_SOURCE_DIR}" PARENT_SCOPE)
|
||||
message(STATUS "Using bundled binaries at ${${cpm_key}_SOURCE_DIR}")
|
||||
endfunction()
|
||||
|
||||
function(download_moltenvk_external platform version)
|
||||
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
|
||||
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
|
||||
if (NOT EXISTS ${MOLTENVK_DIR})
|
||||
if (NOT EXISTS ${MOLTENVK_TAR})
|
||||
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/${version}/MoltenVK-${platform}.tar
|
||||
${MOLTENVK_TAR} SHOW_PROGRESS)
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
|
||||
endif()
|
||||
|
||||
# Add the MoltenVK library path to the prefix so find_library can locate it.
|
||||
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${platform}")
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Determine installation parameters for OS, architecture, and compiler
|
||||
|
@ -96,7 +108,7 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out
|
|||
set(host "linux")
|
||||
set(type "desktop")
|
||||
set(arch "linux_gcc_64")
|
||||
set(arch_path "gcc_64")
|
||||
set(arch_path "linux")
|
||||
endif()
|
||||
|
||||
set(${host_out} "${host}" PARENT_SCOPE)
|
||||
|
@ -131,79 +143,56 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba
|
|||
set(install_args -c "${CURRENT_MODULE_DIR}/aqt_config.ini")
|
||||
if (tool)
|
||||
set(prefix "${base_path}/Tools")
|
||||
list(APPEND install_args install-tool --outputdir "${base_path}" "${host}" desktop "${target}")
|
||||
set(install_args ${install_args} install-tool --outputdir ${base_path} ${host} desktop ${target})
|
||||
else()
|
||||
set(prefix "${base_path}/${target}/${arch_path}")
|
||||
list(APPEND install_args install-qt --outputdir "${base_path}" "${host}" "${type}" "${target}" "${arch}" -m qt_base)
|
||||
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt_base)
|
||||
|
||||
if (YUZU_USE_QT_MULTIMEDIA)
|
||||
list(APPEND install_args qtmultimedia)
|
||||
set(install_args ${install_args} qtmultimedia)
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
list(APPEND install_args qtpositioning qtwebchannel qtwebengine)
|
||||
set(install_args ${install_args} qtpositioning qtwebchannel qtwebengine)
|
||||
endif()
|
||||
|
||||
if (NOT "${YUZU_QT_MIRROR}" STREQUAL "")
|
||||
if (NOT ${YUZU_QT_MIRROR} STREQUAL "")
|
||||
message(STATUS "Using Qt mirror ${YUZU_QT_MIRROR}")
|
||||
list(APPEND install_args -b "${YUZU_QT_MIRROR}")
|
||||
set(install_args ${install_args} -b ${YUZU_QT_MIRROR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Install Args: ${install_args}")
|
||||
|
||||
message(STATUS "Install Args ${install_args}")
|
||||
if (NOT EXISTS "${prefix}")
|
||||
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
|
||||
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.3.0")
|
||||
if (WIN32)
|
||||
set(aqt_path "${base_path}/aqt.exe")
|
||||
if (NOT EXISTS "${aqt_path}")
|
||||
file(DOWNLOAD "${AQT_PREBUILD_BASE_URL}/aqt.exe" "${aqt_path}" SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND "${aqt_path}" ${install_args}
|
||||
WORKING_DIRECTORY "${base_path}"
|
||||
RESULT_VARIABLE aqt_res
|
||||
OUTPUT_VARIABLE aqt_out
|
||||
ERROR_VARIABLE aqt_err)
|
||||
if (NOT aqt_res EQUAL 0)
|
||||
message(FATAL_ERROR "aqt.exe failed: ${aqt_err}")
|
||||
file(DOWNLOAD
|
||||
${AQT_PREBUILD_BASE_URL}/aqt.exe
|
||||
${aqt_path} SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND ${aqt_path} ${install_args}
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
elseif (APPLE)
|
||||
set(aqt_path "${base_path}/aqt-macos")
|
||||
if (NOT EXISTS "${aqt_path}")
|
||||
file(DOWNLOAD "${AQT_PREBUILD_BASE_URL}/aqt-macos" "${aqt_path}" SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND chmod +x "${aqt_path}")
|
||||
execute_process(COMMAND "${aqt_path}" ${install_args}
|
||||
WORKING_DIRECTORY "${base_path}"
|
||||
RESULT_VARIABLE aqt_res
|
||||
ERROR_VARIABLE aqt_err)
|
||||
if (NOT aqt_res EQUAL 0)
|
||||
message(FATAL_ERROR "aqt-macos failed: ${aqt_err}")
|
||||
file(DOWNLOAD
|
||||
${AQT_PREBUILD_BASE_URL}/aqt-macos
|
||||
${aqt_path} SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND chmod +x ${aqt_path})
|
||||
execute_process(COMMAND ${aqt_path} ${install_args}
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
else()
|
||||
find_program(PYTHON3_EXECUTABLE python3)
|
||||
if (NOT PYTHON3_EXECUTABLE)
|
||||
message(FATAL_ERROR "python3 is required to install Qt using aqt (pip mode).")
|
||||
endif()
|
||||
set(aqt_install_path "${base_path}/aqt")
|
||||
file(MAKE_DIRECTORY "${aqt_install_path}")
|
||||
|
||||
execute_process(COMMAND "${PYTHON3_EXECUTABLE}" -m pip install --target="${aqt_install_path}" aqtinstall
|
||||
WORKING_DIRECTORY "${base_path}"
|
||||
RESULT_VARIABLE pip_res
|
||||
ERROR_VARIABLE pip_err)
|
||||
if (NOT pip_res EQUAL 0)
|
||||
message(FATAL_ERROR "pip install aqtinstall failed: ${pip_err}")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -E env PYTHONPATH="${aqt_install_path}" "${PYTHON3_EXECUTABLE}" -m aqt ${install_args}
|
||||
WORKING_DIRECTORY "${base_path}"
|
||||
RESULT_VARIABLE aqt_res
|
||||
ERROR_VARIABLE aqt_err)
|
||||
if (NOT aqt_res EQUAL 0)
|
||||
message(FATAL_ERROR "aqt (python) failed: ${aqt_err}")
|
||||
endif()
|
||||
execute_process(COMMAND python3 -m pip install --target=${aqt_install_path} aqtinstall
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${aqt_install_path} python3 -m aqt ${install_args}
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
endif()
|
||||
|
||||
message(STATUS "Downloaded Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path} to ${prefix}")
|
||||
|
@ -221,7 +210,7 @@ endfunction()
|
|||
function(download_qt target)
|
||||
determine_qt_parameters("${target}" host type arch arch_path host_type host_arch host_arch_path)
|
||||
|
||||
set(base_path "${CMAKE_BINARY_DIR}/externals/qt")
|
||||
get_external_prefix(qt base_path)
|
||||
file(MAKE_DIRECTORY "${base_path}")
|
||||
|
||||
download_qt_configuration(prefix "${target}" "${host}" "${type}" "${arch}" "${arch_path}" "${base_path}")
|
||||
|
@ -238,34 +227,26 @@ function(download_qt target)
|
|||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(download_moltenvk version platform)
|
||||
if(NOT version)
|
||||
message(FATAL_ERROR "download_moltenvk: version argument is required")
|
||||
endif()
|
||||
if(NOT platform)
|
||||
message(FATAL_ERROR "download_moltenvk: platform argument is required")
|
||||
endif()
|
||||
function(download_moltenvk)
|
||||
set(MOLTENVK_PLATFORM "macOS")
|
||||
|
||||
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
|
||||
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
|
||||
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
|
||||
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
|
||||
if (NOT EXISTS ${MOLTENVK_DIR})
|
||||
if (NOT EXISTS ${MOLTENVK_TAR})
|
||||
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/v1.2.10-rc2/MoltenVK-all.tar
|
||||
${MOLTENVK_TAR} SHOW_PROGRESS)
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${MOLTENVK_DIR}")
|
||||
if(NOT EXISTS "${MOLTENVK_TAR}")
|
||||
file(DOWNLOAD "https://github.com/KhronosGroup/MoltenVK/releases/download/${version}/MoltenVK-${platform}.tar"
|
||||
"${MOLTENVK_TAR}" SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals"
|
||||
RESULT_VARIABLE tar_res
|
||||
ERROR_VARIABLE tar_err
|
||||
)
|
||||
if(NOT tar_res EQUAL 0)
|
||||
message(FATAL_ERROR "Extracting MoltenVK failed: ${tar_err}")
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${platform}")
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
# Add the MoltenVK library path to the prefix so find_library can locate it.
|
||||
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${MOLTENVK_PLATFORM}")
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(get_external_prefix lib_name prefix_var)
|
||||
set(${prefix_var} "${CMAKE_BINARY_DIR}/externals/${lib_name}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
|
|
@ -101,7 +101,7 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl
|
|||
<summary>Ubuntu, Debian, Mint Linux</summary>
|
||||
|
||||
```sh
|
||||
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2t64 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libzydis-dev zydis-tools libzycore-dev vulkan-utility-libraries-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev
|
||||
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libzydis-dev zydis-tools libzycore-dev
|
||||
```
|
||||
|
||||
* Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required.
|
||||
|
|
|
@ -31,7 +31,7 @@ Notes:
|
|||
* Currently, build fails without this
|
||||
- `YUZU_USE_FASTER_LD` (ON) Check if a faster linker is available
|
||||
* Only available on UNIX
|
||||
- `YUZU_APPLE_USE_BUNDLED_MONTENVK` (ON, macOS only) Download bundled MoltenVK lib)
|
||||
- `USE_SYSTEM_MOLTENVK` (OFF, macOS only) Use the system MoltenVK lib (instead of the bundled one)
|
||||
- `YUZU_TZDB_PATH` (string) Path to a pre-downloaded timezone database (useful for nixOS)
|
||||
- `ENABLE_OPENSSL` (ON for Linux and *BSD) Enable OpenSSL backend for the ssl service
|
||||
* Always enabled if the web service is enabled
|
||||
|
|
|
@ -68,9 +68,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
|||
var isActivityRecreated = false
|
||||
private lateinit var nfcReader: NfcReader
|
||||
|
||||
private var touchDownTime: Long = 0
|
||||
private val maxTapDuration = 500L
|
||||
|
||||
private val gyro = FloatArray(3)
|
||||
private val accel = FloatArray(3)
|
||||
private var motionTimestamp: Long = 0
|
||||
|
@ -492,38 +489,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
|||
}
|
||||
}
|
||||
|
||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
|
||||
val emulationFragment = navHostFragment?.childFragmentManager?.fragments?.firstOrNull() as? org.yuzu.yuzu_emu.fragments.EmulationFragment
|
||||
|
||||
emulationFragment?.let { fragment ->
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
touchDownTime = System.currentTimeMillis()
|
||||
// show overlay immediately on touch and cancel timer
|
||||
if (!emulationViewModel.drawerOpen.value) {
|
||||
fragment.handler.removeCallbacksAndMessages(null)
|
||||
fragment.showOverlay()
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
if (!emulationViewModel.drawerOpen.value) {
|
||||
val touchDuration = System.currentTimeMillis() - touchDownTime
|
||||
|
||||
if (touchDuration <= maxTapDuration) {
|
||||
fragment.handleScreenTap(false)
|
||||
} else {
|
||||
// just start the auto-hide timer without toggling visibility
|
||||
fragment.handleScreenTap(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.dispatchTouchEvent(event)
|
||||
}
|
||||
|
||||
fun onEmulationStarted() {
|
||||
emulationViewModel.setEmulationStarted(true)
|
||||
}
|
||||
|
|
|
@ -55,8 +55,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||
FRAME_INTERPOLATION("frame_interpolation"),
|
||||
// FRAME_SKIPPING("frame_skipping"),
|
||||
|
||||
ENABLE_INPUT_OVERLAY_AUTO_HIDE("enable_input_overlay_auto_hide"),
|
||||
|
||||
PERF_OVERLAY_BACKGROUND("perf_overlay_background"),
|
||||
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
|
||||
|
||||
|
|
|
@ -59,8 +59,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
|||
OFFLINE_WEB_APPLET("offline_web_applet_mode"),
|
||||
LOGIN_SHARE_APPLET("login_share_applet_mode"),
|
||||
WIFI_WEB_AUTH_APPLET("wifi_web_auth_applet_mode"),
|
||||
MY_PAGE_APPLET("my_page_applet_mode"),
|
||||
INPUT_OVERLAY_AUTO_HIDE("input_overlay_auto_hide")
|
||||
MY_PAGE_APPLET("my_page_applet_mode")
|
||||
;
|
||||
|
||||
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
|
||||
|
|
|
@ -12,7 +12,6 @@ object Settings {
|
|||
SECTION_SYSTEM(R.string.preferences_system),
|
||||
SECTION_RENDERER(R.string.preferences_graphics),
|
||||
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
|
||||
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
|
||||
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
|
||||
SECTION_AUDIO(R.string.preferences_audio),
|
||||
SECTION_INPUT(R.string.preferences_controls),
|
||||
|
|
|
@ -96,7 +96,6 @@ abstract class SettingsItem(
|
|||
const val TYPE_INT_SINGLE_CHOICE = 9
|
||||
const val TYPE_INPUT_PROFILE = 10
|
||||
const val TYPE_STRING_INPUT = 11
|
||||
const val TYPE_SPINBOX = 12
|
||||
|
||||
const val FASTMEM_COMBINED = "fastmem_combined"
|
||||
|
||||
|
@ -386,22 +385,6 @@ abstract class SettingsItem(
|
|||
warningMessage = R.string.warning_resolution
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE,
|
||||
titleId = R.string.enable_input_overlay_auto_hide,
|
||||
)
|
||||
)
|
||||
put(
|
||||
SpinBoxSetting(
|
||||
IntSetting.INPUT_OVERLAY_AUTO_HIDE,
|
||||
titleId = R.string.overlay_auto_hide,
|
||||
descriptionId = R.string.overlay_auto_hide_description,
|
||||
min = 1,
|
||||
max = 999,
|
||||
valueHint = R.string.seconds
|
||||
)
|
||||
)
|
||||
|
||||
put(
|
||||
SwitchSetting(
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractByteSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
|
||||
|
||||
class SpinBoxSetting(
|
||||
setting: AbstractSetting,
|
||||
@StringRes titleId: Int = 0,
|
||||
titleString: String = "",
|
||||
@StringRes descriptionId: Int = 0,
|
||||
descriptionString: String = "",
|
||||
val valueHint: Int,
|
||||
val min: Int,
|
||||
val max: Int
|
||||
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
|
||||
override val type = TYPE_SPINBOX
|
||||
|
||||
fun getSelectedValue(needsGlobal: Boolean = false) =
|
||||
when (setting) {
|
||||
is AbstractByteSetting -> setting.getByte(needsGlobal).toInt()
|
||||
is AbstractShortSetting -> setting.getShort(needsGlobal).toInt()
|
||||
is AbstractIntSetting -> setting.getInt(needsGlobal)
|
||||
is AbstractFloatSetting -> setting.getFloat(needsGlobal).toInt()
|
||||
else -> 0
|
||||
}
|
||||
|
||||
fun setSelectedValue(value: Int) =
|
||||
when (setting) {
|
||||
is AbstractByteSetting -> setting.setByte(value.toByte())
|
||||
is AbstractShortSetting -> setting.setShort(value.toShort())
|
||||
is AbstractFloatSetting -> setting.setFloat(value.toFloat())
|
||||
else -> (setting as AbstractIntSetting).setInt(value)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui
|
||||
|
||||
|
@ -61,10 +61,6 @@ class SettingsAdapter(
|
|||
SliderViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_SPINBOX -> {
|
||||
SpinBoxViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_SUBMENU -> {
|
||||
SubmenuViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
@ -195,14 +191,6 @@ class SettingsAdapter(
|
|||
position
|
||||
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
|
||||
}
|
||||
fun onSpinBoxClick(item: SpinBoxSetting, position: Int) {
|
||||
SettingsDialogFragment.newInstance(
|
||||
settingsViewModel,
|
||||
item,
|
||||
SettingsItem.TYPE_SPINBOX,
|
||||
position
|
||||
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
|
||||
}
|
||||
|
||||
fun onSubmenuClick(item: SubmenuSetting) {
|
||||
val action = SettingsNavigationDirections.actionGlobalSettingsFragment(item.menuKey, null)
|
||||
|
|
|
@ -14,7 +14,6 @@ import android.text.TextWatcher
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
|
@ -23,7 +22,6 @@ import com.google.android.material.slider.Slider
|
|||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
|
||||
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
|
||||
import org.yuzu.yuzu_emu.databinding.DialogSpinboxBinding
|
||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.AnalogInputSetting
|
||||
|
@ -32,7 +30,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
|
|||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SpinBoxSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
|
||||
import org.yuzu.yuzu_emu.utils.ParamPackage
|
||||
|
@ -49,7 +46,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||
|
||||
private lateinit var sliderBinding: DialogSliderBinding
|
||||
private lateinit var stringInputBinding: DialogEditTextBinding
|
||||
private lateinit var spinboxBinding: DialogSpinboxBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -146,76 +142,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||
.create()
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_SPINBOX -> {
|
||||
spinboxBinding = DialogSpinboxBinding.inflate(layoutInflater)
|
||||
val item = settingsViewModel.clickedItem as SpinBoxSetting
|
||||
|
||||
val currentValue = item.getSelectedValue()
|
||||
spinboxBinding.editValue.setText(currentValue.toString())
|
||||
spinboxBinding.textInputLayout.hint = getString(item.valueHint)
|
||||
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(item.title)
|
||||
.setView(spinboxBinding.root)
|
||||
.setPositiveButton(android.R.string.ok, this)
|
||||
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
|
||||
.create()
|
||||
|
||||
val updateButtonState = { enabled: Boolean ->
|
||||
dialog.setOnShowListener { dialogInterface ->
|
||||
(dialogInterface as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = enabled
|
||||
}
|
||||
if (dialog.isShowing) {
|
||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = enabled
|
||||
}
|
||||
}
|
||||
|
||||
val updateValidity = { value: Int ->
|
||||
val isValid = value in item.min..item.max
|
||||
if (isValid) {
|
||||
spinboxBinding.textInputLayout.error = null
|
||||
} else {
|
||||
spinboxBinding.textInputLayout.error = getString(
|
||||
if (value < item.min) R.string.value_too_low else R.string.value_too_high,
|
||||
if (value < item.min) item.min else item.max
|
||||
)
|
||||
}
|
||||
updateButtonState(isValid)
|
||||
}
|
||||
|
||||
spinboxBinding.buttonDecrement.setOnClickListener {
|
||||
val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
|
||||
val newValue = current - 1
|
||||
spinboxBinding.editValue.setText(newValue.toString())
|
||||
updateValidity(newValue)
|
||||
}
|
||||
|
||||
spinboxBinding.buttonIncrement.setOnClickListener {
|
||||
val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
|
||||
val newValue = current + 1
|
||||
spinboxBinding.editValue.setText(newValue.toString())
|
||||
updateValidity(newValue)
|
||||
}
|
||||
|
||||
spinboxBinding.editValue.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
val value = s.toString().toIntOrNull()
|
||||
if (value != null) {
|
||||
updateValidity(value)
|
||||
} else {
|
||||
spinboxBinding.textInputLayout.error = getString(R.string.invalid_value)
|
||||
updateButtonState(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
updateValidity(currentValue)
|
||||
|
||||
dialog
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_STRING_INPUT -> {
|
||||
stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
|
||||
val item = settingsViewModel.clickedItem as StringInputSetting
|
||||
|
@ -355,14 +281,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||
sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
|
||||
}
|
||||
|
||||
is SpinBoxSetting -> {
|
||||
val spinBoxSetting = settingsViewModel.clickedItem as SpinBoxSetting
|
||||
val value = spinboxBinding.editValue.text.toString().toIntOrNull()
|
||||
if (value != null && value in spinBoxSetting.min..spinBoxSetting.max) {
|
||||
spinBoxSetting.setSelectedValue(value)
|
||||
}
|
||||
}
|
||||
|
||||
is StringInputSetting -> {
|
||||
val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
|
||||
stringInputSetting.setSelectedValue(
|
||||
|
|
|
@ -97,7 +97,6 @@ class SettingsFragmentPresenter(
|
|||
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
||||
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
|
||||
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
|
||||
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
|
||||
MenuTag.SECTION_AUDIO -> addAudioSettings(sl)
|
||||
MenuTag.SECTION_INPUT -> addInputSettings(sl)
|
||||
MenuTag.SECTION_INPUT_PLAYER_ONE -> addInputPlayer(sl, 0)
|
||||
|
@ -157,14 +156,6 @@ class SettingsFragmentPresenter(
|
|||
menuKey = MenuTag.SECTION_SOC_OVERLAY
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
titleId = R.string.input_overlay_options,
|
||||
iconId = R.drawable.ic_controller,
|
||||
descriptionId = R.string.input_overlay_options_description,
|
||||
menuKey = MenuTag.SECTION_INPUT_OVERLAY
|
||||
)
|
||||
)
|
||||
}
|
||||
add(
|
||||
SubmenuSetting(
|
||||
|
@ -273,13 +264,6 @@ class SettingsFragmentPresenter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun addInputOverlaySettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.key)
|
||||
add(IntSetting.INPUT_OVERLAY_AUTO_HIDE.key)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSocOverlaySettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(HeaderSetting(R.string.stats_overlay_customization))
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||
|
||||
import android.view.View
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SpinBoxSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||
|
||||
class SpinBoxViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||
SettingViewHolder(binding.root, adapter) {
|
||||
private lateinit var setting: SpinBoxSetting
|
||||
|
||||
override fun bind(item: SettingsItem) {
|
||||
setting = item as SpinBoxSetting
|
||||
binding.textSettingName.text = setting.title
|
||||
binding.textSettingDescription.setVisible(item.description.isNotEmpty())
|
||||
binding.textSettingDescription.text = setting.description
|
||||
binding.textSettingValue.setVisible(true)
|
||||
binding.textSettingValue.text = setting.getSelectedValue().toString()
|
||||
|
||||
binding.buttonClear.setVisible(setting.clearable)
|
||||
binding.buttonClear.setOnClickListener {
|
||||
adapter.onClearClick(setting, bindingAdapterPosition)
|
||||
}
|
||||
|
||||
setStyle(setting.isEditable, binding)
|
||||
}
|
||||
override fun onClick(clicked: View) {
|
||||
if (setting.isEditable) {
|
||||
adapter.onSpinBoxClick(setting, bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
override fun onLongClick(clicked: View): Boolean {
|
||||
if (setting.isEditable) {
|
||||
return adapter.onLongClick(setting, bindingAdapterPosition)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -96,9 +96,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
private var perfStatsUpdater: (() -> Unit)? = null
|
||||
private var socUpdater: (() -> Unit)? = null
|
||||
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
private var isOverlayVisible = true
|
||||
|
||||
private var _binding: FragmentEmulationBinding? = null
|
||||
|
||||
private val binding get() = _binding!!
|
||||
|
@ -455,10 +452,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
/**
|
||||
* Ask user if they want to launch with default settings when custom settings fail
|
||||
*/
|
||||
private suspend fun askUserToLaunchWithDefaultSettings(
|
||||
gameTitle: String,
|
||||
errorMessage: String
|
||||
): Boolean {
|
||||
private suspend fun askUserToLaunchWithDefaultSettings(gameTitle: String, errorMessage: String): Boolean {
|
||||
return suspendCoroutine { continuation ->
|
||||
requireActivity().runOnUiThread {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
|
@ -734,8 +728,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
updateShowStatsOverlay()
|
||||
updateSocOverlay()
|
||||
|
||||
initializeOverlayAutoHide()
|
||||
|
||||
// Re update binding when the specs values get initialized properly
|
||||
binding.inGameMenu.getHeaderView(0).apply {
|
||||
val titleView = findViewById<TextView>(R.id.text_game_title)
|
||||
|
@ -925,11 +917,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
updatePauseMenuEntry(emulationState.isPaused)
|
||||
}
|
||||
}
|
||||
|
||||
// if the overlay auto-hide setting is changed while paused,
|
||||
// we need to reinitialize the auto-hide timer
|
||||
initializeOverlayAutoHide()
|
||||
|
||||
}
|
||||
|
||||
private fun resetInputOverlay() {
|
||||
|
@ -937,7 +924,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
IntSetting.OVERLAY_OPACITY.reset()
|
||||
binding.surfaceInputOverlay.post {
|
||||
binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement()
|
||||
binding.surfaceInputOverlay.resetIndividualControlScale()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1048,7 +1034,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
|
||||
val status = batteryIntent?.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
|
||||
val isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
|
||||
status == BatteryManager.BATTERY_STATUS_FULL
|
||||
status == BatteryManager.BATTERY_STATUS_FULL
|
||||
|
||||
if (isCharging) {
|
||||
sb.append(" ${getString(R.string.charging)}")
|
||||
|
@ -1560,7 +1546,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
.setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int ->
|
||||
setControlScale(50)
|
||||
setControlOpacity(100)
|
||||
binding.surfaceInputOverlay.resetIndividualControlScale()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
@ -1741,61 +1726,4 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
||||
private val socUpdateHandler = Handler(Looper.myLooper()!!)
|
||||
}
|
||||
|
||||
private fun startOverlayAutoHideTimer(seconds: Int) {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
|
||||
handler.postDelayed({
|
||||
if (isOverlayVisible) {
|
||||
hideOverlay()
|
||||
}
|
||||
}, seconds * 1000L)
|
||||
}
|
||||
|
||||
fun handleScreenTap(isLongTap: Boolean) {
|
||||
val autoHideSeconds = IntSetting.INPUT_OVERLAY_AUTO_HIDE.getInt()
|
||||
val shouldProceed = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() && BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.getBoolean()
|
||||
|
||||
if (!shouldProceed) {
|
||||
return
|
||||
}
|
||||
|
||||
// failsafe
|
||||
if (autoHideSeconds == 0) {
|
||||
showOverlay()
|
||||
return
|
||||
}
|
||||
|
||||
if (!isOverlayVisible && !isLongTap) {
|
||||
showOverlay()
|
||||
}
|
||||
|
||||
startOverlayAutoHideTimer(autoHideSeconds)
|
||||
}
|
||||
|
||||
private fun initializeOverlayAutoHide() {
|
||||
val autoHideSeconds = IntSetting.INPUT_OVERLAY_AUTO_HIDE.getInt()
|
||||
val autoHideEnabled = BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.getBoolean()
|
||||
val showOverlay = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
|
||||
|
||||
if (autoHideEnabled && showOverlay) {
|
||||
showOverlay()
|
||||
startOverlayAutoHideTimer(autoHideSeconds)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun showOverlay() {
|
||||
if (!isOverlayVisible) {
|
||||
isOverlayVisible = true
|
||||
ViewUtils.showView(binding.surfaceInputOverlay, 500)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideOverlay() {
|
||||
if (isOverlayVisible) {
|
||||
isOverlayVisible = false
|
||||
ViewUtils.hideView(binding.surfaceInputOverlay, 500)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay
|
||||
|
||||
|
@ -13,8 +13,6 @@ import android.graphics.Rect
|
|||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.VectorDrawable
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.AttributeSet
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.MotionEvent
|
||||
|
@ -54,12 +52,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
private var dpadBeingConfigured: InputOverlayDrawableDpad? = null
|
||||
private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null
|
||||
|
||||
private var scaleDialog: OverlayScaleDialog? = null
|
||||
private var touchStartX = 0f
|
||||
private var touchStartY = 0f
|
||||
private var hasMoved = false
|
||||
private val moveThreshold = 20f
|
||||
|
||||
private lateinit var windowInsets: WindowInsets
|
||||
|
||||
var layout = OverlayLayout.Landscape
|
||||
|
@ -262,44 +254,23 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
) {
|
||||
buttonBeingConfigured = button
|
||||
buttonBeingConfigured!!.onConfigureTouch(event)
|
||||
touchStartX = event.getX(pointerIndex)
|
||||
touchStartY = event.getY(pointerIndex)
|
||||
hasMoved = false
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> if (buttonBeingConfigured != null) {
|
||||
val moveDistance = kotlin.math.sqrt(
|
||||
(event.getX(pointerIndex) - touchStartX).let { it * it } +
|
||||
(event.getY(pointerIndex) - touchStartY).let { it * it }
|
||||
)
|
||||
|
||||
if (moveDistance > moveThreshold) {
|
||||
hasMoved = true
|
||||
buttonBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
buttonBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) {
|
||||
if (!hasMoved) {
|
||||
showScaleDialog(
|
||||
buttonBeingConfigured,
|
||||
null,
|
||||
null,
|
||||
fingerPositionX,
|
||||
fingerPositionY
|
||||
)
|
||||
} else {
|
||||
saveControlPosition(
|
||||
buttonBeingConfigured!!.overlayControlData.id,
|
||||
buttonBeingConfigured!!.bounds.centerX(),
|
||||
buttonBeingConfigured!!.bounds.centerY(),
|
||||
individuaScale = buttonBeingConfigured!!.overlayControlData.individualScale,
|
||||
layout
|
||||
)
|
||||
}
|
||||
// Persist button position by saving new place.
|
||||
saveControlPosition(
|
||||
buttonBeingConfigured!!.overlayControlData.id,
|
||||
buttonBeingConfigured!!.bounds.centerX(),
|
||||
buttonBeingConfigured!!.bounds.centerY(),
|
||||
layout
|
||||
)
|
||||
buttonBeingConfigured = null
|
||||
}
|
||||
}
|
||||
|
@ -316,46 +287,23 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
) {
|
||||
dpadBeingConfigured = dpad
|
||||
dpadBeingConfigured!!.onConfigureTouch(event)
|
||||
touchStartX = event.getX(pointerIndex)
|
||||
touchStartY = event.getY(pointerIndex)
|
||||
hasMoved = false
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> if (dpadBeingConfigured != null) {
|
||||
val moveDistance = kotlin.math.sqrt(
|
||||
(event.getX(pointerIndex) - touchStartX).let { it * it } +
|
||||
(event.getY(pointerIndex) - touchStartY).let { it * it }
|
||||
)
|
||||
|
||||
if (moveDistance > moveThreshold) {
|
||||
hasMoved = true
|
||||
dpadBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
dpadBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> if (dpadBeingConfigured === dpad) {
|
||||
if (!hasMoved) {
|
||||
// This was a click, show scale dialog for dpad
|
||||
showScaleDialog(
|
||||
null,
|
||||
dpadBeingConfigured,
|
||||
null,
|
||||
fingerPositionX,
|
||||
fingerPositionY
|
||||
)
|
||||
} else {
|
||||
// This was a move, save position
|
||||
saveControlPosition(
|
||||
OverlayControl.COMBINED_DPAD.id,
|
||||
dpadBeingConfigured!!.bounds.centerX(),
|
||||
dpadBeingConfigured!!.bounds.centerY(),
|
||||
individuaScale = dpadBeingConfigured!!.individualScale,
|
||||
layout
|
||||
)
|
||||
}
|
||||
// Persist button position by saving new place.
|
||||
saveControlPosition(
|
||||
OverlayControl.COMBINED_DPAD.id,
|
||||
dpadBeingConfigured!!.bounds.centerX(),
|
||||
dpadBeingConfigured!!.bounds.centerY(),
|
||||
layout
|
||||
)
|
||||
dpadBeingConfigured = null
|
||||
}
|
||||
}
|
||||
|
@ -369,43 +317,21 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
) {
|
||||
joystickBeingConfigured = joystick
|
||||
joystickBeingConfigured!!.onConfigureTouch(event)
|
||||
touchStartX = event.getX(pointerIndex)
|
||||
touchStartY = event.getY(pointerIndex)
|
||||
hasMoved = false
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> if (joystickBeingConfigured != null) {
|
||||
val moveDistance = kotlin.math.sqrt(
|
||||
(event.getX(pointerIndex) - touchStartX).let { it * it } +
|
||||
(event.getY(pointerIndex) - touchStartY).let { it * it }
|
||||
)
|
||||
|
||||
if (moveDistance > moveThreshold) {
|
||||
hasMoved = true
|
||||
joystickBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
}
|
||||
joystickBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> if (joystickBeingConfigured != null) {
|
||||
if (!hasMoved) {
|
||||
showScaleDialog(
|
||||
null,
|
||||
null,
|
||||
joystickBeingConfigured,
|
||||
fingerPositionX,
|
||||
fingerPositionY
|
||||
)
|
||||
} else {
|
||||
saveControlPosition(
|
||||
joystickBeingConfigured!!.prefId,
|
||||
joystickBeingConfigured!!.bounds.centerX(),
|
||||
joystickBeingConfigured!!.bounds.centerY(),
|
||||
individuaScale = joystickBeingConfigured!!.individualScale,
|
||||
layout
|
||||
)
|
||||
}
|
||||
saveControlPosition(
|
||||
joystickBeingConfigured!!.prefId,
|
||||
joystickBeingConfigured!!.bounds.centerX(),
|
||||
joystickBeingConfigured!!.bounds.centerY(),
|
||||
layout
|
||||
)
|
||||
joystickBeingConfigured = null
|
||||
}
|
||||
}
|
||||
|
@ -681,117 +607,25 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
invalidate()
|
||||
}
|
||||
|
||||
private fun saveControlPosition(
|
||||
id: String,
|
||||
x: Int,
|
||||
y: Int,
|
||||
individuaScale: Float,
|
||||
layout: OverlayLayout
|
||||
) {
|
||||
private fun saveControlPosition(id: String, x: Int, y: Int, layout: OverlayLayout) {
|
||||
val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight))
|
||||
val min = windowSize.first
|
||||
val max = windowSize.second
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
val data = overlayControlData.firstOrNull { it.id == id }
|
||||
val newPosition = Pair((x - min.x).toDouble() / max.x, (y - min.y).toDouble() / max.y)
|
||||
|
||||
when (layout) {
|
||||
OverlayLayout.Landscape -> data?.landscapePosition = newPosition
|
||||
OverlayLayout.Portrait -> data?.portraitPosition = newPosition
|
||||
OverlayLayout.Foldable -> data?.foldablePosition = newPosition
|
||||
|
||||
}
|
||||
|
||||
data?.individualScale = individuaScale
|
||||
|
||||
NativeConfig.setOverlayControlData(overlayControlData)
|
||||
}
|
||||
|
||||
fun setIsInEditMode(editMode: Boolean) {
|
||||
inEditMode = editMode
|
||||
if (!editMode) {
|
||||
scaleDialog?.dismiss()
|
||||
scaleDialog = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun showScaleDialog(
|
||||
button: InputOverlayDrawableButton?,
|
||||
dpad: InputOverlayDrawableDpad?,
|
||||
joystick: InputOverlayDrawableJoystick?,
|
||||
x: Int, y: Int
|
||||
) {
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
// prevent dialog from being spam opened
|
||||
scaleDialog?.dismiss()
|
||||
|
||||
|
||||
when {
|
||||
button != null -> {
|
||||
val buttonData =
|
||||
overlayControlData.firstOrNull { it.id == button.overlayControlData.id }
|
||||
if (buttonData != null) {
|
||||
scaleDialog =
|
||||
OverlayScaleDialog(context, button.overlayControlData) { newScale ->
|
||||
saveControlPosition(
|
||||
button.overlayControlData.id,
|
||||
button.bounds.centerX(),
|
||||
button.bounds.centerY(),
|
||||
individuaScale = newScale,
|
||||
layout
|
||||
)
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
scaleDialog?.showDialog(x,y, button.bounds.width(), button.bounds.height())
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
dpad != null -> {
|
||||
val dpadData =
|
||||
overlayControlData.firstOrNull { it.id == OverlayControl.COMBINED_DPAD.id }
|
||||
if (dpadData != null) {
|
||||
scaleDialog = OverlayScaleDialog(context, dpadData) { newScale ->
|
||||
saveControlPosition(
|
||||
OverlayControl.COMBINED_DPAD.id,
|
||||
dpad.bounds.centerX(),
|
||||
dpad.bounds.centerY(),
|
||||
newScale,
|
||||
layout
|
||||
)
|
||||
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
scaleDialog?.showDialog(x,y, dpad.bounds.width(), dpad.bounds.height())
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
joystick != null -> {
|
||||
val joystickData = overlayControlData.firstOrNull { it.id == joystick.prefId }
|
||||
if (joystickData != null) {
|
||||
scaleDialog = OverlayScaleDialog(context, joystickData) { newScale ->
|
||||
saveControlPosition(
|
||||
joystick.prefId,
|
||||
joystick.bounds.centerX(),
|
||||
joystick.bounds.centerY(),
|
||||
individuaScale = newScale,
|
||||
layout
|
||||
)
|
||||
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
scaleDialog?.showDialog(x,y, joystick.bounds.width(), joystick.bounds.height())
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Applies and saves all default values for the overlay
|
||||
*/
|
||||
|
@ -830,24 +664,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
overlayControlData.forEach {
|
||||
it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true
|
||||
it.individualScale = OverlayControl.from(it.id)?.defaultIndividualScaleResource!!
|
||||
}
|
||||
NativeConfig.setOverlayControlData(overlayControlData)
|
||||
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
fun resetIndividualControlScale() {
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
overlayControlData.forEach { data ->
|
||||
val defaultControlData = OverlayControl.from(data.id) ?: return@forEach
|
||||
data.individualScale = defaultControlData.defaultIndividualScaleResource
|
||||
}
|
||||
NativeConfig.setOverlayControlData(overlayControlData)
|
||||
NativeConfig.saveGlobalConfig()
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
private fun defaultOverlayPositionByLayout(layout: OverlayLayout) {
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
for (data in overlayControlData) {
|
||||
|
@ -1038,9 +860,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
|
||||
scale /= 100f
|
||||
|
||||
// Apply individual scale
|
||||
scale *= overlayControlData.individualScale
|
||||
|
||||
// Initialize the InputOverlayDrawableButton.
|
||||
val defaultStateBitmap = getBitmap(context, defaultResId, scale)
|
||||
val pressedStateBitmap = getBitmap(context, pressedResId, scale)
|
||||
|
@ -1103,20 +922,11 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
// Resources handle for fetching the initial Drawable resource.
|
||||
val res = context.resources
|
||||
|
||||
// Get the dpad control data for individual scale
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
val dpadData = overlayControlData.firstOrNull { it.id == OverlayControl.COMBINED_DPAD.id }
|
||||
|
||||
// Decide scale based on button ID and user preference
|
||||
var scale = 0.25f
|
||||
scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
|
||||
scale /= 100f
|
||||
|
||||
// Apply individual scale
|
||||
if (dpadData != null) {
|
||||
scale *= dpadData.individualScale
|
||||
}
|
||||
|
||||
// Initialize the InputOverlayDrawableDpad.
|
||||
val defaultStateBitmap =
|
||||
getBitmap(context, defaultResId, scale)
|
||||
|
@ -1190,9 +1000,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
|
||||
scale /= 100f
|
||||
|
||||
// Apply individual scale
|
||||
scale *= overlayControlData.individualScale
|
||||
|
||||
// Initialize the InputOverlayDrawableJoystick.
|
||||
val bitmapOuter = getBitmap(context, resOuter, scale)
|
||||
val bitmapInnerDefault = getBitmap(context, defaultResInner, 1.0f)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay
|
||||
|
||||
|
@ -42,8 +42,6 @@ class InputOverlayDrawableDpad(
|
|||
val width: Int
|
||||
val height: Int
|
||||
|
||||
var individualScale: Float = 1.0f
|
||||
|
||||
private val defaultStateBitmap: BitmapDrawable
|
||||
private val pressedOneDirectionStateBitmap: BitmapDrawable
|
||||
private val pressedTwoDirectionsStateBitmap: BitmapDrawable
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay
|
||||
|
||||
|
@ -51,8 +51,6 @@ class InputOverlayDrawableJoystick(
|
|||
val width: Int
|
||||
val height: Int
|
||||
|
||||
var individualScale: Float = 1.0f
|
||||
|
||||
private var opacity: Int = 0
|
||||
|
||||
private var virtBounds: Rect
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.WindowManager
|
||||
import android.widget.TextView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.slider.Slider
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
|
||||
|
||||
class OverlayScaleDialog(
|
||||
context: Context,
|
||||
private val overlayControlData: OverlayControlData,
|
||||
private val onScaleChanged: (Float) -> Unit
|
||||
) : Dialog(context) {
|
||||
|
||||
private var currentScale = overlayControlData.individualScale
|
||||
private val originalScale = overlayControlData.individualScale
|
||||
private lateinit var scaleValueText: TextView
|
||||
private lateinit var scaleSlider: Slider
|
||||
|
||||
init {
|
||||
setupDialog()
|
||||
}
|
||||
|
||||
private fun setupDialog() {
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.dialog_overlay_scale, null)
|
||||
setContentView(view)
|
||||
|
||||
window?.setBackgroundDrawable(null)
|
||||
|
||||
window?.apply {
|
||||
attributes = attributes.apply {
|
||||
flags = flags and WindowManager.LayoutParams.FLAG_DIM_BEHIND.inv()
|
||||
flags = flags or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||
}
|
||||
}
|
||||
|
||||
scaleValueText = view.findViewById(R.id.scaleValueText)
|
||||
scaleSlider = view.findViewById(R.id.scaleSlider)
|
||||
val resetButton = view.findViewById<MaterialButton>(R.id.resetButton)
|
||||
val confirmButton = view.findViewById<MaterialButton>(R.id.confirmButton)
|
||||
val cancelButton = view.findViewById<MaterialButton>(R.id.cancelButton)
|
||||
|
||||
scaleValueText.text = String.format("%.1fx", currentScale)
|
||||
scaleSlider.value = currentScale
|
||||
|
||||
scaleSlider.addOnChangeListener { _, value, input ->
|
||||
if (input) {
|
||||
currentScale = value
|
||||
scaleValueText.text = String.format("%.1fx", currentScale)
|
||||
}
|
||||
}
|
||||
|
||||
scaleSlider.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
|
||||
override fun onStartTrackingTouch(slider: Slider) {
|
||||
// pass
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(slider: Slider) {
|
||||
onScaleChanged(currentScale)
|
||||
}
|
||||
})
|
||||
|
||||
resetButton.setOnClickListener {
|
||||
currentScale = 1.0f
|
||||
scaleSlider.value = 1.0f
|
||||
scaleValueText.text = String.format("%.1fx", currentScale)
|
||||
onScaleChanged(currentScale)
|
||||
}
|
||||
|
||||
confirmButton.setOnClickListener {
|
||||
overlayControlData.individualScale = currentScale
|
||||
//slider value is already saved on touch dispatch but just to be sure
|
||||
onScaleChanged(currentScale)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
// both cancel button and back gesture should revert the scale change
|
||||
cancelButton.setOnClickListener {
|
||||
onScaleChanged(originalScale)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
setOnCancelListener {
|
||||
onScaleChanged(originalScale)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
fun showDialog(anchorX: Int, anchorY: Int, anchorHeight: Int, anchorWidth: Int) {
|
||||
show()
|
||||
|
||||
show()
|
||||
|
||||
// TODO: this calculation is a bit rough, improve it later on
|
||||
window?.let { window ->
|
||||
val layoutParams = window.attributes
|
||||
layoutParams.gravity = Gravity.TOP or Gravity.START
|
||||
|
||||
val density = context.resources.displayMetrics.density
|
||||
val dialogWidthPx = (320 * density).toInt()
|
||||
val dialogHeightPx = (400 * density).toInt() // set your estimated dialog height
|
||||
|
||||
val screenHeight = context.resources.displayMetrics.heightPixels
|
||||
|
||||
|
||||
layoutParams.x = anchorX + anchorWidth / 2 - dialogWidthPx / 2
|
||||
layoutParams.y = anchorY + anchorHeight / 2 - dialogHeightPx / 2
|
||||
layoutParams.width = dialogWidthPx
|
||||
|
||||
|
||||
window.attributes = layoutParams
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay.model
|
||||
|
||||
|
@ -12,144 +12,126 @@ enum class OverlayControl(
|
|||
val defaultVisibility: Boolean,
|
||||
@IntegerRes val defaultLandscapePositionResources: Pair<Int, Int>,
|
||||
@IntegerRes val defaultPortraitPositionResources: Pair<Int, Int>,
|
||||
@IntegerRes val defaultFoldablePositionResources: Pair<Int, Int>,
|
||||
val defaultIndividualScaleResource: Float,
|
||||
@IntegerRes val defaultFoldablePositionResources: Pair<Int, Int>
|
||||
) {
|
||||
BUTTON_A(
|
||||
"button_a",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_A_X, R.integer.BUTTON_A_Y),
|
||||
Pair(R.integer.BUTTON_A_X_PORTRAIT, R.integer.BUTTON_A_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_B(
|
||||
"button_b",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_B_X, R.integer.BUTTON_B_Y),
|
||||
Pair(R.integer.BUTTON_B_X_PORTRAIT, R.integer.BUTTON_B_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_X(
|
||||
"button_x",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_X_X, R.integer.BUTTON_X_Y),
|
||||
Pair(R.integer.BUTTON_X_X_PORTRAIT, R.integer.BUTTON_X_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_Y(
|
||||
"button_y",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_Y_X, R.integer.BUTTON_Y_Y),
|
||||
Pair(R.integer.BUTTON_Y_X_PORTRAIT, R.integer.BUTTON_Y_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_PLUS(
|
||||
"button_plus",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_PLUS_X, R.integer.BUTTON_PLUS_Y),
|
||||
Pair(R.integer.BUTTON_PLUS_X_PORTRAIT, R.integer.BUTTON_PLUS_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_MINUS(
|
||||
"button_minus",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_MINUS_X, R.integer.BUTTON_MINUS_Y),
|
||||
Pair(R.integer.BUTTON_MINUS_X_PORTRAIT, R.integer.BUTTON_MINUS_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_HOME(
|
||||
"button_home",
|
||||
false,
|
||||
Pair(R.integer.BUTTON_HOME_X, R.integer.BUTTON_HOME_Y),
|
||||
Pair(R.integer.BUTTON_HOME_X_PORTRAIT, R.integer.BUTTON_HOME_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_CAPTURE(
|
||||
"button_capture",
|
||||
false,
|
||||
Pair(R.integer.BUTTON_CAPTURE_X, R.integer.BUTTON_CAPTURE_Y),
|
||||
Pair(R.integer.BUTTON_CAPTURE_X_PORTRAIT, R.integer.BUTTON_CAPTURE_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_L(
|
||||
"button_l",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_L_X, R.integer.BUTTON_L_Y),
|
||||
Pair(R.integer.BUTTON_L_X_PORTRAIT, R.integer.BUTTON_L_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_R(
|
||||
"button_r",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_R_X, R.integer.BUTTON_R_Y),
|
||||
Pair(R.integer.BUTTON_R_X_PORTRAIT, R.integer.BUTTON_R_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_ZL(
|
||||
"button_zl",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_ZL_X, R.integer.BUTTON_ZL_Y),
|
||||
Pair(R.integer.BUTTON_ZL_X_PORTRAIT, R.integer.BUTTON_ZL_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_ZR(
|
||||
"button_zr",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_ZR_X, R.integer.BUTTON_ZR_Y),
|
||||
Pair(R.integer.BUTTON_ZR_X_PORTRAIT, R.integer.BUTTON_ZR_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_STICK_L(
|
||||
"button_stick_l",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_STICK_L_X, R.integer.BUTTON_STICK_L_Y),
|
||||
Pair(R.integer.BUTTON_STICK_L_X_PORTRAIT, R.integer.BUTTON_STICK_L_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_STICK_R(
|
||||
"button_stick_r",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_STICK_R_X, R.integer.BUTTON_STICK_R_Y),
|
||||
Pair(R.integer.BUTTON_STICK_R_X_PORTRAIT, R.integer.BUTTON_STICK_R_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE)
|
||||
),
|
||||
STICK_L(
|
||||
"stick_l",
|
||||
true,
|
||||
Pair(R.integer.STICK_L_X, R.integer.STICK_L_Y),
|
||||
Pair(R.integer.STICK_L_X_PORTRAIT, R.integer.STICK_L_Y_PORTRAIT),
|
||||
Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE)
|
||||
),
|
||||
STICK_R(
|
||||
"stick_r",
|
||||
true,
|
||||
Pair(R.integer.STICK_R_X, R.integer.STICK_R_Y),
|
||||
Pair(R.integer.STICK_R_X_PORTRAIT, R.integer.STICK_R_Y_PORTRAIT),
|
||||
Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE)
|
||||
),
|
||||
COMBINED_DPAD(
|
||||
"combined_dpad",
|
||||
true,
|
||||
Pair(R.integer.COMBINED_DPAD_X, R.integer.COMBINED_DPAD_Y),
|
||||
Pair(R.integer.COMBINED_DPAD_X_PORTRAIT, R.integer.COMBINED_DPAD_Y_PORTRAIT),
|
||||
Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE)
|
||||
);
|
||||
|
||||
fun getDefaultPositionForLayout(layout: OverlayLayout): Pair<Double, Double> {
|
||||
|
@ -191,8 +173,7 @@ enum class OverlayControl(
|
|||
defaultVisibility,
|
||||
getDefaultPositionForLayout(OverlayLayout.Landscape),
|
||||
getDefaultPositionForLayout(OverlayLayout.Portrait),
|
||||
getDefaultPositionForLayout(OverlayLayout.Foldable),
|
||||
defaultIndividualScaleResource
|
||||
getDefaultPositionForLayout(OverlayLayout.Foldable)
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay.model
|
||||
|
||||
|
@ -8,8 +8,7 @@ data class OverlayControlData(
|
|||
var enabled: Boolean,
|
||||
var landscapePosition: Pair<Double, Double>,
|
||||
var portraitPosition: Pair<Double, Double>,
|
||||
var foldablePosition: Pair<Double, Double>,
|
||||
var individualScale: Float
|
||||
var foldablePosition: Pair<Double, Double>
|
||||
) {
|
||||
fun positionFromLayout(layout: OverlayLayout): Pair<Double, Double> =
|
||||
when (layout) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.utils
|
||||
|
||||
|
@ -170,8 +170,7 @@ object DirectoryInitialization {
|
|||
buttonEnabled,
|
||||
Pair(landscapeXPosition, landscapeYPosition),
|
||||
Pair(portraitXPosition, portraitYPosition),
|
||||
Pair(foldableXPosition, foldableYPosition),
|
||||
OverlayControl.map[buttonId]?.defaultIndividualScaleResource ?: 1.0f
|
||||
Pair(foldableXPosition, foldableYPosition)
|
||||
)
|
||||
overlayControlDataMap[buttonId] = controlData
|
||||
setOverlayData = true
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <common/logging/log.h>
|
||||
#include <input_common/main.h>
|
||||
|
@ -103,7 +103,6 @@ void AndroidConfig::ReadOverlayValues() {
|
|||
ReadDoubleSetting(std::string("foldable\\x_position"));
|
||||
control_data.foldable_position.second =
|
||||
ReadDoubleSetting(std::string("foldable\\y_position"));
|
||||
control_data.individual_scale = static_cast<float>(ReadDoubleSetting(std::string("individual_scale")));
|
||||
AndroidSettings::values.overlay_control_data.push_back(control_data);
|
||||
}
|
||||
EndArray();
|
||||
|
@ -256,7 +255,6 @@ void AndroidConfig::SaveOverlayValues() {
|
|||
control_data.foldable_position.first);
|
||||
WriteDoubleSetting(std::string("foldable\\y_position"),
|
||||
control_data.foldable_position.second);
|
||||
WriteDoubleSetting(std::string("individual_scale"), static_cast<double>(control_data.individual_scale));
|
||||
}
|
||||
EndArray();
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace AndroidSettings {
|
|||
std::pair<double, double> landscape_position;
|
||||
std::pair<double, double> portrait_position;
|
||||
std::pair<double, double> foldable_position;
|
||||
float individual_scale;
|
||||
};
|
||||
|
||||
struct Values {
|
||||
|
@ -80,15 +79,6 @@ namespace AndroidSettings {
|
|||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Paired, true,
|
||||
true};
|
||||
Settings::Setting<bool> enable_input_overlay_auto_hide{linkage, false,
|
||||
"enable_input_overlay_auto_hide",
|
||||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Default, true,
|
||||
true,};
|
||||
|
||||
Settings::Setting<u32> input_overlay_auto_hide{linkage, 5, "input_overlay_auto_hide",
|
||||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Default, true, true, &enable_input_overlay_auto_hide};
|
||||
Settings::Setting<bool> perf_overlay_background{linkage, false, "perf_overlay_background",
|
||||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Default, true,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -369,9 +369,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JN
|
|||
env->NewObject(Common::Android::GetOverlayControlDataClass(),
|
||||
Common::Android::GetOverlayControlDataConstructor(),
|
||||
Common::Android::ToJString(env, control_data.id), control_data.enabled,
|
||||
jlandscapePosition, jportraitPosition, jfoldablePosition,
|
||||
control_data.individual_scale);
|
||||
|
||||
jlandscapePosition, jportraitPosition, jfoldablePosition);
|
||||
env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData);
|
||||
}
|
||||
return joverlayControlDataArray;
|
||||
|
@ -420,12 +418,9 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData(
|
|||
env,
|
||||
env->GetObjectField(jfoldablePosition, Common::Android::GetPairSecondField())));
|
||||
|
||||
float individual_scale = static_cast<float>(env->GetFloatField(
|
||||
joverlayControlData, Common::Android::GetOverlayControlDataIndividualScaleField()));
|
||||
|
||||
AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{
|
||||
Common::Android::GetJString(env, jidString), enabled, landscape_position,
|
||||
portrait_position, foldable_position, individual_scale});
|
||||
portrait_position, foldable_position});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="320dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="8dp"
|
||||
app:cardBackgroundColor="#CC222222">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/scaleValueText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="1.0x"
|
||||
android:textAppearance="?attr/textAppearanceBody1"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/scaleSlider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:valueFrom="0.5"
|
||||
android:valueTo="4.0"
|
||||
android:stepSize="0.1"
|
||||
android:value="1.0"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:trackColorActive="@color/eden_border_gradient_start"
|
||||
app:trackColorInactive="@color/eden_border_gradient_end"
|
||||
app:tickColor="@color/eden_border_gradient_start"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/resetButton"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/reset"
|
||||
android:layout_marginEnd="4dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/cancelButton"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@android:string/cancel"
|
||||
android:layout_marginEnd="4dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/confirmButton"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/eden_button_secondary_bg"
|
||||
android:textColor="@color/eden_border_gradient_end"
|
||||
android:text="@string/confirm" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
|
@ -1,55 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginTop="32dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="@dimen/spacing_large"
|
||||
android:paddingRight="@dimen/spacing_large">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_decrement"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/decrement"
|
||||
android:text="-" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/text_input_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/spacing_medlarge"
|
||||
android:layout_marginRight="@dimen/spacing_medlarge"
|
||||
android:layout_weight="1"
|
||||
android:hint="Value">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_value"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:textAlignment="textStart"
|
||||
tools:text="0" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_increment"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/increment"
|
||||
android:text="+" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
|
@ -12,24 +12,6 @@
|
|||
<string name="app_notification_channel_id" translatable="false">Eden</string>
|
||||
<string name="app_notification_channel_description">Eden Switch emulator notifications</string>
|
||||
<string name="app_notification_running">Eden is Running</string>
|
||||
<string name="seconds">Seconds</string>
|
||||
|
||||
<!-- Spinbox strings -->
|
||||
<string name="increment">Increment</string>
|
||||
<string name="decrement">Decrement</string>
|
||||
<string name="value">Value</string>
|
||||
<string name="value_too_low">Value must be at least %1$d</string>
|
||||
<string name="value_too_high">Value must be at most %1$d</string>
|
||||
<string name="invalid_value">Invalid value</string>
|
||||
|
||||
|
||||
<!-- Input Overlay -->
|
||||
<string name="overlay_auto_hide">Overlay Auto Hide</string>
|
||||
<string name="overlay_auto_hide_description">Automatically hide the touch controls overlay after the specified time of inactivity.</string>
|
||||
<string name="enable_input_overlay_auto_hide">Enable Overlay Auto Hide</string>
|
||||
|
||||
<string name="input_overlay_options">Input Overlay</string>
|
||||
<string name="input_overlay_options_description">Configure on-screen controls</string>
|
||||
|
||||
|
||||
<!-- Stats Overlay settings -->
|
||||
|
@ -873,7 +855,6 @@
|
|||
<string name="touchscreen">Touchscreen</string>
|
||||
<string name="lock_drawer">Lock drawer</string>
|
||||
<string name="unlock_drawer">Unlock drawer</string>
|
||||
<string name="reset">Reset</string>
|
||||
|
||||
<string name="load_settings">Loading settings…</string>
|
||||
|
||||
|
@ -889,7 +870,7 @@
|
|||
<string name="save_load_error">Save/Load Error</string>
|
||||
<string name="fatal_error">Fatal Error</string>
|
||||
<string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes.</string>
|
||||
<string name="performance_warning">Turning off this setting will significantly degrade performance. It"s recommended that you leave this setting enabled.</string>
|
||||
<string name="performance_warning">Turning off this setting will significantly degrade performance. It's recommended that you leave this setting enabled.</string>
|
||||
<string name="device_memory_inadequate">Device RAM: %1$s\nRecommended: %2$s</string>
|
||||
<string name="memory_formatted">%1$s %2$s</string>
|
||||
<string name="no_game_present">No bootable game present!</string>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <jni.h>
|
||||
|
@ -46,7 +49,6 @@ static jclass s_overlay_control_data_class;
|
|||
static jmethodID s_overlay_control_data_constructor;
|
||||
static jfieldID s_overlay_control_data_id_field;
|
||||
static jfieldID s_overlay_control_data_enabled_field;
|
||||
static jfieldID s_overlay_control_data_individual_scale_field;
|
||||
static jfieldID s_overlay_control_data_landscape_position_field;
|
||||
static jfieldID s_overlay_control_data_portrait_position_field;
|
||||
static jfieldID s_overlay_control_data_foldable_position_field;
|
||||
|
@ -242,10 +244,6 @@ namespace Common::Android {
|
|||
return s_overlay_control_data_enabled_field;
|
||||
}
|
||||
|
||||
jfieldID GetOverlayControlDataIndividualScaleField() {
|
||||
return s_overlay_control_data_individual_scale_field;
|
||||
}
|
||||
|
||||
jfieldID GetOverlayControlDataLandscapePositionField() {
|
||||
return s_overlay_control_data_landscape_position_field;
|
||||
}
|
||||
|
@ -496,7 +494,7 @@ namespace Common::Android {
|
|||
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
|
||||
s_overlay_control_data_constructor =
|
||||
env->GetMethodID(overlay_control_data_class, "<init>",
|
||||
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
|
||||
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;)V");
|
||||
s_overlay_control_data_id_field =
|
||||
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
|
||||
s_overlay_control_data_enabled_field =
|
||||
|
@ -507,8 +505,6 @@ namespace Common::Android {
|
|||
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_foldable_position_field =
|
||||
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_individual_scale_field =
|
||||
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
|
||||
env->DeleteLocalRef(overlay_control_data_class);
|
||||
|
||||
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
@ -64,7 +67,6 @@ jclass GetOverlayControlDataClass();
|
|||
jmethodID GetOverlayControlDataConstructor();
|
||||
jfieldID GetOverlayControlDataIdField();
|
||||
jfieldID GetOverlayControlDataEnabledField();
|
||||
jfieldID GetOverlayControlDataIndividualScaleField();
|
||||
jfieldID GetOverlayControlDataLandscapePositionField();
|
||||
jfieldID GetOverlayControlDataPortraitPositionField();
|
||||
jfieldID GetOverlayControlDataFoldablePositionField();
|
||||
|
|
|
@ -366,10 +366,10 @@ if (APPLE)
|
|||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
|
||||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
||||
|
||||
if (YUZU_APPLE_USE_BUNDLED_MONTENVK)
|
||||
if (NOT USE_SYSTEM_MOLTENVK)
|
||||
set(MOLTENVK_PLATFORM "macOS")
|
||||
set(MOLTENVK_VERSION "v1.3.0")
|
||||
download_moltenvk(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
|
||||
download_moltenvk_external(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
|
||||
endif()
|
||||
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
|
||||
message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue