Compare commits
4 commits
6aeba9de66
...
bf4dbef16c
Author | SHA1 | Date | |
---|---|---|---|
bf4dbef16c | |||
a8c7b007be | |||
fba3a7e6f6 | |||
a99fd021d7 |
1
.gitignore
vendored
|
@ -44,3 +44,4 @@ eden-windows-msvc
|
|||
artifacts
|
||||
*.AppImage*
|
||||
*.patch
|
||||
.cache
|
||||
|
|
|
@ -114,7 +114,6 @@ else()
|
|||
|
||||
-Werror=all
|
||||
-Werror=extra
|
||||
-Werror=missing-declarations
|
||||
-Werror=shadow
|
||||
-Werror=unused
|
||||
|
||||
|
@ -212,7 +211,7 @@ if (YUZU_ROOM_STANDALONE)
|
|||
endif()
|
||||
|
||||
if (ENABLE_QT)
|
||||
add_subdirectory(yuzu)
|
||||
add_subdirectory(eden)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
|
|
82
src/eden/.gitignore
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
*.qbs.user*
|
||||
CMakeLists.txt.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
||||
# Directories with generated files
|
||||
.moc/
|
||||
.obj/
|
||||
.pch/
|
||||
.rcc/
|
||||
.uic/
|
||||
/build*/
|
83
src/eden/CMakeLists.txt
Normal file
|
@ -0,0 +1,83 @@
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Core Gui Quick QuickControls2)
|
||||
|
||||
qt_standard_project_setup(REQUIRES 6.7)
|
||||
|
||||
qt_add_executable(yuzu
|
||||
main.cpp
|
||||
icons.qrc
|
||||
)
|
||||
|
||||
add_subdirectory(qml)
|
||||
add_subdirectory(interface)
|
||||
add_subdirectory(models)
|
||||
|
||||
set(PLUGINS
|
||||
edenMainplugin
|
||||
edenItemsplugin
|
||||
edenConfigplugin
|
||||
edenInterfaceplugin
|
||||
edenConstantsplugin
|
||||
edenUtilplugin
|
||||
)
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
add_subdirectory(gamepad)
|
||||
set(PLUGINS ${PLUGINS} edenGamepadplugin)
|
||||
endif()
|
||||
|
||||
target_link_libraries(yuzu
|
||||
PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Widgets
|
||||
Qt6::Gui
|
||||
Qt6::Quick
|
||||
Qt6::QuickControls2
|
||||
edenModels
|
||||
|
||||
# Explicitly link to static plugins
|
||||
${PLUGINS}
|
||||
)
|
||||
|
||||
set(NATIVE_MODULES yuzu edenInterface)
|
||||
|
||||
foreach(MODULE ${NATIVE_MODULES})
|
||||
target_link_libraries(${MODULE} PRIVATE common core input_common frontend_common network video_core)
|
||||
target_link_libraries(${MODULE} PRIVATE Boost::headers glad fmt)
|
||||
target_link_libraries(${MODULE} PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||
|
||||
target_link_libraries(${MODULE} PRIVATE Vulkan::Headers)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_include_directories(${MODULE} PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
if (UNIX AND NOT APPLE)
|
||||
target_link_libraries(${MODULE} PRIVATE Qt6::DBus)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${MODULE} PRIVATE
|
||||
# Use QStringBuilder for string concatenation to reduce
|
||||
# the overall number of temporary strings created.
|
||||
-DQT_USE_QSTRINGBUILDER
|
||||
|
||||
# Disable implicit type narrowing in signal/slot connect() calls.
|
||||
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
||||
|
||||
# Disable unsafe overloads of QProcess' start() function.
|
||||
-DQT_NO_PROCESS_COMBINED_ARGUMENT_START
|
||||
|
||||
# Disable implicit QString->QUrl conversions to enforce use of proper resolving functions.
|
||||
-DQT_NO_URL_CAST_FROM_STRING
|
||||
)
|
||||
endforeach()
|
||||
|
||||
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS yuzu
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
9
src/eden/gamepad/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
qt_add_library(edenGamepad STATIC)
|
||||
|
||||
qt_add_qml_module(edenGamepad
|
||||
URI org.eden_emu.gamepad
|
||||
VERSION 1.0
|
||||
SOURCES gamepad.h gamepad.cpp
|
||||
)
|
78
src/eden/gamepad/gamepad.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include "gamepad.h"
|
||||
|
||||
Gamepad::Gamepad(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
SDL_Init(SDL_INIT_GAMECONTROLLER);
|
||||
}
|
||||
|
||||
Gamepad::~Gamepad()
|
||||
{
|
||||
if (controller)
|
||||
SDL_GameControllerClose(controller);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void Gamepad::openController(int deviceIndex)
|
||||
{
|
||||
if (controller) {
|
||||
closeController();
|
||||
}
|
||||
|
||||
controller = SDL_GameControllerOpen(deviceIndex);
|
||||
}
|
||||
|
||||
void Gamepad::closeController()
|
||||
{
|
||||
if (controller) {
|
||||
SDL_GameControllerClose(controller);
|
||||
controller = nullptr;
|
||||
}
|
||||
}
|
||||
void Gamepad::pollEvents()
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_CONTROLLERDEVICEADDED:
|
||||
openController(event.cdevice.which);
|
||||
break;
|
||||
case SDL_CONTROLLERDEVICEREMOVED:
|
||||
if (controller
|
||||
&& event.cdevice.which
|
||||
== SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))) {
|
||||
closeController();
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
switch (event.cbutton.button) {
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
||||
emit upPressed();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||
emit downPressed();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||
emit leftPressed();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||
emit rightPressed();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_A:
|
||||
emit aPressed();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_CONTROLLERAXISMOTION:
|
||||
if (event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX
|
||||
|| event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY) {
|
||||
int x = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
int y = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
emit leftStickMoved(x, y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
31
src/eden/gamepad/gamepad.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include <QElapsedTimer>
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
class Gamepad : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
public:
|
||||
explicit Gamepad(QObject *parent = nullptr);
|
||||
~Gamepad();
|
||||
|
||||
Q_INVOKABLE void pollEvents();
|
||||
|
||||
signals:
|
||||
void upPressed();
|
||||
void downPressed();
|
||||
void leftPressed();
|
||||
void rightPressed();
|
||||
void aPressed();
|
||||
|
||||
void leftStickMoved(int x, int y);
|
||||
|
||||
private:
|
||||
SDL_GameController *controller = nullptr;
|
||||
|
||||
void closeController();
|
||||
void openController(int deviceIndex);
|
||||
};
|
14
src/eden/icons.qrc
Normal file
|
@ -0,0 +1,14 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/audio.svg</file>
|
||||
<file>icons/controls.svg</file>
|
||||
<file>icons/cpu.svg</file>
|
||||
<file>icons/general.svg</file>
|
||||
<file>icons/graphics.svg</file>
|
||||
<file>icons/system.svg</file>
|
||||
<file>icons/debug.svg</file>
|
||||
<file>icons/forward.svg</file>
|
||||
<file>icons/back.svg</file>
|
||||
<file>icons/help.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
1
src/eden/icons/audio.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M560-131v-82q90-26 145-100t55-168q0-94-55-168T560-749v-82q124 28 202 125.5T840-481q0 127-78 224.5T560-131ZM120-360v-240h160l200-200v640L280-360H120Zm440 40v-322q47 22 73.5 66t26.5 96q0 51-26.5 94.5T560-320ZM400-606l-86 86H200v80h114l86 86v-252ZM300-480Z"/></svg>
|
After Width: | Height: | Size: 378 B |
39
src/eden/icons/back.svg
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="20"
|
||||
viewBox="0 -960 227.99999 400"
|
||||
width="11.4"
|
||||
fill="#ffffff"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="back.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="24.291667"
|
||||
inkscape:cx="24.061749"
|
||||
inkscape:cy="17.413379"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="M 200,-560 228,-588.5 56.5,-760 228,-931.5 200,-960 0,-760 Z"
|
||||
id="path1"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.5" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/eden/icons/controls.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M189-160q-60 0-102.5-43T42-307q0-9 1-18t3-18l84-336q14-54 57-87.5t98-33.5h390q55 0 98 33.5t57 87.5l84 336q2 9 3.5 18.5T919-306q0 61-43.5 103.5T771-160q-42 0-78-22t-54-60l-28-58q-5-10-15-15t-21-5H385q-11 0-21 5t-15 15l-28 58q-18 38-54 60t-78 22Zm3-80q19 0 34.5-10t23.5-27l28-57q15-31 44-48.5t63-17.5h190q34 0 63 18t45 48l28 57q8 17 23.5 27t34.5 10q28 0 48-18.5t21-46.5q0 1-2-19l-84-335q-7-27-28-44t-49-17H285q-28 0-49.5 17T208-659l-84 335q-2 6-2 18 0 28 20.5 47t49.5 19Zm348-280q17 0 28.5-11.5T580-560q0-17-11.5-28.5T540-600q-17 0-28.5 11.5T500-560q0 17 11.5 28.5T540-520Zm80-80q17 0 28.5-11.5T660-640q0-17-11.5-28.5T620-680q-17 0-28.5 11.5T580-640q0 17 11.5 28.5T620-600Zm0 160q17 0 28.5-11.5T660-480q0-17-11.5-28.5T620-520q-17 0-28.5 11.5T580-480q0 17 11.5 28.5T620-440Zm80-80q17 0 28.5-11.5T740-560q0-17-11.5-28.5T700-600q-17 0-28.5 11.5T660-560q0 17 11.5 28.5T700-520Zm-360 60q13 0 21.5-8.5T370-490v-40h40q13 0 21.5-8.5T440-560q0-13-8.5-21.5T410-590h-40v-40q0-13-8.5-21.5T340-660q-13 0-21.5 8.5T310-630v40h-40q-13 0-21.5 8.5T240-560q0 13 8.5 21.5T270-530h40v40q0 13 8.5 21.5T340-460Zm140-20Z"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/eden/icons/cpu.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M360-360v-240h240v240H360Zm80-80h80v-80h-80v80Zm-80 320v-80h-80q-33 0-56.5-23.5T200-280v-80h-80v-80h80v-80h-80v-80h80v-80q0-33 23.5-56.5T280-760h80v-80h80v80h80v-80h80v80h80q33 0 56.5 23.5T760-680v80h80v80h-80v80h80v80h-80v80q0 33-23.5 56.5T680-200h-80v80h-80v-80h-80v80h-80Zm320-160v-400H280v400h400ZM480-480Z"/></svg>
|
After Width: | Height: | Size: 435 B |
1
src/eden/icons/debug.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M480-200q66 0 113-47t47-113v-160q0-66-47-113t-113-47q-66 0-113 47t-47 113v160q0 66 47 113t113 47Zm-80-120h160v-80H400v80Zm0-160h160v-80H400v80Zm80 40Zm0 320q-65 0-120.5-32T272-240H160v-80h84q-3-20-3.5-40t-.5-40h-80v-80h80q0-20 .5-40t3.5-40h-84v-80h112q14-23 31.5-43t40.5-35l-64-66 56-56 86 86q28-9 57-9t57 9l88-86 56 56-66 66q23 15 41.5 34.5T688-640h112v80h-84q3 20 3.5 40t.5 40h80v80h-80q0 20-.5 40t-3.5 40h84v80H688q-32 56-87.5 88T480-120Z"/></svg>
|
After Width: | Height: | Size: 566 B |
39
src/eden/icons/forward.svg
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="20"
|
||||
viewBox="0 -960 227.99999 400"
|
||||
width="11.4"
|
||||
fill="#ffffff"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="forward.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="24.291667"
|
||||
inkscape:cx="24.020583"
|
||||
inkscape:cy="24"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="M 28,-560 0,-588.5 171.5,-760 0,-931.5 28,-960 228,-760 Z"
|
||||
id="path1"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.5" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/eden/icons/general.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="m370-80-16-128q-13-5-24.5-12T307-235l-119 50L78-375l103-78q-1-7-1-13.5v-27q0-6.5 1-13.5L78-585l110-190 119 50q11-8 23-15t24-12l16-128h220l16 128q13 5 24.5 12t22.5 15l119-50 110 190-103 78q1 7 1 13.5v27q0 6.5-2 13.5l103 78-110 190-118-50q-11 8-23 15t-24 12L590-80H370Zm70-80h79l14-106q31-8 57.5-23.5T639-327l99 41 39-68-86-65q5-14 7-29.5t2-31.5q0-16-2-31.5t-7-29.5l86-65-39-68-99 42q-22-23-48.5-38.5T533-694l-13-106h-79l-14 106q-31 8-57.5 23.5T321-633l-99-41-39 68 86 64q-5 15-7 30t-2 32q0 16 2 31t7 30l-86 65 39 68 99-42q22 23 48.5 38.5T427-266l13 106Zm42-180q58 0 99-41t41-99q0-58-41-99t-99-41q-59 0-99.5 41T342-480q0 58 40.5 99t99.5 41Zm-2-140Z"/></svg>
|
After Width: | Height: | Size: 771 B |
60
src/eden/icons/graphics.svg
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
|
||||
<svg
|
||||
fill="#000000"
|
||||
height="800px"
|
||||
width="800px"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
viewBox="0 0 512 512"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="graphics.svg"
|
||||
inkscape:version="1.4.1 (93de688d07, 2025-03-30)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs5" /><sodipodi:namedview
|
||||
id="namedview5"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.52947631"
|
||||
inkscape:cx="404.17295"
|
||||
inkscape:cy="224.75038"
|
||||
inkscape:window-width="956"
|
||||
inkscape:window-height="1150"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<g
|
||||
id="g5"
|
||||
style="fill:#000000;fill-opacity:1">
|
||||
<g
|
||||
id="g4"
|
||||
style="fill:#000000;fill-opacity:1">
|
||||
<g
|
||||
id="g3"
|
||||
style="fill:#000000;fill-opacity:1">
|
||||
<path
|
||||
d="M490.667,96H85.333V74.667c0-11.782-9.551-21.333-21.333-21.333H21.333C9.551,53.333,0,62.885,0,74.667 C0,86.449,9.551,96,21.333,96h21.333v21.333v256V416c0,11.782,9.551,21.333,21.333,21.333c11.782,0,21.333-9.551,21.333-21.333 v-21.333H128v42.667c0,11.782,9.551,21.333,21.333,21.333c11.782,0,21.333-9.551,21.333-21.333v-42.667h42.667v42.667 c0,11.782,9.551,21.333,21.333,21.333c11.782,0,21.333-9.551,21.333-21.333v-42.667h42.667v42.667 c0,11.782,9.551,21.333,21.333,21.333s21.333-9.551,21.333-21.333v-42.667h149.333c11.782,0,21.333-9.551,21.333-21.333v-256 C512,105.551,502.449,96,490.667,96z M469.333,352h-384V138.667h384V352z"
|
||||
id="path1"
|
||||
style="fill:#000000;fill-opacity:1" />
|
||||
<path
|
||||
d="M362.667,330.667c47.131,0,85.333-38.202,85.333-85.333S409.798,160,362.667,160s-85.333,38.202-85.333,85.333 S315.535,330.667,362.667,330.667z M362.667,202.667c23.567,0,42.667,19.099,42.667,42.667S386.234,288,362.667,288 S320,268.901,320,245.333S339.099,202.667,362.667,202.667z"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1" />
|
||||
<path
|
||||
d="M192,330.667h42.667c11.782,0,21.333-9.551,21.333-21.333v-128c0-11.782-9.551-21.333-21.333-21.333H192 c-47.131,0-85.333,38.202-85.333,85.333S144.869,330.667,192,330.667z M192,202.667h21.333V288H192 c-23.567,0-42.667-19.099-42.667-42.667S168.433,202.667,192,202.667z"
|
||||
id="path3"
|
||||
style="fill:#000000;fill-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
1
src/eden/icons/help.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#FFFFFF"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>
|
After Width: | Height: | Size: 695 B |
1
src/eden/icons/system.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M560-200q17 0 28.5-11.5T600-240q0-17-11.5-28.5T560-280q-17 0-28.5 11.5T520-240q0 17 11.5 28.5T560-200Zm120 0q17 0 28.5-11.5T720-240q0-17-11.5-28.5T680-280q-17 0-28.5 11.5T640-240q0 17 11.5 28.5T680-200ZM120-440v-360q0-33 23.5-56.5T200-880h560q33 0 56.5 23.5T840-800v360h-80v-360H200v360h-80Zm80 80v200h560v-200H200Zm0 280q-33 0-56.5-23.5T120-160v-280h720v280q0 33-23.5 56.5T760-80H200Zm0-360h560-560Zm0 80h560-560Z"/></svg>
|
After Width: | Height: | Size: 539 B |
14
src/eden/interface/CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
qt_add_library(edenInterface STATIC)
|
||||
qt_add_qml_module(edenInterface
|
||||
URI org.eden_emu.interface
|
||||
VERSION 1.0
|
||||
SOURCES
|
||||
SettingsInterface.h SettingsInterface.cpp
|
||||
uisettings.h uisettings.cpp
|
||||
qt_config.h qt_config.cpp
|
||||
shared_translation.h shared_translation.cpp
|
||||
QMLSetting.h QMLSetting.cpp
|
||||
MetaObjectHelper.h
|
||||
SOURCES QMLConfig.h
|
||||
|
||||
)
|
22
src/eden/interface/MetaObjectHelper.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef METAOBJECTHELPER_H
|
||||
#define METAOBJECTHELPER_H
|
||||
|
||||
#include <QMetaObject>
|
||||
#include <QObject>
|
||||
#include <QQmlProperty>
|
||||
|
||||
class MetaObjectHelper : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
public:
|
||||
using QObject::QObject;
|
||||
Q_INVOKABLE QString typeName(QObject* object, const QString& property) const
|
||||
{
|
||||
QQmlProperty qmlProperty(object, property);
|
||||
QMetaProperty metaProperty = qmlProperty.property();
|
||||
return metaProperty.typeName();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // METAOBJECTHELPER_H
|
26
src/eden/interface/QMLConfig.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef QMLCONFIG_H
|
||||
#define QMLCONFIG_H
|
||||
|
||||
#include "eden/interface/qt_config.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QMLConfig : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
QtConfig *m_config;
|
||||
|
||||
public:
|
||||
QMLConfig()
|
||||
: m_config{new QtConfig}
|
||||
{}
|
||||
|
||||
Q_INVOKABLE inline void reload() {
|
||||
m_config->ReloadAllValues();
|
||||
}
|
||||
Q_INVOKABLE inline void save() {
|
||||
m_config->SaveAllValues();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QMLCONFIG_H
|
261
src/eden/interface/QMLSetting.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
#include "QMLSetting.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
QMLSetting::QMLSetting(Settings::BasicSetting *setting, QObject *parent, RequestType request)
|
||||
: QObject(parent)
|
||||
, m_setting(setting)
|
||||
{
|
||||
|
||||
// TODO: restore/touch
|
||||
/*
|
||||
if (!Settings::IsConfiguringGlobal() && managed) {
|
||||
restore_button = CreateRestoreGlobalButton(setting.UsingGlobal(), this);
|
||||
|
||||
touch = [this]() {
|
||||
LOG_DEBUG(Frontend, "Enabling custom setting for \"{}\"", setting.GetLabel());
|
||||
restore_button->setEnabled(true);
|
||||
restore_button->setVisible(true);
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
const auto type = setting->TypeId();
|
||||
|
||||
request = [&]() {
|
||||
if (request != RequestType::Default) {
|
||||
return request;
|
||||
}
|
||||
switch (setting->Specialization() & Settings::SpecializationTypeMask) {
|
||||
case Settings::Specialization::Default:
|
||||
return RequestType::Default;
|
||||
case Settings::Specialization::Time:
|
||||
return RequestType::DateTimeEdit;
|
||||
case Settings::Specialization::Hex:
|
||||
return RequestType::HexEdit;
|
||||
case Settings::Specialization::RuntimeList:
|
||||
// managed = false;
|
||||
[[fallthrough]];
|
||||
case Settings::Specialization::List:
|
||||
return RequestType::ComboBox;
|
||||
case Settings::Specialization::Scalar:
|
||||
return RequestType::Slider;
|
||||
case Settings::Specialization::Countable:
|
||||
return RequestType::SpinBox;
|
||||
case Settings::Specialization::Radio:
|
||||
return RequestType::RadioGroup;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return request;
|
||||
}();
|
||||
|
||||
if (type == typeid(bool)) {
|
||||
m_type = "bool";
|
||||
m_metaType = QMetaType::Bool;
|
||||
} else if (setting->IsEnum()) {
|
||||
m_metaType = QMetaType::UInt;
|
||||
|
||||
if (request == RequestType::RadioGroup) {
|
||||
m_type = "radio";
|
||||
// TODO: Add the options and whatnot
|
||||
// see CreateRadioGroup
|
||||
} else {
|
||||
m_type = "enumCombo";
|
||||
}
|
||||
} else if (setting->IsIntegral()) {
|
||||
m_metaType = QMetaType::UInt;
|
||||
|
||||
switch (request) {
|
||||
case RequestType::Slider:
|
||||
case RequestType::ReverseSlider:
|
||||
// TODO: Reversal and multiplier
|
||||
m_type = "intSlider";
|
||||
break;
|
||||
case RequestType::Default:
|
||||
case RequestType::LineEdit:
|
||||
m_type = "intSpin";
|
||||
break;
|
||||
case RequestType::DateTimeEdit:
|
||||
// TODO: disabled/restrict
|
||||
m_type = "time";
|
||||
break;
|
||||
case RequestType::SpinBox:
|
||||
// TODO: suffix
|
||||
m_type = "intSpin";
|
||||
break;
|
||||
case RequestType::HexEdit:
|
||||
m_type = "hex";
|
||||
break;
|
||||
case RequestType::ComboBox:
|
||||
// TODO: Add the options and whatnot
|
||||
// see CreateComboBox
|
||||
m_type = "intCombo";
|
||||
break;
|
||||
default:
|
||||
// UNIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
} else if (setting->IsFloatingPoint()) {
|
||||
m_metaType = QMetaType::Double;
|
||||
|
||||
switch (request) {
|
||||
case RequestType::Default:
|
||||
case RequestType::SpinBox:
|
||||
// TODO: suffix
|
||||
m_type = "doubleSpin";
|
||||
break;
|
||||
case RequestType::Slider:
|
||||
case RequestType::ReverseSlider:
|
||||
// TODO: multiplier, suffix, reversal
|
||||
m_type = "doubleSlider";
|
||||
break;
|
||||
default:
|
||||
// UNIMPLEMENTED assert
|
||||
// UNIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
} else if (type == typeid(std::string)) {
|
||||
m_metaType = QMetaType::QString;
|
||||
|
||||
switch (request) {
|
||||
case RequestType::Default:
|
||||
case RequestType::LineEdit:
|
||||
m_type = "stringLine";
|
||||
break;
|
||||
case RequestType::ComboBox:
|
||||
m_type = "stringCombo";
|
||||
break;
|
||||
default:
|
||||
// UNIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariant QMLSetting::value() const
|
||||
{
|
||||
QVariant var = QVariant::fromValue(QString::fromStdString(m_setting->ToString()));
|
||||
var.convert(QMetaType(m_metaType));
|
||||
return var;
|
||||
}
|
||||
|
||||
void QMLSetting::setValue(const QVariant &newValue)
|
||||
{
|
||||
QVariant var = newValue;
|
||||
var.convert(QMetaType(m_metaType));
|
||||
|
||||
m_setting->LoadString(var.toString().toStdString());
|
||||
emit valueChanged();
|
||||
}
|
||||
|
||||
bool QMLSetting::global() const
|
||||
{
|
||||
return m_setting->UsingGlobal();
|
||||
}
|
||||
|
||||
void QMLSetting::setGlobal(bool newGlobal)
|
||||
{
|
||||
m_setting->SetGlobal(newGlobal);
|
||||
emit globalChanged();
|
||||
emit valueChanged();
|
||||
}
|
||||
|
||||
void QMLSetting::restore()
|
||||
{
|
||||
std::string toSet = Settings::IsConfiguringGlobal() ? m_setting->DefaultToString() : m_setting->ToStringGlobal();
|
||||
setValue(QString::fromStdString(toSet));
|
||||
setGlobal(false);
|
||||
}
|
||||
|
||||
QMLSetting *QMLSetting::other() const
|
||||
{
|
||||
return m_other;
|
||||
}
|
||||
|
||||
void QMLSetting::setOther(QMLSetting *newOther)
|
||||
{
|
||||
if (m_other == newOther)
|
||||
return;
|
||||
m_other = newOther;
|
||||
emit otherChanged();
|
||||
}
|
||||
|
||||
u32 QMLSetting::max() const
|
||||
{
|
||||
return std::strtol(m_setting->MaxVal().c_str(), nullptr, 0);
|
||||
}
|
||||
|
||||
u32 QMLSetting::min() const
|
||||
{
|
||||
return std::strtol(m_setting->MinVal().c_str(), nullptr, 0);
|
||||
}
|
||||
|
||||
QString QMLSetting::suffix() const
|
||||
{
|
||||
return m_suffix;
|
||||
}
|
||||
|
||||
void QMLSetting::setSuffix(const QString &newSuffix)
|
||||
{
|
||||
if (m_suffix == newSuffix)
|
||||
return;
|
||||
m_suffix = newSuffix;
|
||||
emit suffixChanged();
|
||||
}
|
||||
|
||||
QStringList QMLSetting::combo() const
|
||||
{
|
||||
return m_combo;
|
||||
}
|
||||
|
||||
void QMLSetting::setCombo(const QStringList &newCombo)
|
||||
{
|
||||
if (m_combo == newCombo)
|
||||
return;
|
||||
m_combo = newCombo;
|
||||
emit comboChanged();
|
||||
}
|
||||
|
||||
QString QMLSetting::type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void QMLSetting::setType(const QString &newType)
|
||||
{
|
||||
if (m_type == newType)
|
||||
return;
|
||||
m_type = newType;
|
||||
emit typeChanged();
|
||||
}
|
||||
|
||||
u32 QMLSetting::id() const
|
||||
{
|
||||
return m_setting->Id();
|
||||
}
|
||||
|
||||
QString QMLSetting::tooltip() const
|
||||
{
|
||||
return m_tooltip;
|
||||
}
|
||||
|
||||
void QMLSetting::setTooltip(const QString &newTooltip)
|
||||
{
|
||||
if (m_tooltip == newTooltip)
|
||||
return;
|
||||
m_tooltip = newTooltip;
|
||||
emit tooltipChanged();
|
||||
}
|
||||
|
||||
QString QMLSetting::label() const
|
||||
{
|
||||
return m_label.isEmpty() ? QString::fromStdString(m_setting->GetLabel()) : m_label;
|
||||
}
|
||||
|
||||
void QMLSetting::setLabel(const QString &newLabel)
|
||||
{
|
||||
if (m_label == newLabel)
|
||||
return;
|
||||
m_label = newLabel;
|
||||
emit labelChanged();
|
||||
}
|
105
src/eden/interface/QMLSetting.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
#ifndef QMLSETTING_H
|
||||
#define QMLSETTING_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtQmlIntegration>
|
||||
#include "common/settings_common.h"
|
||||
|
||||
enum class RequestType {
|
||||
Default,
|
||||
ComboBox,
|
||||
SpinBox,
|
||||
Slider,
|
||||
ReverseSlider,
|
||||
LineEdit,
|
||||
HexEdit,
|
||||
DateTimeEdit,
|
||||
RadioGroup,
|
||||
MaxEnum,
|
||||
};
|
||||
|
||||
class QMLSetting : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QMLSetting(Settings::BasicSetting *setting, QObject *parent = nullptr, RequestType request = RequestType::Default);
|
||||
|
||||
QVariant value() const;
|
||||
void setValue(const QVariant &newValue);
|
||||
|
||||
bool global() const;
|
||||
void setGlobal(bool newGlobal);
|
||||
|
||||
QString label() const;
|
||||
void setLabel(const QString &newLabel);
|
||||
|
||||
QString tooltip() const;
|
||||
void setTooltip(const QString &newTooltip);
|
||||
|
||||
u32 id() const;
|
||||
|
||||
QString type() const;
|
||||
void setType(const QString &newType);
|
||||
|
||||
QStringList combo() const;
|
||||
void setCombo(const QStringList &newCombo);
|
||||
|
||||
QString suffix() const;
|
||||
void setSuffix(const QString &newSuffix);
|
||||
|
||||
// TODO: float versions
|
||||
u32 min() const;
|
||||
u32 max() const;
|
||||
|
||||
QMLSetting *other() const;
|
||||
void setOther(QMLSetting *newOther);
|
||||
|
||||
public slots:
|
||||
void restore();
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
void globalChanged();
|
||||
|
||||
void labelChanged();
|
||||
|
||||
void tooltipChanged();
|
||||
|
||||
void typeChanged();
|
||||
|
||||
void comboChanged();
|
||||
|
||||
void suffixChanged();
|
||||
|
||||
void otherChanged();
|
||||
|
||||
private:
|
||||
Settings::BasicSetting *m_setting;
|
||||
|
||||
QMLSetting *m_other;
|
||||
|
||||
QString m_label;
|
||||
QString m_tooltip;
|
||||
QString m_type;
|
||||
QStringList m_combo;
|
||||
QString m_suffix;
|
||||
|
||||
QMetaType::Type m_metaType;
|
||||
|
||||
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged FINAL)
|
||||
Q_PROPERTY(bool global READ global WRITE setGlobal NOTIFY globalChanged FINAL)
|
||||
Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged FINAL)
|
||||
Q_PROPERTY(QString tooltip READ tooltip WRITE setTooltip NOTIFY tooltipChanged FINAL)
|
||||
Q_PROPERTY(u32 id READ id FINAL CONSTANT)
|
||||
Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged FINAL)
|
||||
Q_PROPERTY(QStringList combo READ combo WRITE setCombo NOTIFY comboChanged FINAL)
|
||||
Q_PROPERTY(QString suffix READ suffix WRITE setSuffix NOTIFY suffixChanged FINAL)
|
||||
|
||||
Q_PROPERTY(u32 min READ min FINAL CONSTANT)
|
||||
Q_PROPERTY(u32 max READ max FINAL CONSTANT)
|
||||
Q_PROPERTY(QMLSetting *other READ other WRITE setOther NOTIFY otherChanged FINAL)
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QMLSetting *)
|
||||
|
||||
#endif // QMLSETTING_H
|
124
src/eden/interface/SettingsInterface.cpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include "SettingsInterface.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "uisettings.h"
|
||||
|
||||
SettingsInterface::SettingsInterface(QObject* parent)
|
||||
: QObject{parent}
|
||||
, translations{ConfigurationShared::InitializeTranslations(parent)}
|
||||
, combobox_translations{ConfigurationShared::ComboboxEnumeration(parent)}
|
||||
{}
|
||||
|
||||
// TODO: idExclude
|
||||
SettingsModel *SettingsInterface::category(SettingsCategories::Category category,
|
||||
QList<QString> idInclude,
|
||||
QList<QString> idExclude)
|
||||
{
|
||||
std::vector<Settings::BasicSetting *> settings = Settings::values.linkage.by_category[static_cast<Settings::Category>(category)];
|
||||
std::vector<Settings::BasicSetting *> uisettings = UISettings::values.linkage.by_category[static_cast<Settings::Category>(category)];
|
||||
|
||||
settings.insert(settings.end(), uisettings.begin(), uisettings.end());
|
||||
|
||||
QList<QMLSetting *> settingsList;
|
||||
for (Settings::BasicSetting *setting : settings) {
|
||||
// paired settings get ignored
|
||||
if (setting->Specialization() == Settings::Specialization::Paired) {
|
||||
LOG_DEBUG(Frontend, "\"{}\" has specialization Paired: ignoring", setting->GetLabel());
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((idInclude.empty() || idInclude.contains(setting->GetLabel()))
|
||||
&& (idExclude.empty() || !idExclude.contains(setting->GetLabel()))) {
|
||||
settingsList.append(this->getSetting(setting));
|
||||
}
|
||||
}
|
||||
|
||||
SettingsModel *model = new SettingsModel(this);
|
||||
model->append(settingsList);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
int SettingsInterface::id(const QString &key)
|
||||
{
|
||||
return setting(key)->id();
|
||||
}
|
||||
|
||||
bool SettingsInterface::global() const
|
||||
{
|
||||
return Settings::IsConfiguringGlobal();
|
||||
}
|
||||
|
||||
void SettingsInterface::setGlobal(bool newGlobal)
|
||||
{
|
||||
Settings::SetConfiguringGlobal(newGlobal);
|
||||
}
|
||||
|
||||
QMLSetting *SettingsInterface::getSetting(Settings::BasicSetting *setting)
|
||||
{
|
||||
if (setting == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_settings.contains(setting->GetLabel())) {
|
||||
return m_settings.value(setting->GetLabel());
|
||||
}
|
||||
|
||||
const int id = setting->Id();
|
||||
|
||||
const auto [label, tooltip] = [&]() {
|
||||
const auto& setting_label = setting->GetLabel();
|
||||
if (translations->contains(id)) {
|
||||
return std::pair{translations->at(id).first, translations->at(id).second};
|
||||
}
|
||||
|
||||
LOG_WARNING(Frontend, "Translation table lacks entry for \"{}\"", setting_label);
|
||||
return std::pair{QString::fromStdString(setting_label), QString()};
|
||||
}();
|
||||
|
||||
const auto type = setting->EnumIndex();
|
||||
QStringList items;
|
||||
|
||||
const ConfigurationShared::ComboboxTranslations* enumeration{nullptr};
|
||||
if (combobox_translations->contains(type)) {
|
||||
enumeration = &combobox_translations->at(type);
|
||||
for (const auto& [_, name] : *enumeration) {
|
||||
items << name;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Suffix (fr)
|
||||
QString suffix = "";
|
||||
|
||||
if ((setting->Specialization() & Settings::SpecializationAttributeMask) ==
|
||||
Settings::Specialization::Percentage) {
|
||||
suffix = "%";
|
||||
}
|
||||
|
||||
// paired setting (I/A)
|
||||
QMLSetting *other = this->getSetting(setting->PairedSetting());
|
||||
|
||||
QMLSetting *qsetting = new QMLSetting(setting, this);
|
||||
qsetting->setLabel(label);
|
||||
qsetting->setTooltip(tooltip);
|
||||
qsetting->setCombo(items);
|
||||
qsetting->setSuffix(suffix);
|
||||
qsetting->setOther(other);
|
||||
|
||||
m_settings.insert(setting->GetLabel(), qsetting);
|
||||
|
||||
return qsetting;
|
||||
}
|
||||
|
||||
QMLSetting *SettingsInterface::setting(const QString &key)
|
||||
{
|
||||
std::string skey = key.toStdString();
|
||||
if (!m_settings.contains(skey)) {
|
||||
Settings::BasicSetting *basicSetting = Settings::values.linkage.by_key.contains(skey) ?
|
||||
Settings::values.linkage.by_key[skey] :
|
||||
UISettings::values.linkage.by_key[skey];
|
||||
return getSetting(basicSetting);
|
||||
} else {
|
||||
return m_settings.value(skey);
|
||||
}
|
||||
}
|
84
src/eden/interface/SettingsInterface.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
#ifndef SETTINGSINTERFACE_H
|
||||
#define SETTINGSINTERFACE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtQmlIntegration/QtQmlIntegration>
|
||||
|
||||
#include "QMLSetting.h"
|
||||
#include "shared_translation.h"
|
||||
#include "eden/models/SettingsModel.h"
|
||||
|
||||
namespace SettingsCategories {
|
||||
Q_NAMESPACE
|
||||
|
||||
enum class Category {
|
||||
Android = static_cast<u32>(Settings::Category::Android),
|
||||
Audio = static_cast<u32>(Settings::Category::Audio),
|
||||
Core = static_cast<u32>(Settings::Category::Core),
|
||||
Cpu = static_cast<u32>(Settings::Category::Cpu),
|
||||
CpuDebug = static_cast<u32>(Settings::Category::CpuDebug),
|
||||
CpuUnsafe = static_cast<u32>(Settings::Category::CpuUnsafe),
|
||||
Overlay = static_cast<u32>(Settings::Category::Overlay),
|
||||
Renderer = static_cast<u32>(Settings::Category::Renderer),
|
||||
RendererAdvanced = static_cast<u32>(Settings::Category::RendererAdvanced),
|
||||
RendererExtensions = static_cast<u32>(Settings::Category::RendererExtensions),
|
||||
RendererDebug = static_cast<u32>(Settings::Category::RendererDebug),
|
||||
System = static_cast<u32>(Settings::Category::System),
|
||||
SystemAudio = static_cast<u32>(Settings::Category::SystemAudio),
|
||||
DataStorage = static_cast<u32>(Settings::Category::DataStorage),
|
||||
Debugging = static_cast<u32>(Settings::Category::Debugging),
|
||||
DebuggingGraphics = static_cast<u32>(Settings::Category::DebuggingGraphics),
|
||||
GpuDriver = static_cast<u32>(Settings::Category::GpuDriver),
|
||||
Miscellaneous = static_cast<u32>(Settings::Category::Miscellaneous),
|
||||
Network = static_cast<u32>(Settings::Category::Network),
|
||||
WebService = static_cast<u32>(Settings::Category::WebService),
|
||||
AddOns = static_cast<u32>(Settings::Category::AddOns),
|
||||
Controls = static_cast<u32>(Settings::Category::Controls),
|
||||
Ui = static_cast<u32>(Settings::Category::Ui),
|
||||
UiAudio = static_cast<u32>(Settings::Category::UiAudio),
|
||||
UiGeneral = static_cast<u32>(Settings::Category::UiGeneral),
|
||||
UiLayout = static_cast<u32>(Settings::Category::UiLayout),
|
||||
UiGameList = static_cast<u32>(Settings::Category::UiGameList),
|
||||
Screenshots = static_cast<u32>(Settings::Category::Screenshots),
|
||||
Shortcuts = static_cast<u32>(Settings::Category::Shortcuts),
|
||||
Multiplayer = static_cast<u32>(Settings::Category::Multiplayer),
|
||||
Services = static_cast<u32>(Settings::Category::Services),
|
||||
Paths = static_cast<u32>(Settings::Category::Paths),
|
||||
Linux = static_cast<u32>(Settings::Category::Linux),
|
||||
LibraryApplet = static_cast<u32>(Settings::Category::LibraryApplet),
|
||||
MaxEnum = static_cast<u32>(Settings::Category::MaxEnum),
|
||||
};
|
||||
Q_ENUM_NS(Category)
|
||||
}
|
||||
|
||||
class SettingsInterface : public QObject {
|
||||
Q_OBJECT
|
||||
QML_SINGLETON
|
||||
QML_ELEMENT
|
||||
public:
|
||||
explicit SettingsInterface(QObject* parent = nullptr);
|
||||
|
||||
QMLSetting *getSetting(Settings::BasicSetting *setting);
|
||||
Q_INVOKABLE QMLSetting *setting(const QString &key);
|
||||
Q_INVOKABLE SettingsModel *category(SettingsCategories::Category category,
|
||||
QList<QString> idInclude = {},
|
||||
QList<QString> idExclude = {});
|
||||
|
||||
Q_INVOKABLE int id(const QString &key);
|
||||
|
||||
bool global() const;
|
||||
void setGlobal(bool newGlobal);
|
||||
|
||||
signals:
|
||||
void globalChanged();
|
||||
|
||||
private:
|
||||
QMap<std::string, QMLSetting *> m_settings;
|
||||
|
||||
std::unique_ptr<ConfigurationShared::TranslationMap> translations;
|
||||
std::unique_ptr<ConfigurationShared::ComboboxTranslationMap> combobox_translations;
|
||||
|
||||
Q_PROPERTY(bool global READ global WRITE setGlobal NOTIFY globalChanged FINAL)
|
||||
};
|
||||
|
||||
#endif // SETTINGSINTERFACE_H
|
562
src/eden/interface/qt_config.cpp
Normal file
|
@ -0,0 +1,562 @@
|
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "qt_config.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "input_common/main.h"
|
||||
#include "uisettings.h"
|
||||
|
||||
const std::array<int, Settings::NativeButton::NumButtons> QtConfig::default_buttons = {
|
||||
Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F,
|
||||
Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T,
|
||||
Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right,
|
||||
Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0,
|
||||
Qt::Key_Q, Qt::Key_E,
|
||||
};
|
||||
|
||||
const std::array<int, Settings::NativeMotion::NumMotions> QtConfig::default_motions = {
|
||||
Qt::Key_7,
|
||||
Qt::Key_8,
|
||||
};
|
||||
|
||||
const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{
|
||||
{
|
||||
Qt::Key_W,
|
||||
Qt::Key_S,
|
||||
Qt::Key_A,
|
||||
Qt::Key_D,
|
||||
},
|
||||
{
|
||||
Qt::Key_I,
|
||||
Qt::Key_K,
|
||||
Qt::Key_J,
|
||||
Qt::Key_L,
|
||||
},
|
||||
}};
|
||||
|
||||
const std::array<int, 2> QtConfig::default_stick_mod = {
|
||||
Qt::Key_Shift,
|
||||
0,
|
||||
};
|
||||
|
||||
const std::array<int, 2> QtConfig::default_ringcon_analogs{{
|
||||
Qt::Key_A,
|
||||
Qt::Key_D,
|
||||
}};
|
||||
|
||||
QtConfig::QtConfig(const std::string& config_name, const ConfigType config_type)
|
||||
: Config(config_type) {
|
||||
Initialize(config_name);
|
||||
if (config_type != ConfigType::InputProfile) {
|
||||
ReadQtValues();
|
||||
SaveQtValues();
|
||||
}
|
||||
}
|
||||
|
||||
QtConfig::~QtConfig() {
|
||||
if (global) {
|
||||
QtConfig::SaveAllValues();
|
||||
}
|
||||
}
|
||||
|
||||
void QtConfig::ReloadAllValues() {
|
||||
Reload();
|
||||
ReadQtValues();
|
||||
SaveQtValues();
|
||||
}
|
||||
|
||||
void QtConfig::SaveAllValues() {
|
||||
SaveValues();
|
||||
SaveQtValues();
|
||||
}
|
||||
|
||||
void QtConfig::ReadQtValues() {
|
||||
if (global) {
|
||||
ReadUIValues();
|
||||
}
|
||||
ReadQtControlValues();
|
||||
}
|
||||
|
||||
void QtConfig::ReadQtPlayerValues(const std::size_t player_index) {
|
||||
std::string player_prefix;
|
||||
if (type != ConfigType::InputProfile) {
|
||||
player_prefix.append("player_").append(ToString(player_index)).append("_");
|
||||
}
|
||||
|
||||
auto& player = Settings::values.players.GetValue()[player_index];
|
||||
if (IsCustomConfig()) {
|
||||
const auto profile_name =
|
||||
ReadStringSetting(std::string(player_prefix).append("profile_name"));
|
||||
if (profile_name.empty()) {
|
||||
// Use the global input config
|
||||
player = Settings::values.players.GetValue(true)[player_index];
|
||||
player.profile_name = "";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||
auto& player_buttons = player.buttons[i];
|
||||
|
||||
player_buttons = ReadStringSetting(
|
||||
std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param);
|
||||
if (player_buttons.empty()) {
|
||||
player_buttons = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||
auto& player_analogs = player.analogs[i];
|
||||
|
||||
player_analogs = ReadStringSetting(
|
||||
std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param);
|
||||
if (player_analogs.empty()) {
|
||||
player_analogs = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
|
||||
auto& player_motions = player.motions[i];
|
||||
|
||||
player_motions = ReadStringSetting(
|
||||
std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param);
|
||||
if (player_motions.empty()) {
|
||||
player_motions = default_param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QtConfig::ReadHidbusValues() {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
|
||||
auto& ringcon_analogs = Settings::values.ringcon_analogs;
|
||||
|
||||
ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param);
|
||||
if (ringcon_analogs.empty()) {
|
||||
ringcon_analogs = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
void QtConfig::ReadDebugControlValues() {
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||
auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i];
|
||||
|
||||
debug_pad_buttons = ReadStringSetting(
|
||||
std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param);
|
||||
if (debug_pad_buttons.empty()) {
|
||||
debug_pad_buttons = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||
auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i];
|
||||
|
||||
debug_pad_analogs = ReadStringSetting(
|
||||
std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param);
|
||||
if (debug_pad_analogs.empty()) {
|
||||
debug_pad_analogs = default_param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QtConfig::ReadQtControlValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||
|
||||
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||
ReadQtPlayerValues(p);
|
||||
}
|
||||
if (IsCustomConfig()) {
|
||||
EndGroup();
|
||||
return;
|
||||
}
|
||||
ReadDebugControlValues();
|
||||
ReadHidbusValues();
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::ReadPathValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Paths));
|
||||
|
||||
UISettings::values.roms_path = ReadStringSetting(std::string("romsPath"));
|
||||
UISettings::values.game_dir_deprecated =
|
||||
ReadStringSetting(std::string("gameListRootDir"), std::string("."));
|
||||
UISettings::values.game_dir_deprecated_deepscan =
|
||||
ReadBooleanSetting(std::string("gameListDeepScan"), std::make_optional(false));
|
||||
|
||||
const int gamedirs_size = BeginArray(std::string("gamedirs"));
|
||||
for (int i = 0; i < gamedirs_size; ++i) {
|
||||
SetArrayIndex(i);
|
||||
UISettings::GameDir game_dir;
|
||||
game_dir.path = ReadStringSetting(std::string("path"));
|
||||
game_dir.deep_scan =
|
||||
ReadBooleanSetting(std::string("deep_scan"), std::make_optional(false));
|
||||
game_dir.expanded = ReadBooleanSetting(std::string("expanded"), std::make_optional(true));
|
||||
UISettings::values.game_dirs.append(game_dir);
|
||||
}
|
||||
EndArray();
|
||||
|
||||
// Create NAND and SD card directories if empty, these are not removable through the UI,
|
||||
// also carries over old game list settings if present
|
||||
if (UISettings::values.game_dirs.empty()) {
|
||||
UISettings::GameDir game_dir;
|
||||
game_dir.path = std::string("SDMC");
|
||||
game_dir.expanded = true;
|
||||
UISettings::values.game_dirs.append(game_dir);
|
||||
game_dir.path = std::string("UserNAND");
|
||||
UISettings::values.game_dirs.append(game_dir);
|
||||
game_dir.path = std::string("SysNAND");
|
||||
UISettings::values.game_dirs.append(game_dir);
|
||||
if (UISettings::values.game_dir_deprecated != std::string(".")) {
|
||||
game_dir.path = UISettings::values.game_dir_deprecated;
|
||||
game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan;
|
||||
UISettings::values.game_dirs.append(game_dir);
|
||||
}
|
||||
}
|
||||
UISettings::values.recent_files =
|
||||
QString::fromStdString(ReadStringSetting(std::string("recentFiles")))
|
||||
.split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive);
|
||||
|
||||
ReadCategory(Settings::Category::Paths);
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::ReadShortcutValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts));
|
||||
|
||||
for (const auto& [name, group, shortcut] : UISettings::default_hotkeys) {
|
||||
BeginGroup(group);
|
||||
BeginGroup(name);
|
||||
|
||||
// No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1
|
||||
// for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open
|
||||
// a file dialog in windowed mode
|
||||
UISettings::values.shortcuts.push_back(
|
||||
{name,
|
||||
group,
|
||||
{ReadStringSetting(std::string("KeySeq"), shortcut.keyseq),
|
||||
ReadStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq),
|
||||
shortcut.context,
|
||||
ReadBooleanSetting(std::string("Repeat"), std::optional(shortcut.repeat))}});
|
||||
|
||||
EndGroup(); // name
|
||||
EndGroup(); // group
|
||||
}
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::ReadUIValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Ui));
|
||||
|
||||
UISettings::values.theme = ReadStringSetting(
|
||||
std::string("theme"),
|
||||
std::string(UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second));
|
||||
|
||||
ReadUIGamelistValues();
|
||||
ReadUILayoutValues();
|
||||
ReadPathValues();
|
||||
ReadScreenshotValues();
|
||||
ReadShortcutValues();
|
||||
ReadMultiplayerValues();
|
||||
|
||||
ReadCategory(Settings::Category::Ui);
|
||||
ReadCategory(Settings::Category::UiGeneral);
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::ReadUIGamelistValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
|
||||
|
||||
ReadCategory(Settings::Category::UiGameList);
|
||||
|
||||
// const int favorites_size = BeginArray("favorites");
|
||||
// for (int i = 0; i < favorites_size; i++) {
|
||||
// SetArrayIndex(i);
|
||||
// UISettings::values.favorited_ids.append(
|
||||
// ReadUnsignedIntegerSetting(std::string("program_id")));
|
||||
// }
|
||||
// EndArray();
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::ReadUILayoutValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
|
||||
|
||||
ReadCategory(Settings::Category::UiLayout);
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::ReadMultiplayerValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Multiplayer));
|
||||
|
||||
ReadCategory(Settings::Category::Multiplayer);
|
||||
|
||||
// Read ban list back
|
||||
int size = BeginArray(std::string("username_ban_list"));
|
||||
UISettings::values.multiplayer_ban_list.first.resize(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
SetArrayIndex(i);
|
||||
UISettings::values.multiplayer_ban_list.first[i] =
|
||||
ReadStringSetting(std::string("username"), std::string(""));
|
||||
}
|
||||
EndArray();
|
||||
|
||||
size = BeginArray(std::string("ip_ban_list"));
|
||||
UISettings::values.multiplayer_ban_list.second.resize(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
UISettings::values.multiplayer_ban_list.second[i] =
|
||||
ReadStringSetting("username", std::string(""));
|
||||
}
|
||||
EndArray();
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::SaveQtValues()
|
||||
{
|
||||
if (global) {
|
||||
LOG_DEBUG(Config, "Saving global Qt configuration values");
|
||||
SaveUIValues();
|
||||
} else {
|
||||
LOG_DEBUG(Config, "Saving Qt configuration values");
|
||||
}
|
||||
SaveQtControlValues();
|
||||
|
||||
WriteToIni();
|
||||
}
|
||||
|
||||
void QtConfig::SaveQtPlayerValues(const std::size_t player_index) {
|
||||
std::string player_prefix;
|
||||
if (type != ConfigType::InputProfile) {
|
||||
player_prefix = std::string("player_").append(ToString(player_index)).append("_");
|
||||
}
|
||||
|
||||
const auto& player = Settings::values.players.GetValue()[player_index];
|
||||
if (IsCustomConfig() && player.profile_name.empty()) {
|
||||
// No custom profile selected
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||
WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]),
|
||||
player.buttons[i], std::make_optional(default_param));
|
||||
}
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||
WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]),
|
||||
player.analogs[i], std::make_optional(default_param));
|
||||
}
|
||||
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
|
||||
WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]),
|
||||
player.motions[i], std::make_optional(default_param));
|
||||
}
|
||||
}
|
||||
|
||||
void QtConfig::SaveDebugControlValues() {
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||
WriteStringSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]),
|
||||
Settings::values.debug_pad_buttons[i],
|
||||
std::make_optional(default_param));
|
||||
}
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||
WriteStringSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]),
|
||||
Settings::values.debug_pad_analogs[i],
|
||||
std::make_optional(default_param));
|
||||
}
|
||||
}
|
||||
|
||||
void QtConfig::SaveHidbusValues() {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
|
||||
WriteStringSetting(std::string("ring_controller"), Settings::values.ringcon_analogs,
|
||||
std::make_optional(default_param));
|
||||
}
|
||||
|
||||
void QtConfig::SaveQtControlValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||
|
||||
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||
SaveQtPlayerValues(p);
|
||||
}
|
||||
if (IsCustomConfig()) {
|
||||
EndGroup();
|
||||
return;
|
||||
}
|
||||
SaveDebugControlValues();
|
||||
SaveHidbusValues();
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::SavePathValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Paths));
|
||||
|
||||
WriteCategory(Settings::Category::Paths);
|
||||
|
||||
WriteStringSetting(std::string("romsPath"), UISettings::values.roms_path);
|
||||
BeginArray(std::string("gamedirs"));
|
||||
for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) {
|
||||
SetArrayIndex(i);
|
||||
const auto& game_dir = UISettings::values.game_dirs[i];
|
||||
WriteStringSetting(std::string("path"), game_dir.path);
|
||||
WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan,
|
||||
std::make_optional(false));
|
||||
WriteBooleanSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true));
|
||||
}
|
||||
EndArray();
|
||||
|
||||
WriteStringSetting(std::string("recentFiles"),
|
||||
UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString());
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::SaveShortcutValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts));
|
||||
|
||||
// Lengths of UISettings::values.shortcuts & default_hotkeys are same.
|
||||
// However, their ordering must also be the same.
|
||||
for (std::size_t i = 0; i < UISettings::default_hotkeys.size(); i++) {
|
||||
const auto& [name, group, shortcut] = UISettings::values.shortcuts[i];
|
||||
const auto& default_hotkey = UISettings::default_hotkeys[i].shortcut;
|
||||
|
||||
BeginGroup(group);
|
||||
BeginGroup(name);
|
||||
|
||||
WriteStringSetting(std::string("KeySeq"), shortcut.keyseq,
|
||||
std::make_optional(default_hotkey.keyseq));
|
||||
WriteStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq,
|
||||
std::make_optional(default_hotkey.controller_keyseq));
|
||||
WriteIntegerSetting(std::string("Context"), shortcut.context,
|
||||
std::make_optional(default_hotkey.context));
|
||||
WriteBooleanSetting(std::string("Repeat"), shortcut.repeat,
|
||||
std::make_optional(default_hotkey.repeat));
|
||||
|
||||
EndGroup(); // name
|
||||
EndGroup(); // group
|
||||
}
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::SaveUIValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Ui));
|
||||
|
||||
WriteCategory(Settings::Category::Ui);
|
||||
WriteCategory(Settings::Category::UiGeneral);
|
||||
|
||||
WriteStringSetting(
|
||||
std::string("theme"), UISettings::values.theme,
|
||||
std::make_optional(std::string(
|
||||
UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second)));
|
||||
|
||||
SaveUIGamelistValues();
|
||||
SaveUILayoutValues();
|
||||
SavePathValues();
|
||||
SaveScreenshotValues();
|
||||
SaveShortcutValues();
|
||||
SaveMultiplayerValues();
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::SaveUIGamelistValues()
|
||||
{
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
|
||||
|
||||
WriteCategory(Settings::Category::UiGameList);
|
||||
|
||||
// BeginArray(std::string("favorites"));
|
||||
// for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
|
||||
// SetArrayIndex(i);
|
||||
// WriteIntegerSetting(std::string("program_id"), UISettings::values.favorited_ids[i]);
|
||||
// }
|
||||
// EndArray(); // favorites
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::SaveUILayoutValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::UiLayout));
|
||||
|
||||
WriteCategory(Settings::Category::UiLayout);
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::SaveMultiplayerValues() {
|
||||
BeginGroup(std::string("Multiplayer"));
|
||||
|
||||
WriteCategory(Settings::Category::Multiplayer);
|
||||
|
||||
// Write ban list
|
||||
BeginArray(std::string("username_ban_list"));
|
||||
for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) {
|
||||
SetArrayIndex(static_cast<int>(i));
|
||||
WriteStringSetting(std::string("username"),
|
||||
UISettings::values.multiplayer_ban_list.first[i]);
|
||||
}
|
||||
EndArray(); // username_ban_list
|
||||
|
||||
BeginArray(std::string("ip_ban_list"));
|
||||
for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) {
|
||||
SetArrayIndex(static_cast<int>(i));
|
||||
WriteStringSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]);
|
||||
}
|
||||
EndArray(); // ip_ban_list
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
std::vector<Settings::BasicSetting*>& QtConfig::FindRelevantList(Settings::Category category) {
|
||||
auto& map = Settings::values.linkage.by_category;
|
||||
if (!map[category].empty()) {
|
||||
return map[category];
|
||||
}
|
||||
return UISettings::values.linkage.by_category[category];
|
||||
}
|
||||
|
||||
void QtConfig::ReadQtControlPlayerValues(std::size_t player_index) {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||
|
||||
ReadPlayerValues(player_index);
|
||||
ReadQtPlayerValues(player_index);
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void QtConfig::SaveQtControlPlayerValues(std::size_t player_index) {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||
|
||||
LOG_DEBUG(Config, "Saving players control configuration values");
|
||||
SavePlayerValues(player_index);
|
||||
SaveQtPlayerValues(player_index);
|
||||
|
||||
EndGroup();
|
||||
|
||||
WriteToIni();
|
||||
}
|
55
src/eden/interface/qt_config.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QMetaType>
|
||||
|
||||
#include "frontend_common/config.h"
|
||||
|
||||
class QtConfig final : public Config {
|
||||
public:
|
||||
explicit QtConfig(const std::string& config_name = "qt-config",
|
||||
ConfigType config_type = ConfigType::GlobalConfig);
|
||||
~QtConfig() override;
|
||||
|
||||
void ReloadAllValues() override;
|
||||
void SaveAllValues() override;
|
||||
|
||||
void ReadQtControlPlayerValues(std::size_t player_index);
|
||||
void SaveQtControlPlayerValues(std::size_t player_index);
|
||||
|
||||
protected:
|
||||
void ReadQtValues();
|
||||
void ReadQtPlayerValues(std::size_t player_index);
|
||||
void ReadQtControlValues();
|
||||
void ReadHidbusValues() override;
|
||||
void ReadDebugControlValues() override;
|
||||
void ReadPathValues() override;
|
||||
void ReadShortcutValues() override;
|
||||
void ReadUIValues() override;
|
||||
void ReadUIGamelistValues() override;
|
||||
void ReadUILayoutValues() override;
|
||||
void ReadMultiplayerValues() override;
|
||||
|
||||
void SaveQtValues();
|
||||
void SaveQtPlayerValues(std::size_t player_index);
|
||||
void SaveQtControlValues();
|
||||
void SaveHidbusValues() override;
|
||||
void SaveDebugControlValues() override;
|
||||
void SavePathValues() override;
|
||||
void SaveShortcutValues() override;
|
||||
void SaveUIValues() override;
|
||||
void SaveUIGamelistValues() override;
|
||||
void SaveUILayoutValues() override;
|
||||
void SaveMultiplayerValues() override;
|
||||
|
||||
std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;
|
||||
|
||||
public:
|
||||
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
|
||||
static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
|
||||
static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
|
||||
static const std::array<int, 2> default_stick_mod;
|
||||
static const std::array<int, 2> default_ringcon_analogs;
|
||||
};
|
692
src/eden/interface/shared_translation.cpp
Normal file
|
@ -0,0 +1,692 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "eden/interface/shared_translation.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "common/settings_setting.h"
|
||||
#include "common/time_zone.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace ConfigurationShared {
|
||||
|
||||
std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
||||
{
|
||||
std::unique_ptr<TranslationMap> translations = std::make_unique<TranslationMap>();
|
||||
const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); };
|
||||
|
||||
#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \
|
||||
translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}})
|
||||
|
||||
// A setting can be ignored by giving it a blank name
|
||||
|
||||
// Applets
|
||||
INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString());
|
||||
INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString());
|
||||
INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString());
|
||||
INSERT(Settings, error_applet_mode, tr("Error"), QString());
|
||||
INSERT(Settings, net_connect_applet_mode, tr("Net connect"), QString());
|
||||
INSERT(Settings, player_select_applet_mode, tr("Player select"), QString());
|
||||
INSERT(Settings, swkbd_applet_mode, tr("Software keyboard"), QString());
|
||||
INSERT(Settings, mii_edit_applet_mode, tr("Mii Edit"), QString());
|
||||
INSERT(Settings, web_applet_mode, tr("Online web"), QString());
|
||||
INSERT(Settings, shop_applet_mode, tr("Shop"), QString());
|
||||
INSERT(Settings, photo_viewer_applet_mode, tr("Photo viewer"), QString());
|
||||
INSERT(Settings, offline_web_applet_mode, tr("Offline web"), QString());
|
||||
INSERT(Settings, login_share_applet_mode, tr("Login share"), QString());
|
||||
INSERT(Settings, wifi_web_auth_applet_mode, tr("Wifi web auth"), QString());
|
||||
INSERT(Settings, my_page_applet_mode, tr("My page"), QString());
|
||||
|
||||
// Audio
|
||||
INSERT(Settings, sink_id, tr("Output Engine:"), QString());
|
||||
INSERT(Settings, audio_output_device_id, tr("Output Device:"), QString());
|
||||
INSERT(Settings, audio_input_device_id, tr("Input Device:"), QString());
|
||||
INSERT(Settings, audio_muted, tr("Mute audio"), QString());
|
||||
INSERT(Settings, volume, tr("Volume:"), QString());
|
||||
INSERT(Settings, dump_audio_commands, QString(), QString());
|
||||
INSERT(UISettings, mute_when_in_background, tr("Mute audio when in background"), QString());
|
||||
|
||||
// Core
|
||||
INSERT(
|
||||
Settings,
|
||||
use_multi_core,
|
||||
tr("Multicore CPU Emulation"),
|
||||
tr("This option increases CPU emulation thread use from 1 to the Switch’s maximum of 4.\n"
|
||||
"This is mainly a debug option and shouldn’t be disabled."));
|
||||
INSERT(
|
||||
Settings,
|
||||
memory_layout_mode,
|
||||
tr("Memory Layout"),
|
||||
tr("Increases the amount of emulated RAM from the stock 4GB of the retail Switch to the "
|
||||
"developer kit's 8/6GB.\nIt’s doesn’t improve stability or performance and is intended "
|
||||
"to let big texture mods fit in emulated RAM.\nEnabling it will increase memory "
|
||||
"use. It is not recommended to enable unless a specific game with a texture mod needs "
|
||||
"it."));
|
||||
INSERT(Settings, use_speed_limit, QString(), QString());
|
||||
INSERT(Settings,
|
||||
speed_limit,
|
||||
tr("Limit Speed Percent"),
|
||||
tr("Controls the game's maximum rendering speed, but it’s up to each game if it runs "
|
||||
"faster or not.\n200% for a 30 FPS game is 60 FPS, and for a "
|
||||
"60 FPS game it will be 120 FPS.\nDisabling it means unlocking the framerate to the "
|
||||
"maximum your PC can reach."));
|
||||
INSERT(Settings,
|
||||
sync_core_speed,
|
||||
tr("Synchronize Core Speed"),
|
||||
tr("Synchronizes CPU core speed with the game's maximum rendering speed to boost FPS "
|
||||
"without affecting game speed (animations, physics, etc.).\n"
|
||||
"Compatibility varies by game; many (especially older ones) may not respond well.\n"
|
||||
"Can help reduce stuttering at lower framerates."));
|
||||
|
||||
// Cpu
|
||||
INSERT(Settings,
|
||||
cpu_accuracy,
|
||||
tr("Accuracy:"),
|
||||
tr("This setting controls the accuracy of the emulated CPU.\nDon't change this unless "
|
||||
"you know what you are doing."));
|
||||
INSERT(Settings, cpu_backend, tr("Backend:"), QString());
|
||||
|
||||
INSERT(Settings, use_fast_cpu_time, QString(), QString());
|
||||
INSERT(Settings,
|
||||
fast_cpu_time,
|
||||
tr("Fast CPU Time"),
|
||||
tr("Overclocks the emulated CPU to remove some FPS limiters. Weaker CPUs may see reduced performance, "
|
||||
"and certain games may behave improperly.\nUse Boost (1700MHz) to run at the Switch's highest native "
|
||||
"clock, or Fast (2000MHz) to run at 2x clock."));
|
||||
INSERT(Settings, cpu_backend, tr("Backend:"), QString());
|
||||
|
||||
// Cpu Debug
|
||||
|
||||
// Cpu Unsafe
|
||||
INSERT(
|
||||
Settings,
|
||||
cpuopt_unsafe_unfuse_fma,
|
||||
tr("Unfuse FMA (improve performance on CPUs without FMA)"),
|
||||
tr("This option improves speed by reducing accuracy of fused-multiply-add instructions on "
|
||||
"CPUs without native FMA support."));
|
||||
INSERT(
|
||||
Settings,
|
||||
cpuopt_unsafe_reduce_fp_error,
|
||||
tr("Faster FRSQRTE and FRECPE"),
|
||||
tr("This option improves the speed of some approximate floating-point functions by using "
|
||||
"less accurate native approximations."));
|
||||
INSERT(Settings,
|
||||
cpuopt_unsafe_ignore_standard_fpcr,
|
||||
tr("Faster ASIMD instructions (32 bits only)"),
|
||||
tr("This option improves the speed of 32 bits ASIMD floating-point functions by running "
|
||||
"with incorrect rounding modes."));
|
||||
INSERT(Settings,
|
||||
cpuopt_unsafe_inaccurate_nan,
|
||||
tr("Inaccurate NaN handling"),
|
||||
tr("This option improves speed by removing NaN checking.\nPlease note this also reduces "
|
||||
"accuracy of certain floating-point instructions."));
|
||||
INSERT(Settings,
|
||||
cpuopt_unsafe_fastmem_check,
|
||||
tr("Disable address space checks"),
|
||||
tr("This option improves speed by eliminating a safety check before every memory "
|
||||
"read/write in guest.\nDisabling it may allow a game to read/write the emulator's "
|
||||
"memory."));
|
||||
INSERT(
|
||||
Settings,
|
||||
cpuopt_unsafe_ignore_global_monitor,
|
||||
tr("Ignore global monitor"),
|
||||
tr("This option improves speed by relying only on the semantics of cmpxchg to ensure "
|
||||
"safety of exclusive access instructions.\nPlease note this may result in deadlocks and "
|
||||
"other race conditions."));
|
||||
|
||||
// Renderer
|
||||
INSERT(
|
||||
Settings,
|
||||
renderer_backend,
|
||||
tr("API:"),
|
||||
tr("Switches between the available graphics APIs.\nVulkan is recommended in most cases."));
|
||||
INSERT(Settings,
|
||||
vulkan_device,
|
||||
tr("Device:"),
|
||||
tr("This setting selects the GPU to use with the Vulkan backend."));
|
||||
INSERT(Settings,
|
||||
shader_backend,
|
||||
tr("Shader Backend:"),
|
||||
tr("The shader backend to use for the OpenGL renderer.\nGLSL is the fastest in "
|
||||
"performance and the best in rendering accuracy.\n"
|
||||
"GLASM is a deprecated NVIDIA-only backend that offers much better shader building "
|
||||
"performance at the cost of FPS and rendering accuracy.\n"
|
||||
"SPIR-V compiles the fastest, but yields poor results on most GPU drivers."));
|
||||
INSERT(Settings,
|
||||
resolution_setup,
|
||||
tr("Resolution:"),
|
||||
tr("Forces the game to render at a different resolution.\nHigher resolutions require "
|
||||
"much more VRAM and bandwidth.\n"
|
||||
"Options lower than 1X can cause rendering issues."));
|
||||
INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QString());
|
||||
INSERT(Settings,
|
||||
fsr_sharpening_slider,
|
||||
tr("FSR Sharpness:"),
|
||||
tr("Determines how sharpened the image will look while using FSR’s dynamic contrast."));
|
||||
INSERT(Settings,
|
||||
anti_aliasing,
|
||||
tr("Anti-Aliasing Method:"),
|
||||
tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA has a "
|
||||
"lower performance impact and can produce a better and more stable picture under "
|
||||
"very low resolutions."));
|
||||
INSERT(Settings,
|
||||
fullscreen_mode,
|
||||
tr("Fullscreen Mode:"),
|
||||
tr("The method used to render the window in fullscreen.\nBorderless offers the best "
|
||||
"compatibility with the on-screen keyboard that some games request for "
|
||||
"input.\nExclusive "
|
||||
"fullscreen may offer better performance and better Freesync/Gsync support."));
|
||||
INSERT(Settings,
|
||||
aspect_ratio,
|
||||
tr("Aspect Ratio:"),
|
||||
tr("Stretches the game to fit the specified aspect ratio.\nSwitch games only support "
|
||||
"16:9, so custom game mods are required to get other ratios.\nAlso controls the "
|
||||
"aspect ratio of captured screenshots."));
|
||||
INSERT(Settings,
|
||||
use_disk_shader_cache,
|
||||
tr("Use disk pipeline cache"),
|
||||
tr("Allows saving shaders to storage for faster loading on following game "
|
||||
"boots.\nDisabling "
|
||||
"it is only intended for debugging."));
|
||||
INSERT(Settings,
|
||||
optimize_spirv_output,
|
||||
tr("Optimize SPIRV output shader"),
|
||||
tr("Runs an additional optimization pass over generated SPIRV shaders.\n"
|
||||
"Will increase time required for shader compilation.\nMay slightly improve "
|
||||
"performance.\nThis feature is experimental."));
|
||||
INSERT(
|
||||
Settings,
|
||||
use_asynchronous_gpu_emulation,
|
||||
tr("Use asynchronous GPU emulation"),
|
||||
tr("Uses an extra CPU thread for rendering.\nThis option should always remain enabled."));
|
||||
INSERT(Settings,
|
||||
nvdec_emulation,
|
||||
tr("NVDEC emulation:"),
|
||||
tr("Specifies how videos should be decoded.\nIt can either use the CPU or the GPU for "
|
||||
"decoding, or perform no decoding at all (black screen on videos).\n"
|
||||
"In most cases, GPU decoding provides the best performance."));
|
||||
INSERT(Settings,
|
||||
accelerate_astc,
|
||||
tr("ASTC Decoding Method:"),
|
||||
tr("This option controls how ASTC textures should be decoded.\n"
|
||||
"CPU: Use the CPU for decoding, slowest but safest method.\n"
|
||||
"GPU: Use the GPU's compute shaders to decode ASTC textures, recommended for most "
|
||||
"games and users.\n"
|
||||
"CPU Asynchronously: Use the CPU to decode ASTC textures as they arrive. Completely "
|
||||
"eliminates ASTC decoding\nstuttering at the cost of rendering issues while the "
|
||||
"texture is being decoded."));
|
||||
INSERT(
|
||||
Settings,
|
||||
astc_recompression,
|
||||
tr("ASTC Recompression Method:"),
|
||||
tr("Almost all desktop and laptop dedicated GPUs lack support for ASTC textures, forcing "
|
||||
"the emulator to decompress to an intermediate format any card supports, RGBA8.\n"
|
||||
"This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but "
|
||||
"negatively affecting image quality."));
|
||||
INSERT(Settings,
|
||||
vram_usage_mode,
|
||||
tr("VRAM Usage Mode:"),
|
||||
tr("Selects whether the emulator should prefer to conserve memory or make maximum usage "
|
||||
"of available video memory for performance. Has no effect on integrated graphics. "
|
||||
"Aggressive mode may severely impact the performance of other applications such as "
|
||||
"recording software."));
|
||||
INSERT(
|
||||
Settings,
|
||||
vsync_mode,
|
||||
tr("VSync Mode:"),
|
||||
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
||||
"refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from "
|
||||
"a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop "
|
||||
"frames.\nImmediate (no synchronization) just presents whatever is available and can "
|
||||
"exhibit tearing."));
|
||||
INSERT(Settings, bg_red, QString(), QString());
|
||||
INSERT(Settings, bg_green, QString(), QString());
|
||||
INSERT(Settings, bg_blue, QString(), QString());
|
||||
|
||||
// Renderer (Advanced Graphics)
|
||||
INSERT(Settings,
|
||||
async_presentation,
|
||||
tr("Enable asynchronous presentation (Vulkan only)"),
|
||||
tr("Slightly improves performance by moving presentation to a separate CPU thread."));
|
||||
INSERT(
|
||||
Settings,
|
||||
renderer_force_max_clock,
|
||||
tr("Force maximum clocks (Vulkan only)"),
|
||||
tr("Runs work in the background while waiting for graphics commands to keep the GPU from "
|
||||
"lowering its clock speed."));
|
||||
INSERT(Settings,
|
||||
max_anisotropy,
|
||||
tr("Anisotropic Filtering:"),
|
||||
tr("Controls the quality of texture rendering at oblique angles.\nIt’s a light setting "
|
||||
"and safe to set at 16x on most GPUs."));
|
||||
INSERT(Settings,
|
||||
gpu_accuracy,
|
||||
tr("Accuracy Level:"),
|
||||
tr("GPU emulation accuracy.\nMost games render fine with Normal, but High is still "
|
||||
"required for some.\nParticles tend to only render correctly with High "
|
||||
"accuracy.\nExtreme should only be used for debugging.\nThis option can "
|
||||
"be changed while playing.\nSome games may require booting on high to render "
|
||||
"properly."));
|
||||
INSERT(Settings,
|
||||
use_asynchronous_shaders,
|
||||
tr("Use asynchronous shader building (Hack)"),
|
||||
tr("Enables asynchronous shader compilation, which may reduce shader stutter.\nThis "
|
||||
"feature "
|
||||
"is experimental."));
|
||||
INSERT(Settings, use_fast_gpu_time, QString(), QString());
|
||||
INSERT(Settings,
|
||||
fast_gpu_time,
|
||||
tr("Fast GPU Time (Hack)"),
|
||||
tr("Overclocks the emulated GPU to increase dynamic resolution and render "
|
||||
"distance.\nUse 128 for maximal performance and 512 for maximal graphics fidelity."));
|
||||
|
||||
INSERT(Settings,
|
||||
use_vulkan_driver_pipeline_cache,
|
||||
tr("Use Vulkan pipeline cache"),
|
||||
tr("Enables GPU vendor-specific pipeline cache.\nThis option can improve shader loading "
|
||||
"time significantly in cases where the Vulkan driver does not store pipeline cache "
|
||||
"files internally."));
|
||||
INSERT(
|
||||
Settings,
|
||||
enable_compute_pipelines,
|
||||
tr("Enable Compute Pipelines (Intel Vulkan Only)"),
|
||||
tr("Enable compute pipelines, required by some games.\nThis setting only exists for Intel "
|
||||
"proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled "
|
||||
"on all other drivers."));
|
||||
INSERT(
|
||||
Settings,
|
||||
use_reactive_flushing,
|
||||
tr("Enable Reactive Flushing"),
|
||||
tr("Uses reactive flushing instead of predictive flushing, allowing more accurate memory "
|
||||
"syncing."));
|
||||
INSERT(Settings,
|
||||
use_video_framerate,
|
||||
tr("Sync to framerate of video playback"),
|
||||
tr("Run the game at normal speed during video playback, even when the framerate is "
|
||||
"unlocked."));
|
||||
INSERT(Settings,
|
||||
barrier_feedback_loops,
|
||||
tr("Barrier feedback loops"),
|
||||
tr("Improves rendering of transparency effects in specific games."));
|
||||
|
||||
// Renderer (Extensions)
|
||||
INSERT(Settings,
|
||||
dyna_state,
|
||||
tr("Extended Dynamic State"),
|
||||
tr("Enables the VkExtendedDynamicState* extensions.\nHigher dynamic states will "
|
||||
"generally improve "
|
||||
"performance, but may cause issues on certain games or devices."));
|
||||
|
||||
INSERT(Settings,
|
||||
provoking_vertex,
|
||||
tr("Provoking Vertex"),
|
||||
tr("Improves lighting and vertex handling in certain games.\n"
|
||||
"Only Vulkan 1.0+ devices support this extension."));
|
||||
|
||||
INSERT(Settings,
|
||||
descriptor_indexing,
|
||||
tr("Descriptor Indexing"),
|
||||
tr("Improves texture & buffer handling and the Maxwell translation layer.\n"
|
||||
"Some Vulkan 1.1+ and all 1.2+ devices support this extension."));
|
||||
|
||||
// Renderer (Debug)
|
||||
|
||||
// System
|
||||
INSERT(Settings,
|
||||
rng_seed,
|
||||
tr("RNG Seed"),
|
||||
tr("Controls the seed of the random number generator.\nMainly used for speedrunning "
|
||||
"purposes."));
|
||||
INSERT(Settings, rng_seed_enabled, QString(), QString());
|
||||
INSERT(Settings, device_name, tr("Device Name"), tr("The name of the emulated Switch."));
|
||||
INSERT(Settings,
|
||||
custom_rtc,
|
||||
tr("Custom RTC Date:"),
|
||||
tr("This option allows to change the emulated clock of the Switch.\n"
|
||||
"Can be used to manipulate time in games."));
|
||||
INSERT(Settings, custom_rtc_enabled, QString(), QString());
|
||||
INSERT(Settings,
|
||||
custom_rtc_offset,
|
||||
QStringLiteral(" "),
|
||||
QStringLiteral("The number of seconds from the current unix time"));
|
||||
INSERT(Settings,
|
||||
language_index,
|
||||
tr("Language:"),
|
||||
tr("Note: this can be overridden when region setting is auto-select"));
|
||||
INSERT(Settings, region_index, tr("Region:"), tr("The region of the emulated Switch."));
|
||||
INSERT(Settings, time_zone_index, tr("Time Zone:"), tr("The time zone of the emulated Switch."));
|
||||
INSERT(Settings, sound_index, tr("Sound Output Mode:"), QString());
|
||||
INSERT(Settings,
|
||||
use_docked_mode,
|
||||
tr("Console Mode:"),
|
||||
tr("Selects if the console is emulated in Docked or Handheld mode.\nGames will change "
|
||||
"their resolution, details and supported controllers and depending on this setting.\n"
|
||||
"Setting to Handheld can help improve performance for low end systems."));
|
||||
INSERT(Settings, current_user, QString(), QString());
|
||||
|
||||
// Controls
|
||||
|
||||
// Data Storage
|
||||
|
||||
// Debugging
|
||||
|
||||
// Debugging Graphics
|
||||
|
||||
// Network
|
||||
|
||||
// Web Service
|
||||
|
||||
// Ui
|
||||
|
||||
// Ui General
|
||||
INSERT(UISettings,
|
||||
select_user_on_boot,
|
||||
tr("Prompt for user on game boot"),
|
||||
tr("Ask to select a user profile on each boot, useful if multiple people use eden on "
|
||||
"the same PC."));
|
||||
INSERT(UISettings,
|
||||
pause_when_in_background,
|
||||
tr("Pause emulation when in background"),
|
||||
tr("This setting pauses eden when focusing other windows."));
|
||||
INSERT(UISettings,
|
||||
confirm_before_stopping,
|
||||
tr("Confirm before stopping emulation"),
|
||||
tr("This setting overrides game prompts asking to confirm stopping the game.\nEnabling "
|
||||
"it bypasses such prompts and directly exits the emulation."));
|
||||
INSERT(UISettings,
|
||||
hide_mouse,
|
||||
tr("Hide mouse on inactivity"),
|
||||
tr("This setting hides the mouse after 2.5s of inactivity."));
|
||||
INSERT(UISettings,
|
||||
controller_applet_disabled,
|
||||
tr("Disable controller applet"),
|
||||
tr("Forcibly disables the use of the controller applet by guests.\nWhen a guest "
|
||||
"attempts to open the controller applet, it is immediately closed."));
|
||||
INSERT(UISettings,
|
||||
check_for_updates,
|
||||
tr("Check for updates"),
|
||||
tr("Whether or not to check for updates upon startup."));
|
||||
|
||||
// Linux
|
||||
INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QString());
|
||||
|
||||
// Ui Debugging
|
||||
|
||||
// Ui Multiplayer
|
||||
|
||||
// Ui Games list
|
||||
|
||||
#undef INSERT
|
||||
|
||||
return translations;
|
||||
}
|
||||
|
||||
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
|
||||
{
|
||||
std::unique_ptr<ComboboxTranslationMap> translations = std::make_unique<ComboboxTranslationMap>();
|
||||
const auto& tr = [&](const char* text, const char* context = "") {
|
||||
return parent->tr(text, context);
|
||||
};
|
||||
|
||||
#define PAIR(ENUM, VALUE, TRANSLATION) {static_cast<u32>(Settings::ENUM::VALUE), (TRANSLATION)}
|
||||
|
||||
// Intentionally skipping VSyncMode to let the UI fill that one out
|
||||
translations->insert({Settings::EnumMetadata<Settings::AppletMode>::Index(),
|
||||
{
|
||||
PAIR(AppletMode, HLE, tr("Custom frontend")),
|
||||
PAIR(AppletMode, LLE, tr("Real applet")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::SpirvOptimizeMode>::Index(),
|
||||
{
|
||||
PAIR(SpirvOptimizeMode, Never, tr("Never")),
|
||||
PAIR(SpirvOptimizeMode, OnLoad, tr("On Load")),
|
||||
PAIR(SpirvOptimizeMode, Always, tr("Always")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(),
|
||||
{
|
||||
PAIR(AstcDecodeMode, Cpu, tr("CPU")),
|
||||
PAIR(AstcDecodeMode, Gpu, tr("GPU")),
|
||||
PAIR(AstcDecodeMode, CpuAsynchronous, tr("CPU Asynchronous")),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
|
||||
{
|
||||
PAIR(AstcRecompression, Uncompressed, tr("Uncompressed (Best quality)")),
|
||||
PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
|
||||
PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
|
||||
{
|
||||
PAIR(VramUsageMode, Conservative, tr("Conservative")),
|
||||
PAIR(VramUsageMode, Aggressive, tr("Aggressive")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
|
||||
{
|
||||
#ifdef HAS_OPENGL
|
||||
PAIR(RendererBackend, OpenGL, tr("OpenGL")),
|
||||
#endif
|
||||
PAIR(RendererBackend, Vulkan, tr("Vulkan")),
|
||||
PAIR(RendererBackend, Null, tr("Null")),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
|
||||
{
|
||||
PAIR(ShaderBackend, Glsl, tr("GLSL")),
|
||||
PAIR(ShaderBackend, Glasm, tr("GLASM (Assembly Shaders, NVIDIA Only)")),
|
||||
PAIR(ShaderBackend, SpirV, tr("SPIR-V (Experimental, AMD/Mesa Only)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(),
|
||||
{
|
||||
PAIR(GpuAccuracy, Normal, tr("Normal")),
|
||||
PAIR(GpuAccuracy, High, tr("High")),
|
||||
PAIR(GpuAccuracy, Extreme, tr("Extreme")),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
|
||||
{
|
||||
PAIR(CpuAccuracy, Auto, tr("Auto")),
|
||||
PAIR(CpuAccuracy, Accurate, tr("Accurate")),
|
||||
PAIR(CpuAccuracy, Unsafe, tr("Unsafe")),
|
||||
PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::CpuBackend>::Index(),
|
||||
{
|
||||
PAIR(CpuBackend, Dynarmic, tr("Dynarmic")),
|
||||
PAIR(CpuBackend, Nce, tr("NCE")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::FullscreenMode>::Index(),
|
||||
{
|
||||
PAIR(FullscreenMode, Borderless, tr("Borderless Windowed")),
|
||||
PAIR(FullscreenMode, Exclusive, tr("Exclusive Fullscreen")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::NvdecEmulation>::Index(),
|
||||
{
|
||||
PAIR(NvdecEmulation, Off, tr("No Video Output")),
|
||||
PAIR(NvdecEmulation, Cpu, tr("CPU Video Decoding")),
|
||||
PAIR(NvdecEmulation, Gpu, tr("GPU Video Decoding (Default)")),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::ResolutionSetup>::Index(),
|
||||
{
|
||||
PAIR(ResolutionSetup, Res1_4X, tr("0.25X (180p/270p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res1_2X, tr("0.5X (360p/540p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res3_4X, tr("0.75X (540p/810p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res1X, tr("1X (720p/1080p)")),
|
||||
PAIR(ResolutionSetup, Res3_2X, tr("1.5X (1080p/1620p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res2X, tr("2X (1440p/2160p)")),
|
||||
PAIR(ResolutionSetup, Res3X, tr("3X (2160p/3240p)")),
|
||||
PAIR(ResolutionSetup, Res4X, tr("4X (2880p/4320p)")),
|
||||
PAIR(ResolutionSetup, Res5X, tr("5X (3600p/5400p)")),
|
||||
PAIR(ResolutionSetup, Res6X, tr("6X (4320p/6480p)")),
|
||||
PAIR(ResolutionSetup, Res7X, tr("7X (5040p/7560p)")),
|
||||
PAIR(ResolutionSetup, Res8X, tr("8X (5760p/8640p)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::ScalingFilter>::Index(),
|
||||
{
|
||||
PAIR(ScalingFilter, NearestNeighbor, tr("Nearest Neighbor")),
|
||||
PAIR(ScalingFilter, Bilinear, tr("Bilinear")),
|
||||
PAIR(ScalingFilter, Bicubic, tr("Bicubic")),
|
||||
PAIR(ScalingFilter, Gaussian, tr("Gaussian")),
|
||||
PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")),
|
||||
PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(),
|
||||
{
|
||||
PAIR(AntiAliasing, None, tr("None")),
|
||||
PAIR(AntiAliasing, Fxaa, tr("FXAA")),
|
||||
PAIR(AntiAliasing, Smaa, tr("SMAA")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(),
|
||||
{
|
||||
PAIR(AspectRatio, R16_9, tr("Default (16:9)")),
|
||||
PAIR(AspectRatio, R4_3, tr("Force 4:3")),
|
||||
PAIR(AspectRatio, R21_9, tr("Force 21:9")),
|
||||
PAIR(AspectRatio, R16_10, tr("Force 16:10")),
|
||||
PAIR(AspectRatio, Stretch, tr("Stretch to Window")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AnisotropyMode>::Index(),
|
||||
{
|
||||
PAIR(AnisotropyMode, Automatic, tr("Automatic")),
|
||||
PAIR(AnisotropyMode, Default, tr("Default")),
|
||||
PAIR(AnisotropyMode, X2, tr("2x")),
|
||||
PAIR(AnisotropyMode, X4, tr("4x")),
|
||||
PAIR(AnisotropyMode, X8, tr("8x")),
|
||||
PAIR(AnisotropyMode, X16, tr("16x")),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::Language>::Index(),
|
||||
{
|
||||
PAIR(Language, Japanese, tr("Japanese (日本語)")),
|
||||
PAIR(Language, EnglishAmerican, tr("American English")),
|
||||
PAIR(Language, French, tr("French (français)")),
|
||||
PAIR(Language, German, tr("German (Deutsch)")),
|
||||
PAIR(Language, Italian, tr("Italian (italiano)")),
|
||||
PAIR(Language, Spanish, tr("Spanish (español)")),
|
||||
PAIR(Language, Chinese, tr("Chinese")),
|
||||
PAIR(Language, Korean, tr("Korean (한국어)")),
|
||||
PAIR(Language, Dutch, tr("Dutch (Nederlands)")),
|
||||
PAIR(Language, Portuguese, tr("Portuguese (português)")),
|
||||
PAIR(Language, Russian, tr("Russian (Русский)")),
|
||||
PAIR(Language, Taiwanese, tr("Taiwanese")),
|
||||
PAIR(Language, EnglishBritish, tr("British English")),
|
||||
PAIR(Language, FrenchCanadian, tr("Canadian French")),
|
||||
PAIR(Language, SpanishLatin, tr("Latin American Spanish")),
|
||||
PAIR(Language, ChineseSimplified, tr("Simplified Chinese")),
|
||||
PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")),
|
||||
PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::Region>::Index(),
|
||||
{
|
||||
PAIR(Region, Japan, tr("Japan")),
|
||||
PAIR(Region, Usa, tr("USA")),
|
||||
PAIR(Region, Europe, tr("Europe")),
|
||||
PAIR(Region, Australia, tr("Australia")),
|
||||
PAIR(Region, China, tr("China")),
|
||||
PAIR(Region, Korea, tr("Korea")),
|
||||
PAIR(Region, Taiwan, tr("Taiwan")),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::TimeZone>::Index(),
|
||||
{
|
||||
{static_cast<u32>(Settings::TimeZone::Auto),
|
||||
tr("Auto (%1)", "Auto select time zone")
|
||||
.arg(QString::fromStdString(
|
||||
Settings::GetTimeZoneString(Settings::TimeZone::Auto)))},
|
||||
{static_cast<u32>(Settings::TimeZone::Default),
|
||||
tr("Default (%1)", "Default time zone")
|
||||
.arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))},
|
||||
PAIR(TimeZone, Cet, tr("CET")),
|
||||
PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")),
|
||||
PAIR(TimeZone, Cuba, tr("Cuba")),
|
||||
PAIR(TimeZone, Eet, tr("EET")),
|
||||
PAIR(TimeZone, Egypt, tr("Egypt")),
|
||||
PAIR(TimeZone, Eire, tr("Eire")),
|
||||
PAIR(TimeZone, Est, tr("EST")),
|
||||
PAIR(TimeZone, Est5Edt, tr("EST5EDT")),
|
||||
PAIR(TimeZone, Gb, tr("GB")),
|
||||
PAIR(TimeZone, GbEire, tr("GB-Eire")),
|
||||
PAIR(TimeZone, Gmt, tr("GMT")),
|
||||
PAIR(TimeZone, GmtPlusZero, tr("GMT+0")),
|
||||
PAIR(TimeZone, GmtMinusZero, tr("GMT-0")),
|
||||
PAIR(TimeZone, GmtZero, tr("GMT0")),
|
||||
PAIR(TimeZone, Greenwich, tr("Greenwich")),
|
||||
PAIR(TimeZone, Hongkong, tr("Hongkong")),
|
||||
PAIR(TimeZone, Hst, tr("HST")),
|
||||
PAIR(TimeZone, Iceland, tr("Iceland")),
|
||||
PAIR(TimeZone, Iran, tr("Iran")),
|
||||
PAIR(TimeZone, Israel, tr("Israel")),
|
||||
PAIR(TimeZone, Jamaica, tr("Jamaica")),
|
||||
PAIR(TimeZone, Japan, tr("Japan")),
|
||||
PAIR(TimeZone, Kwajalein, tr("Kwajalein")),
|
||||
PAIR(TimeZone, Libya, tr("Libya")),
|
||||
PAIR(TimeZone, Met, tr("MET")),
|
||||
PAIR(TimeZone, Mst, tr("MST")),
|
||||
PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")),
|
||||
PAIR(TimeZone, Navajo, tr("Navajo")),
|
||||
PAIR(TimeZone, Nz, tr("NZ")),
|
||||
PAIR(TimeZone, NzChat, tr("NZ-CHAT")),
|
||||
PAIR(TimeZone, Poland, tr("Poland")),
|
||||
PAIR(TimeZone, Portugal, tr("Portugal")),
|
||||
PAIR(TimeZone, Prc, tr("PRC")),
|
||||
PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")),
|
||||
PAIR(TimeZone, Roc, tr("ROC")),
|
||||
PAIR(TimeZone, Rok, tr("ROK")),
|
||||
PAIR(TimeZone, Singapore, tr("Singapore")),
|
||||
PAIR(TimeZone, Turkey, tr("Turkey")),
|
||||
PAIR(TimeZone, Uct, tr("UCT")),
|
||||
PAIR(TimeZone, Universal, tr("Universal")),
|
||||
PAIR(TimeZone, Utc, tr("UTC")),
|
||||
PAIR(TimeZone, WSu, tr("W-SU")),
|
||||
PAIR(TimeZone, Wet, tr("WET")),
|
||||
PAIR(TimeZone, Zulu, tr("Zulu")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AudioMode>::Index(),
|
||||
{
|
||||
PAIR(AudioMode, Mono, tr("Mono")),
|
||||
PAIR(AudioMode, Stereo, tr("Stereo")),
|
||||
PAIR(AudioMode, Surround, tr("Surround")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(),
|
||||
{
|
||||
PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")),
|
||||
PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")),
|
||||
PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM")),
|
||||
PAIR(MemoryLayout, Memory_10Gb, tr("10GB DRAM (Unsafe)")),
|
||||
PAIR(MemoryLayout, Memory_12Gb, tr("12GB DRAM (Unsafe)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
|
||||
{
|
||||
PAIR(ConsoleMode, Docked, tr("Docked")),
|
||||
PAIR(ConsoleMode, Handheld, tr("Handheld")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::CpuClock>::Index(),
|
||||
{
|
||||
PAIR(CpuClock, Boost, tr("Boost (1700MHz)")),
|
||||
PAIR(CpuClock, Fast, tr("Fast (2000MHz)")),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::ConfirmStop>::Index(),
|
||||
{
|
||||
PAIR(ConfirmStop, Ask_Always, tr("Always ask (Default)")),
|
||||
PAIR(ConfirmStop, Ask_Based_On_Game, tr("Only if game specifies not to stop")),
|
||||
PAIR(ConfirmStop, Ask_Never, tr("Never ask")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::GpuOverclock>::Index(),
|
||||
{
|
||||
PAIR(GpuOverclock, Low, tr("Low (128)")),
|
||||
PAIR(GpuOverclock, Medium, tr("Medium (256)")),
|
||||
PAIR(GpuOverclock, High, tr("High (512)")),
|
||||
}});
|
||||
|
||||
#undef PAIR
|
||||
#undef CTX_PAIR
|
||||
|
||||
return translations;
|
||||
}
|
||||
} // namespace ConfigurationShared
|
65
src/eden/interface/shared_translation.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
namespace ConfigurationShared {
|
||||
using TranslationMap = std::map<u32, std::pair<QString, QString>>;
|
||||
using ComboboxTranslations = std::vector<std::pair<u32, QString>>;
|
||||
using ComboboxTranslationMap = std::map<u32, ComboboxTranslations>;
|
||||
|
||||
std::unique_ptr<TranslationMap> InitializeTranslations(QObject *parent);
|
||||
|
||||
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject *parent);
|
||||
|
||||
static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map = {
|
||||
{Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))},
|
||||
{Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))},
|
||||
{Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map = {
|
||||
{Settings::ScalingFilter::NearestNeighbor,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))},
|
||||
{Settings::ScalingFilter::Bilinear,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))},
|
||||
{Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))},
|
||||
{Settings::ScalingFilter::Gaussian,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))},
|
||||
{Settings::ScalingFilter::ScaleForce,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))},
|
||||
{Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map = {
|
||||
{Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))},
|
||||
{Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = {
|
||||
{Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))},
|
||||
{Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))},
|
||||
{Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map = {
|
||||
{Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))},
|
||||
{Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))},
|
||||
{Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map = {
|
||||
{Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))},
|
||||
{Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))},
|
||||
{Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))},
|
||||
};
|
||||
|
||||
} // namespace ConfigurationShared
|
112
src/eden/interface/uisettings.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "uisettings.h"
|
||||
#include <QSettings>
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.h"
|
||||
|
||||
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
|
||||
namespace Settings {
|
||||
template class Setting<bool>;
|
||||
template class Setting<std::string>;
|
||||
template class Setting<u16, true>;
|
||||
template class Setting<u32>;
|
||||
template class Setting<u8, true>;
|
||||
template class Setting<u8>;
|
||||
template class Setting<unsigned long long>;
|
||||
} // namespace Settings
|
||||
#endif
|
||||
|
||||
namespace FS = Common::FS;
|
||||
|
||||
namespace UISettings {
|
||||
|
||||
const Themes themes{{
|
||||
{"Default", "default"},
|
||||
{"Default Colorful", "colorful"},
|
||||
{"Dark", "qdarkstyle"},
|
||||
{"Dark Colorful", "colorful_dark"},
|
||||
{"Midnight Blue", "qdarkstyle_midnight_blue"},
|
||||
{"Midnight Blue Colorful", "colorful_midnight_blue"},
|
||||
}};
|
||||
|
||||
bool IsDarkTheme() {
|
||||
const auto& theme = UISettings::values.theme;
|
||||
return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") ||
|
||||
theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue");
|
||||
}
|
||||
|
||||
Values values = {};
|
||||
|
||||
u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) {
|
||||
switch (ratio) {
|
||||
case Settings::AspectRatio::R4_3:
|
||||
return height * 4 / 3;
|
||||
case Settings::AspectRatio::R21_9:
|
||||
return height * 21 / 9;
|
||||
case Settings::AspectRatio::R16_10:
|
||||
return height * 16 / 10;
|
||||
case Settings::AspectRatio::R16_9:
|
||||
case Settings::AspectRatio::Stretch:
|
||||
// TODO: Move this function wherever appropriate to implement Stretched aspect
|
||||
break;
|
||||
}
|
||||
return height * 16 / 9;
|
||||
}
|
||||
|
||||
void SaveWindowState() {
|
||||
const auto window_state_config_loc =
|
||||
FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "window_state.ini");
|
||||
|
||||
void(FS::CreateParentDir(window_state_config_loc));
|
||||
QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
|
||||
|
||||
config.setValue(QStringLiteral("geometry"), values.geometry);
|
||||
config.setValue(QStringLiteral("state"), values.state);
|
||||
config.setValue(QStringLiteral("geometryRenderWindow"), values.renderwindow_geometry);
|
||||
config.setValue(QStringLiteral("gameListHeaderState"), values.gamelist_header_state);
|
||||
config.setValue(QStringLiteral("microProfileDialogGeometry"), values.microprofile_geometry);
|
||||
|
||||
config.sync();
|
||||
}
|
||||
|
||||
void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig) {
|
||||
const auto window_state_config_loc =
|
||||
FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "window_state.ini");
|
||||
|
||||
// Migrate window state from old location
|
||||
if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) {
|
||||
const auto config_loc =
|
||||
FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "qt-config.ini");
|
||||
QSettings config(QString::fromStdString(config_loc), QSettings::IniFormat);
|
||||
|
||||
config.beginGroup(QStringLiteral("UI"));
|
||||
config.beginGroup(QStringLiteral("UILayout"));
|
||||
values.geometry = config.value(QStringLiteral("geometry")).toByteArray();
|
||||
values.state = config.value(QStringLiteral("state")).toByteArray();
|
||||
values.renderwindow_geometry =
|
||||
config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
|
||||
values.gamelist_header_state =
|
||||
config.value(QStringLiteral("gameListHeaderState")).toByteArray();
|
||||
values.microprofile_geometry =
|
||||
config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
|
||||
config.endGroup();
|
||||
config.endGroup();
|
||||
return;
|
||||
}
|
||||
|
||||
void(FS::CreateParentDir(window_state_config_loc));
|
||||
const QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
|
||||
|
||||
values.geometry = config.value(QStringLiteral("geometry")).toByteArray();
|
||||
values.state = config.value(QStringLiteral("state")).toByteArray();
|
||||
values.renderwindow_geometry =
|
||||
config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
|
||||
values.gamelist_header_state =
|
||||
config.value(QStringLiteral("gameListHeaderState")).toByteArray();
|
||||
values.microprofile_geometry =
|
||||
config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
|
||||
}
|
||||
|
||||
} // namespace UISettings
|
288
src/eden/interface/uisettings.h
Normal file
|
@ -0,0 +1,288 @@
|
|||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "qt_config.h"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
using Settings::Category;
|
||||
using Settings::ConfirmStop;
|
||||
using Settings::Setting;
|
||||
using Settings::SwitchableSetting;
|
||||
|
||||
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
|
||||
namespace Settings {
|
||||
extern template class Setting<bool>;
|
||||
extern template class Setting<std::string>;
|
||||
extern template class Setting<u16, true>;
|
||||
extern template class Setting<u32>;
|
||||
extern template class Setting<u8, true>;
|
||||
extern template class Setting<u8>;
|
||||
extern template class Setting<unsigned long long>;
|
||||
} // namespace Settings
|
||||
#endif
|
||||
|
||||
namespace UISettings {
|
||||
|
||||
bool IsDarkTheme();
|
||||
|
||||
struct ContextualShortcut {
|
||||
std::string keyseq;
|
||||
std::string controller_keyseq;
|
||||
int context;
|
||||
bool repeat;
|
||||
};
|
||||
|
||||
struct Shortcut {
|
||||
std::string name;
|
||||
std::string group;
|
||||
ContextualShortcut shortcut;
|
||||
};
|
||||
|
||||
enum class Theme {
|
||||
Default,
|
||||
DefaultColorful,
|
||||
Dark,
|
||||
DarkColorful,
|
||||
MidnightBlue,
|
||||
MidnightBlueColorful,
|
||||
};
|
||||
|
||||
enum class GameView {
|
||||
Grid,
|
||||
List,
|
||||
Carousel,
|
||||
};
|
||||
|
||||
static constexpr Theme default_theme{
|
||||
#ifdef _WIN32
|
||||
Theme::DarkColorful
|
||||
#else
|
||||
Theme::DefaultColorful
|
||||
#endif
|
||||
};
|
||||
|
||||
using Themes = std::array<std::pair<const char*, const char*>, 6>;
|
||||
extern const Themes themes;
|
||||
|
||||
struct GameDir {
|
||||
std::string path;
|
||||
bool deep_scan = false;
|
||||
bool expanded = false;
|
||||
bool operator==(const GameDir& rhs) const {
|
||||
return path == rhs.path;
|
||||
}
|
||||
bool operator!=(const GameDir& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
struct Values {
|
||||
Settings::Linkage linkage{1000};
|
||||
|
||||
QByteArray geometry;
|
||||
QByteArray state;
|
||||
|
||||
QByteArray renderwindow_geometry;
|
||||
|
||||
QByteArray gamelist_header_state;
|
||||
|
||||
QByteArray microprofile_geometry;
|
||||
Setting<bool> microprofile_visible{linkage, false, "microProfileDialogVisible",
|
||||
Category::UiLayout};
|
||||
|
||||
Setting<bool> single_window_mode{linkage, true, "singleWindowMode", Category::Ui};
|
||||
Setting<bool> fullscreen{linkage, false, "fullscreen", Category::Ui};
|
||||
Setting<bool> display_titlebar{linkage, true, "displayTitleBars", Category::Ui};
|
||||
Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui};
|
||||
Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui};
|
||||
|
||||
SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage,
|
||||
ConfirmStop::Ask_Always,
|
||||
"confirmStop",
|
||||
Category::UiGeneral,
|
||||
Settings::Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
|
||||
Setting<bool> first_start{linkage, true, "firstStart", Category::Ui};
|
||||
Setting<bool> pause_when_in_background{linkage,
|
||||
false,
|
||||
"pauseWhenInBackground",
|
||||
Category::UiGeneral,
|
||||
Settings::Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
Setting<bool> mute_when_in_background{linkage,
|
||||
false,
|
||||
"muteWhenInBackground",
|
||||
Category::UiAudio,
|
||||
Settings::Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
Setting<bool> hide_mouse{
|
||||
linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
|
||||
true, true};
|
||||
Setting<bool> controller_applet_disabled{linkage, false, "disableControllerApplet",
|
||||
Category::UiGeneral};
|
||||
// Set when Vulkan is known to crash the application
|
||||
bool has_broken_vulkan = false;
|
||||
|
||||
Setting<bool> select_user_on_boot{linkage,
|
||||
false,
|
||||
"select_user_on_boot",
|
||||
Category::UiGeneral,
|
||||
Settings::Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Ui};
|
||||
|
||||
// Discord RPC
|
||||
Setting<bool> enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui};
|
||||
|
||||
// logging
|
||||
Setting<bool> show_console{linkage, false, "showConsole", Category::Ui};
|
||||
|
||||
// Screenshots
|
||||
Setting<bool> enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
|
||||
Category::Screenshots};
|
||||
Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots};
|
||||
|
||||
std::string roms_path;
|
||||
std::string game_dir_deprecated;
|
||||
bool game_dir_deprecated_deepscan;
|
||||
QVector<GameDir> game_dirs;
|
||||
QStringList recent_files;
|
||||
Setting<std::string> language{linkage, {}, "language", Category::Paths};
|
||||
|
||||
std::string theme;
|
||||
|
||||
// Shortcut name <Shortcut, context>
|
||||
std::vector<Shortcut> shortcuts;
|
||||
|
||||
Setting<u32> callout_flags{linkage, 0, "calloutFlags", Category::Ui};
|
||||
|
||||
// multiplayer settings
|
||||
Setting<std::string> multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_filter_text{linkage, {}, "filter_text", Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_games_owned{linkage, false, "filter_games_owned",
|
||||
Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_hide_empty{linkage, false, "filter_games_hide_empty",
|
||||
Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_hide_full{linkage, false, "filter_games_hide_full",
|
||||
Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_ip{linkage, {}, "ip", Category::Multiplayer};
|
||||
Setting<u16, true> multiplayer_port{linkage, 24872, 0,
|
||||
UINT16_MAX, "port", Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_room_nickname{
|
||||
linkage, {}, "room_nickname", Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_room_name{linkage, {}, "room_name", Category::Multiplayer};
|
||||
Setting<u8, true> multiplayer_max_player{linkage, 8, 0, 8, "max_player", Category::Multiplayer};
|
||||
Setting<u16, true> multiplayer_room_port{linkage, 24872, 0,
|
||||
UINT16_MAX, "room_port", Category::Multiplayer};
|
||||
Setting<u8, true> multiplayer_host_type{linkage, 0, 0, 1, "host_type", Category::Multiplayer};
|
||||
Setting<unsigned long long> multiplayer_game_id{linkage, {}, "game_id", Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_room_description{
|
||||
linkage, {}, "room_description", Category::Multiplayer};
|
||||
std::pair<std::vector<std::string>, std::vector<std::string>> multiplayer_ban_list;
|
||||
|
||||
// Game List
|
||||
// Setting<bool> show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
|
||||
// Setting<u32> game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList};
|
||||
// Setting<u32> folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList};
|
||||
// Setting<u8> row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
|
||||
// Setting<u8> row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
|
||||
// std::atomic_bool is_game_list_reload_pending{false};
|
||||
// Setting<bool> cache_game_list{linkage, true, "cache_game_list", Category::UiGameList};
|
||||
// Setting<bool> favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList};
|
||||
// QVector<u64> favorited_ids;
|
||||
|
||||
Setting<u8, true> grid_columns{linkage, 4, 1, 8, "grid_columns", Category::UiGameList};
|
||||
|
||||
// Compatibility List
|
||||
Setting<bool> show_compat{linkage, false, "show_compat", Category::UiGameList};
|
||||
|
||||
// Size & File Types Column
|
||||
Setting<bool> show_size{linkage, true, "show_size", Category::UiGameList};
|
||||
Setting<bool> show_types{linkage, true, "show_types", Category::UiGameList};
|
||||
|
||||
// Play time
|
||||
Setting<bool> show_play_time{linkage, true, "show_play_time", Category::UiGameList};
|
||||
|
||||
bool configuration_applied;
|
||||
bool reset_to_defaults;
|
||||
bool shortcut_already_warned{false};
|
||||
};
|
||||
|
||||
extern Values values;
|
||||
|
||||
u32 CalculateWidth(u32 height, Settings::AspectRatio ratio);
|
||||
|
||||
void SaveWindowState();
|
||||
void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig);
|
||||
|
||||
// This shouldn't have anything except static initializers (no functions). So
|
||||
// QKeySequence(...).toString() is NOT ALLOWED HERE.
|
||||
// This must be in alphabetical order according to action name as it must have the same order as
|
||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||
// clang-format off
|
||||
const std::array<Shortcut, 28> default_hotkeys{{
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit eden")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F6"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}},
|
||||
}};
|
||||
// clang-format on
|
||||
|
||||
} // namespace UISettings
|
||||
|
||||
Q_DECLARE_METATYPE(UISettings::GameDir*);
|
||||
|
||||
// These metatype declarations cannot be in common/settings.h because core is devoid of QT
|
||||
Q_DECLARE_METATYPE(Settings::CpuAccuracy);
|
||||
Q_DECLARE_METATYPE(Settings::GpuAccuracy);
|
||||
Q_DECLARE_METATYPE(Settings::FullscreenMode);
|
||||
Q_DECLARE_METATYPE(Settings::NvdecEmulation);
|
||||
Q_DECLARE_METATYPE(Settings::ResolutionSetup);
|
||||
Q_DECLARE_METATYPE(Settings::ScalingFilter);
|
||||
Q_DECLARE_METATYPE(Settings::AntiAliasing);
|
||||
Q_DECLARE_METATYPE(Settings::RendererBackend);
|
||||
Q_DECLARE_METATYPE(Settings::ShaderBackend);
|
||||
Q_DECLARE_METATYPE(Settings::AstcRecompression);
|
||||
Q_DECLARE_METATYPE(Settings::AstcDecodeMode);
|
||||
Q_DECLARE_METATYPE(Settings::SpirvOptimizeMode);
|
59
src/eden/main.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include <QApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include "core/core.h"
|
||||
#include "interface/QMLConfig.h"
|
||||
#include "models/GameListModel.h"
|
||||
#include "interface/SettingsInterface.h"
|
||||
|
||||
#include <QQuickStyle>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QQuickStyle::setStyle(QObject::tr("Material"));
|
||||
|
||||
QCoreApplication::setOrganizationName(QStringLiteral("eden-emu"));
|
||||
QCoreApplication::setApplicationName(QStringLiteral("eden"));
|
||||
QApplication::setDesktopFileName(QStringLiteral("org.eden-emu.eden"));
|
||||
|
||||
/// Settings, etc
|
||||
Settings::SetConfiguringGlobal(true);
|
||||
QMLConfig *config = new QMLConfig;
|
||||
|
||||
// // TODO: Save all values on launch and per game etc
|
||||
// app.connect(&app, &QCoreApplication::aboutToQuit, &app, [config]() {
|
||||
// config->save();
|
||||
// });
|
||||
|
||||
/// Expose Enums
|
||||
|
||||
// Core
|
||||
std::unique_ptr<Core::System> system = std::make_unique<Core::System>();
|
||||
|
||||
/// CONTEXT
|
||||
QQmlApplicationEngine engine;
|
||||
auto ctx = engine.rootContext();
|
||||
|
||||
ctx->setContextProperty(QStringLiteral("QtConfig"), QVariant::fromValue(config));
|
||||
|
||||
// Enums
|
||||
qmlRegisterUncreatableMetaObject(SettingsCategories::staticMetaObject, "org.eden_emu.interface", 1, 0, "SettingsCategories", QString());
|
||||
|
||||
// Directory List
|
||||
GameListModel *gameListModel = new GameListModel(&app);
|
||||
ctx->setContextProperty(QStringLiteral("EdenGameList"), gameListModel);
|
||||
|
||||
/// LOAD
|
||||
QObject::connect(
|
||||
&engine,
|
||||
&QQmlApplicationEngine::objectCreationFailed,
|
||||
&app,
|
||||
[]() { QCoreApplication::exit(-1); },
|
||||
Qt::QueuedConnection);
|
||||
|
||||
engine.loadFromModule("org.eden_emu.main", "Main");
|
||||
|
||||
return app.exec();
|
||||
}
|
16
src/eden/models/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
# TODO: This might not need to be exposed to QML?
|
||||
qt_add_library(edenModels STATIC)
|
||||
qt_add_qml_module(edenModels
|
||||
URI org.eden_emu.models
|
||||
VERSION 1.0
|
||||
SOURCES
|
||||
GameListModel.h GameListModel.cpp
|
||||
SettingsModel.h SettingsModel.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(edenModels
|
||||
PRIVATE
|
||||
Qt6::Gui
|
||||
)
|
67
src/eden/models/GameListModel.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "GameListModel.h"
|
||||
|
||||
#include <QDirIterator>
|
||||
|
||||
const QStringList GameListModel::ValidSuffixes{"jpg", "png", "webp", "jpeg"};
|
||||
|
||||
GameListModel::GameListModel(QObject *parent) {
|
||||
QHash<int, QByteArray> rez = QStandardItemModel::roleNames();
|
||||
rez.insert(GLMRoleTypes::NAME, "name");
|
||||
rez.insert(GLMRoleTypes::PATH, "path");
|
||||
rez.insert(GLMRoleTypes::FILESIZE, "size");
|
||||
|
||||
QStandardItemModel::setItemRoleNames(rez);
|
||||
}
|
||||
|
||||
QVariant GameListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (role == GLMRoleTypes::NAME) {
|
||||
return itemFromIndex(index)->text();
|
||||
}
|
||||
|
||||
return QStandardItemModel::data(index, role);
|
||||
}
|
||||
|
||||
void GameListModel::addDir(const QString &toAdd)
|
||||
{
|
||||
QString name = toAdd;
|
||||
#ifdef Q_OS_WINDOWS
|
||||
name.replace("file:///", "");
|
||||
#else
|
||||
name.replace("file://", "");
|
||||
#endif
|
||||
|
||||
m_dirs << name;
|
||||
reload();
|
||||
}
|
||||
|
||||
void GameListModel::removeDir(const QString &toRemove)
|
||||
{
|
||||
m_dirs.removeAll(toRemove);
|
||||
reload();
|
||||
}
|
||||
|
||||
void GameListModel::reload()
|
||||
{
|
||||
clear();
|
||||
for (const QString &dir : std::as_const(m_dirs)) {
|
||||
qDebug() << dir;
|
||||
for (const auto &entry : QDirListing(dir, QDirListing::IteratorFlag::FilesOnly)) {
|
||||
if (ValidSuffixes.contains(entry.completeSuffix().toLower())) {
|
||||
QString path = entry.absoluteFilePath();
|
||||
QString name = entry.baseName();
|
||||
qreal size = entry.size();
|
||||
QString sizeString = QLocale::system().formattedDataSize(size);
|
||||
|
||||
QStandardItem *game = new QStandardItem(name);
|
||||
game->setData(path, GLMRoleTypes::PATH);
|
||||
game->setData(sizeString, GLMRoleTypes::FILESIZE);
|
||||
|
||||
invisibleRootItem()->appendRow(game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
src/eden/models/GameListModel.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef GAMELISTMODEL_H
|
||||
#define GAMELISTMODEL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
typedef struct Game {
|
||||
QString absPath;
|
||||
QString name;
|
||||
QString fileSize;
|
||||
} Game;
|
||||
|
||||
class GameListModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum GLMRoleTypes {
|
||||
NAME = Qt::UserRole + 1,
|
||||
PATH,
|
||||
FILESIZE
|
||||
};
|
||||
|
||||
GameListModel(QObject *parent = nullptr);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
Q_INVOKABLE void addDir(const QString &toAdd);
|
||||
Q_INVOKABLE void removeDir(const QString &toRemove);
|
||||
|
||||
static const QStringList ValidSuffixes;
|
||||
|
||||
private:
|
||||
QStringList m_dirs;
|
||||
QList<Game> m_data;
|
||||
|
||||
void reload();
|
||||
};
|
||||
|
||||
#endif // GAMELISTMODEL_H
|
90
src/eden/models/SettingsModel.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include "SettingsModel.h"
|
||||
|
||||
SettingsModel::SettingsModel(QObject* parent) : QAbstractListModel(parent) {}
|
||||
|
||||
int SettingsModel::rowCount(const QModelIndex& parent) const {
|
||||
return m_data.count();
|
||||
}
|
||||
|
||||
QVariant SettingsModel::data(const QModelIndex& index, int role) const {
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
QMLSetting *s = m_data[index.row()];
|
||||
|
||||
switch (role) {
|
||||
case LABEL:
|
||||
return s->label();
|
||||
case TOOLTIP:
|
||||
return s->tooltip();
|
||||
case VALUE:
|
||||
return s->value();
|
||||
case ID:
|
||||
return s->id();
|
||||
case TYPE:
|
||||
return s->type();
|
||||
case COMBO:
|
||||
return s->combo();
|
||||
case SUFFIX:
|
||||
return s->suffix();
|
||||
case MIN:
|
||||
return s->min();
|
||||
case MAX:
|
||||
return s->max();
|
||||
case OTHER:
|
||||
return QVariant::fromValue(s->other());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool SettingsModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (data(index, role) != value) {
|
||||
QMLSetting *s = m_data[index.row()];
|
||||
|
||||
switch (role) {
|
||||
case VALUE:
|
||||
s->setValue(value);
|
||||
|
||||
break;
|
||||
}
|
||||
emit dataChanged(index, index, {role});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void SettingsModel::append(QMLSetting *setting)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
||||
m_data << setting;
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void SettingsModel::append(QList<QMLSetting *> settings)
|
||||
{
|
||||
for (QMLSetting *setting : settings) {
|
||||
append(setting);
|
||||
}
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> SettingsModel::roleNames() const
|
||||
{
|
||||
QHash<int,QByteArray> rez;
|
||||
rez[LABEL] = "label";
|
||||
rez[TOOLTIP] = "tooltip";
|
||||
rez[VALUE] = "value";
|
||||
rez[ID] = "id";
|
||||
rez[TYPE] = "type";
|
||||
rez[COMBO] = "combo";
|
||||
rez[SUFFIX] = "suffix";
|
||||
rez[MIN] = "min";
|
||||
rez[MAX] = "max";
|
||||
rez[OTHER] = "other";
|
||||
|
||||
return rez;
|
||||
}
|
42
src/eden/models/SettingsModel.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef SETTINGSMODEL_H
|
||||
#define SETTINGSMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include "eden/interface/QMLSetting.h"
|
||||
|
||||
class SettingsModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum SMTypes {
|
||||
LABEL = Qt::UserRole + 1,
|
||||
TOOLTIP,
|
||||
ID,
|
||||
VALUE,
|
||||
TYPE,
|
||||
COMBO, // combobox translations
|
||||
SUFFIX,
|
||||
MIN,
|
||||
MAX,
|
||||
OTHER
|
||||
};
|
||||
|
||||
explicit SettingsModel(QObject* parent = nullptr);
|
||||
|
||||
// Basic functionality:
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
|
||||
void append(QMLSetting *setting);
|
||||
void append(QList<QMLSetting *> settings);
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
QList<QMLSetting *> m_data;
|
||||
};
|
||||
|
||||
#endif // SETTINGSMODEL_H
|
6
src/eden/qml/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
add_subdirectory(config)
|
||||
add_subdirectory(constants)
|
||||
add_subdirectory(items)
|
||||
add_subdirectory(util)
|
||||
|
||||
add_subdirectory(main)
|
57
src/eden/qml/config/CMakeLists.txt
Normal file
|
@ -0,0 +1,57 @@
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
qt_add_library(edenConfig STATIC)
|
||||
qt_add_qml_module(edenConfig
|
||||
URI org.eden_emu.config
|
||||
VERSION 1.0
|
||||
|
||||
QML_FILES GlobalConfigureDialog.qml
|
||||
QML_FILES Setting.qml
|
||||
QML_FILES SectionHeader.qml
|
||||
|
||||
QML_FILES pages/SettingsList.qml
|
||||
|
||||
QML_FILES pages/global/GlobalTab.qml
|
||||
QML_FILES pages/global/GlobalTabSwipeView.qml
|
||||
QML_FILES pages/global/GlobalGeneralPage.qml
|
||||
|
||||
QML_FILES pages/global/GlobalSystemPage.qml
|
||||
QML_FILES pages/global/GlobalCpuPage.qml
|
||||
QML_FILES pages/global/GlobalGraphicsPage.qml
|
||||
QML_FILES pages/global/GlobalAudioPage.qml
|
||||
|
||||
QML_FILES pages/general/UiGeneralPage.qml
|
||||
QML_FILES pages/general/UiGameListPage.qml
|
||||
QML_FILES
|
||||
|
||||
QML_FILES pages/graphics/RendererPage.qml
|
||||
QML_FILES pages/graphics/RendererAdvancedPage.qml
|
||||
QML_FILES pages/graphics/RendererExtensionsPage.qml
|
||||
|
||||
QML_FILES pages/system/SystemGeneralPage.qml
|
||||
QML_FILES
|
||||
QML_FILES pages/system/FileSystemPage.qml
|
||||
QML_FILES pages/system/AppletsPage.qml
|
||||
|
||||
QML_FILES pages/cpu/CpuGeneralPage.qml
|
||||
|
||||
QML_FILES pages/audio/AudioGeneralPage.qml
|
||||
QML_FILES pages/global/GlobalDebugPage.qml
|
||||
QML_FILES pages/debug/DebugGeneralPage.qml
|
||||
QML_FILES pages/debug/DebugGraphicsPage.qml
|
||||
QML_FILES pages/debug/DebugAdvancedPage.qml
|
||||
QML_FILES pages/debug/DebugCpuPage.qml
|
||||
QML_FILES fields/ConfigCheckbox.qml
|
||||
QML_FILES fields/FieldLabel.qml
|
||||
QML_FILES fields/ConfigComboBox.qml
|
||||
QML_FILES TestSetting.qml
|
||||
QML_FILES fields/ConfigIntLine.qml
|
||||
QML_FILES fields/ConfigTimeEdit.qml
|
||||
QML_FILES fields/ConfigIntSpin.qml
|
||||
QML_FILES fields/ConfigHexEdit.qml
|
||||
QML_FILES fields/ConfigStringEdit.qml
|
||||
QML_FILES fields/FieldCheckbox.qml
|
||||
QML_FILES fields/ConfigIntSlider.qml
|
||||
QML_FILES pages/system/SystemCorePage.qml
|
||||
QML_FILES fields/BaseField.qml
|
||||
)
|
80
src/eden/qml/config/GlobalConfigureDialog.qml
Normal file
|
@ -0,0 +1,80 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.constants
|
||||
import org.eden_emu.items
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.util
|
||||
|
||||
AnimatedDialog {
|
||||
property list<var> configs
|
||||
|
||||
preferredWidth: 1280
|
||||
|
||||
title: "Configuration"
|
||||
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||
|
||||
Component.onCompleted: configs = Util.searchItem(swipe, "BaseField")
|
||||
|
||||
onAccepted: {
|
||||
configs.forEach(config => {
|
||||
config.apply()
|
||||
// console.log(config.setting.label)
|
||||
})
|
||||
QtConfig.save()
|
||||
}
|
||||
onRejected: {
|
||||
configs.forEach(config => config.sync())
|
||||
QtConfig.reload()
|
||||
}
|
||||
|
||||
VerticalTabBar {
|
||||
id: tabBar
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: 55 * Constants.scalar
|
||||
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
}
|
||||
contentWidth: 100
|
||||
|
||||
currentIndex: swipe.currentIndex
|
||||
|
||||
Repeater {
|
||||
model: ["General", "System", "CPU", "Graphics", "Audio", "Debug", "Controls"]
|
||||
|
||||
SettingsTabButton {
|
||||
required property string modelData
|
||||
label: modelData
|
||||
onClicked: tabBar.currentIndex = TabBar.index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwipeView {
|
||||
id: swipe
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
orientation: Qt.Vertical
|
||||
anchors {
|
||||
left: tabBar.right
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
|
||||
leftMargin: 5 * Constants.scalar
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
||||
GlobalGeneralPage {}
|
||||
GlobalSystemPage {}
|
||||
GlobalCpuPage {}
|
||||
GlobalGraphicsPage {}
|
||||
GlobalAudioPage {}
|
||||
GlobalDebugPage {}
|
||||
}
|
||||
}
|
8
src/eden/qml/config/SectionHeader.qml
Normal file
|
@ -0,0 +1,8 @@
|
|||
import QtQuick
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
Text {
|
||||
color: Constants.text
|
||||
font.pixelSize: 16
|
||||
}
|
92
src/eden/qml/config/Setting.qml
Normal file
|
@ -0,0 +1,92 @@
|
|||
import QtQuick
|
||||
|
||||
import Qt.labs.qmlmodels
|
||||
|
||||
import org.eden_emu.config
|
||||
|
||||
// TODO: make settings independently available (model vs setting?
|
||||
DelegateChooser {
|
||||
id: chooser
|
||||
role: "type"
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "bool"
|
||||
|
||||
ConfigCheckbox {
|
||||
setting: model
|
||||
width: ListView.view.width
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "enumCombo"
|
||||
|
||||
ConfigComboBox {
|
||||
setting: model
|
||||
width: ListView.view.width
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "intCombo"
|
||||
|
||||
ConfigComboBox {
|
||||
setting: model
|
||||
width: ListView.view.width
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "intLine"
|
||||
|
||||
ConfigIntLine {
|
||||
setting: model
|
||||
width: ListView.view.width
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "intSlider"
|
||||
|
||||
ConfigIntSlider {
|
||||
setting: model
|
||||
width: ListView.view.width
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "time"
|
||||
|
||||
ConfigTimeEdit {
|
||||
setting: model
|
||||
width: ListView.view.width
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "intSpin"
|
||||
|
||||
ConfigIntSpin {
|
||||
setting: model
|
||||
width: ListView.view.width
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "stringLine"
|
||||
|
||||
ConfigStringEdit {
|
||||
setting: model
|
||||
width: ListView.view.width
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "hex"
|
||||
|
||||
ConfigHexEdit {
|
||||
setting: model
|
||||
width: ListView.view.width
|
||||
}
|
||||
}
|
||||
}
|
39
src/eden/qml/config/TestSetting.qml
Normal file
|
@ -0,0 +1,39 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
Column {
|
||||
topPadding: 5 * Constants.scalar
|
||||
leftPadding: 10 * Constants.scalar
|
||||
|
||||
RowLayout {
|
||||
uniformCellSizes: true
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: model.label
|
||||
color: Constants.text
|
||||
font.pixelSize: 16
|
||||
|
||||
height: 40
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: model.value
|
||||
color: "lightblue"
|
||||
font.pixelSize: 14
|
||||
|
||||
height: 40
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: model.type + " " + typeof model.value + " " + model.other
|
||||
color: "lightgray"
|
||||
font.pixelSize: 12
|
||||
|
||||
height: 25
|
||||
}
|
||||
}
|
170
src/eden/qml/config/fields/BaseField.qml
Normal file
|
@ -0,0 +1,170 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.items
|
||||
import org.eden_emu.config
|
||||
import org.eden_emu.constants
|
||||
|
||||
Item {
|
||||
id: field
|
||||
property var setting
|
||||
property var value
|
||||
property bool showLabel: true
|
||||
property bool forceCheckbox: false
|
||||
|
||||
property alias enable: enable.checked
|
||||
property Item contentItem
|
||||
|
||||
readonly property string typeName: "BaseField"
|
||||
|
||||
clip: true
|
||||
height: content.height + (helpText.height + helpText.anchors.topMargin)
|
||||
|
||||
Component.onCompleted: sync()
|
||||
|
||||
function apply() {
|
||||
if (setting.value !== value) {
|
||||
setting.value = value
|
||||
}
|
||||
}
|
||||
|
||||
function sync() {
|
||||
if (value !== setting.value) {
|
||||
value = setting.value
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
height: 50 * Constants.scalar
|
||||
|
||||
spacing: 0
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
z: 2
|
||||
|
||||
IconButton {
|
||||
label: "help"
|
||||
icon.width: 20
|
||||
icon.height: 20
|
||||
|
||||
onClicked: helpText.toggle()
|
||||
icon.color: setting.tooltip !== "" ? Constants.text : Constants.dialog
|
||||
z: 2
|
||||
}
|
||||
|
||||
FieldCheckbox {
|
||||
id: enable
|
||||
setting: field.setting
|
||||
z: 2
|
||||
force: field.forceCheckbox
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
uniformCellSizes: true
|
||||
spacing: 0
|
||||
z: 2
|
||||
|
||||
FieldLabel {
|
||||
z: 2
|
||||
id: label
|
||||
setting: field.setting
|
||||
}
|
||||
|
||||
children: showLabel ? [label, contentItem] : [contentItem]
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: Constants.dialog
|
||||
anchors.fill: content
|
||||
z: 0
|
||||
}
|
||||
|
||||
Text {
|
||||
id: helpText
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: 20 * Constants.scalar
|
||||
right: parent.right
|
||||
rightMargin: 20 * Constants.scalar
|
||||
|
||||
top: content.bottom
|
||||
topMargin: -height
|
||||
}
|
||||
|
||||
z: -1
|
||||
|
||||
text: setting.tooltip
|
||||
color: Constants.subText
|
||||
font.pixelSize: 12 * Constants.scalar
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
visible: false
|
||||
opacity: 0
|
||||
|
||||
function toggle() {
|
||||
if (visible) {
|
||||
hideAnim.start()
|
||||
} else {
|
||||
showAnim.start()
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: showAnim
|
||||
|
||||
SmoothedAnimation {
|
||||
target: helpText
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
|
||||
velocity: 3
|
||||
}
|
||||
|
||||
SmoothedAnimation {
|
||||
target: helpText
|
||||
property: "anchors.topMargin"
|
||||
from: -helpText.height
|
||||
to: 0
|
||||
|
||||
duration: 300
|
||||
velocity: -1
|
||||
}
|
||||
|
||||
onStarted: helpText.visible = true
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: hideAnim
|
||||
|
||||
SmoothedAnimation {
|
||||
target: helpText
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
|
||||
velocity: 3
|
||||
}
|
||||
|
||||
SmoothedAnimation {
|
||||
target: helpText
|
||||
property: "anchors.topMargin"
|
||||
from: 0
|
||||
to: -helpText.height
|
||||
|
||||
duration: 300
|
||||
velocity: -1
|
||||
}
|
||||
|
||||
onFinished: helpText.visible = false
|
||||
}
|
||||
}
|
||||
}
|
27
src/eden/qml/config/fields/ConfigCheckbox.qml
Normal file
|
@ -0,0 +1,27 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
BaseField {
|
||||
forceCheckbox: true
|
||||
// // TODO: global/custom
|
||||
// contentItem: CheckBox {
|
||||
// id: control
|
||||
|
||||
// Layout.rightMargin: 10 * Constants.scalar
|
||||
// Layout.fillWidth: true
|
||||
|
||||
// font.pixelSize: 15 * Constants.scalar
|
||||
// indicator.implicitHeight: 25 * Constants.scalar
|
||||
// indicator.implicitWidth: 25 * Constants.scalar
|
||||
|
||||
// text: setting.label
|
||||
// checked: setting.value
|
||||
|
||||
// onClicked: value = checked
|
||||
|
||||
// checkable: true
|
||||
// }
|
||||
}
|
33
src/eden/qml/config/fields/ConfigComboBox.qml
Normal file
|
@ -0,0 +1,33 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls.Material.impl
|
||||
|
||||
import org.eden_emu.constants
|
||||
import org.eden_emu.config
|
||||
|
||||
BaseField {
|
||||
contentItem: ComboBox {
|
||||
id: control
|
||||
enabled: enable
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 10 * Constants.scalar
|
||||
|
||||
font.pixelSize: 14 * Constants.scalar
|
||||
model: setting.combo
|
||||
currentIndex: value
|
||||
|
||||
background: MaterialTextContainer {
|
||||
implicitWidth: 120
|
||||
implicitHeight: 40 * Constants.scalar
|
||||
|
||||
outlineColor: (enabled
|
||||
&& control.hovered) ? control.Material.primaryTextColor : control.Material.hintTextColor
|
||||
focusedOutlineColor: control.Material.accentColor
|
||||
controlHasActiveFocus: control.activeFocus
|
||||
controlHasText: true
|
||||
horizontalPadding: control.Material.textFieldHorizontalPadding
|
||||
}
|
||||
}
|
||||
}
|
26
src/eden/qml/config/fields/ConfigHexEdit.qml
Normal file
|
@ -0,0 +1,26 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.items
|
||||
import org.eden_emu.config
|
||||
import org.eden_emu.constants
|
||||
|
||||
BaseField {
|
||||
contentItem: BetterTextField {
|
||||
enabled: enable
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 10 * Constants.scalar
|
||||
|
||||
validator: RegularExpressionValidator {
|
||||
regularExpression: /[0-9a-fA-F]{0,8}/
|
||||
}
|
||||
|
||||
font.pixelSize: 15 * Constants.scalar
|
||||
|
||||
text: Number(value).toString(16)
|
||||
suffix: setting.suffix
|
||||
|
||||
onTextEdited: value = Number("0x" + text)
|
||||
}
|
||||
}
|
28
src/eden/qml/config/fields/ConfigIntLine.qml
Normal file
|
@ -0,0 +1,28 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.items
|
||||
import org.eden_emu.config
|
||||
import org.eden_emu.constants
|
||||
|
||||
BaseField {
|
||||
contentItem: BetterTextField {
|
||||
enabled: enable
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 10 * Constants.scalar
|
||||
|
||||
inputMethodHints: Qt.ImhDigitsOnly
|
||||
validator: IntValidator {
|
||||
bottom: setting.min
|
||||
top: setting.max
|
||||
}
|
||||
|
||||
font.pixelSize: 15 * Constants.scalar
|
||||
|
||||
text: value
|
||||
suffix: setting.suffix
|
||||
|
||||
onTextEdited: value = parseInt(text)
|
||||
}
|
||||
}
|
40
src/eden/qml/config/fields/ConfigIntSlider.qml
Normal file
|
@ -0,0 +1,40 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.items
|
||||
import org.eden_emu.config
|
||||
import org.eden_emu.constants
|
||||
|
||||
// Lots of cancer but idrc
|
||||
BaseField {
|
||||
id: field
|
||||
contentItem: RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Slider {
|
||||
Layout.fillWidth: true
|
||||
|
||||
from: setting.min
|
||||
to: setting.max
|
||||
stepSize: 1
|
||||
|
||||
value: field.value
|
||||
|
||||
onMoved: field.value = value
|
||||
|
||||
Layout.rightMargin: 10 * Constants.scalar
|
||||
|
||||
snapMode: Slider.SnapAlways
|
||||
}
|
||||
|
||||
Text {
|
||||
font.pixelSize: 14 * Constants.scalar
|
||||
color: Constants.text
|
||||
|
||||
text: field.value + setting.suffix
|
||||
|
||||
Layout.rightMargin: 10 * Constants.scalar
|
||||
}
|
||||
}
|
||||
}
|
26
src/eden/qml/config/fields/ConfigIntSpin.qml
Normal file
|
@ -0,0 +1,26 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.items
|
||||
import org.eden_emu.config
|
||||
import org.eden_emu.constants
|
||||
|
||||
BaseField {
|
||||
id: field
|
||||
contentItem: BetterSpinBox {
|
||||
enabled: enable
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 10 * Constants.scalar
|
||||
|
||||
from: setting.min
|
||||
to: setting.max
|
||||
|
||||
font.pixelSize: 15 * Constants.scalar
|
||||
|
||||
value: field.value
|
||||
label: setting.suffix
|
||||
|
||||
onValueModified: field.value = value
|
||||
}
|
||||
}
|
22
src/eden/qml/config/fields/ConfigStringEdit.qml
Normal file
|
@ -0,0 +1,22 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.items
|
||||
import org.eden_emu.config
|
||||
import org.eden_emu.constants
|
||||
|
||||
BaseField {
|
||||
contentItem: BetterTextField {
|
||||
enabled: enable
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 10 * Constants.scalar
|
||||
|
||||
font.pixelSize: 15 * Constants.scalar
|
||||
|
||||
text: value
|
||||
suffix: setting.suffix
|
||||
|
||||
onTextEdited: value = text
|
||||
}
|
||||
}
|
27
src/eden/qml/config/fields/ConfigTimeEdit.qml
Normal file
|
@ -0,0 +1,27 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.items
|
||||
import org.eden_emu.config
|
||||
import org.eden_emu.constants
|
||||
|
||||
BaseField {
|
||||
// TODO: real impl
|
||||
contentItem: BetterTextField {
|
||||
enabled: enable
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 10 * Constants.scalar
|
||||
|
||||
inputMethodHints: Qt.ImhDigitsOnly
|
||||
validator: IntValidator {
|
||||
bottom: setting.min
|
||||
top: setting.max
|
||||
}
|
||||
|
||||
font.pixelSize: 15 * Constants.scalar
|
||||
|
||||
text: value
|
||||
suffix: setting.suffix
|
||||
}
|
||||
}
|
20
src/eden/qml/config/fields/FieldCheckbox.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
CheckBox {
|
||||
property bool force: false
|
||||
property var setting
|
||||
property var other: setting.other === null ? setting : setting.other
|
||||
|
||||
indicator.implicitHeight: 25 * Constants.scalar
|
||||
indicator.implicitWidth: 25 * Constants.scalar
|
||||
|
||||
checked: visible ? other.value : true
|
||||
onClicked: if (visible)
|
||||
other.value = checked
|
||||
|
||||
visible: setting.other !== null || force
|
||||
}
|
18
src/eden/qml/config/fields/FieldLabel.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
Text {
|
||||
property var setting
|
||||
|
||||
text: setting.label
|
||||
color: Constants.text
|
||||
font.pixelSize: 14 * Constants.scalar
|
||||
|
||||
height: 50 * Constants.scalar
|
||||
ToolTip.text: setting.tooltip
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
1
src/eden/qml/config/icons.qrc
Normal file
|
@ -0,0 +1 @@
|
|||
<RCC/>
|
47
src/eden/qml/config/pages/SettingsList.qml
Normal file
|
@ -0,0 +1,47 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.config
|
||||
import org.eden_emu.constants
|
||||
import org.eden_emu.interface
|
||||
|
||||
ColumnLayout {
|
||||
required property int category
|
||||
|
||||
property bool inset: false
|
||||
property string header: ""
|
||||
property list<string> idInclude: []
|
||||
property list<string> idExclude: []
|
||||
|
||||
SectionHeader {
|
||||
text: header
|
||||
visible: header != ""
|
||||
}
|
||||
|
||||
ListView {
|
||||
clip: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
interactive: false
|
||||
|
||||
implicitHeight: contentHeight
|
||||
delegate: Setting {}
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 5 * Constants.scalar
|
||||
spacing: 8 * Constants.scalar
|
||||
|
||||
model: SettingsInterface.category(category, idInclude, idExclude)
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
border {
|
||||
color: inset ? Constants.text : "transparent"
|
||||
width: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
src/eden/qml/config/pages/audio/AudioGeneralPage.qml
Normal file
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.Audio
|
||||
}
|
||||
}
|
||||
}
|
17
src/eden/qml/config/pages/cpu/CpuGeneralPage.qml
Normal file
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.Cpu
|
||||
}
|
||||
}
|
||||
}
|
19
src/eden/qml/config/pages/debug/DebugAdvancedPage.qml
Normal file
|
@ -0,0 +1,19 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
// TODO: filter
|
||||
SettingsList {
|
||||
category: SettingsCategories.Debugging
|
||||
}
|
||||
}
|
||||
}
|
18
src/eden/qml/config/pages/debug/DebugCpuPage.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.CpuDebug
|
||||
}
|
||||
}
|
||||
}
|
28
src/eden/qml/config/pages/debug/DebugGeneralPage.qml
Normal file
|
@ -0,0 +1,28 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
// TODO: split
|
||||
SettingsList {
|
||||
category: SettingsCategories.Debugging
|
||||
}
|
||||
|
||||
// TODO: wrong category?
|
||||
SettingsList {
|
||||
category: SettingsCategories.Miscellaneous
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
src/eden/qml/config/pages/debug/DebugGraphicsPage.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
Layout.fillWidth: true
|
||||
|
||||
category: SettingsCategories.DebuggingGraphics
|
||||
}
|
||||
}
|
||||
}
|
18
src/eden/qml/config/pages/general/UiGameListPage.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
// TODO: language, theme
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.UiGameList
|
||||
}
|
||||
}
|
||||
}
|
23
src/eden/qml/config/pages/general/UiGeneralPage.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.UiGeneral
|
||||
// onContentHeightChanged: console.log(height, parent.height)
|
||||
}
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.Linux
|
||||
visible: Qt.platform.os === "linux"
|
||||
}
|
||||
}
|
||||
}
|
16
src/eden/qml/config/pages/global/GlobalAudioPage.qml
Normal file
|
@ -0,0 +1,16 @@
|
|||
import QtQuick
|
||||
|
||||
import org.eden_emu.config
|
||||
|
||||
GlobalTab {
|
||||
property alias swipe: swipe
|
||||
|
||||
tabs: ["Audio"]
|
||||
|
||||
GlobalTabSwipeView {
|
||||
id: swipe
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
AudioGeneralPage {}
|
||||
}
|
||||
}
|
15
src/eden/qml/config/pages/global/GlobalCpuPage.qml
Normal file
|
@ -0,0 +1,15 @@
|
|||
import QtQuick
|
||||
|
||||
import org.eden_emu.config
|
||||
|
||||
GlobalTab {
|
||||
property alias swipe: swipe
|
||||
tabs: ["CPU"]
|
||||
|
||||
GlobalTabSwipeView {
|
||||
id: swipe
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
CpuGeneralPage {}
|
||||
}
|
||||
}
|
18
src/eden/qml/config/pages/global/GlobalDebugPage.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
import QtQuick
|
||||
|
||||
import org.eden_emu.config
|
||||
|
||||
GlobalTab {
|
||||
property alias swipe: swipe
|
||||
tabs: ["General", "Graphics", "Advanced", "CPU"]
|
||||
|
||||
GlobalTabSwipeView {
|
||||
id: swipe
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
DebugGeneralPage {}
|
||||
DebugGraphicsPage {}
|
||||
DebugAdvancedPage {}
|
||||
DebugCpuPage {}
|
||||
}
|
||||
}
|
18
src/eden/qml/config/pages/global/GlobalGeneralPage.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
import QtQuick
|
||||
|
||||
import org.eden_emu.config
|
||||
|
||||
GlobalTab {
|
||||
property alias swipe: swipe
|
||||
tabs: ["General", "Hotkeys", "Game List"]
|
||||
|
||||
GlobalTabSwipeView {
|
||||
id: swipe
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
// TODO: platform-specific stuff
|
||||
UiGeneralPage {}
|
||||
Item {}
|
||||
UiGameListPage {}
|
||||
}
|
||||
}
|
17
src/eden/qml/config/pages/global/GlobalGraphicsPage.qml
Normal file
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
|
||||
import org.eden_emu.config
|
||||
|
||||
GlobalTab {
|
||||
property alias swipe: swipe
|
||||
tabs: ["Graphics", "Advanced", "Extensions"]
|
||||
|
||||
GlobalTabSwipeView {
|
||||
id: swipe
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
RendererPage {}
|
||||
RendererAdvancedPage {}
|
||||
RendererExtensionsPage {}
|
||||
}
|
||||
}
|
19
src/eden/qml/config/pages/global/GlobalSystemPage.qml
Normal file
|
@ -0,0 +1,19 @@
|
|||
import QtQuick
|
||||
|
||||
import org.eden_emu.config
|
||||
|
||||
GlobalTab {
|
||||
property alias swipe: swipe
|
||||
tabs: ["System", "Core", "Profiles", "Filesystem", "Applets"]
|
||||
|
||||
GlobalTabSwipeView {
|
||||
id: swipe
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
SystemGeneralPage {}
|
||||
SystemCorePage {}
|
||||
Item {}
|
||||
FileSystemPage {}
|
||||
AppletsPage {}
|
||||
}
|
||||
}
|
34
src/eden/qml/config/pages/global/GlobalTab.qml
Normal file
|
@ -0,0 +1,34 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
Item {
|
||||
required property list<string> tabs
|
||||
property alias tabBar: tabBar
|
||||
|
||||
TabBar {
|
||||
id: tabBar
|
||||
currentIndex: swipe.currentIndex
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: tabs
|
||||
|
||||
TabButton {
|
||||
font.pixelSize: 16 * Constants.scalar
|
||||
text: modelData
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: tabBar.Material.backgroundColor
|
||||
radius: 8 * Constants.scalar
|
||||
}
|
||||
}
|
||||
}
|
16
src/eden/qml/config/pages/global/GlobalTabSwipeView.qml
Normal file
|
@ -0,0 +1,16 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
SwipeView {
|
||||
anchors {
|
||||
top: tabBar.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
|
||||
leftMargin: 20 * Constants.scalar
|
||||
topMargin: 10 * Constants.scalar
|
||||
}
|
||||
}
|
17
src/eden/qml/config/pages/graphics/RendererAdvancedPage.qml
Normal file
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.RendererAdvanced
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.RendererExtensions
|
||||
}
|
||||
}
|
||||
}
|
17
src/eden/qml/config/pages/graphics/RendererPage.qml
Normal file
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.Renderer
|
||||
}
|
||||
}
|
||||
}
|
17
src/eden/qml/config/pages/system/AppletsPage.qml
Normal file
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.LibraryApplet
|
||||
}
|
||||
}
|
||||
}
|
17
src/eden/qml/config/pages/system/FileSystemPage.qml
Normal file
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.DataStorage
|
||||
}
|
||||
}
|
||||
}
|
17
src/eden/qml/config/pages/system/SystemCorePage.qml
Normal file
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.Core
|
||||
}
|
||||
}
|
||||
}
|
22
src/eden/qml/config/pages/system/SystemGeneralPage.qml
Normal file
|
@ -0,0 +1,22 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.config
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
ColumnLayout {
|
||||
width: scroll.width - scroll.effectiveScrollBarWidth
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.Network
|
||||
}
|
||||
|
||||
SettingsList {
|
||||
category: SettingsCategories.System
|
||||
idExclude: ["custom_rtc", "custom_rtc_offset", "current_user"]
|
||||
}
|
||||
}
|
||||
}
|
23
src/eden/qml/constants/CMakeLists.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Quick)
|
||||
|
||||
set_source_files_properties(Constants.qml
|
||||
PROPERTIES
|
||||
QT_QML_SINGLETON_TYPE true
|
||||
)
|
||||
|
||||
qt_add_library(edenConstants STATIC)
|
||||
qt_add_qml_module(edenConstants
|
||||
URI org.eden_emu.constants
|
||||
OUTPUT_DIRECTORY EdenConstants
|
||||
VERSION 1.0
|
||||
QML_FILES
|
||||
|
||||
Constants.qml
|
||||
)
|
||||
|
||||
target_link_libraries(edenConstants
|
||||
PRIVATE
|
||||
Qt6::Quick
|
||||
)
|
24
src/eden/qml/constants/Constants.qml
Normal file
|
@ -0,0 +1,24 @@
|
|||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
readonly property int width: 1200
|
||||
readonly property int height: 1000
|
||||
|
||||
property color accent: "#FF4444"
|
||||
property color accentPressed: "#ff5252"
|
||||
|
||||
readonly property color bg: "#111111"
|
||||
readonly property color dialog: "#222222"
|
||||
readonly property color dialogButton: "#000000"
|
||||
readonly property color sub: "#181818"
|
||||
|
||||
readonly property color button: "#1E1E1E"
|
||||
readonly property color buttonHighlighted: "#4A4A4A"
|
||||
|
||||
readonly property color text: "#EEEEEE"
|
||||
readonly property color subText: "#AAAAAA"
|
||||
|
||||
property real scalar: 1.0
|
||||
}
|
79
src/eden/qml/items/AnimatedDialog.qml
Normal file
|
@ -0,0 +1,79 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
Dialog {
|
||||
id: dia
|
||||
|
||||
property int preferredWidth: Overlay.overlay.width / 2
|
||||
property int preferredHeight: Overlay.overlay.height / 1.25
|
||||
|
||||
width: Math.min(preferredWidth, Overlay.overlay.width)
|
||||
height: Math.min(preferredHeight, Overlay.overlay.height)
|
||||
|
||||
property int radius: 12
|
||||
property bool colorful: false
|
||||
|
||||
anchors.centerIn: Overlay.overlay
|
||||
|
||||
enter: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
duration: 200
|
||||
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
}
|
||||
}
|
||||
|
||||
exit: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
duration: 200
|
||||
|
||||
from: 1.0
|
||||
to: 0.0
|
||||
}
|
||||
}
|
||||
|
||||
header: Rectangle {
|
||||
topLeftRadius: dia.radius
|
||||
topRightRadius: dia.radius
|
||||
|
||||
color: colorful ? Qt.alpha(Constants.accent, 0.5) : Constants.dialog
|
||||
|
||||
height: 50
|
||||
|
||||
Text {
|
||||
anchors.fill: parent
|
||||
font.pixelSize: Math.round(25)
|
||||
|
||||
text: title
|
||||
color: Constants.text
|
||||
|
||||
font.bold: true
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
radius: dia.radius
|
||||
|
||||
color: Constants.dialog
|
||||
}
|
||||
|
||||
footer: DialogButtonBox {
|
||||
id: control
|
||||
|
||||
background: Item {}
|
||||
|
||||
delegate: Button {
|
||||
id: btn
|
||||
}
|
||||
}
|
||||
Overlay.modal: Item {}
|
||||
Overlay.modeless: Item {}
|
||||
}
|
59
src/eden/qml/items/BetterMenu.qml
Normal file
|
@ -0,0 +1,59 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
Menu {
|
||||
background: Rectangle {
|
||||
implicitWidth: 200
|
||||
implicitHeight: 40
|
||||
color: Constants.button
|
||||
|
||||
radius: 10
|
||||
}
|
||||
|
||||
function fixAmpersands(originalText) {
|
||||
var regex = /&(\w)/g
|
||||
return originalText.replace(regex, "<u>$1</u>")
|
||||
}
|
||||
|
||||
delegate: MenuItem {
|
||||
id: control
|
||||
|
||||
font.pixelSize: 14
|
||||
|
||||
background: Rectangle {
|
||||
color: control.down || control.hovered
|
||||
|| control.highlighted ? Constants.buttonHighlighted : Constants.button
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
Text {
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: 5 + (control.checkable ? control.indicator.width : 0)
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
text: fixAmpersands(control.text)
|
||||
color: Constants.text
|
||||
font: control.font
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: 5
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Component.onCompleted: if (control.action != null
|
||||
&& typeof control.action.shortcut !== 'undefined')
|
||||
text = control.action.shortcut
|
||||
|
||||
color: Constants.text
|
||||
font: control.font
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
src/eden/qml/items/BetterMenuBar.qml
Normal file
|
@ -0,0 +1,33 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
MenuBar {
|
||||
background: Rectangle {
|
||||
implicitHeight: 30
|
||||
color: Constants.button
|
||||
}
|
||||
|
||||
function fixAmpersands(originalText) {
|
||||
var regex = /&(\w)/g
|
||||
return originalText.replace(regex, "<u>$1</u>")
|
||||
}
|
||||
|
||||
delegate: MenuBarItem {
|
||||
id: control
|
||||
|
||||
font.pixelSize: 16
|
||||
|
||||
background: Rectangle {
|
||||
color: control.down || control.hovered
|
||||
|| control.highlighted ? Constants.buttonHighlighted : Constants.button
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
text: fixAmpersands(control.text)
|
||||
color: Constants.text
|
||||
font: control.font
|
||||
}
|
||||
}
|
||||
}
|
22
src/eden/qml/items/CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
qt_add_library(edenItems STATIC)
|
||||
|
||||
qt_add_qml_module(edenItems
|
||||
URI org.eden_emu.items
|
||||
VERSION 1.0
|
||||
QML_FILES
|
||||
|
||||
StatusBarButton.qml
|
||||
BetterMenu.qml
|
||||
AnimatedDialog.qml
|
||||
BetterMenuBar.qml
|
||||
|
||||
SettingsTabButton.qml
|
||||
IconButton.qml
|
||||
QML_FILES VerticalTabBar.qml
|
||||
QML_FILES
|
||||
QML_FILES fields/BetterSpinBox.qml
|
||||
QML_FILES fields/BetterTextField.qml
|
||||
QML_FILES fields/FieldFooter.qml
|
||||
)
|
23
src/eden/qml/items/IconButton.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
Button {
|
||||
required property string label
|
||||
|
||||
bottomInset: 0
|
||||
topInset: 0
|
||||
leftPadding: 5 * Constants.scalar
|
||||
rightPadding: 5 * Constants.scalar
|
||||
|
||||
width: icon.width
|
||||
height: icon.height
|
||||
|
||||
icon.source: "qrc:/icons/" + label.toLowerCase() + ".svg"
|
||||
icon.width: 45
|
||||
icon.height: 45
|
||||
icon.color: Constants.text
|
||||
|
||||
background: Item {}
|
||||
}
|
40
src/eden/qml/items/SettingsTabButton.qml
Normal file
|
@ -0,0 +1,40 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
TabButton {
|
||||
required property string label
|
||||
|
||||
id: button
|
||||
|
||||
implicitHeight: 100 * Constants.scalar
|
||||
width: 95 * Constants.scalar
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
IconButton {
|
||||
label: button.label
|
||||
|
||||
Layout.maximumHeight: 60 * Constants.scalar
|
||||
Layout.maximumWidth: 65 * Constants.scalar
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
|
||||
onClicked: button.clicked()
|
||||
}
|
||||
|
||||
Text {
|
||||
font.pixelSize: 16 * Constants.scalar
|
||||
text: label
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
|
||||
color: Constants.text
|
||||
}
|
||||
}
|
||||
|
||||
// background: Rectangle {
|
||||
// color: button.Material.backgroundColor
|
||||
// }
|
||||
}
|
36
src/eden/qml/items/StatusBarButton.qml
Normal file
|
@ -0,0 +1,36 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
MouseArea {
|
||||
id: button
|
||||
|
||||
required property string text
|
||||
property color textColor: Constants.text
|
||||
|
||||
implicitHeight: 20
|
||||
implicitWidth: txt.width
|
||||
|
||||
hoverEnabled: true
|
||||
onHoveredChanged: rect.color = containsMouse ? Constants.buttonHighlighted : "transparent"
|
||||
|
||||
Rectangle {
|
||||
id: rect
|
||||
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
Text {
|
||||
id: txt
|
||||
|
||||
font.pixelSize: 12 * Constants.scalar
|
||||
leftPadding: 4
|
||||
rightPadding: 4
|
||||
|
||||
color: button.textColor
|
||||
text: button.text
|
||||
}
|
||||
}
|
||||
}
|
46
src/eden/qml/items/VerticalTabBar.qml
Normal file
|
@ -0,0 +1,46 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
TabBar {
|
||||
clip: true
|
||||
id: control
|
||||
|
||||
contentItem: ListView {
|
||||
model: control.contentModel
|
||||
currentIndex: control.currentIndex
|
||||
|
||||
spacing: control.spacing
|
||||
orientation: ListView.Vertical
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
flickableDirection: Flickable.AutoFlickIfNeeded
|
||||
snapMode: ListView.SnapToItem
|
||||
|
||||
highlightMoveDuration: 300
|
||||
highlightRangeMode: ListView.ApplyRange
|
||||
preferredHighlightBegin: 40
|
||||
preferredHighlightEnd: height - 40
|
||||
|
||||
highlight: Item {
|
||||
z: 2
|
||||
Rectangle {
|
||||
radius: 5 * Constants.scalar
|
||||
anchors {
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
height: parent.height / 2
|
||||
width: 5 * Constants.scalar
|
||||
|
||||
color: Constants.accent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: control.Material.backgroundColor
|
||||
radius: 8 * Constants.scalar
|
||||
}
|
||||
}
|
68
src/eden/qml/items/fields/BetterSpinBox.qml
Normal file
|
@ -0,0 +1,68 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Controls.impl
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
SpinBox {
|
||||
id: control
|
||||
property string label: ""
|
||||
|
||||
from: -0x7FFFFFFF
|
||||
to: 0x7FFFFFFF
|
||||
|
||||
contentItem: BetterTextField {
|
||||
text: parent.textFromValue(parent.value, parent.locale)
|
||||
|
||||
placeholderText: parent.label
|
||||
|
||||
width: parent.width
|
||||
|
||||
font: parent.font
|
||||
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
|
||||
inputMethodHints: Qt.ImhFormattedNumbersOnly
|
||||
|
||||
onEditingFinished: {
|
||||
control.value = parseFloat(text.replace(/,/g, ""))
|
||||
valueModified()
|
||||
}
|
||||
}
|
||||
|
||||
up.indicator: IconLabel {
|
||||
icon {
|
||||
source: "qrc:/icons/forward.svg"
|
||||
}
|
||||
|
||||
x: control.mirrored ? 0 : control.width - width
|
||||
|
||||
implicitWidth: 40 * Constants.scalar
|
||||
implicitHeight: 40 * Constants.scalar
|
||||
|
||||
height: parent.height
|
||||
width: height / 2
|
||||
}
|
||||
|
||||
down.indicator: IconLabel {
|
||||
icon {
|
||||
source: "qrc:/icons/back.svg"
|
||||
}
|
||||
|
||||
x: control.mirrored ? control.width - width : 0
|
||||
|
||||
implicitWidth: 40 * Constants.scalar
|
||||
implicitHeight: 40 * Constants.scalar
|
||||
|
||||
height: parent.height
|
||||
width: height / 2
|
||||
}
|
||||
background: Item {}
|
||||
|
||||
FieldFooter {
|
||||
anchors {
|
||||
bottom: contentItem.bottom
|
||||
}
|
||||
}
|
||||
}
|
38
src/eden/qml/items/fields/BetterTextField.qml
Normal file
|
@ -0,0 +1,38 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
import org.eden_emu.constants
|
||||
import org.eden_emu.items
|
||||
|
||||
TextField {
|
||||
property string suffix: ""
|
||||
|
||||
placeholderTextColor: enabled && activeFocus ? Constants.accent : Qt.darker(
|
||||
Constants.text, 1.3)
|
||||
|
||||
color: enabled ? Constants.text : Qt.darker(Constants.text, 1.5)
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
FieldFooter {}
|
||||
|
||||
horizontalAlignment: "AlignHCenter"
|
||||
|
||||
Text {
|
||||
id: txt
|
||||
text: suffix
|
||||
|
||||
font.pixelSize: 14 * Constants.scalar
|
||||
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
right: parent.right
|
||||
|
||||
rightMargin: 5 * Constants.scalar
|
||||
}
|
||||
|
||||
color: "gray"
|
||||
}
|
||||
}
|
20
src/eden/qml/items/fields/FieldFooter.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import org.eden_emu.constants
|
||||
|
||||
Rectangle {
|
||||
height: 2 * Constants.scalar
|
||||
color: enabled ? Constants.text : Qt.darker(Constants.text, 1.5)
|
||||
width: parent.width
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
}
|
18
src/eden/qml/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
qt_add_library(edenMain STATIC)
|
||||
qt_add_qml_module(edenMain
|
||||
URI org.eden_emu.main
|
||||
VERSION 1.0
|
||||
QML_FILES
|
||||
|
||||
Main.qml
|
||||
StatusBar.qml
|
||||
GameList.qml
|
||||
GameGridCard.qml
|
||||
MarqueeText.qml
|
||||
GameGrid.qml
|
||||
|
||||
GameCarouselCard.qml
|
||||
GameCarousel.qml
|
||||
)
|
94
src/eden/qml/main/GameCarousel.qml
Normal file
|
@ -0,0 +1,94 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Qt.labs.platform
|
||||
import QtCore
|
||||
|
||||
import org.eden_emu.constants
|
||||
import org.eden_emu.interface
|
||||
|
||||
ListView {
|
||||
id: carousel
|
||||
|
||||
focus: true
|
||||
focusPolicy: Qt.StrongFocus
|
||||
|
||||
model: EdenGameList
|
||||
orientation: ListView.Horizontal
|
||||
clip: false
|
||||
flickDeceleration: 1000
|
||||
snapMode: ListView.SnapToItem
|
||||
|
||||
onHeightChanged: console.log(width, height)
|
||||
|
||||
spacing: 20
|
||||
|
||||
Keys.enabled: true
|
||||
Keys.onRightPressed: incrementCurrentIndex()
|
||||
Keys.onLeftPressed: decrementCurrentIndex()
|
||||
|
||||
onCurrentIndexChanged: scrollToCenter()
|
||||
|
||||
highlight: Rectangle {
|
||||
id: hg
|
||||
clip: false
|
||||
z: 3
|
||||
|
||||
color: "transparent"
|
||||
border {
|
||||
color: "deepskyblue"
|
||||
width: 4 * Constants.scalar
|
||||
}
|
||||
|
||||
radius: 8 * Constants.scalar
|
||||
|
||||
// TODO: marquee
|
||||
Text {
|
||||
function toTitleCase(str) {
|
||||
return str.replace(/\w\S*/g, text => text.charAt(0).toUpperCase(
|
||||
) + text.substring(1).toLowerCase())
|
||||
}
|
||||
|
||||
property var item: carousel.currentItem
|
||||
|
||||
text: toTitleCase(item.title)
|
||||
font.pixelSize: 22 * Constants.scalar
|
||||
color: "lightblue"
|
||||
|
||||
anchors {
|
||||
bottom: hg.top
|
||||
|
||||
bottomMargin: 10 * Constants.scalar
|
||||
left: hg.left
|
||||
right: hg.right
|
||||
}
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
highlightFollowsCurrentItem: true
|
||||
highlightMoveDuration: 300
|
||||
highlightMoveVelocity: -1
|
||||
|
||||
delegate: GameCarouselCard {
|
||||
id: game
|
||||
width: 300
|
||||
height: 300
|
||||
}
|
||||
|
||||
function scrollToCenter() {
|
||||
let targetX = currentIndex * 320 - (width - 320) / 2
|
||||
let min = 0
|
||||
let max = contentWidth
|
||||
|
||||
contentX = Math.max(min, Math.min(max, targetX))
|
||||
}
|
||||
|
||||
Behavior on contentX {
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
}
|
44
src/eden/qml/main/GameGrid.qml
Normal file
|
@ -0,0 +1,44 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Qt.labs.platform
|
||||
import QtCore
|
||||
|
||||
import org.eden_emu.constants
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.gamepad
|
||||
|
||||
GridView {
|
||||
property var setting
|
||||
id: grid
|
||||
|
||||
property int cellSize: Math.floor(width / setting.value)
|
||||
|
||||
highlightFollowsCurrentItem: true
|
||||
clip: true
|
||||
|
||||
cellWidth: cellSize
|
||||
cellHeight: cellSize + 60 * Constants.scalar
|
||||
|
||||
model: EdenGameList
|
||||
|
||||
delegate: GameGridCard {
|
||||
id: game
|
||||
|
||||
width: grid.cellSize - 20 * Constants.scalar
|
||||
height: grid.cellHeight - 20 * Constants.scalar
|
||||
}
|
||||
|
||||
highlight: Rectangle {
|
||||
color: "transparent"
|
||||
z: 5
|
||||
|
||||
radius: 16 * Constants.scalar
|
||||
border {
|
||||
color: Constants.text
|
||||
width: 3
|
||||
}
|
||||
}
|
||||
|
||||
focus: true
|
||||
focusPolicy: "StrongFocus"
|
||||
}
|
77
src/eden/qml/main/GameGridCard.qml
Normal file
|
@ -0,0 +1,77 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Qt.labs.platform
|
||||
import QtCore
|
||||
|
||||
import org.eden_emu.constants
|
||||
|
||||
Rectangle {
|
||||
id: wrapper
|
||||
|
||||
color: Constants.dialog
|
||||
radius: 16 * Constants.scalar
|
||||
|
||||
Image {
|
||||
id: image
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "file://" + model.path
|
||||
|
||||
clip: true
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
|
||||
margins: 4 * Constants.scalar
|
||||
}
|
||||
|
||||
height: parent.height - 40 * Constants.scalar
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
hoverEnabled: true
|
||||
|
||||
z: 3
|
||||
|
||||
x: (parent.width - parent.paintedWidth) / 2
|
||||
y: (parent.height - parent.paintedHeight) / 2
|
||||
|
||||
width: parent.paintedWidth
|
||||
height: parent.paintedHeight
|
||||
|
||||
onContainsMouseChanged: {
|
||||
if (containsMouse) {
|
||||
wrapper.GridView.view.currentIndex = index
|
||||
wrapper.GridView.view.focus = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: nameText
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 5 * Constants.scalar
|
||||
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
style: Text.Outline
|
||||
styleColor: Constants.bg
|
||||
|
||||
text: model.name.replace(/-/g, " ")
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
|
||||
font {
|
||||
pixelSize: 15 * Constants.scalar
|
||||
}
|
||||
|
||||
color: "white"
|
||||
}
|
||||
}
|
131
src/eden/qml/main/GameList.qml
Normal file
|
@ -0,0 +1,131 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Qt.labs.platform
|
||||
import QtCore
|
||||
|
||||
import org.eden_emu.constants
|
||||
import org.eden_emu.interface
|
||||
import org.eden_emu.gamepad
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var setting: SettingsInterface.setting("grid_columns")
|
||||
|
||||
property int gx: 0
|
||||
property int gy: 0
|
||||
|
||||
readonly property int deadzone: 8000
|
||||
readonly property int repeatTimeMs: 125
|
||||
|
||||
color: Constants.bg
|
||||
|
||||
// TODO: use the original yuzu backend for dis
|
||||
Gamepad {
|
||||
id: gamepad
|
||||
|
||||
// onUpPressed: grid.moveCurrentIndexUp()
|
||||
// onDownPressed: grid.moveCurrentIndexDown()
|
||||
// onLeftPressed: grid.moveCurrentIndexLeft()
|
||||
// onRightPressed: grid.moveCurrentIndexRight()
|
||||
onLeftPressed: carousel.decrementCurrentIndex()
|
||||
onRightPressed: carousel.incrementCurrentIndex()
|
||||
onAPressed: console.log("A pressed")
|
||||
onLeftStickMoved: (x, y) => {
|
||||
gx = x
|
||||
gy = y
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: repeatTimeMs
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (gx > deadzone) {
|
||||
gamepad.rightPressed()
|
||||
} else if (gx < -deadzone) {
|
||||
gamepad.leftPressed()
|
||||
}
|
||||
|
||||
if (gy > deadzone) {
|
||||
gamepad.downPressed()
|
||||
} else if (gy < -deadzone) {
|
||||
gamepad.upPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
interval: 16
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: gamepad.pollEvents()
|
||||
}
|
||||
FolderDialog {
|
||||
id: openDir
|
||||
folder: StandardPaths.writableLocation(StandardPaths.HomeLocation)
|
||||
onAccepted: {
|
||||
button.visible = false
|
||||
view.anchors.bottom = root.bottom
|
||||
EdenGameList.addDir(folder)
|
||||
}
|
||||
}
|
||||
|
||||
// GameGrid {
|
||||
// setting: parent.setting
|
||||
|
||||
// id: grid
|
||||
|
||||
// anchors.bottom: button.top
|
||||
// anchors.left: parent.left
|
||||
// anchors.margins: 8
|
||||
// anchors.right: parent.right
|
||||
// anchors.top: parent.top
|
||||
// }
|
||||
Item {
|
||||
id: view
|
||||
|
||||
anchors {
|
||||
bottom: button.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
margins: 8 * Constants.scalar
|
||||
}
|
||||
|
||||
GameCarousel {
|
||||
id: carousel
|
||||
|
||||
height: 300
|
||||
|
||||
anchors {
|
||||
right: view.right
|
||||
left: view.left
|
||||
|
||||
verticalCenter: view.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: button
|
||||
font.pixelSize: 25
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
|
||||
bottom: parent.bottom
|
||||
|
||||
margins: 8
|
||||
}
|
||||
|
||||
text: "Add Directory"
|
||||
onClicked: openDir.open()
|
||||
|
||||
background: Rectangle {
|
||||
color: button.pressed ? Constants.accentPressed : Constants.accent
|
||||
radius: 5
|
||||
}
|
||||
}
|
||||
}
|
207
src/eden/qml/main/Main.qml
Normal file
|
@ -0,0 +1,207 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
import org.eden_emu.config
|
||||
import org.eden_emu.items
|
||||
import org.eden_emu.constants
|
||||
|
||||
ApplicationWindow {
|
||||
width: Constants.width
|
||||
height: Constants.height
|
||||
visible: true
|
||||
title: qsTr("eden")
|
||||
|
||||
Material.theme: Material.Dark
|
||||
Material.accent: Material.Red
|
||||
|
||||
Material.roundedScale: Material.NotRounded
|
||||
|
||||
GameList {
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: status.top
|
||||
}
|
||||
}
|
||||
|
||||
/** Dialogs */
|
||||
GlobalConfigureDialog {
|
||||
id: globalConfig
|
||||
}
|
||||
|
||||
menuBar: BetterMenuBar {
|
||||
BetterMenu {
|
||||
title: qsTr("&File")
|
||||
contentWidth: 225
|
||||
|
||||
Action {
|
||||
text: qsTr("&Install files to NAND...")
|
||||
}
|
||||
MenuSeparator {}
|
||||
|
||||
Action {
|
||||
text: qsTr("L&oad File...")
|
||||
shortcut: "Ctrl+O"
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Load &Folder...")
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
BetterMenu {
|
||||
title: "&Recent Files"
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
Action {
|
||||
text: qsTr("Load/Remove &Amiibo...")
|
||||
shortcut: "F2"
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
Action {
|
||||
text: qsTr("Open &eden Directory")
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
Action {
|
||||
text: qsTr("E&xit")
|
||||
shortcut: "Ctrl+Q"
|
||||
}
|
||||
}
|
||||
BetterMenu {
|
||||
title: qsTr("&Emulation")
|
||||
contentWidth: 240
|
||||
|
||||
Action {
|
||||
text: qsTr("&Pause")
|
||||
shortcut: "F4"
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("&Stop")
|
||||
shortcut: "F5"
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("&Restart")
|
||||
shortcut: "F6"
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
Action {
|
||||
text: qsTr("Con&figure...")
|
||||
shortcut: "Ctrl+,"
|
||||
onTriggered: globalConfig.open()
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Configure &Current Game...")
|
||||
shortcut: "Ctrl+."
|
||||
}
|
||||
}
|
||||
|
||||
BetterMenu {
|
||||
title: qsTr("&View")
|
||||
contentWidth: 260
|
||||
|
||||
Action {
|
||||
text: qsTr("F&ullscreen")
|
||||
shortcut: "F11"
|
||||
checkable: true
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Single &Window Mode")
|
||||
checkable: true
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Display D&ock Widget Headers")
|
||||
checkable: true
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Show &Filter Bar")
|
||||
shortcut: "Ctrl+F"
|
||||
checkable: true
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Show &Status Bar")
|
||||
shortcut: "Ctrl+S"
|
||||
checkable: true
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
}
|
||||
|
||||
BetterMenu {
|
||||
title: qsTr("&Tools")
|
||||
contentWidth: 225
|
||||
|
||||
Action {
|
||||
text: qsTr("Install &Decryption Keys")
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Install &Firmware")
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("&Verify Installed Contents")
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
BetterMenu {
|
||||
title: qsTr("&Amiibo")
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Open A&lbum")
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Open &Mii Editor")
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Open Co&ntroller Menu")
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Open &Home Menu")
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
Action {
|
||||
text: qsTr("&Capture Screenshot")
|
||||
shortcut: "Ctrl+P"
|
||||
}
|
||||
|
||||
BetterMenu {
|
||||
title: "&TAS"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusBar {
|
||||
id: status
|
||||
|
||||
height: 30
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
}
|
43
src/eden/qml/main/MarqueeText.qml
Normal file
|
@ -0,0 +1,43 @@
|
|||
import QtQuick
|
||||
|
||||
Item {
|
||||
required property string text
|
||||
|
||||
property int spacing: 30
|
||||
property int startDelay: 2000
|
||||
property int speed: 40
|
||||
|
||||
property alias font: t1.font
|
||||
property alias color: t1.color
|
||||
|
||||
id: root
|
||||
|
||||
width: t1.width + spacing
|
||||
height: t1.height
|
||||
clip: true
|
||||
|
||||
Text {
|
||||
id: t1
|
||||
|
||||
SequentialAnimation on x {
|
||||
loops: Animation.Infinite
|
||||
running: true
|
||||
|
||||
PauseAnimation {
|
||||
duration: root.startDelay
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
from: root.width
|
||||
to: -t1.width
|
||||
duration: (root.width + t1.width) * 1000 / root.speed
|
||||
easing.type: Easing.Linear
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
x: root.width
|
||||
text: t1.text
|
||||
}
|
||||
}
|
||||
}
|
160
src/eden/qml/main/StatusBar.qml
Normal file
|
@ -0,0 +1,160 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.eden_emu.constants
|
||||
import org.eden_emu.items
|
||||
|
||||
ToolBar {
|
||||
id: toolbar
|
||||
|
||||
property string graphicsBackend: "vulkan"
|
||||
property string gpuAccuracy: "high"
|
||||
property string consoleMode: "docked"
|
||||
property int adapting: 5
|
||||
property int antialiasing: 0
|
||||
property int volume: 100
|
||||
|
||||
property string firmwareVersion: "16.0.3"
|
||||
|
||||
implicitHeight: 30
|
||||
|
||||
background: Rectangle {
|
||||
color: Constants.bg
|
||||
}
|
||||
|
||||
// TODO: reduce duplicate code
|
||||
RowLayout {
|
||||
id: row
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
|
||||
leftMargin: 10
|
||||
}
|
||||
|
||||
StatusBarButton {
|
||||
property alias value: toolbar.graphicsBackend
|
||||
|
||||
text: value.toUpperCase()
|
||||
|
||||
textColor: value === "vulkan" ? "orange" : "lightblue"
|
||||
|
||||
onClicked: {
|
||||
if (value === "vulkan") {
|
||||
value = "opengl"
|
||||
} else {
|
||||
value = "vulkan"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusBarButton {
|
||||
property alias value: toolbar.gpuAccuracy
|
||||
|
||||
text: value.toUpperCase()
|
||||
|
||||
textColor: value === "high" ? "orange" : "lightgreen"
|
||||
|
||||
onClicked: {
|
||||
if (value === "high") {
|
||||
value = "normal"
|
||||
} else {
|
||||
value = "high"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusBarButton {
|
||||
property alias value: toolbar.consoleMode
|
||||
|
||||
text: value.toUpperCase()
|
||||
|
||||
textColor: Constants.text
|
||||
|
||||
onClicked: {
|
||||
if (value === "docked") {
|
||||
value = "handheld"
|
||||
} else {
|
||||
value = "docked"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusBarButton {
|
||||
property list<string> choices: ["nearest", "bilinear", "bicubic", "gaussian", "scaleforce", "fsr"]
|
||||
|
||||
property alias index: toolbar.adapting
|
||||
property string value: choices[index]
|
||||
|
||||
text: value.toUpperCase()
|
||||
|
||||
onClicked: {
|
||||
let newIndex = index + 1
|
||||
if (newIndex >= choices.length) {
|
||||
newIndex = 0
|
||||
}
|
||||
|
||||
index = newIndex
|
||||
}
|
||||
}
|
||||
|
||||
StatusBarButton {
|
||||
property list<string> choices: ["no aa", "fxaa", "msaa"]
|
||||
|
||||
property alias index: toolbar.antialiasing
|
||||
property string value: choices[index]
|
||||
|
||||
text: value.toUpperCase()
|
||||
|
||||
onClicked: {
|
||||
let newIndex = index + 1
|
||||
if (newIndex >= choices.length) {
|
||||
newIndex = 0
|
||||
}
|
||||
|
||||
index = newIndex
|
||||
}
|
||||
}
|
||||
|
||||
StatusBarButton {
|
||||
id: volumeButton
|
||||
|
||||
property alias value: toolbar.volume
|
||||
|
||||
text: "VOLUME: " + value + "%"
|
||||
|
||||
onClicked: {
|
||||
volumeSlider.open()
|
||||
}
|
||||
|
||||
onWheel: wheel => {
|
||||
value += wheel.angleDelta.y / 120
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Popup {
|
||||
id: volumeSlider
|
||||
|
||||
width: 200
|
||||
height: 50
|
||||
|
||||
x: volumeButton.x
|
||||
y: volumeButton.y - height
|
||||
|
||||
focus: true
|
||||
|
||||
Slider {
|
||||
value: volumeButton.value
|
||||
onMoved: volumeButton.value = value
|
||||
|
||||
from: 0
|
||||
to: 200
|
||||
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
}
|